python-mobius 0.7.1__py3-none-any.whl → 0.7.2__py3-none-any.whl
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.
- mobius/__init__.py +1 -1
- mobius/device.py +42 -7
- {python_mobius-0.7.1.dist-info → python_mobius-0.7.2.dist-info}/METADATA +14 -3
- {python_mobius-0.7.1.dist-info → python_mobius-0.7.2.dist-info}/RECORD +7 -7
- {python_mobius-0.7.1.dist-info → python_mobius-0.7.2.dist-info}/WHEEL +0 -0
- {python_mobius-0.7.1.dist-info → python_mobius-0.7.2.dist-info}/entry_points.txt +0 -0
- {python_mobius-0.7.1.dist-info → python_mobius-0.7.2.dist-info}/licenses/LICENSE +0 -0
mobius/__init__.py
CHANGED
mobius/device.py
CHANGED
|
@@ -12,7 +12,7 @@ from __future__ import annotations
|
|
|
12
12
|
import asyncio
|
|
13
13
|
import struct
|
|
14
14
|
import time
|
|
15
|
-
from dataclasses import dataclass
|
|
15
|
+
from dataclasses import dataclass, field
|
|
16
16
|
from typing import Optional, Callable
|
|
17
17
|
|
|
18
18
|
from bleak import BleakClient, BleakScanner
|
|
@@ -190,6 +190,11 @@ class FullPollResult:
|
|
|
190
190
|
caller needing a separate get_pump_schedule() call just to also
|
|
191
191
|
get schedule_point_count alongside everything else here.
|
|
192
192
|
|
|
193
|
+
configured_scenes/current_scene -- everything get_configured_scenes()/
|
|
194
|
+
get_current_scene() themselves cover, for whichever device types
|
|
195
|
+
support scenes at all (an empty list / None if not, matching those
|
|
196
|
+
methods' own behavior exactly).
|
|
197
|
+
|
|
193
198
|
used_batch mirrors every other *Result/Snapshot's own field of the
|
|
194
199
|
same name and purpose.
|
|
195
200
|
"""
|
|
@@ -198,6 +203,8 @@ class FullPollResult:
|
|
|
198
203
|
light_poll: Optional[LightPollResult]
|
|
199
204
|
pump_telemetry: Optional[dict]
|
|
200
205
|
pump_schedule_points: Optional[list[PumpSchedulePoint]] = None
|
|
206
|
+
configured_scenes: list[Scene] = field(default_factory=list)
|
|
207
|
+
current_scene: Optional[ActiveScene] = None
|
|
201
208
|
used_batch: bool = True
|
|
202
209
|
|
|
203
210
|
|
|
@@ -1277,18 +1284,31 @@ class MobiusDevice:
|
|
|
1277
1284
|
|
|
1278
1285
|
# ---- scenes -----------------------------------------------------------
|
|
1279
1286
|
|
|
1280
|
-
async def start_scene(self, scene_id: int, duration_seconds: int = 0) -> None:
|
|
1287
|
+
async def start_scene(self, scene_id: int, duration_seconds: int = 0, broadcast: bool = True) -> None:
|
|
1281
1288
|
"""
|
|
1282
1289
|
Activates a scene by id -- one of the ten SceneID presets, or a
|
|
1283
1290
|
user-created scene's own device-assigned id (see get_configured_scenes()).
|
|
1284
1291
|
duration_seconds=0 lets the device use the scene's own configured
|
|
1285
1292
|
timeout instead.
|
|
1293
|
+
|
|
1294
|
+
broadcast=True (the default) sets the frame's own reserved-byte
|
|
1295
|
+
"group" field to 1 (see make_reserved()), which propagates this
|
|
1296
|
+
write to the rest of the mesh from a single write to just this
|
|
1297
|
+
device -- confirmed against real hardware for set_time_to_now()'s
|
|
1298
|
+
own Epoch write; the same group=1 mechanism is used here, though
|
|
1299
|
+
this hasn't been independently confirmed against real hardware
|
|
1300
|
+
for CurrentScene specifically. group=1 only ever reaches devices
|
|
1301
|
+
on THIS SAME mesh (a Thread network is its own isolated network,
|
|
1302
|
+
identified by its own pan_id) -- it cannot reach a different
|
|
1303
|
+
tank's own, separate mesh, even one within physical radio range.
|
|
1304
|
+
Pass broadcast=False to write to only this one device instead.
|
|
1286
1305
|
"""
|
|
1287
1306
|
value = struct.pack("<HH", int(scene_id), duration_seconds)
|
|
1288
|
-
|
|
1307
|
+
reserved = make_reserved(group=1) if broadcast else b"\x00\x00"
|
|
1308
|
+
await self.set_attribute(C2Attribute.CurrentScene, value, reserved=reserved)
|
|
1289
1309
|
|
|
1290
|
-
async def start_feed_mode(self, duration_seconds: int = 0) -> None:
|
|
1291
|
-
await self.start_scene(SceneID.FeedMode, duration_seconds)
|
|
1310
|
+
async def start_feed_mode(self, duration_seconds: int = 0, broadcast: bool = True) -> None:
|
|
1311
|
+
await self.start_scene(SceneID.FeedMode, duration_seconds, broadcast=broadcast)
|
|
1292
1312
|
|
|
1293
1313
|
async def resume_schedule(self) -> None:
|
|
1294
1314
|
"""Cancel whatever scene is running and go back to the normal schedule."""
|
|
@@ -3655,6 +3675,8 @@ class MobiusDevice:
|
|
|
3655
3675
|
(C2Attribute.FirmwareVersion, 0, 0xFFFF),
|
|
3656
3676
|
(C2Attribute.HardwareRevision, 0, 0xFFFF),
|
|
3657
3677
|
(schedule_attr, 0, 0xFFFF),
|
|
3678
|
+
(C2Attribute.ConfiguredScenes, 0, 0xFFFF),
|
|
3679
|
+
(C2Attribute.CurrentScene, 0, 1),
|
|
3658
3680
|
]
|
|
3659
3681
|
if primitive == PrimitiveType.VisualV1:
|
|
3660
3682
|
intensity_attr = C2Attribute.Schedule1Intensity if which == 1 else C2Attribute.Schedule2Intensity
|
|
@@ -3726,10 +3748,16 @@ class MobiusDevice:
|
|
|
3726
3748
|
[motor_power_raw] if motor_power_raw else [], flow_range, model, primitive,
|
|
3727
3749
|
)
|
|
3728
3750
|
|
|
3751
|
+
configured_scenes = decode_configured_scenes(_values_for(C2Attribute.ConfiguredScenes), primitive)
|
|
3752
|
+
current_scene_raw = _first_value(C2Attribute.CurrentScene)
|
|
3753
|
+
current_scene = decode_active_scene(current_scene_raw) if current_scene_raw else None
|
|
3754
|
+
|
|
3729
3755
|
return FullPollResult(
|
|
3730
3756
|
device_info=device_info, metadata=metadata,
|
|
3731
3757
|
light_poll=light_poll, pump_telemetry=pump_telemetry,
|
|
3732
|
-
pump_schedule_points=pump_schedule_points,
|
|
3758
|
+
pump_schedule_points=pump_schedule_points,
|
|
3759
|
+
configured_scenes=configured_scenes, current_scene=current_scene,
|
|
3760
|
+
used_batch=True,
|
|
3733
3761
|
)
|
|
3734
3762
|
|
|
3735
3763
|
async def _get_full_poll_via_individual_reads(
|
|
@@ -3752,10 +3780,17 @@ class MobiusDevice:
|
|
|
3752
3780
|
else:
|
|
3753
3781
|
pump_schedule_points = await self.get_pump_schedule(which=which)
|
|
3754
3782
|
pump_telemetry = await self.get_pump_telemetry(model=model, primitive=primitive)
|
|
3783
|
+
try:
|
|
3784
|
+
configured_scenes = await self.get_configured_scenes(primitive=primitive)
|
|
3785
|
+
except Exception:
|
|
3786
|
+
configured_scenes = []
|
|
3787
|
+
current_scene = await self.get_current_scene()
|
|
3755
3788
|
return FullPollResult(
|
|
3756
3789
|
device_info=device_info, metadata=metadata,
|
|
3757
3790
|
light_poll=light_poll, pump_telemetry=pump_telemetry,
|
|
3758
|
-
pump_schedule_points=pump_schedule_points,
|
|
3791
|
+
pump_schedule_points=pump_schedule_points,
|
|
3792
|
+
configured_scenes=configured_scenes, current_scene=current_scene,
|
|
3793
|
+
used_batch=False,
|
|
3759
3794
|
)
|
|
3760
3795
|
|
|
3761
3796
|
async def get_current_light_percentages(self, which: int = 1,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: python-mobius
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: Reverse-engineered Python client for the Mobius BLE protocol (EcoTech Marine VorTech/Radion, AquaIllumination, Neptune Systems, NYOS)
|
|
5
5
|
Project-URL: Homepage, https://code.r3pek.org/r3pek/python-mobius
|
|
6
6
|
Project-URL: Documentation, https://code.r3pek.org/r3pek/python-mobius/src/branch/main/documentation
|
|
@@ -108,14 +108,25 @@ mobius-scan --adapter hci0
|
|
|
108
108
|
- **Read light schedules**: per-channel intensity at any given time,
|
|
109
109
|
replicating the app's own client-side interpolation (there's no "current
|
|
110
110
|
intensity" attribute — lights only expose the programmed curve).
|
|
111
|
+
- **Read every configured scene** (`get_configured_scenes()`) — name,
|
|
112
|
+
timeout, and its own light/pump payload, at whatever slot it lives in,
|
|
113
|
+
plus the currently active one (`get_current_scene()`).
|
|
114
|
+
- **Control scenes**: start feed mode, resume the normal schedule, or any
|
|
115
|
+
other configured scene — one write, broadcast to the whole mesh by
|
|
116
|
+
default (`broadcast=True`). Uses the same mesh-propagation mechanism
|
|
117
|
+
confirmed against real hardware for the clock-sync write below;
|
|
118
|
+
applying it to scene activation specifically hasn't been
|
|
119
|
+
independently verified the same way yet.
|
|
120
|
+
- **Fetch everything one device poll needs in a single round-trip**
|
|
121
|
+
(`get_full_poll_batch()`) — identity, metadata, light/pump state, and
|
|
122
|
+
scene data together, confirmed 2-2.6x faster on real hardware than
|
|
123
|
+
reading each piece separately.
|
|
111
124
|
- **Read device-specific settings**: VorTech's own "Local Control"/"Led
|
|
112
125
|
Auto Dim" and Radion's own "Max Fan Speed"/"Fan Shutdown"
|
|
113
126
|
(`get_advanced_features()`), plus Vectra and NYOS Quantum settings
|
|
114
127
|
(`get_vectra_info()`/`get_coffee_info()` — no real hardware to verify
|
|
115
128
|
either against, see
|
|
116
129
|
[known gaps](./documentation/10-known-gaps-and-open-questions.md)).
|
|
117
|
-
- **Control scenes**: start feed mode, resume the normal schedule, or any
|
|
118
|
-
other configured scene.
|
|
119
130
|
- **Fix a desynced device clock** (`set_time_to_now()`) — a WRITE.
|
|
120
131
|
Writing to one device appears to propagate to the rest of its Thread
|
|
121
132
|
mesh too, confirmed against real hardware — see
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
mobius/__init__.py,sha256=
|
|
1
|
+
mobius/__init__.py,sha256=gcj_rnHfu_zczKCP4aBKOuKREHxuvmdXV9zFvMcj4eQ,6788
|
|
2
2
|
mobius/cli.py,sha256=antaLPQysyPethop24fjeKowczEvfoVodgYkyIT5YxE,50008
|
|
3
3
|
mobius/coap.py,sha256=dRE4yUp413etAMhDg2bLvFMLWusqjEWgUpC36i76mJs,10966
|
|
4
4
|
mobius/constants.py,sha256=ytpf9S_cHBKFWi_scr06ydmv-MW1dLGlG3CYfOAkiAw,42480
|
|
5
5
|
mobius/crc.py,sha256=kLtAYWZvLbo5_p9ep08ZlLg5Yah8Q2qq0IwTvqbBGW0,2700
|
|
6
|
-
mobius/device.py,sha256=
|
|
6
|
+
mobius/device.py,sha256=YxfIgKWsERx1m-ueU1Bau1cXCWYOf-dzu2z3fUq7IeI,190773
|
|
7
7
|
mobius/device_status.py,sha256=xlLCMU4gLnp59Uqix679jRdVBY2Jt6oI4EUr8fraeRg,34089
|
|
8
8
|
mobius/discovery.py,sha256=Q_Z0riOBrEOwqpwAhk1wesh3340fiIYFi-8BWqhZ0JI,11949
|
|
9
9
|
mobius/dump.py,sha256=S7-KNeDi9TOETm4ty5DwMXTrthvuMau196UENDQoAb4,16785
|
|
@@ -16,8 +16,8 @@ mobius/pump_status.py,sha256=RWTl8ZViCFDbiFU2mX-WAIH_cWhZOZ0M2B0oYXnPx3Y,1598
|
|
|
16
16
|
mobius/relay.py,sha256=IG15TtKDjSkmmi_C2cJwPmucX7V4psfamI0hKgTb_v8,24197
|
|
17
17
|
mobius/scenes.py,sha256=Wt0Ys2x1YjF8MNDEd6kxWqYBIYPdBSbfzXD-L5ZKzag,3592
|
|
18
18
|
mobius/schedule.py,sha256=kkQgwkFtM3pvik7UFzHKVhPVZrCGSH9AYvAlVA6kAck,10848
|
|
19
|
-
python_mobius-0.7.
|
|
20
|
-
python_mobius-0.7.
|
|
21
|
-
python_mobius-0.7.
|
|
22
|
-
python_mobius-0.7.
|
|
23
|
-
python_mobius-0.7.
|
|
19
|
+
python_mobius-0.7.2.dist-info/METADATA,sha256=X1Pa4FH6dPjYwjNRxFaRpu-hHgRn68f5F5eZubCNgqg,9036
|
|
20
|
+
python_mobius-0.7.2.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
21
|
+
python_mobius-0.7.2.dist-info/entry_points.txt,sha256=Q2hlcek-bWm70zvd12v32essflPgC2su-dKDHAqbPoE,48
|
|
22
|
+
python_mobius-0.7.2.dist-info/licenses/LICENSE,sha256=7a72Msu2Q-TnoiFxemxEGkwafJGObk1W3rw9hzmyM_Y,17984
|
|
23
|
+
python_mobius-0.7.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|