quilt-hp-python 0.4.0__tar.gz → 0.5.0__tar.gz

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.
Files changed (121) hide show
  1. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/CHANGELOG.md +14 -0
  2. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/PKG-INFO +1 -1
  3. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/how-to/home-assistant.md +1 -0
  4. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/reference/client.md +1 -1
  5. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/reference/hds-entities.md +1 -1
  6. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/proto/cleaned/quilt_device_pairing.proto +2 -4
  7. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/proto/cleaned/quilt_hds.proto +103 -95
  8. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/proto/cleaned/quilt_notifier.proto +12 -13
  9. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/proto/cleaned/quilt_services.proto +6 -15
  10. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/proto/cleaned/quilt_system.proto +4 -4
  11. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/pyproject.toml +1 -1
  12. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/__init__.py +1 -1
  13. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_proto/quilt_device_pairing_pb2.pyi +2 -4
  14. quilt_hp_python-0.5.0/src/quilt_hp/_proto/quilt_hds_pb2.py +296 -0
  15. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_proto/quilt_hds_pb2.pyi +173 -166
  16. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_proto/quilt_notifier_pb2.pyi +13 -14
  17. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_proto/quilt_services_pb2.pyi +6 -19
  18. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_proto/quilt_system_pb2.pyi +4 -4
  19. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/cli/main.py +6 -2
  20. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/cli/tui.py +42 -2
  21. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/const.py +1 -1
  22. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/models/__init__.py +2 -0
  23. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/models/controller.py +13 -3
  24. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/models/enums.py +28 -0
  25. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/models/indoor_unit.py +5 -9
  26. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/models/qsm.py +12 -1
  27. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/models/sensor.py +0 -2
  28. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/models/software_update.py +0 -2
  29. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/models/system.py +11 -0
  30. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/services/hds.py +14 -10
  31. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_cli_feature_completion.py +3 -0
  32. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_cli_surfaces_extra.py +1 -1
  33. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_hds_payloads.py +18 -0
  34. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_models.py +16 -0
  35. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_models_from_proto.py +215 -0
  36. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_transport.py +1 -1
  37. quilt_hp_python-0.4.0/src/quilt_hp/_proto/quilt_hds_pb2.py +0 -292
  38. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/.github/copilot-instructions.md +0 -0
  39. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/.github/workflows/ci.yml +0 -0
  40. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/.github/workflows/docs-deploy.yml +0 -0
  41. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/.github/workflows/release.yml +0 -0
  42. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/.gitignore +0 -0
  43. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/LICENSE +0 -0
  44. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/README.md +0 -0
  45. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/explanation/architecture.md +0 -0
  46. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/explanation/authentication.md +0 -0
  47. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/explanation/grpc-and-protobuf.md +0 -0
  48. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/explanation/snapshot-and-stream.md +0 -0
  49. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/explanation/streaming-protocol.md +0 -0
  50. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/how-to/authenticate.md +0 -0
  51. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/how-to/automation-daemon.md +0 -0
  52. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/how-to/cli-scripting.md +0 -0
  53. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/how-to/configure-comfort-settings.md +0 -0
  54. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/how-to/configure-schedules.md +0 -0
  55. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/how-to/contribute.md +0 -0
  56. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/how-to/control-spaces.md +0 -0
  57. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/how-to/regenerate-protos.md +0 -0
  58. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/how-to/stream-updates.md +0 -0
  59. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/how-to/tui-app.md +0 -0
  60. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/index.md +0 -0
  61. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/reference/api-reference.md +0 -0
  62. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/reference/documentation-standards.md +0 -0
  63. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/reference/grpc-services-matrix.md +0 -0
  64. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/reference/models.md +0 -0
  65. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/reference/token-management.md +0 -0
  66. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/docs/tutorial/get-started.md +0 -0
  67. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/mkdocs.yml +0 -0
  68. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/scripts/bump_version.py +0 -0
  69. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/scripts/check_docs_nav.py +0 -0
  70. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/scripts/generate_public_api_reference.py +0 -0
  71. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/scripts/regen_protos.sh +0 -0
  72. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_paths.py +0 -0
  73. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_proto/__init__.py +0 -0
  74. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_proto/quilt_device_pairing_pb2.py +0 -0
  75. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_proto/quilt_device_pairing_pb2_grpc.py +0 -0
  76. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_proto/quilt_hds_pb2_grpc.py +0 -0
  77. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_proto/quilt_notifier_pb2.py +0 -0
  78. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_proto/quilt_notifier_pb2_grpc.py +0 -0
  79. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_proto/quilt_services_pb2.py +0 -0
  80. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_proto/quilt_services_pb2_grpc.py +0 -0
  81. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_proto/quilt_system_pb2.py +0 -0
  82. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/_proto/quilt_system_pb2_grpc.py +0 -0
  83. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/auth.py +0 -0
  84. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/cli/__init__.py +0 -0
  85. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/cli/settings.py +0 -0
  86. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/cli/store.py +0 -0
  87. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/client.py +0 -0
  88. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/exceptions.py +0 -0
  89. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/models/_helpers.py +0 -0
  90. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/models/comfort.py +0 -0
  91. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/models/energy.py +0 -0
  92. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/models/outdoor_unit.py +0 -0
  93. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/models/schedule.py +0 -0
  94. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/models/space.py +0 -0
  95. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/py.typed +0 -0
  96. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/services/__init__.py +0 -0
  97. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/services/streaming.py +0 -0
  98. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/services/system.py +0 -0
  99. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/services/user.py +0 -0
  100. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/tokens.py +0 -0
  101. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/src/quilt_hp/transport.py +0 -0
  102. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/__init__.py +0 -0
  103. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/conftest.py +0 -0
  104. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_auth.py +0 -0
  105. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_auth_store_settings_edges.py +0 -0
  106. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_cli_login.py +0 -0
  107. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_client_cache.py +0 -0
  108. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_client_service_error_paths.py +0 -0
  109. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_grpc_retry.py +0 -0
  110. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_hds_schedule_mapping.py +0 -0
  111. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_hds_service_branches.py +0 -0
  112. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_models_extra.py +0 -0
  113. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_settings_store.py +0 -0
  114. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_streaming.py +0 -0
  115. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_streaming_concurrency.py +0 -0
  116. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_streaming_debounce.py +0 -0
  117. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_streaming_health.py +0 -0
  118. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_streaming_reconnect_dispatch_extra.py +0 -0
  119. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_tokens.py +0 -0
  120. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_transport_interceptor_extra.py +0 -0
  121. {quilt_hp_python-0.4.0 → quilt_hp_python-0.5.0}/tests/test_tui_bindings.py +0 -0
