python-mobius 0.8.4__tar.gz → 0.10.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.
- python_mobius-0.10.0/CHANGELOG.md +260 -0
- python_mobius-0.10.0/PKG-INFO +161 -0
- python_mobius-0.10.0/README.md +129 -0
- python_mobius-0.10.0/documentation/00-overview.md +92 -0
- python_mobius-0.10.0/documentation/01-ble-transport.md +71 -0
- python_mobius-0.10.0/documentation/02-framing-and-crc.md +131 -0
- python_mobius-0.10.0/documentation/03-attributes-and-opcodes.md +150 -0
- python_mobius-0.10.0/documentation/04-device-identity.md +113 -0
- python_mobius-0.10.0/documentation/05-scenes.md +122 -0
- python_mobius-0.10.0/documentation/06-light-schedule.md +327 -0
- python_mobius-0.10.0/documentation/07-pump-schedule.md +102 -0
- python_mobius-0.10.0/documentation/08-manufacturer-data.md +63 -0
- python_mobius-0.10.0/documentation/09-thread-coap-relay.md +187 -0
- python_mobius-0.10.0/documentation/10-known-gaps-and-open-questions.md +62 -0
- python_mobius-0.10.0/documentation/11-device-status-attributes.md +190 -0
- python_mobius-0.10.0/documentation/12-device-identity-and-address-stability.md +31 -0
- python_mobius-0.10.0/documentation/13-attribute-dump.md +64 -0
- python_mobius-0.10.0/documentation/14-attribute-reference.md +667 -0
- python_mobius-0.10.0/documentation/15-mob-template-format.md +64 -0
- python_mobius-0.10.0/documentation/16-python-library.md +172 -0
- python_mobius-0.10.0/documentation/17-configuration-checksums.md +84 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/pyproject.toml +1 -1
- {python_mobius-0.8.4 → python_mobius-0.10.0}/src/mobius/__init__.py +29 -20
- python_mobius-0.10.0/src/mobius/checksums.py +119 -0
- python_mobius-0.10.0/src/mobius/cli.py +1113 -0
- python_mobius-0.10.0/src/mobius/coap.py +158 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/src/mobius/constants.py +269 -277
- {python_mobius-0.8.4 → python_mobius-0.10.0}/src/mobius/crc.py +3 -5
- python_mobius-0.10.0/src/mobius/device.py +2783 -0
- python_mobius-0.10.0/src/mobius/device_status.py +431 -0
- python_mobius-0.10.0/src/mobius/discovery.py +190 -0
- python_mobius-0.10.0/src/mobius/dump.py +253 -0
- python_mobius-0.10.0/src/mobius/frame.py +216 -0
- python_mobius-0.10.0/src/mobius/manufacturer.py +70 -0
- python_mobius-0.10.0/src/mobius/mesh_address.py +96 -0
- python_mobius-0.10.0/src/mobius/mob.py +132 -0
- python_mobius-0.10.0/src/mobius/modifiers.py +134 -0
- python_mobius-0.10.0/src/mobius/power.py +65 -0
- python_mobius-0.10.0/src/mobius/pump_status.py +39 -0
- python_mobius-0.10.0/src/mobius/relay.py +225 -0
- python_mobius-0.10.0/src/mobius/scenes.py +114 -0
- python_mobius-0.10.0/src/mobius/schedule.py +353 -0
- python_mobius-0.10.0/src/mobius/timezone.py +63 -0
- python_mobius-0.10.0/tests/test_battery_settings.py +143 -0
- python_mobius-0.10.0/tests/test_bluetooth_only.py +119 -0
- python_mobius-0.10.0/tests/test_checksums.py +98 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_coap.py +2 -6
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_coap_indication_handling.py +4 -10
- python_mobius-0.10.0/tests/test_configuration_cache.py +259 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_device_control.py +3 -6
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_device_status.py +1 -2
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_full_poll_batch.py +51 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_light_poll_batch.py +20 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_light_schedule.py +2 -10
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_manufacturer_lookup.py +3 -7
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_metadata_batch.py +18 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_mob.py +2 -4
- python_mobius-0.10.0/tests/test_pump_param_ranges.py +81 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_pump_reverse.py +4 -9
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_relay.py +55 -26
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_scenes.py +137 -8
- python_mobius-0.10.0/tests/test_shared_helpers.py +85 -0
- python_mobius-0.10.0/tests/test_time_zone.py +68 -0
- python_mobius-0.10.0/tests/test_write_size.py +64 -0
- python_mobius-0.8.4/CHANGELOG.md +0 -890
- python_mobius-0.8.4/PKG-INFO +0 -208
- python_mobius-0.8.4/README.md +0 -176
- python_mobius-0.8.4/documentation/00-overview.md +0 -81
- python_mobius-0.8.4/documentation/01-ble-transport.md +0 -67
- python_mobius-0.8.4/documentation/02-framing-and-crc.md +0 -82
- python_mobius-0.8.4/documentation/03-attributes-and-opcodes.md +0 -97
- python_mobius-0.8.4/documentation/04-device-identity.md +0 -81
- python_mobius-0.8.4/documentation/05-scenes.md +0 -137
- python_mobius-0.8.4/documentation/06-light-schedule.md +0 -454
- python_mobius-0.8.4/documentation/07-pump-schedule.md +0 -185
- python_mobius-0.8.4/documentation/08-manufacturer-data.md +0 -95
- python_mobius-0.8.4/documentation/09-thread-coap-relay.md +0 -369
- python_mobius-0.8.4/documentation/10-known-gaps-and-open-questions.md +0 -171
- python_mobius-0.8.4/documentation/11-device-status-attributes.md +0 -336
- python_mobius-0.8.4/documentation/12-device-identity-and-address-stability.md +0 -83
- python_mobius-0.8.4/documentation/13-attribute-dump.md +0 -246
- python_mobius-0.8.4/documentation/14-batched-attribute-reads.md +0 -112
- python_mobius-0.8.4/documentation/15-mob-template-format.md +0 -107
- python_mobius-0.8.4/src/mobius/cli.py +0 -1380
- python_mobius-0.8.4/src/mobius/coap.py +0 -250
- python_mobius-0.8.4/src/mobius/device.py +0 -4211
- python_mobius-0.8.4/src/mobius/device_status.py +0 -751
- python_mobius-0.8.4/src/mobius/discovery.py +0 -274
- python_mobius-0.8.4/src/mobius/dump.py +0 -377
- python_mobius-0.8.4/src/mobius/frame.py +0 -266
- python_mobius-0.8.4/src/mobius/manufacturer.py +0 -73
- python_mobius-0.8.4/src/mobius/mesh_address.py +0 -136
- python_mobius-0.8.4/src/mobius/mob.py +0 -188
- python_mobius-0.8.4/src/mobius/modifiers.py +0 -169
- python_mobius-0.8.4/src/mobius/power.py +0 -91
- python_mobius-0.8.4/src/mobius/pump_status.py +0 -50
- python_mobius-0.8.4/src/mobius/relay.py +0 -496
- python_mobius-0.8.4/src/mobius/scenes.py +0 -97
- python_mobius-0.8.4/src/mobius/schedule.py +0 -418
- {python_mobius-0.8.4 → python_mobius-0.10.0}/.forgejo/scripts/extract_changelog_section.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/.forgejo/workflows/release.yml +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/.gitignore +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/LICENSE +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_attributes_batch.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_cli_group_targets.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_cli_mob_file.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_cli_schedule_file.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_connection_cleanup.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_device_summary.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_device_time.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_discovery_company_ids.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_dump.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_extra_physical_values.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_fan_thresholds.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_firmware_versions.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_frame.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_frame_sniffer.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_group_bitmap.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_hyperdrive_device.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_insolation_detection.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_light_intensity_branching.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_manufacturer.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_mesh_address.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_mesh_discovery.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_mesh_discovery_direct_connect.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_modifiers.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_networked_thread_devices.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_new_diagnostic_attributes.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_power.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_pump_schedule.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_pump_status.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_pump_supported_modes.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_pump_telemetry.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_schedule_file_format.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_schedule_intensity_scalar.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_serial_decoding.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_serial_identity.py +0 -0
- {python_mobius-0.8.4 → python_mobius-0.10.0}/tests/test_supported_attributes.py +0 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.10.0
|
|
4
|
+
|
|
5
|
+
- Added `set_time_zone()`; the batched polls now include the device's time
|
|
6
|
+
zone strings.
|
|
7
|
+
- Relayed requests now accept a late response to the first attempt, as
|
|
8
|
+
the app does.
|
|
9
|
+
- Fixed an unreachable light returning an empty poll as a success.
|
|
10
|
+
- Added configuration checksums (`get_configuration_checksums()`, CLI
|
|
11
|
+
`--check-checksums`).
|
|
12
|
+
- `get_full_poll_batch(cache=...)` reads scenes and schedules only when
|
|
13
|
+
their checksum changed.
|
|
14
|
+
- `start_scene()` now runs a scene for its configured length by default
|
|
15
|
+
(a duration of 0 makes the device reuse its last scene length).
|
|
16
|
+
- Fixed a scene briefly reporting about 18 hours remaining as it ends.
|
|
17
|
+
- Added Bluetooth-only device support (Blades, MXM): `is_bluetooth_only()`
|
|
18
|
+
and `find_bluetooth_only_tank_members()`. The CLI connects to them
|
|
19
|
+
directly and includes them in schedule group writes.
|
|
20
|
+
- Writes use the negotiated MTU instead of 20-byte fragments, as the app
|
|
21
|
+
does (fewer writes per request).
|
|
22
|
+
- The pump's operation state is now part of the batched poll.
|
|
23
|
+
- `ConfigurationCache(static_refresh_interval=...)` reads rarely-changing
|
|
24
|
+
attributes (identity, firmware, settings) only at that interval.
|
|
25
|
+
|
|
26
|
+
## 0.9.0
|
|
27
|
+
|
|
28
|
+
- **Breaking:** `RelayedMobiusDevice` writes now raise an error when the
|
|
29
|
+
device rejects them, like direct writes already did.
|
|
30
|
+
- Added helpers shared with ha-mobius: `enum_or_none()`,
|
|
31
|
+
`primitive_type_from_name()`, `support_tier()`, `parse_advertisement()`,
|
|
32
|
+
`schedule_capacity()`/`min_schedule_capacity()`, `format_mesh_address()`,
|
|
33
|
+
`pump_params_to_dict()`, `Scene.is_empty` and `PUMP_PRIMITIVES`.
|
|
34
|
+
- Added pump battery settings: `set_battery_backup_speed()` (limited to the
|
|
35
|
+
pump's battery backup max speed) and `set_boosted_battery()` (only while
|
|
36
|
+
running on battery), with the `--set-battery-backup-speed` and
|
|
37
|
+
`--set-boosted-battery-*` options.
|
|
38
|
+
- Added `get_operation_mode()` and the `OperationMode` enum; pump telemetry
|
|
39
|
+
now includes `operation_mode` (`"BatteryBackup"` while running on
|
|
40
|
+
battery).
|
|
41
|
+
- `get_full_poll_batch()` now includes the battery settings
|
|
42
|
+
(`battery_backup`, `boosted_battery`) and the operation mode.
|
|
43
|
+
- The boosted battery power is permille (0-100 %) and its on/off times are
|
|
44
|
+
seconds.
|
|
45
|
+
- `mobius-scan`: the debug mesh listing now shows peer age as unsigned, like
|
|
46
|
+
the library.
|
|
47
|
+
- **Breaking:** fixed the running scene's remaining time: it's now read from
|
|
48
|
+
`SceneTimer`, so it counts down, and `ActiveScene.timeout_seconds` holds
|
|
49
|
+
the scene's total time. `get_current_scene()` returns None when no scene
|
|
50
|
+
is running.
|
|
51
|
+
- Starting a scene, returning to the schedule and restarting all devices now
|
|
52
|
+
use the tank's group, like the app (`get_tank_group()`, `tank_group()`).
|
|
53
|
+
**Breaking:** `resume_schedule()` now ends the scene on every device of
|
|
54
|
+
the tank with one write (`broadcast=False` for one device only).
|
|
55
|
+
- **Breaking:** `set_pump_schedule()` now rejects parameters outside the
|
|
56
|
+
ranges the app allows (for example a Short Pulse time of 0), before
|
|
57
|
+
writing. Added `pump_param_range()` and `pump_param_errors()`.
|
|
58
|
+
- Internal cleanup: removed duplicated code and simplified comments.
|
|
59
|
+
|
|
60
|
+
## 0.8.4
|
|
61
|
+
|
|
62
|
+
- Added `LightPollResult.lunar_enabled` and `lunar_phase_day`, valid at any
|
|
63
|
+
time of day (the matching `diagnostics` keys are only set at night).
|
|
64
|
+
|
|
65
|
+
## 0.8.3
|
|
66
|
+
|
|
67
|
+
- Added `set_lunar_enabled(enabled)`: the value the app's Lunar chip
|
|
68
|
+
writes.
|
|
69
|
+
|
|
70
|
+
## 0.8.2
|
|
71
|
+
|
|
72
|
+
- Added `LightPollResult.schedule_intensity`: the schedule intensity
|
|
73
|
+
setting (unlike `diagnostics["scalar"]`, which is the lunar reduction at
|
|
74
|
+
night).
|
|
75
|
+
|
|
76
|
+
## 0.8.1
|
|
77
|
+
|
|
78
|
+
- Added `get_pump_reverse(primitive_type, params)`: whether a pump
|
|
79
|
+
point's speed means reverse rotation (AlpacaV1 only).
|
|
80
|
+
- Added `reboot_all()`: restarts every device of the tank, like the app's
|
|
81
|
+
"Restart all Devices".
|
|
82
|
+
|
|
83
|
+
## 0.8.0
|
|
84
|
+
|
|
85
|
+
- Added `supported_pump_modes(primitive_type, closed_loop=None)`: the pump
|
|
86
|
+
modes each pump supports (see `documentation/07-pump-schedule.md`,
|
|
87
|
+
"Modes per pump").
|
|
88
|
+
- Added schedule writing: `set_light_schedule()`, `set_pump_schedule()`,
|
|
89
|
+
`GroupBitmap` (`group_mask`), and the `--dump-schedule-file` /
|
|
90
|
+
`--load-schedule-file` options.
|
|
91
|
+
- Added `.mob` template files: export and import for light and pump
|
|
92
|
+
schedules, and the `--dump-mob-file` / `--load-mob-file` options.
|
|
93
|
+
- Loading a schedule into a light now also writes every light in its
|
|
94
|
+
schedule group, after checking the group's smallest capacity.
|
|
95
|
+
- `get_pump_telemetry()` now includes every other sensor value the pump
|
|
96
|
+
reports (`extra_physical_values`).
|
|
97
|
+
- Added `get_extra_physical_values()`, also shown for lights in
|
|
98
|
+
`get_device_summary()`.
|
|
99
|
+
- Added `get_fan_thresholds()`.
|
|
100
|
+
|
|
101
|
+
## 0.7.2
|
|
102
|
+
|
|
103
|
+
- `get_full_poll_batch()` now includes the scenes.
|
|
104
|
+
- `start_scene()` / `start_feed_mode()` now apply to the whole tank by
|
|
105
|
+
default; `broadcast=False` writes one device only.
|
|
106
|
+
|
|
107
|
+
## 0.7.1
|
|
108
|
+
|
|
109
|
+
- Added scenes: `get_configured_scenes()`, `get_current_scene()`,
|
|
110
|
+
`start_scene()`.
|
|
111
|
+
- Fixed `get_current_scene()` failing on user-created scenes.
|
|
112
|
+
- `start_scene()`'s duration is in seconds (it was documented as minutes).
|
|
113
|
+
|
|
114
|
+
## 0.7.0
|
|
115
|
+
|
|
116
|
+
- Added `get_full_poll_batch()`: everything a poll needs in one request,
|
|
117
|
+
2-2.6× faster.
|
|
118
|
+
- Added `get_light_poll_batch()`: a light's schedule and intensity inputs
|
|
119
|
+
in one request.
|
|
120
|
+
- `get_current_pump_block()` accepts an already-read schedule (`points`).
|
|
121
|
+
|
|
122
|
+
## 0.6.0
|
|
123
|
+
|
|
124
|
+
- Added `get_metadata_batch()`: settings, calibration, firmware, hardware,
|
|
125
|
+
channels, error state and clock in one request (6-14× faster over the
|
|
126
|
+
relay), with a fallback to individual reads (`used_batch`,
|
|
127
|
+
`force_individual_reads`).
|
|
128
|
+
- Added `get_attributes_batch()`: several attributes in one request.
|
|
129
|
+
- Added attribute dumps: `get_supported_attributes()`,
|
|
130
|
+
`dump_attributes()`, `enrich_attribute_dump()` and the
|
|
131
|
+
`--dump-attributes` / `--parse-dump` options.
|
|
132
|
+
- Added `set_advanced_features()` and the `--set-local-control-enabled`,
|
|
133
|
+
`--set-auto-dim-timeout`, `--set-max-fan-speed` and
|
|
134
|
+
`--set-fan-shutdown-enabled` options.
|
|
135
|
+
- The lunar calculation now uses the same date as the app, so the values
|
|
136
|
+
match what the app shows.
|
|
137
|
+
- Fixed `RelayedMobiusDevice` not relaying `get_supported_attributes()`
|
|
138
|
+
and `get_attributes_batch()`.
|
|
139
|
+
- Fixed `--dump-attributes` and `--set-time-to-now` ignoring
|
|
140
|
+
`--relay-target`.
|
|
141
|
+
|
|
142
|
+
## 0.5.0
|
|
143
|
+
|
|
144
|
+
- `get_pump_telemetry()` now returns `gph_reliable`, `minimum_gph` and
|
|
145
|
+
`maximum_gph`; flow is only reliable when the pump reports a flow range.
|
|
146
|
+
- Added `motor_power_watts` to `get_pump_telemetry()` (Vectra, NYOS
|
|
147
|
+
Quantum).
|
|
148
|
+
- Added support for AquaIllumination devices (company ID `0x0001`).
|
|
149
|
+
**Breaking:** `MOBIUS_COMPANY_ID` is now `MOBIUS_COMPANY_ID_ECOTECH`.
|
|
150
|
+
- Added `get_lunar_phase_info()` (the device's own lunar state) and show
|
|
151
|
+
it in `--dump-schedule`. Read errors are now raised instead of
|
|
152
|
+
returning `None`.
|
|
153
|
+
- Added `get_advanced_features()`, `get_vectra_info()` and
|
|
154
|
+
`get_coffee_info()`.
|
|
155
|
+
- Added `set_time_to_now()` (sets the clock of the whole tank) and
|
|
156
|
+
`reboot()`.
|
|
157
|
+
- Fixed firmware labels for AquaIllumination devices.
|
|
158
|
+
- A relayed device that timed out now fails its other reads in the same
|
|
159
|
+
poll immediately.
|
|
160
|
+
|
|
161
|
+
## 0.4.4
|
|
162
|
+
|
|
163
|
+
- The device model list is now complete (EcoTech Marine,
|
|
164
|
+
AquaIllumination, Neptune Systems, NYOS). `Model.VersaVX1` is now listed
|
|
165
|
+
under EcoTech Marine.
|
|
166
|
+
- Several models are now named after their product (e.g. `Model.Axis40`,
|
|
167
|
+
`Model.Blade`, `Model.Quantum160`).
|
|
168
|
+
- Fixed the lunar-dimmed light intensity disagreeing with the app for
|
|
169
|
+
hours at a time.
|
|
170
|
+
|
|
171
|
+
## 0.4.3
|
|
172
|
+
|
|
173
|
+
- Relayed reads are retried once before failing, like the app does.
|
|
174
|
+
|
|
175
|
+
## 0.4.2
|
|
176
|
+
|
|
177
|
+
- Fixed `MeshPeer.age` being read as signed. It is the time since the peer
|
|
178
|
+
was last heard on the mesh, so it can go down.
|
|
179
|
+
- Fixed `mobius-scan --dump-schedule` failing for pumps.
|
|
180
|
+
|
|
181
|
+
## 0.4.1
|
|
182
|
+
|
|
183
|
+
- Fixed `discover_tank()` sometimes listing the connected device twice.
|
|
184
|
+
|
|
185
|
+
## 0.4.0
|
|
186
|
+
|
|
187
|
+
- Added mesh discovery through `NetworkedThreadDevices`, which works
|
|
188
|
+
without an MXM hub: `discover_networked_thread_devices()`, `MeshPeer.age`
|
|
189
|
+
and `mesh_local_prefix_from_mlprefix()`.
|
|
190
|
+
- Added `discover_mesh_peers_auto()`, the recommended way to discover the
|
|
191
|
+
tank's devices.
|
|
192
|
+
- Added `Tank` and `discover_tank()`: every device of a tank with its mesh
|
|
193
|
+
address and age.
|
|
194
|
+
- `mobius-scan` now lists devices by tank and connects to one device to
|
|
195
|
+
show the tank's mesh addresses; `--scan-only` skips connecting,
|
|
196
|
+
`--full-summaries` connects to every device and `--dump-tanks` shows
|
|
197
|
+
every tank.
|
|
198
|
+
|
|
199
|
+
## 0.3.1
|
|
200
|
+
|
|
201
|
+
- Fixed the Brightness channel not dimming the other channels, which
|
|
202
|
+
made light intensities too high.
|
|
203
|
+
|
|
204
|
+
## 0.3.0
|
|
205
|
+
|
|
206
|
+
- Fixed lunar dimming being applied to the wrong part of the night.
|
|
207
|
+
- `get_hardware_info()` now returns labels for colour, product, radio and
|
|
208
|
+
motor type, and is included in `get_device_summary()`.
|
|
209
|
+
|
|
210
|
+
## 0.2.1
|
|
211
|
+
|
|
212
|
+
- Fixed lists that the device returns in several parts being cut short
|
|
213
|
+
(for example some firmware versions were missing).
|
|
214
|
+
|
|
215
|
+
## 0.2.0
|
|
216
|
+
|
|
217
|
+
- Added relaying through the Thread mesh: `RelayedMobiusDevice` reaches
|
|
218
|
+
every device of a tank through one BLE connection. Added `mobius.coap`
|
|
219
|
+
and `mobius.mesh_address`.
|
|
220
|
+
- Added mesh discovery: `get_own_mesh_address()`,
|
|
221
|
+
`discover_mesh_peers()` (MXM hub) and
|
|
222
|
+
`discover_mesh_peers_via_direct_connect()`.
|
|
223
|
+
- Added the `mobius-scan` options `--dump-mesh-peers`, `--relay-target`,
|
|
224
|
+
`--debug-relay`, `--build-peer-map` and `--dump-schedule`.
|
|
225
|
+
- Added `get_device_time_info()` (clock drift).
|
|
226
|
+
- `get_current_light_intensities()` now reports how its result was
|
|
227
|
+
computed in `.diagnostics`.
|
|
228
|
+
|
|
229
|
+
## 0.1.4
|
|
230
|
+
|
|
231
|
+
- Added `MobiusDevice.is_connected`.
|
|
232
|
+
|
|
233
|
+
## 0.1.3
|
|
234
|
+
|
|
235
|
+
- Devices are now identified by serial number instead of BLE address,
|
|
236
|
+
which can change: `find_device_by_serial()`, `dedupe_by_serial()`,
|
|
237
|
+
`MobiusDevice(serial=...)` and `mobius-scan --by-serial`.
|
|
238
|
+
- Added `get_firmware_versions()` and `get_hardware_info()`.
|
|
239
|
+
- Added `get_group_info()`, `get_calibration_info()` and
|
|
240
|
+
`get_maintenance_info()`.
|
|
241
|
+
- Added `get_pump_flow_range()`, `get_pump_override_mode()`,
|
|
242
|
+
`get_battery_backup_info()` and `get_boosted_battery_info()`, included
|
|
243
|
+
in `get_device_summary()`.
|
|
244
|
+
- Light intensities now include the schedule intensity, lunar phases,
|
|
245
|
+
acclimation and hyperdrive (`get_current_light_percentages()`), and flag
|
|
246
|
+
Insolation (not supported).
|
|
247
|
+
|
|
248
|
+
## 0.1.2
|
|
249
|
+
|
|
250
|
+
- Added `manufacturer_for_model()` / `MODEL_MANUFACTURER`.
|
|
251
|
+
- Serial numbers are returned as text instead of hex.
|
|
252
|
+
- `get_pump_telemetry()` now includes `speed_percent`.
|
|
253
|
+
- Fixed a connection left open when subscribing to notifications failed.
|
|
254
|
+
|
|
255
|
+
## 0.1.0
|
|
256
|
+
|
|
257
|
+
- First release: framing, CRC and attribute get/set; scenes; pump
|
|
258
|
+
telemetry and schedules; light schedules and current intensities;
|
|
259
|
+
device identity and `get_device_summary()`; discovery and tank grouping
|
|
260
|
+
from advertisements; the `mobius-scan` command.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: python-mobius
|
|
3
|
+
Version: 0.10.0
|
|
4
|
+
Summary: Reverse-engineered Python client for the Mobius BLE protocol (EcoTech Marine VorTech/Radion, AquaIllumination, Neptune Systems, NYOS)
|
|
5
|
+
Project-URL: Homepage, https://code.r3pek.org/r3pek/python-mobius
|
|
6
|
+
Project-URL: Documentation, https://code.r3pek.org/r3pek/python-mobius/src/branch/main/documentation
|
|
7
|
+
Project-URL: Issues, https://code.r3pek.org/r3pek/python-mobius/issues
|
|
8
|
+
Author: r3pek
|
|
9
|
+
License: GPL-2.0-only
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: aquarium,ble,bleak,bluetooth,ecotech,fsci,mobius,radion,reef,vortech
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2)
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Home Automation
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Topic :: System :: Hardware
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Requires-Dist: bleak>=0.21
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: bleak-retry-connector>=3.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
29
|
+
Provides-Extra: retry
|
|
30
|
+
Requires-Dist: bleak-retry-connector>=3.0; extra == 'retry'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# python-mobius
|
|
34
|
+
|
|
35
|
+
A Python client for the Bluetooth protocol of "Mobius" aquarium devices:
|
|
36
|
+
EcoTech Marine (VorTech and Vectra pumps, Radion lights),
|
|
37
|
+
AquaIllumination (Prime, Hydra, Orbit, Axis), Neptune Systems and NYOS.
|
|
38
|
+
Built on [`bleak`](https://github.com/hbldh/bleak).
|
|
39
|
+
|
|
40
|
+
**Not affiliated with or endorsed by any of these companies.** This is an
|
|
41
|
+
independent implementation of the protocol for interoperability with
|
|
42
|
+
hardware you own, based on reverse engineering of the Mobius app and
|
|
43
|
+
public community research. The protocol is documented in
|
|
44
|
+
[`documentation/`](./documentation/00-overview.md), in enough detail to
|
|
45
|
+
implement it in another language.
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- **Discovery without connecting**: model, serial number and tank (pan_id)
|
|
50
|
+
from BLE advertisements.
|
|
51
|
+
- **Lights**: channels, schedules, and the current intensity computed the
|
|
52
|
+
way the app does it (schedule intensity, lunar phases, acclimation,
|
|
53
|
+
hyperdrive).
|
|
54
|
+
- **Pumps**: speed, flow, motor power and other sensor values; schedules
|
|
55
|
+
and the active mode; battery backup settings and whether the pump runs
|
|
56
|
+
on battery.
|
|
57
|
+
- **Schedules**: read and write, as editable JSON or as the app's `.mob`
|
|
58
|
+
template files; light schedule groups are handled.
|
|
59
|
+
- **Scenes**: list, start (whole tank) and cancel.
|
|
60
|
+
- **Settings and commands**: advanced features (Local Control, LED auto
|
|
61
|
+
dim, fan speed, fan shutdown), lunar phases, schedule intensity, time
|
|
62
|
+
sync, reboot, restart all.
|
|
63
|
+
- **One connection per tank**: every other device of the tank is reached
|
|
64
|
+
through it over the Thread mesh (`RelayedMobiusDevice`).
|
|
65
|
+
- **Batched polling**: everything a poll needs in one request.
|
|
66
|
+
- **Diagnostics**: attribute dumps, firmware and hardware information,
|
|
67
|
+
Thread and clock diagnostics.
|
|
68
|
+
- **`mobius-scan`** command line tool.
|
|
69
|
+
|
|
70
|
+
## Supported devices
|
|
71
|
+
|
|
72
|
+
| PrimitiveType | Devices | Support |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| `VisualV1` | Radion, Prime, Hydra | Tested |
|
|
75
|
+
| `VorTechV1`, `TurtleV1` | VorTech, Axis | Tested |
|
|
76
|
+
| `PumpV1`, `VectraV1`, `AlpacaV1` | Nero, Vectra, Orbit | Same format as the tested pumps; not tested |
|
|
77
|
+
| `CoffeeV1` | NYOS Quantum | Experimental: decoded with the pump format, not tested |
|
|
78
|
+
| `DoseV1`, `HotSauceV1` | Dosers, sensors | Identity only |
|
|
79
|
+
|
|
80
|
+
See [known gaps](./documentation/10-known-gaps-and-open-questions.md) for
|
|
81
|
+
what isn't covered or tested.
|
|
82
|
+
|
|
83
|
+
## Install
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pip install python-mobius
|
|
87
|
+
# recommended: more reliable connections
|
|
88
|
+
pip install "python-mobius[retry]"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Python 3.9 or newer.
|
|
92
|
+
|
|
93
|
+
## Quick start
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
import asyncio
|
|
97
|
+
from mobius import scan_for_mobius_devices_with_info, group_by_pan_id, MobiusDevice
|
|
98
|
+
|
|
99
|
+
async def main():
|
|
100
|
+
found = await scan_for_mobius_devices_with_info()
|
|
101
|
+
for pan_id, members in group_by_pan_id(found).items():
|
|
102
|
+
print(f"tank {pan_id:#06x}:")
|
|
103
|
+
for device, info in members:
|
|
104
|
+
print(f" {info.serial} {info.model.name if info.model else info.model_raw}")
|
|
105
|
+
|
|
106
|
+
device, info = found[0]
|
|
107
|
+
async with MobiusDevice(device, serial=info.serial) as d:
|
|
108
|
+
print(await d.get_device_summary())
|
|
109
|
+
|
|
110
|
+
asyncio.run(main())
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Reaching the rest of the tank through one connection:
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from mobius import RelayedMobiusDevice
|
|
117
|
+
|
|
118
|
+
async with MobiusDevice(serial="00000000000002") as gateway:
|
|
119
|
+
for peer in await gateway.discover_mesh_peers_auto():
|
|
120
|
+
print(await RelayedMobiusDevice(gateway, peer).get_device_info())
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Command line:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
mobius-scan # list devices by tank
|
|
127
|
+
mobius-scan --by-serial SERIAL --dump-schedule
|
|
128
|
+
mobius-scan --by-serial SERIAL --relay-target OTHER_SERIAL
|
|
129
|
+
mobius-scan --help
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The full API and every CLI option are described in
|
|
133
|
+
[documentation/16-python-library.md](./documentation/16-python-library.md).
|
|
134
|
+
|
|
135
|
+
## Development
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
git clone https://code.r3pek.org/r3pek/python-mobius
|
|
139
|
+
cd python-mobius
|
|
140
|
+
pip install -e ".[dev]"
|
|
141
|
+
pytest
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Tests use captured packets and advertisements from real devices where
|
|
145
|
+
possible.
|
|
146
|
+
|
|
147
|
+
## Related
|
|
148
|
+
|
|
149
|
+
[ha-mobius](https://code.r3pek.org/r3pek/ha-mobius) is a Home Assistant
|
|
150
|
+
integration built on this library.
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
GPLv2, see [`LICENSE`](./LICENSE).
|
|
155
|
+
|
|
156
|
+
## Acknowledgments
|
|
157
|
+
|
|
158
|
+
The Reef2Reef thread "Controlling Mobius enabled VorTech pump using 0-10V
|
|
159
|
+
and BLE" and the `danmrossi/MobiusControl` project, whose work this
|
|
160
|
+
builds on. The reverse engineering and implementation were done with
|
|
161
|
+
substantial help from Claude (Anthropic).
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# python-mobius
|
|
2
|
+
|
|
3
|
+
A Python client for the Bluetooth protocol of "Mobius" aquarium devices:
|
|
4
|
+
EcoTech Marine (VorTech and Vectra pumps, Radion lights),
|
|
5
|
+
AquaIllumination (Prime, Hydra, Orbit, Axis), Neptune Systems and NYOS.
|
|
6
|
+
Built on [`bleak`](https://github.com/hbldh/bleak).
|
|
7
|
+
|
|
8
|
+
**Not affiliated with or endorsed by any of these companies.** This is an
|
|
9
|
+
independent implementation of the protocol for interoperability with
|
|
10
|
+
hardware you own, based on reverse engineering of the Mobius app and
|
|
11
|
+
public community research. The protocol is documented in
|
|
12
|
+
[`documentation/`](./documentation/00-overview.md), in enough detail to
|
|
13
|
+
implement it in another language.
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- **Discovery without connecting**: model, serial number and tank (pan_id)
|
|
18
|
+
from BLE advertisements.
|
|
19
|
+
- **Lights**: channels, schedules, and the current intensity computed the
|
|
20
|
+
way the app does it (schedule intensity, lunar phases, acclimation,
|
|
21
|
+
hyperdrive).
|
|
22
|
+
- **Pumps**: speed, flow, motor power and other sensor values; schedules
|
|
23
|
+
and the active mode; battery backup settings and whether the pump runs
|
|
24
|
+
on battery.
|
|
25
|
+
- **Schedules**: read and write, as editable JSON or as the app's `.mob`
|
|
26
|
+
template files; light schedule groups are handled.
|
|
27
|
+
- **Scenes**: list, start (whole tank) and cancel.
|
|
28
|
+
- **Settings and commands**: advanced features (Local Control, LED auto
|
|
29
|
+
dim, fan speed, fan shutdown), lunar phases, schedule intensity, time
|
|
30
|
+
sync, reboot, restart all.
|
|
31
|
+
- **One connection per tank**: every other device of the tank is reached
|
|
32
|
+
through it over the Thread mesh (`RelayedMobiusDevice`).
|
|
33
|
+
- **Batched polling**: everything a poll needs in one request.
|
|
34
|
+
- **Diagnostics**: attribute dumps, firmware and hardware information,
|
|
35
|
+
Thread and clock diagnostics.
|
|
36
|
+
- **`mobius-scan`** command line tool.
|
|
37
|
+
|
|
38
|
+
## Supported devices
|
|
39
|
+
|
|
40
|
+
| PrimitiveType | Devices | Support |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `VisualV1` | Radion, Prime, Hydra | Tested |
|
|
43
|
+
| `VorTechV1`, `TurtleV1` | VorTech, Axis | Tested |
|
|
44
|
+
| `PumpV1`, `VectraV1`, `AlpacaV1` | Nero, Vectra, Orbit | Same format as the tested pumps; not tested |
|
|
45
|
+
| `CoffeeV1` | NYOS Quantum | Experimental: decoded with the pump format, not tested |
|
|
46
|
+
| `DoseV1`, `HotSauceV1` | Dosers, sensors | Identity only |
|
|
47
|
+
|
|
48
|
+
See [known gaps](./documentation/10-known-gaps-and-open-questions.md) for
|
|
49
|
+
what isn't covered or tested.
|
|
50
|
+
|
|
51
|
+
## Install
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install python-mobius
|
|
55
|
+
# recommended: more reliable connections
|
|
56
|
+
pip install "python-mobius[retry]"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Python 3.9 or newer.
|
|
60
|
+
|
|
61
|
+
## Quick start
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import asyncio
|
|
65
|
+
from mobius import scan_for_mobius_devices_with_info, group_by_pan_id, MobiusDevice
|
|
66
|
+
|
|
67
|
+
async def main():
|
|
68
|
+
found = await scan_for_mobius_devices_with_info()
|
|
69
|
+
for pan_id, members in group_by_pan_id(found).items():
|
|
70
|
+
print(f"tank {pan_id:#06x}:")
|
|
71
|
+
for device, info in members:
|
|
72
|
+
print(f" {info.serial} {info.model.name if info.model else info.model_raw}")
|
|
73
|
+
|
|
74
|
+
device, info = found[0]
|
|
75
|
+
async with MobiusDevice(device, serial=info.serial) as d:
|
|
76
|
+
print(await d.get_device_summary())
|
|
77
|
+
|
|
78
|
+
asyncio.run(main())
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Reaching the rest of the tank through one connection:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from mobius import RelayedMobiusDevice
|
|
85
|
+
|
|
86
|
+
async with MobiusDevice(serial="00000000000002") as gateway:
|
|
87
|
+
for peer in await gateway.discover_mesh_peers_auto():
|
|
88
|
+
print(await RelayedMobiusDevice(gateway, peer).get_device_info())
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Command line:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
mobius-scan # list devices by tank
|
|
95
|
+
mobius-scan --by-serial SERIAL --dump-schedule
|
|
96
|
+
mobius-scan --by-serial SERIAL --relay-target OTHER_SERIAL
|
|
97
|
+
mobius-scan --help
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The full API and every CLI option are described in
|
|
101
|
+
[documentation/16-python-library.md](./documentation/16-python-library.md).
|
|
102
|
+
|
|
103
|
+
## Development
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
git clone https://code.r3pek.org/r3pek/python-mobius
|
|
107
|
+
cd python-mobius
|
|
108
|
+
pip install -e ".[dev]"
|
|
109
|
+
pytest
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Tests use captured packets and advertisements from real devices where
|
|
113
|
+
possible.
|
|
114
|
+
|
|
115
|
+
## Related
|
|
116
|
+
|
|
117
|
+
[ha-mobius](https://code.r3pek.org/r3pek/ha-mobius) is a Home Assistant
|
|
118
|
+
integration built on this library.
|
|
119
|
+
|
|
120
|
+
## License
|
|
121
|
+
|
|
122
|
+
GPLv2, see [`LICENSE`](./LICENSE).
|
|
123
|
+
|
|
124
|
+
## Acknowledgments
|
|
125
|
+
|
|
126
|
+
The Reef2Reef thread "Controlling Mobius enabled VorTech pump using 0-10V
|
|
127
|
+
and BLE" and the `danmrossi/MobiusControl` project, whose work this
|
|
128
|
+
builds on. The reverse engineering and implementation were done with
|
|
129
|
+
substantial help from Claude (Anthropic).
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Mobius BLE protocol
|
|
2
|
+
|
|
3
|
+
This directory describes the Bluetooth Low Energy protocol spoken by
|
|
4
|
+
"Mobius" aquarium devices: EcoTech Marine (VorTech and Vectra pumps,
|
|
5
|
+
Radion lights, MXM hub), AquaIllumination (Prime and Hydra lights, Orbit
|
|
6
|
+
and Axis pumps), Neptune Systems and NYOS (Quantum). It is written so the
|
|
7
|
+
protocol can be implemented in any language; Python-specific notes are
|
|
8
|
+
kept in [16-python-library.md](./16-python-library.md).
|
|
9
|
+
|
|
10
|
+
The protocol was worked out through reverse engineering of the official
|
|
11
|
+
Mobius app, public community research (the Reef2Reef thread
|
|
12
|
+
["Controlling Mobius enabled VorTech pump using 0-10V and BLE"](https://www.reef2reef.com/threads/controlling-mobius-enabled-vortech-pump-using-0-10v-and-ble.814921/)
|
|
13
|
+
and the `danmrossi/MobiusControl` project) and testing on real devices.
|
|
14
|
+
|
|
15
|
+
## Where to start
|
|
16
|
+
|
|
17
|
+
| If you want to... | Read |
|
|
18
|
+
|---|---|
|
|
19
|
+
| Connect and exchange a first message | [01](./01-ble-transport.md), [02](./02-framing-and-crc.md), [03](./03-attributes-and-opcodes.md) |
|
|
20
|
+
| Find devices and group them by tank without connecting | [08](./08-manufacturer-data.md), [12](./12-device-identity-and-address-stability.md) |
|
|
21
|
+
| Identify what kind of device you are talking to | [04](./04-device-identity.md) |
|
|
22
|
+
| Look up an attribute ID, its encoding or an enum value | [14](./14-attribute-reference.md) |
|
|
23
|
+
| Show what a light is doing right now | [06](./06-light-schedule.md) |
|
|
24
|
+
| Show what a pump is doing right now | [07](./07-pump-schedule.md), [11](./11-device-status-attributes.md) |
|
|
25
|
+
| Read or write schedules | [06](./06-light-schedule.md), [07](./07-pump-schedule.md), [15](./15-mob-template-format.md) |
|
|
26
|
+
| Start or stop scenes (feed mode, ...) | [05](./05-scenes.md) |
|
|
27
|
+
| Reach many devices through one BLE connection | [09](./09-thread-coap-relay.md) |
|
|
28
|
+
| Read settings, diagnostics or send commands (reboot, set time) | [11](./11-device-status-attributes.md) |
|
|
29
|
+
| Dump every attribute of a device | [13](./13-attribute-dump.md) |
|
|
30
|
+
| Avoid re-reading scenes, schedules or the attribute table | [17](./17-configuration-checksums.md) |
|
|
31
|
+
| Know what is not covered or not tested | [10](./10-known-gaps-and-open-questions.md) |
|
|
32
|
+
|
|
33
|
+
## Document map
|
|
34
|
+
|
|
35
|
+
| File | Covers |
|
|
36
|
+
|---|---|
|
|
37
|
+
| [01-ble-transport.md](./01-ble-transport.md) | GATT service and characteristics, fragmentation, connection notes |
|
|
38
|
+
| [02-framing-and-crc.md](./02-framing-and-crc.md) | Frame layout, opGroups, the reserved field, CRC16, message IDs, status codes |
|
|
39
|
+
| [03-attributes-and-opcodes.md](./03-attributes-and-opcodes.md) | Get/Set attribute, multi-element values, batched reads, listing supported attributes, group writes |
|
|
40
|
+
| [04-device-identity.md](./04-device-identity.md) | `PrimitiveType`, `Model`, support tiers, `ErrorState`, firmware and hardware info |
|
|
41
|
+
| [05-scenes.md](./05-scenes.md) | Configured scenes, starting and cancelling a scene |
|
|
42
|
+
| [06-light-schedule.md](./06-light-schedule.md) | Light schedule format, computing the current intensity, lunar and acclimation modifiers, hyperdrive, writing, schedule groups |
|
|
43
|
+
| [07-pump-schedule.md](./07-pump-schedule.md) | Pump schedule format, modes and parameters, supported modes per pump, writing |
|
|
44
|
+
| [08-manufacturer-data.md](./08-manufacturer-data.md) | Advertisement contents: model, serial and pan_id without connecting |
|
|
45
|
+
| [09-thread-coap-relay.md](./09-thread-coap-relay.md) | Thread mesh addressing, peer discovery, relaying requests through a connected device |
|
|
46
|
+
| [10-known-gaps-and-open-questions.md](./10-known-gaps-and-open-questions.md) | Unimplemented features, untested areas, open questions |
|
|
47
|
+
| [11-device-status-attributes.md](./11-device-status-attributes.md) | Pump telemetry, settings, calibration, maintenance, clock, diagnostics, commands |
|
|
48
|
+
| [12-device-identity-and-address-stability.md](./12-device-identity-and-address-stability.md) | Why devices are identified by serial number, not BLE address |
|
|
49
|
+
| [13-attribute-dump.md](./13-attribute-dump.md) | Reading every supported attribute; dump file formats |
|
|
50
|
+
| [14-attribute-reference.md](./14-attribute-reference.md) | Every known attribute ID and enum value |
|
|
51
|
+
| [15-mob-template-format.md](./15-mob-template-format.md) | The app's `.mob` schedule template file |
|
|
52
|
+
| [16-python-library.md](./16-python-library.md) | How this Python library maps onto the protocol; CLI |
|
|
53
|
+
| [17-configuration-checksums.md](./17-configuration-checksums.md) | Checksums of the attribute table, scenes and schedules |
|
|
54
|
+
|
|
55
|
+
## Conventions
|
|
56
|
+
|
|
57
|
+
- All multi-byte integers are **little-endian** unless stated otherwise.
|
|
58
|
+
- `u8`/`u16`/`u32`/`u64` are unsigned, `i8`/`i16`/`i32`/`i64` signed.
|
|
59
|
+
- **Permille**: many percentages are sent as tenths of a percent
|
|
60
|
+
(0-1000 = 0.0-100.0 %).
|
|
61
|
+
- Times of day in schedules are **minutes since midnight** (0-1439).
|
|
62
|
+
- Absolute times are **Unix seconds** unless stated otherwise.
|
|
63
|
+
- Strings are UTF-8 (or ASCII), padded with `0x00` to their field size.
|
|
64
|
+
- "Attribute 500" means the attribute with ID 500; names are those used in
|
|
65
|
+
[14-attribute-reference.md](./14-attribute-reference.md).
|
|
66
|
+
|
|
67
|
+
## Glossary
|
|
68
|
+
|
|
69
|
+
| Term | Meaning |
|
|
70
|
+
|---|---|
|
|
71
|
+
| FSCI / C2CI | Framing layer (FSCI) and the attribute get/set command set on top of it (C2CI) |
|
|
72
|
+
| Attribute | A numbered value on the device (read with Get, written with Set), optionally with several elements addressed by index |
|
|
73
|
+
| Element / index | One value of a multi-value attribute (a schedule point, a firmware component, ...) |
|
|
74
|
+
| Primitive | The device-type-specific payload of a schedule point or scene (channel intensities, pump mode and parameters) |
|
|
75
|
+
| Tank | The set of devices sharing one Thread mesh (same pan_id and mesh prefix) |
|
|
76
|
+
| Gateway | The device a client is connected to over BLE, used to reach the other devices of the tank over Thread |
|
|
77
|
+
| Relayed device | A device reached through the gateway instead of its own BLE connection |
|
|
78
|
+
|
|
79
|
+
## Verification status
|
|
80
|
+
|
|
81
|
+
Statements about the protocol come from the app's behaviour and, where
|
|
82
|
+
noted, from tests on real hardware (VorTech MP40 pumps, Radion XR15 G6
|
|
83
|
+
lights, an AquaIllumination Axis pump). Parts that were never exercised on
|
|
84
|
+
real hardware are listed in
|
|
85
|
+
[10-known-gaps-and-open-questions.md](./10-known-gaps-and-open-questions.md).
|
|
86
|
+
|
|
87
|
+
## Legal and scope
|
|
88
|
+
|
|
89
|
+
This is independent reverse engineering for interoperability with hardware
|
|
90
|
+
you own. No vendor code is reproduced; only the protocol facts needed to
|
|
91
|
+
interoperate (wire formats, constants, byte layouts). Not affiliated with
|
|
92
|
+
or endorsed by EcoTech Marine, AquaIllumination, Neptune Systems or NYOS.
|