python-mobius 0.4.0__py3-none-any.whl → 0.4.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 +38 -10
- mobius/device_status.py +15 -6
- mobius/discovery.py +31 -7
- mobius/schedule.py +10 -0
- {python_mobius-0.4.0.dist-info → python_mobius-0.4.2.dist-info}/METADATA +2 -2
- {python_mobius-0.4.0.dist-info → python_mobius-0.4.2.dist-info}/RECORD +10 -10
- {python_mobius-0.4.0.dist-info → python_mobius-0.4.2.dist-info}/WHEEL +1 -1
- {python_mobius-0.4.0.dist-info → python_mobius-0.4.2.dist-info}/entry_points.txt +0 -0
- {python_mobius-0.4.0.dist-info → python_mobius-0.4.2.dist-info}/licenses/LICENSE +0 -0
mobius/__init__.py
CHANGED
mobius/device.py
CHANGED
|
@@ -709,12 +709,22 @@ class MobiusDevice:
|
|
|
709
709
|
ShortAddressArray/SerialNumberArray/DeviceModelArray
|
|
710
710
|
(3700/3701/3702, the same "get all elements" pattern used
|
|
711
711
|
elsewhere in this library) from THIS connected device, acting as
|
|
712
|
-
a Thread mesh gateway, and returns
|
|
713
|
-
|
|
714
|
-
|
|
712
|
+
a Thread mesh gateway, and returns what it reports about devices
|
|
713
|
+
over the mesh -- not devices we necessarily have (or even can
|
|
714
|
+
have) a direct BLE connection to. See documentation/
|
|
715
715
|
09-thread-coap-relay.md for the full protocol trace this is
|
|
716
716
|
based on.
|
|
717
717
|
|
|
718
|
+
Whether this includes the connected device's own entry
|
|
719
|
+
alongside others isn't confirmed either way -- unlike
|
|
720
|
+
discover_networked_thread_devices() (whose sibling docstring
|
|
721
|
+
this once matched, until a real capture disproved it there),
|
|
722
|
+
real hardware evidence specific to THIS older mechanism was
|
|
723
|
+
never gathered. Callers that also separately add the connected
|
|
724
|
+
device's own entry (e.g. mobius.discovery.discover_tank()) treat
|
|
725
|
+
this as a real possibility and deduplicate by serial regardless,
|
|
726
|
+
rather than assuming either way.
|
|
727
|
+
|
|
718
728
|
**Confirmed via real hardware testing to be Cowboy-hub-specific.**
|
|
719
729
|
These three arrays were originally found being fetched as part of
|
|
720
730
|
the app's own network-setup logic for a dedicated Cowboy hub device,
|
|
@@ -789,9 +799,19 @@ class MobiusDevice:
|
|
|
789
799
|
"""
|
|
790
800
|
Fetches MLPrefix (2128) plus NetworkedThreadDevices (1001, the
|
|
791
801
|
same "get all elements" pattern used elsewhere in this library)
|
|
792
|
-
from THIS connected device, and returns every
|
|
793
|
-
|
|
794
|
-
|
|
802
|
+
from THIS connected device, and returns every device it knows
|
|
803
|
+
about over the Thread mesh -- not devices we necessarily have
|
|
804
|
+
(or even can have) a direct BLE connection to.
|
|
805
|
+
|
|
806
|
+
**Includes the connected device's own entry, not just others.**
|
|
807
|
+
An earlier version of this docstring claimed "every OTHER
|
|
808
|
+
device," an untested assumption rather than a confirmed one --
|
|
809
|
+
disproven by a real 4-device tank capture where a single
|
|
810
|
+
connected device's own NetworkedThreadDevices read returned all
|
|
811
|
+
4 real devices, necessarily including itself. Callers building
|
|
812
|
+
a peer list that also separately adds the connected device's own
|
|
813
|
+
entry (e.g. mobius.discovery.discover_tank()) need to
|
|
814
|
+
deduplicate by serial, or that device ends up listed twice.
|
|
795
815
|
|
|
796
816
|
A second, better mesh-peer-discovery mechanism than
|
|
797
817
|
discover_mesh_peers() -- confirmed via reverse engineering the
|
|
@@ -823,9 +843,11 @@ class MobiusDevice:
|
|
|
823
843
|
build_rloc_address(), which is for the different case of only
|
|
824
844
|
having a 2-byte short address to encode into the prefix's last 2
|
|
825
845
|
bytes -- here the full 8-byte suffix is already present in the
|
|
826
|
-
entry, so it's used as-is); bytes 8-11 are a 4-byte
|
|
827
|
-
|
|
828
|
-
|
|
846
|
+
entry, so it's used as-is); bytes 8-11 are a 4-byte unsigned
|
|
847
|
+
"age" value in milliseconds -- confirmed to mean time since this
|
|
848
|
+
peer was last heard from over the mesh, a resetting value, not
|
|
849
|
+
time since first discovered (see MeshPeer's own docstring for
|
|
850
|
+
the full detail); bytes 12-13 are the 2-byte model
|
|
829
851
|
ID; bytes 14-27 are the 14-byte ASCII serial number, matching the
|
|
830
852
|
SerialNumberArray format used elsewhere in this library. All
|
|
831
853
|
multi-byte numeric fields are read little-endian -- confirmed
|
|
@@ -868,7 +890,13 @@ class MobiusDevice:
|
|
|
868
890
|
if len(entry) != 28:
|
|
869
891
|
continue
|
|
870
892
|
address = prefix + entry[0:8]
|
|
871
|
-
|
|
893
|
+
# Unsigned -- confirmed via reverse engineering the app's own
|
|
894
|
+
# network-troubleshooting screen, which explicitly treats this
|
|
895
|
+
# same 4-byte field as an unsigned value before ever using it
|
|
896
|
+
# for anything else. See MeshPeer's own docstring for the full,
|
|
897
|
+
# now-confirmed meaning (milliseconds since this peer was last
|
|
898
|
+
# heard from over the mesh).
|
|
899
|
+
age = struct.unpack("<I", entry[8:12])[0]
|
|
872
900
|
model_raw = struct.unpack("<h", entry[12:14])[0]
|
|
873
901
|
try:
|
|
874
902
|
serial = entry[14:28].decode("ascii").rstrip("\x00")
|
mobius/device_status.py
CHANGED
|
@@ -130,18 +130,27 @@ class MeshPeer:
|
|
|
130
130
|
`age` is only ever set by discover_networked_thread_devices() --
|
|
131
131
|
None from every other source of MeshPeer, including
|
|
132
132
|
discover_mesh_peers() and discover_mesh_peers_via_direct_connect().
|
|
133
|
-
Confirmed
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
133
|
+
Confirmed via reverse engineering the app's own network-
|
|
134
|
+
troubleshooting screen: milliseconds since this specific peer was
|
|
135
|
+
last heard from over the Thread mesh, as far as the connected
|
|
136
|
+
gateway currently knows -- NOT time since it was first discovered
|
|
137
|
+
or added to the tank. A RESETTING value, not a monotonic one: it
|
|
138
|
+
legitimately drops back toward zero whenever the mesh genuinely
|
|
139
|
+
receives fresh activity from that peer, which happens on its own
|
|
140
|
+
schedule, independent of whenever this is read. Two checks in
|
|
141
|
+
quick succession can validly show a SMALLER age the second time --
|
|
142
|
+
that's expected, not a parsing error. The app's own troubleshooting
|
|
143
|
+
screen treats anything over roughly 5 minutes (300000) as long
|
|
144
|
+
enough to flag that peer as currently unreachable/failed, which is
|
|
145
|
+
a reasonable rule of thumb for interpreting this value generally,
|
|
146
|
+
though not enforced by this library itself.
|
|
138
147
|
"""
|
|
139
148
|
serial: str
|
|
140
149
|
model_raw: int
|
|
141
150
|
model: Optional[Model] # None if model_raw doesn't match a known Model value
|
|
142
151
|
short_address: int
|
|
143
152
|
address: bytes # 16-byte Thread mesh-local IPv6, ready to pass to encode_coap_request()
|
|
144
|
-
age: Optional[int] = None #
|
|
153
|
+
age: Optional[int] = None # milliseconds since last heard from on the mesh -- see docstring above
|
|
145
154
|
|
|
146
155
|
|
|
147
156
|
@dataclass
|
mobius/discovery.py
CHANGED
|
@@ -193,12 +193,28 @@ async def discover_tank(mdevice) -> "Tank":
|
|
|
193
193
|
(not just serial/model, the way advertisement-only grouping like
|
|
194
194
|
group_by_pan_id() can offer).
|
|
195
195
|
|
|
196
|
-
Calls mdevice.discover_mesh_peers_auto()
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
196
|
+
Calls mdevice.discover_mesh_peers_auto() plus
|
|
197
|
+
get_own_mesh_address()/get_device_info() to build the connected
|
|
198
|
+
device's own entry directly. These are deliberately DEDUPLICATED by
|
|
199
|
+
serial before returning, keeping the directly-built own entry over
|
|
200
|
+
whatever discover_mesh_peers_auto() reported for the same serial --
|
|
201
|
+
confirmed via a real 4-device tank capture that
|
|
202
|
+
discover_networked_thread_devices() (the mechanism
|
|
203
|
+
discover_mesh_peers_auto() tries first) is self-INCLUSIVE, not
|
|
204
|
+
self-exclusive as an earlier version of this docstring claimed
|
|
205
|
+
(based on an untested assumption, not a confirmed one): all 4 real
|
|
206
|
+
devices came back from a single connected device's own
|
|
207
|
+
NetworkedThreadDevices read, necessarily including whichever one was
|
|
208
|
+
actually connected to. Without deduplication, that connected
|
|
209
|
+
device's own peer would appear twice in the result -- once from this
|
|
210
|
+
function's own direct build, once from discover_mesh_peers_auto()'s
|
|
211
|
+
own report of it as "just another peer" on its own network. Not
|
|
212
|
+
confirmed whether the OLDER discover_mesh_peers() mechanism
|
|
213
|
+
(discover_mesh_peers_auto()'s own fallback) shares this same
|
|
214
|
+
self-inclusive behavior or not -- the deduplication here is
|
|
215
|
+
unconditional specifically so it's correct either way, rather than
|
|
216
|
+
depending on getting that confirmation for every code path that
|
|
217
|
+
could produce peers.
|
|
202
218
|
|
|
203
219
|
tank.prefix is None if this device didn't report a valid mesh
|
|
204
220
|
address at all (unsupported, or not currently part of an active
|
|
@@ -240,5 +256,13 @@ async def discover_tank(mdevice) -> "Tank":
|
|
|
240
256
|
other_peers = await mdevice.discover_mesh_peers_auto()
|
|
241
257
|
prefix = mesh_local_prefix_from_own_address(own_address)
|
|
242
258
|
|
|
243
|
-
|
|
259
|
+
# own_peer always wins over whatever discover_mesh_peers_auto()
|
|
260
|
+
# separately reported for the same serial -- see this function's
|
|
261
|
+
# own docstring for why that duplicate is a real, confirmed
|
|
262
|
+
# possibility, not just a defensive guard against a hypothetical.
|
|
263
|
+
deduplicated = [own_peer] + [
|
|
264
|
+
peer for peer in other_peers if peer.serial != own_peer.serial
|
|
265
|
+
]
|
|
266
|
+
|
|
267
|
+
return Tank(prefix=prefix, peers=deduplicated)
|
|
244
268
|
|
mobius/schedule.py
CHANGED
|
@@ -235,6 +235,16 @@ class PumpSchedulePoint:
|
|
|
235
235
|
return None
|
|
236
236
|
return cls(time_minutes, flags, PumpPrimitiveValue.parse(data[3:]))
|
|
237
237
|
|
|
238
|
+
def has(self, flag: int) -> bool:
|
|
239
|
+
# Same flags field, same bit meanings as SchedulePoint's own
|
|
240
|
+
# has() (see this class's own docstring: identical wire format,
|
|
241
|
+
# just different primitiveData) -- an earlier version of this
|
|
242
|
+
# class omitted this entirely, which crashed mobius.cli's own
|
|
243
|
+
# --dump-schedule for pumps specifically (its own _format_flags()
|
|
244
|
+
# helper is shared between the light and pump branches, calling
|
|
245
|
+
# point.has() either way).
|
|
246
|
+
return (self.flags & flag) == flag
|
|
247
|
+
|
|
238
248
|
|
|
239
249
|
def get_active_pump_block(points: list[PumpSchedulePoint], minute_of_day: int) -> Optional[PumpSchedulePoint]:
|
|
240
250
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: python-mobius
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.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
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
mobius/__init__.py,sha256=
|
|
1
|
+
mobius/__init__.py,sha256=BpkSMm-tv7BC2F_vWHd-jym24Hsmwfd_OSMeJa2FEfQ,5722
|
|
2
2
|
mobius/cli.py,sha256=8XH-pVTX4KObzd0IOGXicT7KrcNEjm5xYZS8JOWfHDA,30726
|
|
3
3
|
mobius/coap.py,sha256=eXf_-9heQD1UjLyqZU9KA-c0jB50NGzAd8D7d6kFMb0,10750
|
|
4
4
|
mobius/constants.py,sha256=z_KrFev5vGD9-9lKn4J0nGVtzTmelGQ13bYlVcCdjm0,25217
|
|
5
5
|
mobius/crc.py,sha256=kLtAYWZvLbo5_p9ep08ZlLg5Yah8Q2qq0IwTvqbBGW0,2700
|
|
6
|
-
mobius/device.py,sha256=
|
|
7
|
-
mobius/device_status.py,sha256=
|
|
8
|
-
mobius/discovery.py,sha256=
|
|
6
|
+
mobius/device.py,sha256=H5JGFtV90xu69jEOydMPqpj53e-5ws6TUVej0xd7WSg,79078
|
|
7
|
+
mobius/device_status.py,sha256=p1l6RpCcg_G4p9nudhSo8MzBSgqkH8m5_0qrnjsFQ2k,8374
|
|
8
|
+
mobius/discovery.py,sha256=LqHOEA_j1ZROuounn3PPmy8IEbpL6-N1TOW1MpoKg6A,11619
|
|
9
9
|
mobius/frame.py,sha256=UNLTHuzVue5b6L4nv1hWJTSbn5k8lETWdsiL_52yI0Q,6141
|
|
10
10
|
mobius/manufacturer.py,sha256=8-vBzckN8xmsPSMj5EWtOCXenbyQueoY5pnZHePgb_k,1937
|
|
11
11
|
mobius/mesh_address.py,sha256=PKQ-mm7Z4bY11ZnVmeWZO9EmOiAHp8hNtXceMGMs2tk,5940
|
|
@@ -13,9 +13,9 @@ mobius/modifiers.py,sha256=zWJCsjaJ4TtwS1QgQoRFH-ve1mykuPWn5KX4YQpNqco,7215
|
|
|
13
13
|
mobius/power.py,sha256=5l9ehjNCDrSsJjQkaU4M6pYnSMqw2FVF8Ogg6KIE5vQ,3844
|
|
14
14
|
mobius/pump_status.py,sha256=RWTl8ZViCFDbiFU2mX-WAIH_cWhZOZ0M2B0oYXnPx3Y,1598
|
|
15
15
|
mobius/relay.py,sha256=tMpV_67CYt9A1L_DPERzbqOgy3BOdG4NZpAG_IlefhY,16587
|
|
16
|
-
mobius/schedule.py,sha256=
|
|
17
|
-
python_mobius-0.4.
|
|
18
|
-
python_mobius-0.4.
|
|
19
|
-
python_mobius-0.4.
|
|
20
|
-
python_mobius-0.4.
|
|
21
|
-
python_mobius-0.4.
|
|
16
|
+
mobius/schedule.py,sha256=d5iAHvKuFDwfbrSptPx6viiA_lj2qGfWhsZwM_Bpr1k,10974
|
|
17
|
+
python_mobius-0.4.2.dist-info/METADATA,sha256=PBqNDTyqaF-wG4Q8YUZsMqsQ2TkBTFfOoUNKe0yYZG4,5952
|
|
18
|
+
python_mobius-0.4.2.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
19
|
+
python_mobius-0.4.2.dist-info/entry_points.txt,sha256=Q2hlcek-bWm70zvd12v32essflPgC2su-dKDHAqbPoE,48
|
|
20
|
+
python_mobius-0.4.2.dist-info/licenses/LICENSE,sha256=7a72Msu2Q-TnoiFxemxEGkwafJGObk1W3rw9hzmyM_Y,17984
|
|
21
|
+
python_mobius-0.4.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|