@@ -2,6 +2,20 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.5.0] - 2026-06-04
6
+
7
+ ### Added protocol support
8
+ - `HVACMode.DRY = 8` — dehumidification mode; gate: `mobile_dry_mode_selection_enabled`. Fan non-interactive (QSM forces ~600 RPM). No user-configurable temperature setpoint; built-in temperature floor is server-side.
9
+ - `HVACState.DRY = 11`, `DRY_DEFERRED = 12`, `DRY_PREPARING = 13`
10
+ - `LocalCommsHealthStatus` enum (`UNSPECIFIED=0`, `HEALTHY=1`, `DEGRADED=2`, `OFFLINE=3`, `STARTING_UP=4`) — gate: `mobile_local_control_health_enabled`
11
+ - `QuiltSmartModule.local_comms_health` — extracted from new `LocalCommsStatus` nested message (proto field 8, subfield 2)
12
+ - `Controller.local_comms_health` — extracted from new `LocalCommsStatus` nested message (proto field 9, subfield 2)
13
+ - `LocalCommsStatus` proto message with `updated_ts`, `health`, `link_state`, `version`, `health_changed_ts`, `connection_state` subfields (fields 1–6; wire-confirmed)
14
+
15
+ ### Changed
16
+ - `APP_VERSION` bumped to `1.0.26`
17
+ - `LocalCommsStatus` is a **nested message** (not a simple enum) on both QSM and Controller — the earlier inferred field type was incorrect; wire-confirmed via 2026-06-04 mitmproxy capture
18
+
5
19
  ## [0.4.0] - 2026-05-16
6
20
 
7
21
  ## [0.3.2] - 2026-05-19
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quilt-hp-python
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Async Python client for Quilt mini-split HVAC systems
5
5
  Project-URL: Repository, https://github.com/eman/quilt-hp-python
6
6
  Project-URL: Issues, https://github.com/eman/quilt-hp-python/issues
@@ -283,6 +283,7 @@ _MODE_MAP: dict[QHVACMode, HAHVACMode] = {
283
283
  QHVACMode.HEAT: HAHVACMode.HEAT,
284
284
  QHVACMode.AUTO: HAHVACMode.HEAT_COOL,
285
285
  QHVACMode.FAN: HAHVACMode.FAN_ONLY,
286
+ QHVACMode.DRY: HAHVACMode.DRY, # v1.0.26: dehumidification mode
286
287
  }
287
288
 
288
289
  _HA_TO_QUILT: dict[HAHVACMode, QHVACMode] = {v: k for k, v in _MODE_MAP.items()}
@@ -69,7 +69,7 @@ Raised when a requested resource does not exist (gRPC `NOT_FOUND`).
69
69
  ### `__version__`
70
70
 
71
71
  ```python
72
- __version__: str # e.g. "0.4.0"
72
+ __version__: str # e.g. "0.5.0"
73
73
  ```
74
74
 
75
75
  ---
@@ -49,7 +49,7 @@ The Quilt apps use several placeholder values to represent "not set", "ignored i
49
49
  | `comfort_setting_id=""` | Manual/direct-control mode (no preset bound) | `SpaceControls.has_linked_comfort_setting`, `SpaceControls.comfort_setting_id_or_none` |
50
50
  | `louver_fixed_position=0.0` with non-`FIXED` mode | Louver position ignored for AUTO/SWEEP/CLOSED | `IndoorUnitControls.louver_position_is_placeholder`, `ComfortSetting.louver_position_is_placeholder` |
51
51
  | `fan_speed_mode=0` | Proto3 default = fan fields absent / unknown in sparse diff | `IndoorUnitControls.fan_speed_is_placeholder` |
52
- | `fanSpeedMaxRpm=0.0` | Indoor-unit hardware spec missing/unpopulated (KMP model) | Reserved constant: `UNSET_MAX_FAN_SPEED_RPM_SENTINEL` |
52
+ | `fanSpeedMaxRpm=0.0` | Indoor-unit hardware spec missing/unpopulated | Reserved constant: `UNSET_MAX_FAN_SPEED_RPM_SENTINEL` |
53
53
  | `NaN` in temperatures/energy | Missing or invalid measurement samples | `SpaceState.has_missing_ambient_temperature`, `SpaceState.has_missing_setpoint`, `EnergyBucket.has_missing_energy_value` |
54
54
  | timestamp seconds `0` | Proto timestamp unset (no check-in yet) | Parsed as `None` for model datetimes (`updated_at`, `wifi_last_seen`) |
55
55
  | unknown schedule weekday | Invalid/unknown day in ordering logic | `ScheduleWeekDay.weekday_sort_order` maps to tail sentinel |
@@ -1,7 +1,6 @@
1
1
  // quilt_device_pairing.proto
2
2
  // BLE/WiFi device pairing protocol — serialized over Bluetooth (not gRPC).
3
3
  // Used during initial setup of Quilt Smart Module (QSM) and Controller devices.
4
- // Reconstructed from Quilt app v1.0.25 KMP source (ProtoSerializationClientService).
5
4
 
6
5
  syntax = "proto3";
7
6
 
