python-mobius 0.1.1__py3-none-any.whl → 0.1.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 +41 -7
- {python_mobius-0.1.1.dist-info → python_mobius-0.1.2.dist-info}/METADATA +2 -1
- {python_mobius-0.1.1.dist-info → python_mobius-0.1.2.dist-info}/RECORD +7 -7
- {python_mobius-0.1.1.dist-info → python_mobius-0.1.2.dist-info}/WHEEL +0 -0
- {python_mobius-0.1.1.dist-info → python_mobius-0.1.2.dist-info}/entry_points.txt +0 -0
- {python_mobius-0.1.1.dist-info → python_mobius-0.1.2.dist-info}/licenses/LICENSE +0 -0
mobius/__init__.py
CHANGED
mobius/device.py
CHANGED
|
@@ -131,8 +131,29 @@ class MobiusDevice:
|
|
|
131
131
|
if attempt == 2:
|
|
132
132
|
raise
|
|
133
133
|
await asyncio.sleep(2.0)
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
|
|
135
|
+
# IMPORTANT: from here on, self._client holds a real, already-open
|
|
136
|
+
# BLE connection. If anything below fails, connect() (== __aenter__)
|
|
137
|
+
# raises -- and per the async context manager protocol, a raising
|
|
138
|
+
# __aenter__ means __aexit__/disconnect() is NEVER called by the
|
|
139
|
+
# caller's `async with` block. Without this try/except, a failure
|
|
140
|
+
# here would leak an orphaned open connection on the adapter every
|
|
141
|
+
# single time it happens -- and since coordinators retry on a timer,
|
|
142
|
+
# that leak compounds over repeated failures until the adapter's
|
|
143
|
+
# real connection-slot pool is exhausted, independent of range or
|
|
144
|
+
# any other integration. Confirmed as the likely cause of "no
|
|
145
|
+
# available connection slot" errors appearing over time rather than
|
|
146
|
+
# immediately, reported against real hardware.
|
|
147
|
+
try:
|
|
148
|
+
await self._client.start_notify(CHAR_RX_DATA, self._on_rx_data)
|
|
149
|
+
await self._client.start_notify(CHAR_RX_FINAL, self._on_rx_final)
|
|
150
|
+
except Exception:
|
|
151
|
+
try:
|
|
152
|
+
if self._client.is_connected:
|
|
153
|
+
await self._client.disconnect()
|
|
154
|
+
except Exception:
|
|
155
|
+
pass # best-effort cleanup; the original error is what matters
|
|
156
|
+
raise
|
|
136
157
|
|
|
137
158
|
async def disconnect(self):
|
|
138
159
|
if self._client and self._client.is_connected:
|
|
@@ -345,12 +366,24 @@ class MobiusDevice:
|
|
|
345
366
|
|
|
346
367
|
async def get_pump_telemetry(self) -> dict:
|
|
347
368
|
"""
|
|
348
|
-
Returns {"speed": int, "gph": int}.
|
|
349
|
-
|
|
350
|
-
|
|
369
|
+
Returns {"speed": int, "speed_percent": float, "gph": int}. speed
|
|
370
|
+
and gph are genuinely read live from the device -- confirmed via
|
|
371
|
+
FlowRange.java, which is what the app's dashboard actually queries
|
|
372
|
+
for the pump gauge widget.
|
|
351
373
|
|
|
352
374
|
"gph" comes from PhysicalValues/GallonsPerHour (int32 LE).
|
|
353
|
-
|
|
375
|
+
|
|
376
|
+
"speed" comes from MotorSpeed directly (int16). CONFIRMED (not
|
|
377
|
+
inferred) to be a percentage of max pump power in tenths of a
|
|
378
|
+
percent, not RPM: the app's own display code does
|
|
379
|
+
`String.format("%.0f%%", Math.abs(currentSpeed / 10.0f))` on this
|
|
380
|
+
exact value (FlowFragment.java/WidgetViewCell.java). "speed_percent"
|
|
381
|
+
is that same abs(speed)/10 conversion, provided as a convenience --
|
|
382
|
+
the sign of the raw "speed" value encodes rotation direction
|
|
383
|
+
(reverse), matching the same convention as the schedule's MaxSpeed
|
|
384
|
+
parameter (see PumpPrimitiveValue), so check the sign of "speed"
|
|
385
|
+
yourself if direction matters; speed_percent is always non-negative.
|
|
386
|
+
|
|
354
387
|
MotorRPM is defined in the protocol but never queried anywhere in the
|
|
355
388
|
app -- not included here since it's unconfirmed whether firmware
|
|
356
389
|
actually populates it.
|
|
@@ -361,7 +394,8 @@ class MobiusDevice:
|
|
|
361
394
|
)
|
|
362
395
|
speed = struct.unpack("<h", speed_raw[0])[0] if speed_raw else None
|
|
363
396
|
gph = struct.unpack("<i", gph_raw[0])[0] if gph_raw else None
|
|
364
|
-
|
|
397
|
+
speed_percent = abs(speed) / 10 if speed is not None else None
|
|
398
|
+
return {"speed": speed, "speed_percent": speed_percent, "gph": gph}
|
|
365
399
|
|
|
366
400
|
# ---- light schedule (Radion/XR15 etc.) --------------------------------
|
|
367
401
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-mobius
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.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
|
|
@@ -24,6 +24,7 @@ Requires-Python: >=3.9
|
|
|
24
24
|
Requires-Dist: bleak>=0.21
|
|
25
25
|
Provides-Extra: dev
|
|
26
26
|
Requires-Dist: bleak-retry-connector>=3.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
27
28
|
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
28
29
|
Provides-Extra: retry
|
|
29
30
|
Requires-Dist: bleak-retry-connector>=3.0; extra == 'retry'
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
mobius/__init__.py,sha256=
|
|
1
|
+
mobius/__init__.py,sha256=2TkA717bDRzec96psyBxp1NEUi12azr93DxI0iYSfrY,3381
|
|
2
2
|
mobius/cli.py,sha256=uhGZIDrhpTp8LkTGOl4BZVQWgJYHbaIVH2HzX3RFCCs,2642
|
|
3
3
|
mobius/constants.py,sha256=wKrWU-QnqMuWuvczHwt3ha3sPw6D9NNK-kIhxJcTbHA,14702
|
|
4
4
|
mobius/crc.py,sha256=WwIfUXGN_UKdsv-_Q303-L1-L1Rc1fvJnB5176ftzqU,2669
|
|
5
|
-
mobius/device.py,sha256=
|
|
5
|
+
mobius/device.py,sha256=3kR34RLQYd3lbqG8HeRC5HMvD7k5A6XpBfu_eyASNVw,22779
|
|
6
6
|
mobius/discovery.py,sha256=4MjGwpd0bUK-koiZ-a2Cvq-gCTImAKAQ4lZ-9vOge3Q,2290
|
|
7
7
|
mobius/frame.py,sha256=zG2vh8PceJHD8R43MwZiJnm0Ge1dr8nFcKsJR9_c9LM,6135
|
|
8
8
|
mobius/manufacturer.py,sha256=8-vBzckN8xmsPSMj5EWtOCXenbyQueoY5pnZHePgb_k,1937
|
|
9
9
|
mobius/schedule.py,sha256=kHr684TIKPZ2BplIySoeD-Yn1Xa_2bE6rfGUs-waWMQ,7483
|
|
10
|
-
python_mobius-0.1.
|
|
11
|
-
python_mobius-0.1.
|
|
12
|
-
python_mobius-0.1.
|
|
13
|
-
python_mobius-0.1.
|
|
14
|
-
python_mobius-0.1.
|
|
10
|
+
python_mobius-0.1.2.dist-info/METADATA,sha256=ZfFhhqMEx8S5lyZumY2nMBlmO2bW0HrDtwFi8_gKbbE,5959
|
|
11
|
+
python_mobius-0.1.2.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
12
|
+
python_mobius-0.1.2.dist-info/entry_points.txt,sha256=Q2hlcek-bWm70zvd12v32essflPgC2su-dKDHAqbPoE,48
|
|
13
|
+
python_mobius-0.1.2.dist-info/licenses/LICENSE,sha256=7a72Msu2Q-TnoiFxemxEGkwafJGObk1W3rw9hzmyM_Y,17984
|
|
14
|
+
python_mobius-0.1.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|