python-mobius 0.8.2__py3-none-any.whl → 0.8.4__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 +64 -2
- {python_mobius-0.8.2.dist-info → python_mobius-0.8.4.dist-info}/METADATA +1 -1
- {python_mobius-0.8.2.dist-info → python_mobius-0.8.4.dist-info}/RECORD +7 -7
- {python_mobius-0.8.2.dist-info → python_mobius-0.8.4.dist-info}/WHEEL +0 -0
- {python_mobius-0.8.2.dist-info → python_mobius-0.8.4.dist-info}/entry_points.txt +0 -0
- {python_mobius-0.8.2.dist-info → python_mobius-0.8.4.dist-info}/licenses/LICENSE +0 -0
mobius/__init__.py
CHANGED
mobius/device.py
CHANGED
|
@@ -47,7 +47,7 @@ from .schedule import (
|
|
|
47
47
|
)
|
|
48
48
|
from .scenes import Scene, ActiveScene, decode_configured_scenes, decode_active_scene
|
|
49
49
|
from .modifiers import (
|
|
50
|
-
AcclimationInfo, is_night_segment, lunar_percent_reduction,
|
|
50
|
+
AcclimationInfo, is_night_segment, lunar_percent_reduction, lunar_days_into_phase,
|
|
51
51
|
)
|
|
52
52
|
from .power import ChannelPowerInfo, channel_percent_value
|
|
53
53
|
from .pump_status import PumpFlowRange, BatteryBackupInfo, BoostedBatteryInfo
|
|
@@ -163,6 +163,35 @@ class LightPollResult:
|
|
|
163
163
|
# failed and decode_schedule_intensity() had truly nothing to fall
|
|
164
164
|
# back to.
|
|
165
165
|
schedule_intensity: Optional[float] = None
|
|
166
|
+
# The device's own raw LunarPhasesEnabled (907) setting -- confirmed
|
|
167
|
+
# against the app's own "Lunar" chip, whose on/off state this
|
|
168
|
+
# matches exactly, at any time of day.
|
|
169
|
+
#
|
|
170
|
+
# A second, real, confirmed bug lived here before this field
|
|
171
|
+
# existed, same shape as schedule_intensity's own bug above:
|
|
172
|
+
# intensities.diagnostics["lunar_enabled"] is NOT this. Read
|
|
173
|
+
# process_light_intensities()'s own source: outside the night
|
|
174
|
+
# segment, it unconditionally sets lunar_enabled = None ("not
|
|
175
|
+
# checked/relevant outside the night segment" -- true for ITS OWN
|
|
176
|
+
# calculation, since the toggle only affects anything during the
|
|
177
|
+
# night segment, but not true for a caller that wants to know the
|
|
178
|
+
# device's own current setting regardless of time of day). A
|
|
179
|
+
# caller reading diagnostics["lunar_enabled"] during the day always
|
|
180
|
+
# gets None, even when the device's own toggle is genuinely on --
|
|
181
|
+
# this field is the one that's always correct, any time of day.
|
|
182
|
+
lunar_enabled: Optional[bool] = None
|
|
183
|
+
# The current lunar-cycle phase day (0-29, lunar_days_into_phase()'s
|
|
184
|
+
# own "days since new moon" convention), for a caller that wants to
|
|
185
|
+
# display the current moon phase -- not the same thing as the raw
|
|
186
|
+
# date this is computed from (which is only useful internally, for
|
|
187
|
+
# the schedule's own night-segment reduction calculation, and isn't
|
|
188
|
+
# exposed here at all). Falls back to today's local date when the
|
|
189
|
+
# device itself didn't provide one (Epoch/LocalTime unavailable),
|
|
190
|
+
# matching process_light_intensities()'s own "local_fallback"
|
|
191
|
+
# philosophy, so this is populated whenever `now` itself is valid --
|
|
192
|
+
# which it always is, since callers of get_light_poll_batch() are
|
|
193
|
+
# required to supply it.
|
|
194
|
+
lunar_phase_day: Optional[int] = None
|
|
166
195
|
|
|
167
196
|
|
|
168
197
|
@dataclass
|
|
@@ -565,6 +594,7 @@ def decode_light_poll_from_batch(
|
|
|
565
594
|
)
|
|
566
595
|
return LightPollResult(
|
|
567
596
|
schedule_points=points, intensities=intensities, used_batch=True, schedule_intensity=schedule_intensity,
|
|
597
|
+
lunar_enabled=lunar_enabled, lunar_phase_day=lunar_days_into_phase(lunar_date or now.date()),
|
|
568
598
|
)
|
|
569
599
|
|
|
570
600
|
|
|
@@ -3463,6 +3493,35 @@ class MobiusDevice:
|
|
|
3463
3493
|
return False
|
|
3464
3494
|
return decode_lunar_enabled(raw)
|
|
3465
3495
|
|
|
3496
|
+
async def set_lunar_enabled(self, enabled: bool) -> None:
|
|
3497
|
+
"""Writes LunarPhasesEnabled (907) -- confirmed byte-for-byte
|
|
3498
|
+
against the app's own compiled bytecode (LunarInfo.smali's own
|
|
3499
|
+
save() method): a single byte, the boolean enabled field stored
|
|
3500
|
+
directly as 0 or 1, via the exact same SetC2AttrFsciRequest.
|
|
3501
|
+
addAttribute() mechanism this library's own set_attribute()
|
|
3502
|
+
uses. This is exactly what the app's own "Lunar" chip (top of
|
|
3503
|
+
the light schedule editor) toggles: clicking it turns
|
|
3504
|
+
lunar-phase night-time dimming on/off, and while enabled that
|
|
3505
|
+
same chip also displays the current moon phase.
|
|
3506
|
+
|
|
3507
|
+
No group/broadcast involved -- confirmed by tracing
|
|
3508
|
+
LightingFragment's own saveLunar(), which loops over every
|
|
3509
|
+
light device in the tank and calls this same per-device,
|
|
3510
|
+
ungrouped write on EACH one individually (not a single
|
|
3511
|
+
mesh-wide broadcast the way set_time_to_now() works). The
|
|
3512
|
+
app's own UI applies the same new value to every light in the
|
|
3513
|
+
tank with that one tap, but the underlying wire mechanism is
|
|
3514
|
+
still one ordinary, targeted write per device -- this method
|
|
3515
|
+
only ever writes to the single device it's called on, matching
|
|
3516
|
+
every other attribute write in this library.
|
|
3517
|
+
|
|
3518
|
+
No which/schedule parameter -- unlike Schedule1Intensity/
|
|
3519
|
+
Schedule2Intensity, there's only ever a single
|
|
3520
|
+
LunarPhasesEnabled attribute (confirmed: no LunarPhasesEnabled2
|
|
3521
|
+
exists), so this applies to the light as a whole rather than to
|
|
3522
|
+
either schedule individually."""
|
|
3523
|
+
await self.set_attribute(C2Attribute.LunarPhasesEnabled, bytes([1 if enabled else 0]))
|
|
3524
|
+
|
|
3466
3525
|
async def get_acclimation_info(self) -> Optional[AcclimationInfo]:
|
|
3467
3526
|
"""
|
|
3468
3527
|
Fetches all 4 acclimation attributes (AcclimationEnabled/Period/
|
|
@@ -3811,9 +3870,12 @@ class MobiusDevice:
|
|
|
3811
3870
|
points = await self.get_light_schedule(which)
|
|
3812
3871
|
intensities = await self.get_current_light_intensities(which, minute_of_day, now)
|
|
3813
3872
|
schedule_intensity = await self.get_schedule_intensity(which)
|
|
3873
|
+
lunar_enabled = await self.get_lunar_enabled(which)
|
|
3874
|
+
lunar_date = await self.get_app_lunar_date()
|
|
3814
3875
|
return LightPollResult(
|
|
3815
3876
|
schedule_points=points, intensities=intensities, used_batch=False,
|
|
3816
|
-
schedule_intensity=schedule_intensity,
|
|
3877
|
+
schedule_intensity=schedule_intensity, lunar_enabled=lunar_enabled,
|
|
3878
|
+
lunar_phase_day=lunar_days_into_phase(lunar_date or now.date()),
|
|
3817
3879
|
)
|
|
3818
3880
|
|
|
3819
3881
|
async def get_full_poll_batch(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: python-mobius
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.4
|
|
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,9 +1,9 @@
|
|
|
1
|
-
mobius/__init__.py,sha256=
|
|
1
|
+
mobius/__init__.py,sha256=zJ7qeHhqVm9-cdr0eJP8VTPoXL95gcjpIPkQV8esqhw,7620
|
|
2
2
|
mobius/cli.py,sha256=DJNKcBB7VCROZ90QmFWeCkRzPCRfoTaeTZaCLJ41s-Y,79735
|
|
3
3
|
mobius/coap.py,sha256=ZRBy8ivgl1o2cVLjIp-df8Jg34c58K0_1Oec1P-gQI4,10464
|
|
4
4
|
mobius/constants.py,sha256=OlbC0GSPT3Lp7rGfIqSMkAqY535oNNRRoOd15TTVt7k,46286
|
|
5
5
|
mobius/crc.py,sha256=T6PWTp3gAHu-C05ua2LH8z8leD8mSjizM7nuC9G8KhU,2643
|
|
6
|
-
mobius/device.py,sha256=
|
|
6
|
+
mobius/device.py,sha256=H-q8SDEjbS7OeapUJTOY4dUFCdc88j2NRdE-gQf8Ib8,205390
|
|
7
7
|
mobius/device_status.py,sha256=tKZwi12fS3PVl7F-Pr5tvTNOTAttaOtAWom7ahl0LZM,33080
|
|
8
8
|
mobius/discovery.py,sha256=-N_RK8ZK91Ep-XePm9cHJa44yKiBL_Ind9wFHi_TZ-8,11742
|
|
9
9
|
mobius/dump.py,sha256=2uy-bq8Ja2W3D4dz9VboSO_KqYQ4bE8xmVxYTxWOjXg,16525
|
|
@@ -17,8 +17,8 @@ mobius/pump_status.py,sha256=qLprWM0gAoltZj7w8ykdXHPfBDMl-QnBOwrmBlvknIA,1536
|
|
|
17
17
|
mobius/relay.py,sha256=BmUc1l0mDOt9isTGs7wCh0NxehbMxfaTzm3cYs7VucA,26445
|
|
18
18
|
mobius/scenes.py,sha256=Wt0Ys2x1YjF8MNDEd6kxWqYBIYPdBSbfzXD-L5ZKzag,3592
|
|
19
19
|
mobius/schedule.py,sha256=BDm8Uh8O85AlAZuR7i7pgqKC2GNXcV_HikFoG6_3Xgo,17590
|
|
20
|
-
python_mobius-0.8.
|
|
21
|
-
python_mobius-0.8.
|
|
22
|
-
python_mobius-0.8.
|
|
23
|
-
python_mobius-0.8.
|
|
24
|
-
python_mobius-0.8.
|
|
20
|
+
python_mobius-0.8.4.dist-info/METADATA,sha256=zBB4TSObJ1G1aMtSgw4J69til5vj1wevuz1suQ99beY,9899
|
|
21
|
+
python_mobius-0.8.4.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
22
|
+
python_mobius-0.8.4.dist-info/entry_points.txt,sha256=Q2hlcek-bWm70zvd12v32essflPgC2su-dKDHAqbPoE,48
|
|
23
|
+
python_mobius-0.8.4.dist-info/licenses/LICENSE,sha256=7a72Msu2Q-TnoiFxemxEGkwafJGObk1W3rw9hzmyM_Y,17984
|
|
24
|
+
python_mobius-0.8.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|