@@ -49,9 +48,8 @@ enum DevicePairingStatus {
49
48
  // ---------------------------------------------------------------------------
50
49
 
51
50
  message WifiScan {
52
- // Field ordering based on KMP model (WifiScan.kt) and confirmed by
53
- // observed data: field 4 contains negative dBm values (RSSI).
54
- // NM.smali is a DIFFERENT message (WifiState for established connections).
51
+ // Field 4 contains negative dBm values (RSSI); wire-confirmed.
52
+ // Note: WifiState (for established connections) is a different message.
55
53
  string mac_address = 1; // BSSID
56
54
  string ssid = 2;
57
55
  int32 frequency = 3; // MHz; >5000 = 5GHz band
@@ -1,5 +1,6 @@
1
1
  // quilt_hds.proto
2
2
  // Home Datastore (HDS) messages — objects managed by the gRPC API.
3
+ // Field numbers and wire types confirmed via live mitmproxy capture.
3
4
 
4
5
  syntax = "proto3";
5
6
 
@@ -16,7 +17,7 @@ option java_outer_classname = "QuiltHdsProto";
16
17
  // Enums
17
18
  // ---------------------------------------------------------------------------
18
19
 
19
- // COOL=2, HEAT=3
20
+ // Wire-confirmed: COOL=2, HEAT=3.
20
21
  enum HVACMode {
21
22
  HVAC_MODE_UNSPECIFIED = 0;
22
23
  HVAC_MODE_STANDBY = 1;
@@ -26,10 +27,10 @@ enum HVACMode {
26
27
  HVAC_MODE_FAN = 5;
27
28
  HVAC_MODE_FALLBACK_AUTO = 6;
28
29
  HVAC_MODE_FALLBACK_OFF = 7;
30
+ HVAC_MODE_DRY = 8; // dehumidification mode
29
31
  }
30
32
 
31
- // Confirmed by Android proto Java enum SJ (implements ProtocolMessageEnum).
32
- // DRY states were iOS KMP-layer only and do not exist in the wire proto.
33
+ // Wire-confirmed: DRY states added alongside HVAC_MODE_DRY.
33
34
  enum HVACState {
34
35
  HVAC_STATE_UNSPECIFIED = 0;
35
36
  HVAC_STATE_STANDBY = 1;
@@ -42,6 +43,30 @@ enum HVACState {
42
43
  HVAC_STATE_FAN_DEFERRED = 8;
43
44
  HVAC_STATE_COOL_PREPARING = 9;
44
45
  HVAC_STATE_HEAT_PREPARING = 10;
46
+ HVAC_STATE_DRY = 11; // DRY actively dehumidifying
47
+ HVAC_STATE_DRY_DEFERRED = 12; // DRY waiting for mode-switch delay
48
+ HVAC_STATE_DRY_PREPARING = 13; // DRY compressor pre-conditioning
49
+ }
50
+
51
+ // Local communications health for QSM and Controller mesh nodes.
52
+ enum LocalCommsHealthStatus {
53
+ LOCAL_COMMS_HEALTH_STATUS_UNSPECIFIED = 0;
54
+ LOCAL_COMMS_HEALTH_STATUS_HEALTHY = 1;
55
+ LOCAL_COMMS_HEALTH_STATUS_DEGRADED = 2;
56
+ LOCAL_COMMS_HEALTH_STATUS_OFFLINE = 3;
57
+ LOCAL_COMMS_HEALTH_STATUS_STARTING_UP = 4;
58
+ }
59
+
60
+ // Local communications health status for a QSM or Controller mesh node.
61
+ // Carried as field 8 on QuiltSmartModule and field 9 on Controller.
62
+ // The `health` subfield (2) is the primary value; subfields 3, 4, 6 semantics TBD.
63
+ message LocalCommsStatus {
64
+ google.protobuf.Timestamp updated_ts = 1; // most-recent server update timestamp
65
+ LocalCommsHealthStatus health = 2; // current health
66
+ int32 link_state = 3; // observed: HEALTHY=9, DEGRADED=8; enum TBD
67
+ int32 version = 4; // observed: always 9
68
+ google.protobuf.Timestamp health_changed_ts = 5; // when health last changed
69
+ int32 connection_state = 6; // observed: HEALTHY=1, DEGRADED=5; enum TBD
45
70
  }
46
71
 
47
72
  enum OccupancyMode {
@@ -52,7 +77,7 @@ enum OccupancyMode {
52
77
 
53
78
  // Freeze-protection setting on SpaceSettings (field 9).
54
79
  // UNSPECIFIED is treated as ENABLED by the app (freeze protection on by default).
55
- // KMP: SafetyHeatingMode — field number unconfirmed (not present in APK build; added post-release).
80
+ // Field number unconfirmed (assumed f9; added post-initial release).
56
81
  enum SafetyHeatingMode {
57
82
  SAFETY_HEATING_MODE_UNSPECIFIED = 0;
58
83
  SAFETY_HEATING_MODE_DISABLED = 1;
@@ -217,9 +242,8 @@ message SpaceRelationships {
217
242
  // Wire-confirmed SpaceSettings fields (from field_3.f3):
218
243
  // f1=name, f2=description, f3=updated_ts, f4=timezone, f5=OccupancyMode,
219
244
  // f6=HvacControllerType, f7=occupied_timeout_s(180.0), f8=unoccupied_timeout_s(1200.0)
220
- // APK-confirmed (C5149oM.java): fields 1–8 exactly.
221
- // f9=SafetyHeatingMode (freeze protection): KMP-confirmed in SpaceSettings.safetyHeating,
222
- // field number unconfirmed (not in APK build; added post-release, assumed f9).
245
+ // Wire-confirmed: fields 1–8.
246
+ // f9=SafetyHeatingMode (freeze protection): field number unconfirmed (assumed f9).
223
247
  message SpaceSettings {
224
248
  string name = 1; // wire-confirmed: f1
225
249
  string description = 2; // wire-confirmed: f2
@@ -246,7 +270,7 @@ message SpaceControls {
246
270
  google.protobuf.Timestamp updated_ts = 3; // wire-confirmed: f3
247
271
  float cooling_temperature_setpoint_c = 4; // wire-confirmed: f4 (cooling at 4, not heating!)
248
272
  float heating_temperature_setpoint_c = 5; // wire-confirmed: f5 (heating at 5, not cooling!)
249
- string comfort_setting_id = 6; // Android proto: COMFORT_SETTING_ID_FIELD_NUMBER=6
273
+ string comfort_setting_id = 6; // wire-confirmed: COMFORT_SETTING_ID_FIELD_NUMBER=6
250
274
  BoostMode boost_mode = 7; // wire-confirmed: f7 (varint, 0=UNSPECIFIED)
251
275
  ComfortSettingOverride comfort_setting_override = 8; // wire-confirmed: f8 (varint, 2=UNTIL_NEXT_SCHEDULE)
252
276
  string comfort_setting_id_string = 9; // wire-confirmed: f9 (UUID string)
@@ -312,7 +336,7 @@ message IndoorUnitSettings {
312
336
  // f12=lightState(varint), f13=lightAnimation(varint).
313
337
  // NOTE: These are FLAT fields, NOT nested sub-messages.
314
338
  message IndoorUnitControls {
315
- // f1, f2 absent in Android DEX (C2523cK.java)
339
+ // f1, f2 absent from wire captures
316
340
  uint32 led_color_code = 3; // RGBW packed uint32
317
341
  float led_color_brightness_percent = 4; // stored brightness 0.0–1.0; preserved when led_state=OFF
318
342
  FanSpeedMode fan_speed_mode = 5;
@@ -321,21 +345,19 @@ message IndoorUnitControls {
321
345
  // f8, f9: uuid-string field confirmed at f9 in captures; purpose TBD
322
346
  IndoorUnitLouverMode louver_mode = 10;
323
347
  float louver_fixed_position = 11; // degrees, used when louver_mode=FIXED
324
- LightAnimation led_animation = 12; // confirmed Android C2523cK: LED_ANIMATION_FIELD_NUMBER=12
348
+ LightAnimation led_animation = 12; // LED_ANIMATION_FIELD_NUMBER=12; wire-confirmed
325
349
  LightState led_state = 13; // wire-confirmed f13: UNSPECIFIED=0,ON=1,OFF=2
326
350
  // sent when mobile_led_scheduling_enabled Statsig gate is on;
327
351
  // brightness is PRESERVED (not zeroed) when state=OFF
328
352
  }
329
353
 
330
- // Android-confirmed field layout (CK.java):
354
+ // Wire-confirmed field layout (from binary capture):
331
355
  // 1=updated_ts, 2=temperature_setpoint_c, 3=ambient_temperature_c, 4=hvac_state,
332
356
  // 5=fan_speed_setpoint_rpm, 6=fan_speed_rpm, 7=light_brightness_percent,
333
357
  // 8=presence_detection_level, 9=inlet_temperature_c, 10=outlet_temperature_c,
334
358
  // 11=ambient_humidity_percent, 12=hvac_mode, 13=calculated_ambient_temperature_c,
335
359
  // 14=louver_angle_up_down_degrees
336
- // Note: KMP IndoorUnit.kt adds `ledState: LightState` to IndoorUnitState, but this
337
- // field is NOT in the APK (CK.java) or on the wire. The led_state field (f13) lives
338
- // in IndoorUnitControls (confirmed), not IndoorUnitState.
360
+ // Note: led_state (f13) lives in IndoorUnitControls, not IndoorUnitState.
339
361
  message IndoorUnitState {
340
362
  google.protobuf.Timestamp updated_ts = 1;
341
363
  float temperature_setpoint_c = 2;
@@ -351,7 +373,7 @@ message IndoorUnitState {
351
373
  HVACMode hvac_mode = 12;
352
374
  float calculated_ambient_temperature_c = 13;
353
375
  float louver_angle_up_down_degrees = 14;
354
- // fields 15+ reserved for future ledState enum (KMP-only, not yet deployed)
376
+ // fields 15+ reserved for future ledState enum (not yet deployed)
355
377
  }
356
378
 
357
379
  message IndoorUnitConditions {
@@ -390,8 +412,8 @@ message IndoorUnitHardwareAttributes {
390
412
  string firmware_version = 4;
391
413
  float fan_speed_max_rpm = 5;
392
414
  google.protobuf.Timestamp updated_ts = 6;
393
- string indoor_unit_serial_number = 7; // APK: INDOOR_UNIT_SERIAL_NUMBER_FIELD_NUMBER
394
- string quilt_smart_module_serial_number = 8; // APK: QUILT_SMART_MODULE_SERIAL_NUMBER_FIELD_NUMBER
415
+ string indoor_unit_serial_number = 7;
416
+ string quilt_smart_module_serial_number = 8;
395
417
  }
396
418
 
397
419
  message IndoorUnitHardware {
@@ -399,7 +421,7 @@ message IndoorUnitHardware {
399
421
  IndoorUnitHardwareAttributes attributes = 2;
400
422
  }
401
423
 
402
- // APK-confirmed (C4363kK.java): HVAC controller inputs — what the controller sends to the IDU.
424
+ // HVAC controller inputs — what the controller sends to the IDU.
403
425
  message IndoorUnitHvacInputs {
404
426
  google.protobuf.Timestamp updated_ts = 1;
405
427
  float external_ambient_temperature_c = 2; // ambient temp used by controller
@@ -410,7 +432,7 @@ message IndoorUnitHvacInputs {
410
432
  HVACState hvac_state = 7;
411
433
  }
412
434
 
413
- // APK-confirmed (C5918sK.java): raw IDU performance measurements.
435
+ // Raw IDU performance measurements.
414
436
  message IndoorUnitPerformanceData {
415
437
  google.protobuf.Timestamp updated_ts = 1;
416
438
  float measurement_interval_s = 2;
@@ -426,7 +448,7 @@ message IndoorUnitPerformanceData {
426
448
  HVACState hvac_state = 12;
427
449
  }
428
450
 
429
- // APK-confirmed (C6306uK.java): computed energy/power metrics over a measurement window.
451
+ // Computed energy/power metrics over a measurement window.
430
452
  message IndoorUnitPerformanceMetrics {
431
453
  google.protobuf.Timestamp updated_ts = 1; // field 1 inferred
432
454
  float measurement_duration_s = 11; // window length in seconds
@@ -441,8 +463,7 @@ message IndoorUnitPerformanceMetrics {
441
463
  float led_energy_j = 13;
442
464
  }
443
465
 
444
- // APK-confirmed (C5337pK.java): occupancy detection result for this IDU/space.
445
- // OccupancyState (MK.java): UNSPECIFIED=0, UNDETECTED=1, DETECTED=2.
466
+ // Occupancy detection result for this IDU/space.
446
467
  enum OccupancyState {
447
468
  OCCUPANCY_STATE_UNSPECIFIED = 0;
448
469
  OCCUPANCY_STATE_UNDETECTED = 1;
@@ -455,21 +476,20 @@ message IndoorUnitOccupancy {
455
476
  }
456
477
 
457
478
 
458
- // Wire-confirmed top-level layout from binary capture: header=1(LEN/102), relationships=2(LEN/203),
459
- // settings=3(LEN/67), controls=4(LEN/40), state=5(LEN/79), then f6–f12 per APK.
479
+ // Wire-confirmed field layout: header=1, relationships=2, settings=3, controls=4, state=5, f6–f12.
460
480
  message IndoorUnit {
461
481
  EntityMetadata header = 1; // wire-confirmed: f1
462
482
  IndoorUnitRelationships relationships = 2; // wire-confirmed: f2
463
483
  IndoorUnitSettings settings = 3; // wire-confirmed: f3
464
484
  IndoorUnitControls controls = 4; // wire-confirmed: f4
465
485
  IndoorUnitState state = 5; // wire-confirmed: f5
466
- IndoorUnitHvacInputs hvac_inputs = 6; // APK: HVAC_INPUTS_FIELD_NUMBER=6 (C4363kK)
467
- IndoorUnitPresenceState presence = 7; // APK: PRESENCE_FIELD_NUMBER=7 (C6694wK)
468
- IndoorUnitConditions conditions = 8; // APK: CONDITIONS_FIELD_NUMBER=8 (C2132aK)
469
- IndoorUnitCommands commands = 9; // APK: COMMANDS_FIELD_NUMBER=9 (YJ)
470
- IndoorUnitPerformanceData performance_data = 10; // APK: PERFORMANCE_DATA_FIELD_NUMBER=10 (C5918sK)
471
- IndoorUnitPerformanceMetrics performance_metrics = 11; // APK: PERFORMANCE_METRICS_FIELD_NUMBER=11 (C6306uK)
472
- IndoorUnitOccupancy occupancy = 12; // APK: OCCUPANCY_FIELD_NUMBER=12 (C5337pK)
486
+ IndoorUnitHvacInputs hvac_inputs = 6;
487
+ IndoorUnitPresenceState presence = 7;
488
+ IndoorUnitConditions conditions = 8;
489
+ IndoorUnitCommands commands = 9;
490
+ IndoorUnitPerformanceData performance_data = 10;
491
+ IndoorUnitPerformanceMetrics performance_metrics = 11;
492
+ IndoorUnitOccupancy occupancy = 12;
473
493
  }
474
494
 
475
495
  // ---------------------------------------------------------------------------
@@ -497,7 +517,7 @@ message OutdoorUnitState {
497
517
  HVACState hvac_state = 2;
498
518
  }
499
519
 
500
- // APK-confirmed: YK.java — compressor telemetry from the outdoor unit.
520
+ // Compressor telemetry from the outdoor unit.
501
521
  // Populated during active operation; empty/zero in standby.
502
522
  message OutdoorUnitPerformanceData {
503
523
  google.protobuf.Timestamp updated_ts = 1;
@@ -525,8 +545,7 @@ message OutdoorUnitHardware {
525
545
  OutdoorUnitHardwareAttributes attributes = 2;
526
546
  }
527
547
 
528
- // Wire-confirmed field layout: header=1, relationships=2, settings=3, state=4.
529
- // APK-confirmed (QK.java): performance_data=5.
548
+ // Wire-confirmed field layout: header=1, relationships=2, settings=3, state=4, performance_data=5.
530
549
  message OutdoorUnit {
531
550
  EntityMetadata header = 1;
532
551
  OutdoorUnitRelationships relationships = 2;
@@ -558,8 +577,7 @@ message ControllerSettings {
558
577
 
559
578
  message ControllerState {
560
579
  // Wire-confirmed from field_11.f4 of HomeDatastoreSystem.
561
- // f1 = updated_ts (KMP: ControllerState.updatedTimestamp, used by Controller.isOnline())
562
- // f2 = raw Dial surface thermistor (inflated by self-heating; used for display).
580
+ // f1 = updated_ts; f2 = raw Dial surface thermistor (inflated by self-heating; used for display).
563
581
  // f5 = calibrated/corrected ambient temperature sent to IDU as external_ambient_temperature_c.
564
582
  // Cross-confirmed: f5 value matches IndoorUnitHvacInputs.external_ambient_temperature_c
565
583
  // for all 5 rooms during live operation.
@@ -590,7 +608,7 @@ enum WifiConnectionState {
590
608
  WIFI_STATE_WPA_COMPLETED = 10;
591
609
  }
592
610
 
593
- // APK-confirmed field layout (NM.java). Used in QSM (f4/f5/f6) and Controller (f5/f6/f7).
611
+ // Wire-confirmed field layout. Used in QSM (f4/f5/f6) and Controller (f5/f6/f7).
594
612
  message WifiState {
595
613
  WifiConnectionState wifi_state = 1; // connection phase (DISCONNECTED→WPA_COMPLETED)
596
614
  string ssid = 2; // "Tigger" — shared Quilt AP
@@ -620,7 +638,7 @@ message ControllerHardware {
620
638
  ControllerHardwareAttributes attributes = 2; // wire-confirmed: f2 (replaces ControllerHardwareSpecs)
621
639
  }
622
640
 
623
- // APK-confirmed field layout (C5331pI.java):
641
+ // Wire-confirmed field layout:
624
642
  // header=1, relationships=2, settings=3, state=4,
625
643
  // hosted_wifi_state=5, ap_wifi_state=6, p2p_wifi_state=7, controls=8.
626
644
  message Controller {
@@ -632,52 +650,47 @@ message Controller {
632
650
  WifiState ap_wifi_state = 6; // the upstream AP the controller connects to
633
651
  WifiState p2p_wifi_state = 7; // peer-to-peer WiFi (usually empty)
634
652
  ControllerControls controls = 8;
653
+ LocalCommsStatus local_comms_status = 9; // local mesh communication status
635
654
  }
636
655
 
637
656
  // ---------------------------------------------------------------------------
638
657
  // Remote Sensor (BLE temperature/humidity sensor)
639
658
  // ---------------------------------------------------------------------------
640
659
 
641
- // APK-confirmed (C5921sL.java): MAC_FIELD_NUMBER=1, UPDATED_TS_FIELD_NUMBER=2.
642
- // APK-confirmed (C5921sL.java): MAC_FIELD_NUMBER=1, UPDATED_TS_FIELD_NUMBER=2.
643
660
  // Shared by both RemoteSensor and ControllerRemoteSensor.
644
661
  message RemoteSensorAttributes {
645
- string mac = 1; // APK: MAC_FIELD_NUMBER=1
646
- google.protobuf.Timestamp updated_ts = 2; // APK: UPDATED_TS_FIELD_NUMBER=2
662
+ string mac = 1;
663
+ google.protobuf.Timestamp updated_ts = 2;
647
664
  }
648
665
 
649
- // APK-confirmed (AL.java): ambient_temp=1, humidity=2, updated_ts=3, battery=4, signal=5.
650
666
  // Shared by both RemoteSensor and ControllerRemoteSensor.
651
667
  message RemoteSensorState {
652
- float ambient_temperature_c = 1; // APK: AMBIENT_TEMPERATURE_C_FIELD_NUMBER=1
653
- float humidity_percent = 2; // APK: HUMIDITY_PERCENT_FIELD_NUMBER=2
654
- google.protobuf.Timestamp updated_ts = 3; // APK: UPDATED_TS_FIELD_NUMBER=3
655
- float battery_level_percent = 4; // APK: BATTERY_LEVEL_PERCENT_FIELD_NUMBER=4
656
- int32 signal_level_dbm = 5; // APK: SIGNAL_LEVEL_DBM_FIELD_NUMBER=5
668
+ float ambient_temperature_c = 1;
669
+ float humidity_percent = 2;
670
+ google.protobuf.Timestamp updated_ts = 3;
671
+ float battery_level_percent = 4;
672
+ int32 signal_level_dbm = 5;
657
673
  }
658
674
 
659
- // APK-confirmed (C7085yL.java): indoor_unit_id=1, updated_ts=2.
660
675
  // Used by standalone RemoteSensor (field 12 in HomeDatastoreSystem).
661
676
  message RemoteSensorRelationships {
662
- string indoor_unit_id = 1; // APK: INDOOR_UNIT_ID_FIELD_NUMBER=1
677
+ string indoor_unit_id = 1;
663
678
  google.protobuf.Timestamp updated_ts = 2;
664
679
  }
665
680
 
666
- // APK-confirmed (FI.java): controller_id=1, updated_ts=2.
667
681
  // Used by ControllerRemoteSensor (field 16 in HomeDatastoreSystem).
668
682
  message ControllerRemoteSensorRelationships {
669
- string controller_id = 1; // APK: CONTROLLER_ID_FIELD_NUMBER=1
683
+ string controller_id = 1;
670
684
  google.protobuf.Timestamp updated_ts = 2;
671
685
  }
672
686
 
673
- // APK-confirmed (C6503vL.java): updated_ts=1, control_mode=2.
674
687
  // Shared by both RemoteSensor and ControllerRemoteSensor.
675
688
  message RemoteSensorControls {
676
- google.protobuf.Timestamp updated_ts = 1; // APK: UPDATED_TS_FIELD_NUMBER=1
677
- RemoteSensorControlMode control_mode = 2; // APK: CONTROL_MODE_FIELD_NUMBER=2
689
+ google.protobuf.Timestamp updated_ts = 1;
690
+ RemoteSensorControlMode control_mode = 2;
678
691
  }
679
692
 
680
- // APK-confirmed (C5534qL.java): header=1, attributes=2, state=3, relationships=4, controls=5.
693
+ // Wire-confirmed: header=1, attributes=2, state=3, relationships=4, controls=5.
681
694
  // Standalone remote sensor linked to an IndoorUnit (field 12 in HomeDatastoreSystem).
682
695
  // Not present in installations without paired remote sensors.
683
696
  message RemoteSensor {
@@ -688,7 +701,7 @@ message RemoteSensor {
688
701
  RemoteSensorControls controls = 5;
689
702
  }
690
703
 
691
- // APK-confirmed (CI.java): header=1, attributes=2, state=3, relationships=4, controls=5.
704
+ // Wire-confirmed: header=1, attributes=2, state=3, relationships=4, controls=5.
692
705
  // Sensor capability of a Controller (Dial) used for zone temperature control.
693
706
  // Linked to a Controller via controller_id. Field 16 in HomeDatastoreSystem.
694
707
  // Not present unless remote sensor control mode is configured on a Dial.
@@ -773,8 +786,8 @@ message ScheduleDayRelationships {
773
786
  string space_id = 2;
774
787
  }
775
788
 
776
- // APK-confirmed (DL.java): EVENTS_FIELD_NUMBER=3, RELATIONSHIPS_FIELD_NUMBER=4.
777
- // (Earlier proto.json source had these swapped — APK takes precedence.)
789
+ // Wire-confirmed: EVENTS_FIELD_NUMBER=3, RELATIONSHIPS_FIELD_NUMBER=4.
790
+ // (Earlier proto.json source had these swapped.)
778
791
  message ScheduleDay {
779
792
  EntityMetadata header = 1;
780
793
  ScheduleDayAttributes attributes = 2;
@@ -794,21 +807,16 @@ message ScheduleWeekRelationships {
794
807
  string space_id = 2;
795
808
  }
796
809
 
797
- // APK-confirmed (OL.java): DAYS_FIELD_NUMBER=2, RELATIONSHIPS_FIELD_NUMBER=3.
798
- // (Earlier proto.json source had relationships=2, days=3 — APK takes precedence.)
810
+ // Wire-confirmed: DAYS_FIELD_NUMBER=2, RELATIONSHIPS_FIELD_NUMBER=3.
811
+ // (Earlier proto.json source had these swapped.)
799
812
  message ScheduleWeek {
800
813
  EntityMetadata header = 1;
801
814
  repeated ScheduleWeekDay days = 2;
802
815
  ScheduleWeekRelationships relationships = 3;
803
816
  }
804
817
 
805
- // ---------------------------------------------------------------------------
806
- // QuiltSmartModule (QSM — embedded compute module in the IDU)
807
- // ---------------------------------------------------------------------------
808
-
809
818
  // ---------------------------------------------------------------------------
810
819
  // QuiltSmartModule (QSM — WiFi compute module embedded in every IDU)
811
- // Wire-confirmed: field 7 in HomeDatastoreSystem (5 items for 5 IDUs)
812
820
  // ---------------------------------------------------------------------------
813
821
 
814
822
  message QuiltSmartModuleRelationships {
@@ -817,13 +825,13 @@ message QuiltSmartModuleRelationships {
817
825
  string firmware_update_info_id = 3;
818
826
  }
819
827
 
820
- // APK-confirmed (C4171jL.java): LED_COLOR_CODE_FIELD_NUMBER=1, UPDATED_TS_FIELD_NUMBER=2.
828
+ // QSM LED color code and timestamp.
821
829
  message QuiltSmartModuleControls {
822
830
  int32 led_color_code = 1;
823
831
  google.protobuf.Timestamp updated_ts = 2;
824
832
  }
825
833
 
826
- // APK-confirmed (C5146oL.java): 9 fields, presence/ALS/accelerometer sensor data.
834
+ // QSM sensor data: presence, ambient light, and accelerometer readings.
827
835
  message QuiltSmartModuleState {
828
836
  float phase_detected_raw = 1; // presence sensor: phase (float, fixed32)
829
837
  float target_detected_raw = 2; // presence sensor: target (float, fixed32)
@@ -836,23 +844,24 @@ message QuiltSmartModuleState {
836
844
  google.protobuf.Timestamp updated_ts = 9;
837
845
  }
838
846
 
839
- // APK-confirmed (C3678hL.java):
847
+ // Wire-confirmed field layout:
840
848
  // header=1, controls=2, state=3, hosted_wifi_state=4, ap_wifi_state=5, p2p_wifi_state=6, relationships=7.
841
849
  message QuiltSmartModule {
842
850
  EntityMetadata header = 1;
843
- QuiltSmartModuleControls controls = 2; // APK: CONTROLS_FIELD_NUMBER=2
844
- QuiltSmartModuleState state = 3; // APK: STATE_FIELD_NUMBER=3 (was incorrectly at f2)
845
- WifiState hosted_wifi_state = 4; // APK: HOSTED_WIFI_STATE_FIELD_NUMBER=4
846
- WifiState ap_wifi_state = 5; // APK: AP_WIFI_STATE_FIELD_NUMBER=5
847
- WifiState p2p_wifi_state = 6; // APK: P2P_WIFI_STATE_FIELD_NUMBER=6 (usually empty)
851
+ QuiltSmartModuleControls controls = 2;
852
+ QuiltSmartModuleState state = 3;
853
+ WifiState hosted_wifi_state = 4;
854
+ WifiState ap_wifi_state = 5;
855
+ WifiState p2p_wifi_state = 6;
848
856
  QuiltSmartModuleRelationships relationships = 7;
857
+ LocalCommsStatus local_comms_status = 8; // local mesh communication status
849
858
  }
850
859
 
851
860
  // ---------------------------------------------------------------------------
852
861
  // Software / Firmware Update
853
862
  // ---------------------------------------------------------------------------
854
863
 
855
- // APK-confirmed (WL.java): SoftwareUpdateInfoAttributes fields.
864
+ // Software/firmware update state and progress for a device.
856
865
  message SoftwareUpdateInfoAttributes {
857
866
  google.protobuf.Timestamp updated_ts = 1;
858
867
  int32 state = 2; // update state (enum TBD)
@@ -864,37 +873,36 @@ message SoftwareUpdateInfoAttributes {
864
873
  int32 progress_unit = 8; // unit for progress values
865
874
  }
866
875
 
867
- // APK-confirmed (YL.java): HEADER_FIELD_NUMBER=1, ATTRIBUTES_FIELD_NUMBER=2.
868
876
  message SoftwareUpdateInfo {
869
- EntityMetadata header = 1; // APK: was named "metadata" — fix to "header"
877
+ EntityMetadata header = 1;
870
878
  SoftwareUpdateInfoAttributes attributes = 2;
871
879
  }
872
880
 
873
881
  // ---------------------------------------------------------------------------
874
882
  // HomeDatastoreSystem (full system snapshot)
875
- // ALL field numbers APK-confirmed from OJ.java (HomeDatastoreSystem proto class).
876
- // Fields 1, 2, 4 are unknown. Fields 12 and 16 are empty for installations
877
- // without standalone remote sensors or configured ControllerRemoteSensors.
883
+ // Wire-confirmed field numbers. Fields 1, 2, 4 are unknown/empty.
884
+ // Fields 12 and 16 are empty for installations without standalone remote
885
+ // sensors or configured ControllerRemoteSensors.
878
886
  // ---------------------------------------------------------------------------
879
887
 
880
888
  message HomeDatastoreSystem {
881
889
  // field 1, 2 — unknown/empty in captured system
882
- repeated Space spaces = 3; // APK: SPACES_FIELD_NUMBER=3; confirmed: 6 items
890
+ repeated Space spaces = 3;
883
891
  // field 4 — unknown/empty
884
- repeated OutdoorUnitHardware outdoor_unit_hardware = 5; // APK: OUTDOOR_UNIT_HARDWARE_FIELD_NUMBER=5; confirmed: 3 items
885
- repeated OutdoorUnit outdoor_units = 6; // APK: OUTDOOR_UNITS_FIELD_NUMBER=6; confirmed: 3 items
886
- repeated QuiltSmartModule quilt_smart_modules = 7; // APK: QUILT_SMART_MODULES_FIELD_NUMBER=7; confirmed: 5 items
887
- repeated IndoorUnitHardware indoor_unit_hardware = 8; // APK: INDOOR_UNIT_HARDWARE_FIELD_NUMBER=8; confirmed: 5 items
888
- repeated IndoorUnit indoor_units = 9; // APK: INDOOR_UNITS_FIELD_NUMBER=9; confirmed: 5 items
889
- repeated ControllerHardware controller_hardware = 10; // APK: CONTROLLER_HARDWARE_FIELD_NUMBER=10; confirmed: 5 items
890
- repeated Controller controllers = 11; // APK: CONTROLLERS_FIELD_NUMBER=11; confirmed: 5 items
891
- repeated RemoteSensor remote_sensors = 12; // APK: REMOTE_SENSORS_FIELD_NUMBER=12; empty without paired sensors
892
- repeated ComfortSetting comfort_settings = 13; // APK: COMFORT_SETTINGS_FIELD_NUMBER=13; confirmed: 20+ items
893
- repeated ScheduleDay schedule_days = 14; // APK: SCHEDULE_DAYS_FIELD_NUMBER=14; confirmed: 5 items
894
- repeated ScheduleWeek schedule_weeks = 15; // APK: SCHEDULE_WEEKS_FIELD_NUMBER=15; confirmed: 5 items
895
- repeated ControllerRemoteSensor controller_remote_sensors = 16; // APK: CONTROLLER_REMOTE_SENSORS_FIELD_NUMBER=16; empty without sensor mode configured
896
- repeated Location locations = 17; // APK: LOCATIONS_FIELD_NUMBER=17; confirmed: 1 item
897
- repeated SoftwareUpdateInfo software_update_infos = 18; // APK: SOFTWARE_UPDATE_INFOS_FIELD_NUMBER=18; confirmed: 28 items (SUI+FUI for all devices)
892
+ repeated OutdoorUnitHardware outdoor_unit_hardware = 5;
893
+ repeated OutdoorUnit outdoor_units = 6;
894
+ repeated QuiltSmartModule quilt_smart_modules = 7;
895
+ repeated IndoorUnitHardware indoor_unit_hardware = 8;
896
+ repeated IndoorUnit indoor_units = 9;
897
+ repeated ControllerHardware controller_hardware = 10;
898
+ repeated Controller controllers = 11;
899
+ repeated RemoteSensor remote_sensors = 12; // empty without paired sensors
900
+ repeated ComfortSetting comfort_settings = 13;
901
+ repeated ScheduleDay schedule_days = 14;
902
+ repeated ScheduleWeek schedule_weeks = 15;
903
+ repeated ControllerRemoteSensor controller_remote_sensors = 16; // empty without sensor mode configured
904
+ repeated Location locations = 17;
905
+ repeated SoftwareUpdateInfo software_update_infos = 18;
898
906
  }
899
907
 
900
908
  // ---------------------------------------------------------------------------
@@ -2,18 +2,17 @@
2
2
  // NotifierService — bidirectional streaming subscription service.
3
3
  // Confirmed gRPC path: /core.protos.notifier.NotifierService/Subscribe
4
4
  //
5
- // Android APK DEX class reference (authoritative):
6
- // HR0 = SubscribeRequest (oneof: append=2 | remove=3, each a TopicsMessage)
7
- // SR0 = TopicsMessage (subscriptions=1, repeated Subscription)
8
- // LR0 = Subscription (topic=1, string)
9
- // CR0 = SubscribeResponse (notifier_events=1, control_events=2, system_events=3)
10
- // ER0 = NotifierEvent (topic=1 string, payload=2 google.protobuf.Any)
11
- // C7104yR0 = ControlEvent (topics=1 repeated string, type=2 ControlEventType)
12
- // C6328uR0 = HdsNotification (notification_type=1, payload=2 HomeDatastoreObjectDiff)
13
- // MJ = HomeDatastoreObjectDiff (space=3, indoor_unit=9, ..., see quilt_hds.proto)
5
+ // Message type reference:
6
+ // SubscribeRequest (oneof: append=2 | remove=3, each a TopicsMessage)
7
+ // TopicsMessage (subscriptions=1, repeated Subscription)
8
+ // Subscription (topic=1, string)
9
+ // SubscribeResponse (notifier_events=1, control_events=2, system_events=3)
10
+ // NotifierEvent (topic=1 string, payload=2 google.protobuf.Any)
11
+ // ControlEvent (topics=1 repeated string, type=2 ControlEventType)
12
+ // HdsNotification (notification_type=1, payload=2 HomeDatastoreObjectDiff)
13
+ // HomeDatastoreObjectDiff (space=3, indoor_unit=9, ..., see quilt_hds.proto)
14
14
  //
15
- // NOTE: The current Android APK only exposes Subscribe. The previous cleaned proto
16
- // included a Publish RPC, but no matching descriptor was found in the APK.
15
+ // NOTE: Only Subscribe is exposed; no Publish RPC exists.
17
16
 
18
17
  syntax = "proto3";
19
18
 
@@ -27,7 +26,7 @@ option swift_prefix = "Quilt";
27
26
  // ---------------------------------------------------------------------------
28
27
  // Topics follow the pattern: hds/<object_type>/<object_id>
29
28
  // e.g. "hds/space/98f9121d-...", "hds/indoor_unit/abc123"
30
- // Object types (from EnumC5979se0.java):
29
+ // Object types:
31
30
  // space, outdoor_unit_hardware, outdoor_unit, indoor_unit_hardware,
32
31
  // indoor_unit, controller_hardware, controller, controller_remote_sensor,
33
32
  // remote_sensor, quilt_smart_module, schedule_week, schedule_day,
@@ -68,7 +67,7 @@ message SubscribeRequest {
68
67
  // outer_any = google.protobuf.Any{type_url="type.googleapis.com/core.protos.hds.HdsNotification",
69
68
  // value=HdsNotification bytes}
70
69
  // HdsNotification (C6328uR0): {notification_type=1(varint), payload=2(HomeDatastoreObjectDiff)}
71
- // HomeDatastoreObjectDiff (MJ.java): space=3, outdoor_unit=6, indoor_unit=9, etc.
70
+ // HomeDatastoreObjectDiff: space=3, outdoor_unit=6, indoor_unit=9, etc.
72
71
  // HEARTBEATS: topic (f1) absent (b""); payload (f2) = C1517Ta{type_url="hds/space/<uuid>",
73
72
  // value=b"" or varint control byte}
74
73
  // NOTE: topic field is 'bytes' (not string) because data events embed a binary C1517Ta message