@alteriom/painlessmesh 1.8.15 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BRIDGE_TO_INTERNET.md +229 -0
- package/CHANGELOG.md +61 -1
- package/CONTRIBUTING.md +79 -0
- package/README.md +69 -144
- package/docs/README.md +1 -0
- package/docs/api/shared-gateway.md +1207 -0
- package/examples/bridge_failover/README.md +81 -0
- package/examples/bridge_failover/bridge_failover.ino +35 -4
- package/examples/sharedGateway/README.md +235 -0
- package/examples/{meshCommandNode → sharedGateway}/platformio.ini +3 -2
- package/examples/sharedGateway/sharedGateway.ino +303 -0
- package/library.json +3 -22
- package/library.properties +1 -1
- package/package.json +3 -6
- package/src/arduino/wifi.hpp +342 -4
- package/src/painlessmesh/gateway.hpp +2120 -0
- package/src/painlessmesh/mesh.hpp +1034 -6
- package/src/painlessmesh/message_tracker.hpp +311 -0
- package/src/painlessmesh/protocol.hpp +6 -0
- package/DOCUMENTATION_INDEX.md +0 -146
- package/RELEASE_NOTES_1.8.15.md +0 -160
- package/RELEASE_READINESS_PLAN.md +0 -323
- package/TESTING_WITH_SIMULATOR.md +0 -259
- package/docs/API_DESIGN_GUIDELINES.md +0 -414
- package/docs/ARDUINO_LIBRARY_MANAGER_SUBMISSION.md +0 -331
- package/docs/BOOLEAN_NAMING_CONVENTION.md +0 -235
- package/docs/BRIDGE_FAILOVER.md +0 -512
- package/docs/BRIDGE_HEALTH_MONITORING.md +0 -293
- package/docs/BRIDGE_INITIALIZATION_FALLBACK.md +0 -357
- package/docs/CHANNEL_SYNCHRONIZATION.md +0 -209
- package/docs/CREATE_MISSING_RELEASES.md +0 -321
- package/docs/DOCUMENTATION_MIGRATION_PLAN.md +0 -176
- package/docs/FAQ_VERSION_NUMBERS.md +0 -152
- package/docs/IMPLEMENTATION_PLAN_MESH_TOPOLOGY.md +0 -1062
- package/docs/MESH_TOPOLOGY_GUIDE.md +0 -992
- package/docs/MESH_TOPOLOGY_PROGRESS.md +0 -422
- package/docs/MQTT_BRIDGE_COMMANDS.md +0 -894
- package/docs/MQTT_BRIDGE_IMPLEMENTATION_SUMMARY.md +0 -324
- package/docs/MQTT_COMMAND_SCHEMA_PROPOSAL.md +0 -576
- package/docs/MQTT_SCHEMA_COMPLIANCE.md +0 -340
- package/docs/MQTT_SCHEMA_PROPOSALS.md +0 -446
- package/docs/MQTT_SCHEMA_REVIEW.md +0 -690
- package/docs/OTA_COMMANDS_REFERENCE.md +0 -554
- package/docs/PHASE1_GUIDE.md +0 -349
- package/docs/PHASE2_GUIDE.md +0 -543
- package/docs/QUICK_REFERENCE_VERSIONING.md +0 -127
- package/docs/RELEASE_AGENT_SUMMARY.md +0 -386
- package/docs/SCHEMA_VALIDATION_CHECKLIST.md +0 -222
- package/docs/SIMULATOR_TESTING.md +0 -408
- package/docs/VERSION_MANAGEMENT.md +0 -213
- package/docs/archive/DOCUSAURUS_DEPLOYMENT.md +0 -166
- package/docs/archive/FEATURE_PROPOSALS.md +0 -337
- package/docs/archive/LIBRARY_JSON_FIX.md +0 -98
- package/docs/archive/LIBRARY_STRUCTURE_FIX.md +0 -215
- package/docs/archive/PHASE1_IMPLEMENTATION.md +0 -325
- package/docs/archive/PHASE2_IMPLEMENTATION.md +0 -567
- package/docs/archive/RELEASE_SUMMARY.md +0 -173
- package/docs/archive/SCONS_BUILD_FIX.md +0 -313
- package/docs/archive/TRIGGER_RELEASE.md +0 -280
- package/docs/archive/VECTOR_INCLUDE_FIX.md +0 -129
- package/docs/archive/ota-and-status-enhancements.md +0 -911
- package/docs/archive/ota-status-architecture-diagrams.md +0 -658
- package/docs/archive/ota-status-quick-reference.md +0 -284
- package/docs/design/.gitkeep +0 -1
- package/docs/design/STATION_CREDENTIALS_DESIGN.md +0 -182
- package/docs/development/ARDUINO_COMPLIANCE_SUMMARY.md +0 -71
- package/docs/development/CODE_REFACTORING_RECOMMENDATIONS.md +0 -1011
- package/docs/development/DOCKER_TESTING.md +0 -196
- package/docs/development/PLATFORMIO_USAGE.md +0 -180
- package/docs/development/TESTING_SUMMARY.md +0 -126
- package/docs/development/contributing.md +0 -301
- package/docs/development/documentation.md +0 -583
- package/docs/features/DIAGNOSTICS_API.md +0 -534
- package/docs/implementation/BRIDGE_ARCHITECTURE_IMPLEMENTATION.md +0 -340
- package/docs/implementation/BRIDGE_HEALTH_MONITORING_IMPLEMENTATION.md +0 -213
- package/docs/implementation/BRIDGE_STATUS_FEATURE.md +0 -635
- package/docs/implementation/DIAGNOSTICS_API_IMPLEMENTATION.md +0 -232
- package/docs/implementation/IMPLEMENTATION_COMPLETE.md +0 -228
- package/docs/implementation/IMPLEMENTATION_NTP_TIME_SYNC.md +0 -325
- package/docs/implementation/IMPLEMENTATION_SUMMARY.md +0 -316
- package/docs/implementation/MESSAGE_QUEUE_IMPLEMENTATION.md +0 -405
- package/docs/implementation/MULTI_BRIDGE_IMPLEMENTATION.md +0 -520
- package/docs/implementation/NTP_TIME_SYNC_FEATURE.md +0 -392
- package/docs/improvements/FUTURE_PROPOSALS.md +0 -1016
- package/docs/improvements/IMPLEMENTATION_HISTORY.md +0 -1091
- package/docs/improvements/OTA_STATUS_ENHANCEMENTS.md +0 -709
- package/docs/improvements/README.md +0 -212
- package/docs/internal/CUSTOM_AGENT_ANALYSIS.md +0 -391
- package/docs/internal/ISSUE_65_VERIFICATION.md +0 -947
- package/docs/internal/ISSUE_66_CLOSURE.md +0 -249
- package/docs/internal/ISSUE_66_STATUS.md +0 -316
- package/docs/internal/PR_SUMMARY.md +0 -315
- package/docs/internal/REVIEW_SUMMARY.md +0 -332
- package/docs/multi-bridge-setup.md +0 -1025
- package/docs/platformio-publishing.md +0 -255
- package/docs/platformio-setup-summary.md +0 -121
- package/docs/releases/ANNOUNCEMENT_v1.8.6.md +0 -63
- package/docs/releases/ANNOUNCEMENT_v1.8.7.md +0 -113
- package/docs/releases/BRIDGE_STATUS_SELF_REGISTRATION_FIX.md +0 -221
- package/docs/releases/FEATURE_HISTORY.md +0 -543
- package/docs/releases/GITHUB_RELEASE_v1.8.6.md +0 -71
- package/docs/releases/GITHUB_RELEASE_v1.8.7.md +0 -90
- package/docs/releases/PATCH_v1.7.2.md +0 -262
- package/docs/releases/PATCH_v1.7.3.md +0 -262
- package/docs/releases/PATCH_v1.7.4.md +0 -219
- package/docs/releases/PHASE1_SUMMARY.md +0 -246
- package/docs/releases/PHASE2_SUMMARY.md +0 -499
- package/docs/releases/PUBLISH_v1.8.0_INSTRUCTIONS.md +0 -163
- package/docs/releases/QUICK_START_RELEASES.md +0 -113
- package/docs/releases/RELEASE_CHECKLIST_1.8.10.md +0 -331
- package/docs/releases/RELEASE_CHECKLIST_1.8.9.md +0 -207
- package/docs/releases/RELEASE_CHECKLIST_v1.7.4.md +0 -253
- package/docs/releases/RELEASE_CHECKLIST_v1.7.5.md +0 -315
- package/docs/releases/RELEASE_CHECKLIST_v1.7.6.md +0 -389
- package/docs/releases/RELEASE_CHECKLIST_v1.8.0.md +0 -331
- package/docs/releases/RELEASE_CHECKLIST_v1.8.2.md +0 -309
- package/docs/releases/RELEASE_NOTES_1.7.0.md +0 -539
- package/docs/releases/RELEASE_NOTES_1.8.10.md +0 -239
- package/docs/releases/RELEASE_NOTES_1.8.9.md +0 -213
- package/docs/releases/RELEASE_NOTES_v1.8.0.md +0 -685
- package/docs/releases/RELEASE_NOTES_v1.8.1.md +0 -221
- package/docs/releases/RELEASE_NOTES_v1.8.2.md +0 -421
- package/docs/releases/RELEASE_NOTES_v1.8.3.md +0 -292
- package/docs/releases/RELEASE_NOTES_v1.8.4.md +0 -277
- package/docs/releases/RELEASE_NOTES_v1.8.6.md +0 -205
- package/docs/releases/RELEASE_NOTES_v1.8.7.md +0 -184
- package/docs/releases/RELEASE_PLAN_v1.7.6.md +0 -816
- package/docs/releases/RELEASE_SUMMARY_1.8.10.md +0 -193
- package/docs/releases/RELEASE_SUMMARY_v1.7.4.md +0 -276
- package/docs/releases/RELEASE_SUMMARY_v1.7.5.md +0 -322
- package/docs/releases/RELEASE_SUMMARY_v1.7.6.md +0 -436
- package/docs/releases/RELEASE_SUMMARY_v1.7.7.md +0 -391
- package/docs/releases/RELEASE_SUMMARY_v1.7.8.md +0 -523
- package/docs/releases/RELEASE_SUMMARY_v1.7.9.md +0 -542
- package/docs/troubleshooting/ARDUINO_IDE_VERSION_FIX_SUMMARY.md +0 -229
- package/docs/troubleshooting/ARDUINO_LIBRARY_NAME_FIX.md +0 -197
- package/docs/troubleshooting/CRASH_QUICK_REF.md +0 -93
- package/docs/troubleshooting/ESP32_C6_COMPATIBILITY.md +0 -157
- package/docs/troubleshooting/FREERTOS_ASSERTION_FAILURE.md +0 -288
- package/docs/troubleshooting/FREERTOS_FIX_IMPLEMENTATION.md +0 -267
- package/docs/troubleshooting/NPM_PUBLISHING_ISSUE_SUMMARY.md +0 -110
- package/docs/troubleshooting/PAINLESSMESH_V1.7.4_COMPILATION_ISSUES.md +0 -547
- package/docs/troubleshooting/QUICK_FIX_FREERTOS.md +0 -164
- package/docs/troubleshooting/SENSOR_NODE_CONNECTION_CRASH.md +0 -264
- package/docs/troubleshooting/common-architecture-mistakes.md +0 -438
- package/docs/troubleshooting/internet-access-faq.md +0 -299
- package/docs/troubleshooting/station-reconnection-issues.md +0 -172
- package/docs/v1.7.7_MQTT_IMPROVEMENTS.md +0 -794
- package/docs/wiki/API-Reference.md +0 -246
- package/docs/wiki/Complete-Documentation.md +0 -123
- package/examples/alteriomImproved/alteriom_sensor_package.hpp +0 -224
- package/examples/alteriomImproved/improved_sensor_node.ino +0 -248
- package/examples/alteriomImproved/platformio.ini +0 -32
- package/examples/alteriomMetricsHealth/alteriom_sensor_package.hpp +0 -796
- package/examples/alteriomMetricsHealth/metrics_health_node.ino +0 -429
- package/examples/alteriomMetricsHealth/platformio.ini +0 -26
- package/examples/alteriomPhase1/alteriom_sensor_package.hpp +0 -224
- package/examples/alteriomPhase1/phase1_features.ino +0 -242
- package/examples/alteriomPhase1/platformio.ini +0 -26
- package/examples/alteriomPhase2/alteriom_sensor_package.hpp +0 -224
- package/examples/alteriomPhase2/phase2_features.ino +0 -186
- package/examples/alteriomPhase2/platformio.ini +0 -26
- package/examples/alteriomSensorNode/alteriom_sensor_node.ino +0 -186
- package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +0 -1227
- package/examples/alteriomSensorNode/platformio.ini +0 -26
- package/examples/bridge/alteriom_sensor_package.hpp +0 -1170
- package/examples/bridge/bridge_health_monitoring_example.ino +0 -188
- package/examples/bridge/enhanced_mqtt_bridge.hpp +0 -610
- package/examples/bridge/enhanced_mqtt_bridge_example.ino +0 -226
- package/examples/bridge/mesh_event_publisher.hpp +0 -253
- package/examples/bridge/mesh_topology_reporter.hpp +0 -303
- package/examples/bridge/mqtt_command_bridge.hpp +0 -459
- package/examples/bridge/mqtt_status_bridge.hpp +0 -519
- package/examples/bridgeAwareSensorNode/alteriom_sensor_package.hpp +0 -1227
- package/examples/bridgeAwareSensorNode/bridgeAwareSensorNode.ino +0 -342
- package/examples/bridgeAwareSensorNode/platformio.ini +0 -26
- package/examples/diagnosticsExample/diagnosticsExample.ino +0 -171
- package/examples/diagnosticsExample/platformio.ini +0 -26
- package/examples/echoNode/echoNode.ino +0 -33
- package/examples/echoNode/platformio.ini +0 -26
- package/examples/meshCommandNode/alteriom_sensor_package.hpp +0 -235
- package/examples/meshCommandNode/meshCommandNode.ino +0 -265
- package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +0 -235
- package/examples/mqttCommandBridge/mesh_event_publisher.hpp +0 -253
- package/examples/mqttCommandBridge/mesh_topology_reporter.hpp +0 -303
- package/examples/mqttCommandBridge/mqttCommandBridge.ino +0 -254
- package/examples/mqttCommandBridge/mqtt_command_bridge.hpp +0 -462
- package/examples/mqttCommandBridge/platformio.ini +0 -27
- package/examples/mqttStatusBridge/mqttStatusBridge.ino +0 -218
- package/examples/mqttStatusBridge/mqtt_status_bridge.hpp +0 -522
- package/examples/mqttStatusBridge/platformio.ini +0 -27
- package/examples/mqttTopologyTest/README.md +0 -467
- package/examples/mqttTopologyTest/mqttTopologyTest.ino +0 -754
- package/examples/mqttTopologyTest/platformio.ini +0 -27
- package/examples/multi_bridge/README.md +0 -346
- package/examples/multi_bridge/primary_bridge.ino +0 -108
- package/examples/multi_bridge/regular_node.ino +0 -141
- package/examples/multi_bridge/secondary_bridge.ino +0 -123
- package/examples/ntpTimeSyncBridge/alteriom_sensor_package.hpp +0 -1383
- package/examples/ntpTimeSyncBridge/ntpTimeSyncBridge.ino +0 -86
- package/examples/ntpTimeSyncNode/alteriom_sensor_package.hpp +0 -1383
- package/examples/ntpTimeSyncNode/ntpTimeSyncNode.ino +0 -109
- package/examples/queued_alarms/README.md +0 -390
- package/examples/queued_alarms/queued_alarms.ino +0 -265
- package/examples/routing_demo/README.md +0 -172
- package/examples/routing_demo/routing_demo.ino +0 -102
- package/examples/rtcIntegration/README.md +0 -294
- package/examples/rtcIntegration/rtcIntegration.ino +0 -210
|
@@ -1,414 +0,0 @@
|
|
|
1
|
-
# API Design Guidelines for Alteriom Packages
|
|
2
|
-
|
|
3
|
-
This document provides guidelines for designing consistent and maintainable JSON configuration structures in Alteriom packages, particularly for StatusPackage and related message types.
|
|
4
|
-
|
|
5
|
-
## Table of Contents
|
|
6
|
-
|
|
7
|
-
- [Overview](#overview)
|
|
8
|
-
- [Nesting vs Flat Structure Guidelines](#nesting-vs-flat-structure-guidelines)
|
|
9
|
-
- [Current Structure Patterns](#current-structure-patterns)
|
|
10
|
-
- [Decision Tree](#decision-tree)
|
|
11
|
-
- [Examples](#examples)
|
|
12
|
-
- [Best Practices](#best-practices)
|
|
13
|
-
|
|
14
|
-
## Overview
|
|
15
|
-
|
|
16
|
-
Alteriom packages use JSON serialization for configuration and status data. This document establishes clear patterns for when to use nested structures versus flat key-value pairs to ensure consistency and maintainability across the codebase.
|
|
17
|
-
|
|
18
|
-
**Related Issues:**
|
|
19
|
-
- [Issue #28](https://github.com/Alteriom/painlessMesh/issues/28) - Inconsistent Nested vs Flat Configuration Structure
|
|
20
|
-
- [Issue #29](https://github.com/Alteriom/painlessMesh/issues/29) - Inconsistent Optional vs Required Field Serialization Pattern
|
|
21
|
-
- [PR #36](https://github.com/Alteriom/painlessMesh/pull/36) - Documented nesting patterns (this file)
|
|
22
|
-
- [PR #37](https://github.com/Alteriom/painlessMesh/pull/37) - Removed conditional serialization for predictable JSON structure
|
|
23
|
-
|
|
24
|
-
### Key Principles
|
|
25
|
-
|
|
26
|
-
1. **Consistency over perfection** - Follow existing patterns in similar sections
|
|
27
|
-
2. **Simplicity by default** - Use flat structures unless nesting provides clear benefits
|
|
28
|
-
3. **Future-proof** - Consider extensibility when designing structures
|
|
29
|
-
4. **Clarity** - Structure should reflect logical grouping
|
|
30
|
-
5. **Predictable structure** - All sections always serialize with default values (addressed in PR #37)
|
|
31
|
-
|
|
32
|
-
## Nesting vs Flat Structure Guidelines
|
|
33
|
-
|
|
34
|
-
### Use FLAT Structure When:
|
|
35
|
-
|
|
36
|
-
- **< 4 total fields** in a configuration section
|
|
37
|
-
- **No clear logical subsystems** within the section
|
|
38
|
-
- **Simple value types** without complex relationships
|
|
39
|
-
- **Low likelihood of expansion** in the future
|
|
40
|
-
|
|
41
|
-
**Benefits:**
|
|
42
|
-
- Simpler code (fewer nested object creations)
|
|
43
|
-
- Easier to parse and validate
|
|
44
|
-
- More concise JSON output
|
|
45
|
-
- Faster serialization/deserialization
|
|
46
|
-
|
|
47
|
-
### Use NESTED Structure When:
|
|
48
|
-
|
|
49
|
-
- **3+ fields belong to same logical subsystem**
|
|
50
|
-
- **Clear semantic grouping** exists
|
|
51
|
-
- **Future extensibility anticipated** for subsystem
|
|
52
|
-
- **Subsystem has distinct meaning** separate from parent
|
|
53
|
-
|
|
54
|
-
**Benefits:**
|
|
55
|
-
- Better logical organization
|
|
56
|
-
- Easier to add related fields without cluttering parent
|
|
57
|
-
- Clear separation of concerns
|
|
58
|
-
- More extensible architecture
|
|
59
|
-
|
|
60
|
-
## Current Structure Patterns
|
|
61
|
-
|
|
62
|
-
**Important Note (as of PR #37):** All configuration sections now **always serialize** regardless of whether values are at their defaults. This provides predictable JSON structure and eliminates the need for consumers to check key existence. Default values (0, false, "") clearly indicate "not configured" state.
|
|
63
|
-
|
|
64
|
-
### Flat Sections (No Nesting)
|
|
65
|
-
|
|
66
|
-
These sections use simple key-value pairs at a single level:
|
|
67
|
-
|
|
68
|
-
#### Display Configuration
|
|
69
|
-
```json
|
|
70
|
-
"display_config": {
|
|
71
|
-
"enabled": true,
|
|
72
|
-
"brightness": 128,
|
|
73
|
-
"timeout_ms": 30000,
|
|
74
|
-
"timeout_s": 30
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
**Rationale:** Only 3-4 fields, all directly related to display, no subsystems.
|
|
79
|
-
|
|
80
|
-
#### Power Configuration
|
|
81
|
-
```json
|
|
82
|
-
"power_config": {
|
|
83
|
-
"deep_sleep_enabled": false,
|
|
84
|
-
"deep_sleep_interval_ms": 300000,
|
|
85
|
-
"deep_sleep_interval_s": 300,
|
|
86
|
-
"battery_percent": 85
|
|
87
|
-
}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
**Rationale:** Small number of fields (4), even though battery and sleep are different concerns, nesting would add unnecessary complexity.
|
|
91
|
-
|
|
92
|
-
#### MQTT Retry Configuration
|
|
93
|
-
```json
|
|
94
|
-
"mqtt_retry": {
|
|
95
|
-
"max_attempts": 5,
|
|
96
|
-
"circuit_breaker_ms": 60000,
|
|
97
|
-
"circuit_breaker_s": 60,
|
|
98
|
-
"hourly_retry_enabled": true,
|
|
99
|
-
"initial_retry_ms": 1000,
|
|
100
|
-
"initial_retry_s": 1,
|
|
101
|
-
"max_retry_ms": 30000,
|
|
102
|
-
"max_retry_s": 30,
|
|
103
|
-
"backoff_multiplier": 2.0
|
|
104
|
-
}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
**Rationale:** While this has 9 fields with distinct concerns (retry policy vs backoff strategy), it remains flat for simplicity. The retry configuration is cohesive enough that nesting would fragment it without clear benefit.
|
|
108
|
-
|
|
109
|
-
### Nested Sections (With Subsystems)
|
|
110
|
-
|
|
111
|
-
These sections use nested objects for logical grouping:
|
|
112
|
-
|
|
113
|
-
#### Sensor Configuration with Calibration
|
|
114
|
-
```json
|
|
115
|
-
"sensors": {
|
|
116
|
-
"read_interval_ms": 30000,
|
|
117
|
-
"read_interval_s": 30,
|
|
118
|
-
"transmission_interval_ms": 60000,
|
|
119
|
-
"transmission_interval_s": 60,
|
|
120
|
-
"calibration": {
|
|
121
|
-
"temperature_offset": 0.5,
|
|
122
|
-
"humidity_offset": -2.0,
|
|
123
|
-
"pressure_offset": 0.0
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
**Rationale:** Calibration is a distinct subsystem with its own semantic meaning. It's optional, extensible, and conceptually separate from sensor timing configuration.
|
|
129
|
-
|
|
130
|
-
**Benefits of nesting here:**
|
|
131
|
-
- Calibration can be added/removed as a unit
|
|
132
|
-
- Easy to add more calibration fields without cluttering main sensors object
|
|
133
|
-
- Clear semantic boundary - calibration is a specific tuning operation
|
|
134
|
-
|
|
135
|
-
#### Organization Metadata
|
|
136
|
-
```json
|
|
137
|
-
"organization": {
|
|
138
|
-
"organizationId": "org-123",
|
|
139
|
-
"customerId": "cust-456",
|
|
140
|
-
"deviceGroup": "sensors",
|
|
141
|
-
"device_name": "sensor-01",
|
|
142
|
-
"device_location": "warehouse-a",
|
|
143
|
-
"device_secret_set": true
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
**Rationale:** Organization metadata is an optional, self-contained subsystem that may not be present on all devices.
|
|
148
|
-
|
|
149
|
-
## Decision Tree
|
|
150
|
-
|
|
151
|
-
Use this decision tree when designing new configuration sections:
|
|
152
|
-
|
|
153
|
-
```
|
|
154
|
-
START: New configuration section needed
|
|
155
|
-
│
|
|
156
|
-
├─ Does section have < 4 fields?
|
|
157
|
-
│ ├─ YES → Use FLAT structure
|
|
158
|
-
│ └─ NO → Continue
|
|
159
|
-
│
|
|
160
|
-
├─ Do 3+ fields belong to same logical subsystem?
|
|
161
|
-
│ ├─ NO → Use FLAT structure
|
|
162
|
-
│ └─ YES → Continue
|
|
163
|
-
│
|
|
164
|
-
├─ Is subsystem likely to grow in future?
|
|
165
|
-
│ ├─ NO → Consider FLAT (unless strong semantic grouping)
|
|
166
|
-
│ └─ YES → Continue
|
|
167
|
-
│
|
|
168
|
-
├─ Would nesting improve clarity significantly?
|
|
169
|
-
│ ├─ NO → Use FLAT structure
|
|
170
|
-
│ └─ YES → Use NESTED structure
|
|
171
|
-
│
|
|
172
|
-
END
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
## Examples
|
|
176
|
-
|
|
177
|
-
### Example 1: Adding OTA Configuration (Flat Approach)
|
|
178
|
-
|
|
179
|
-
**Scenario:** Adding Over-The-Air update configuration with 3 fields.
|
|
180
|
-
|
|
181
|
-
```cpp
|
|
182
|
-
// C++ Fields
|
|
183
|
-
bool otaEnabled = false;
|
|
184
|
-
TSTRING otaServer = "";
|
|
185
|
-
uint16_t otaPort = 0;
|
|
186
|
-
|
|
187
|
-
// JSON Serialization (FLAT)
|
|
188
|
-
JsonObject ota = jsonObj["ota"].to<JsonObject>();
|
|
189
|
-
ota["enabled"] = otaEnabled;
|
|
190
|
-
ota["server"] = otaServer;
|
|
191
|
-
ota["port"] = otaPort;
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
**Result:**
|
|
195
|
-
```json
|
|
196
|
-
"ota": {
|
|
197
|
-
"enabled": true,
|
|
198
|
-
"server": "ota.example.com",
|
|
199
|
-
"port": 8080
|
|
200
|
-
}
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
**Decision:** Keep FLAT - only 3 fields, no subsystems.
|
|
204
|
-
|
|
205
|
-
### Example 2: Adding Sensor Thresholds (Nested Approach)
|
|
206
|
-
|
|
207
|
-
**Scenario:** Adding temperature, humidity, and pressure thresholds to sensor configuration.
|
|
208
|
-
|
|
209
|
-
```cpp
|
|
210
|
-
// C++ Fields (added to existing sensor config)
|
|
211
|
-
double tempThresholdMin = -40.0;
|
|
212
|
-
double tempThresholdMax = 85.0;
|
|
213
|
-
double humidityThresholdMin = 0.0;
|
|
214
|
-
double humidityThresholdMax = 100.0;
|
|
215
|
-
|
|
216
|
-
// JSON Serialization (NESTED under sensors)
|
|
217
|
-
JsonObject sensors = jsonObj["sensors"].to<JsonObject>();
|
|
218
|
-
// ... existing sensor fields ...
|
|
219
|
-
|
|
220
|
-
JsonObject thresholds = sensors["thresholds"].to<JsonObject>();
|
|
221
|
-
thresholds["temperature_min"] = tempThresholdMin;
|
|
222
|
-
thresholds["temperature_max"] = tempThresholdMax;
|
|
223
|
-
thresholds["humidity_min"] = humidityThresholdMin;
|
|
224
|
-
thresholds["humidity_max"] = humidityThresholdMax;
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
**Result:**
|
|
228
|
-
```json
|
|
229
|
-
"sensors": {
|
|
230
|
-
"read_interval_ms": 30000,
|
|
231
|
-
"calibration": { ... },
|
|
232
|
-
"thresholds": {
|
|
233
|
-
"temperature_min": -40.0,
|
|
234
|
-
"temperature_max": 85.0,
|
|
235
|
-
"humidity_min": 0.0,
|
|
236
|
-
"humidity_max": 100.0
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
**Decision:** Use NESTED - 4+ fields, clear subsystem (alerting/validation logic), logical grouping.
|
|
242
|
-
|
|
243
|
-
### Example 3: Adding Encoding Configuration (Flat Approach)
|
|
244
|
-
|
|
245
|
-
**Scenario:** Adding message encoding/compression settings.
|
|
246
|
-
|
|
247
|
-
```cpp
|
|
248
|
-
// C++ Fields
|
|
249
|
-
bool compressionEnabled = false;
|
|
250
|
-
TSTRING encodingType = "json";
|
|
251
|
-
uint8_t compressionLevel = 6;
|
|
252
|
-
|
|
253
|
-
// JSON Serialization (FLAT)
|
|
254
|
-
JsonObject encoding = jsonObj["encoding"].to<JsonObject>();
|
|
255
|
-
encoding["compression_enabled"] = compressionEnabled;
|
|
256
|
-
encoding["encoding_type"] = encodingType;
|
|
257
|
-
encoding["compression_level"] = compressionLevel;
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
**Result:**
|
|
261
|
-
```json
|
|
262
|
-
"encoding": {
|
|
263
|
-
"compression_enabled": false,
|
|
264
|
-
"encoding_type": "json",
|
|
265
|
-
"compression_level": 6
|
|
266
|
-
}
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
**Decision:** Keep FLAT - only 3 fields, cohesive purpose.
|
|
270
|
-
|
|
271
|
-
## Best Practices
|
|
272
|
-
|
|
273
|
-
### 1. Be Conservative with Nesting
|
|
274
|
-
|
|
275
|
-
**Rationale:** Flat structures are simpler to implement and consume.
|
|
276
|
-
|
|
277
|
-
**Rule:** When in doubt, start flat. Nesting can be added later if needed, but removing nesting is a breaking change.
|
|
278
|
-
|
|
279
|
-
### 2. Consider Backward Compatibility
|
|
280
|
-
|
|
281
|
-
When adding fields to existing sections:
|
|
282
|
-
|
|
283
|
-
```cpp
|
|
284
|
-
// Deserialization with backward compatibility
|
|
285
|
-
displayTimeout = displayConfig["timeout_ms"] | displayConfig["timeout"] | 0;
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
This allows reading old format (`timeout`) while preferring new format (`timeout_ms`).
|
|
289
|
-
|
|
290
|
-
### 3. Group Optional Subsystems
|
|
291
|
-
|
|
292
|
-
**Good:**
|
|
293
|
-
```json
|
|
294
|
-
"sensors": {
|
|
295
|
-
"read_interval_ms": 30000,
|
|
296
|
-
"calibration": { ... } // Optional, can be omitted entirely
|
|
297
|
-
}
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
**Avoid:**
|
|
301
|
-
```json
|
|
302
|
-
"sensors": {
|
|
303
|
-
"read_interval_ms": 30000,
|
|
304
|
-
"temperature_offset": 0.0, // Mixed levels - unclear if calibration is a concept
|
|
305
|
-
"humidity_offset": 0.0,
|
|
306
|
-
"pressure_offset": 0.0
|
|
307
|
-
}
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
### 4. Maintain Consistent Field Naming
|
|
311
|
-
|
|
312
|
-
Follow existing conventions:
|
|
313
|
-
- Time fields: Follow [Time Field Naming Convention](../examples/alteriom/alteriom_sensor_package.hpp#L10-L55)
|
|
314
|
-
- Boolean fields: Follow [Boolean Naming Convention](BOOLEAN_NAMING_CONVENTION.md)
|
|
315
|
-
- Use snake_case for JSON keys
|
|
316
|
-
- Use camelCase for C++ field names
|
|
317
|
-
|
|
318
|
-
### 5. Document Structure Decisions
|
|
319
|
-
|
|
320
|
-
Add comments explaining nesting choices:
|
|
321
|
-
|
|
322
|
-
```cpp
|
|
323
|
-
// Display configuration (flat - only 3 fields, no subsystems)
|
|
324
|
-
JsonObject displayConfig = jsonObj["display_config"].to<JsonObject>();
|
|
325
|
-
|
|
326
|
-
// Sensor configuration with nested calibration (calibration is distinct subsystem)
|
|
327
|
-
JsonObject sensors = jsonObj["sensors"].to<JsonObject>();
|
|
328
|
-
JsonObject calibration = sensors["calibration"].to<JsonObject>();
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
### 6. Test Structure Consistency
|
|
332
|
-
|
|
333
|
-
Create tests to validate structure patterns:
|
|
334
|
-
|
|
335
|
-
```cpp
|
|
336
|
-
TEST(StatusPackage, StructureConsistency) {
|
|
337
|
-
alteriom::StatusPackage pkg;
|
|
338
|
-
pkg.tempOffset = 0.5;
|
|
339
|
-
|
|
340
|
-
JsonDocument doc;
|
|
341
|
-
JsonObject obj = doc.to<JsonObject>();
|
|
342
|
-
pkg.addTo(std::move(obj));
|
|
343
|
-
|
|
344
|
-
// Verify nested structures
|
|
345
|
-
REQUIRE(obj["sensors"]["calibration"].is<JsonObject>());
|
|
346
|
-
|
|
347
|
-
// Verify flat structures remain flat
|
|
348
|
-
REQUIRE(obj["display_config"]["enabled"].is<bool>());
|
|
349
|
-
REQUIRE_FALSE(obj["display_config"].containsKey("nested_section"));
|
|
350
|
-
}
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
## Migration Path
|
|
354
|
-
|
|
355
|
-
If restructuring becomes necessary:
|
|
356
|
-
|
|
357
|
-
1. **Add new structure** while maintaining old structure
|
|
358
|
-
2. **Support both formats** in deserialization
|
|
359
|
-
3. **Deprecate old format** (document in release notes)
|
|
360
|
-
4. **Remove old format** in next major version
|
|
361
|
-
|
|
362
|
-
```cpp
|
|
363
|
-
// Example: Supporting both flat and nested
|
|
364
|
-
if (jsonObj["network"]["wifi"].is<JsonObject>()) {
|
|
365
|
-
// New nested format
|
|
366
|
-
JsonObject wifi = jsonObj["network"]["wifi"];
|
|
367
|
-
wifiSSID = wifi["ssid"].as<TSTRING>();
|
|
368
|
-
} else {
|
|
369
|
-
// Old flat format (deprecated)
|
|
370
|
-
wifiSSID = jsonObj["network"]["wifi_ssid"].as<TSTRING>();
|
|
371
|
-
}
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
## Summary
|
|
375
|
-
|
|
376
|
-
| Criteria | Flat Structure | Nested Structure |
|
|
377
|
-
|----------|---------------|------------------|
|
|
378
|
-
| **Field Count** | < 4 fields | 3+ fields in subsystem |
|
|
379
|
-
| **Logical Grouping** | No clear subsystems | Clear semantic grouping |
|
|
380
|
-
| **Extensibility** | Low likelihood of growth | Anticipated expansion |
|
|
381
|
-
| **Complexity** | Simple values | Complex relationships |
|
|
382
|
-
| **Serialization** | Always present (PR #37) | Always present (PR #37) |
|
|
383
|
-
| **Examples** | display_config, power_config, ota, encoding, mqtt_retry | sensors.calibration, organization |
|
|
384
|
-
|
|
385
|
-
**Golden Rule:** When uncertain, prefer flat structures. Nesting should provide clear organizational or extensibility benefits to justify the added complexity.
|
|
386
|
-
|
|
387
|
-
### Resolution of Issue #28
|
|
388
|
-
|
|
389
|
-
Issue #28 identified inconsistent nesting patterns and proposed three options:
|
|
390
|
-
|
|
391
|
-
1. **Option 1: Keep Current Structure (Document Pattern)** ✅ **ADOPTED**
|
|
392
|
-
2. Option 2: Nest Network Configuration (Breaking Change)
|
|
393
|
-
3. Option 3: Nest MQTT Retry Backoff Settings (Minimal Change)
|
|
394
|
-
|
|
395
|
-
**Decision Rationale:**
|
|
396
|
-
- Current flat structure for most sections (display_config, power_config, mqtt_retry) is functional and simple
|
|
397
|
-
- Only sensors.calibration uses nesting, which is justified by its semantic separation
|
|
398
|
-
- Avoiding breaking changes preserves compatibility with existing consumers
|
|
399
|
-
- Clear documentation (this file) addresses the inconsistency concern
|
|
400
|
-
- PR #37's unconditional serialization provides the predictable structure that was the real underlying concern
|
|
401
|
-
|
|
402
|
-
**Result:** The pattern is now documented and validated. Future additions should follow the decision tree in this document.
|
|
403
|
-
|
|
404
|
-
## References
|
|
405
|
-
|
|
406
|
-
- [StatusPackage Implementation](../examples/alteriom/alteriom_sensor_package.hpp)
|
|
407
|
-
- [Boolean Naming Convention](BOOLEAN_NAMING_CONVENTION.md)
|
|
408
|
-
- [Time Field Naming Convention](../examples/alteriom/alteriom_sensor_package.hpp#L10-L55)
|
|
409
|
-
- [Test Cases](../test/catch/catch_alteriom_packages.cpp)
|
|
410
|
-
|
|
411
|
-
## Revision History
|
|
412
|
-
|
|
413
|
-
- **2025-11-04 (PR #37)**: Updated to reflect unconditional serialization pattern - all sections always serialize with default values for predictable structure
|
|
414
|
-
- **2025-11-04 (PR #36)**: Initial version documenting StatusPackage nesting patterns in response to Issue #28
|