python-mobius 0.3.0__py3-none-any.whl → 0.3.1__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 CHANGED
@@ -63,7 +63,7 @@ from .discovery import (
63
63
  dedupe_by_serial, find_device_by_serial, discover_mesh_peers_via_direct_connect,
64
64
  )
65
65
 
66
- __version__ = "0.3.0"
66
+ __version__ = "0.3.1"
67
67
 
68
68
  __all__ = [
69
69
  "__version__",
mobius/schedule.py CHANGED
@@ -88,6 +88,41 @@ def interpolate_light_schedule(points: list[SchedulePoint], minute_of_day: int)
88
88
  schedule points and a target time (0-1439, minutes since midnight),
89
89
  returns {VisualID: intensity_permille} by linearly interpolating between
90
90
  the two points that bracket that time, wrapping around midnight.
91
+
92
+ Applies LightPrimitive.flatten()'s confirmed semantics (see that
93
+ method and its two call sites in getIntensitiesAtTime() in the real
94
+ smali -- JADX's decompiled Java for this class carried its own "Code
95
+ duplicated" warning, the same signal that led to finding the
96
+ is_night_segment() bug, so this was re-verified against raw bytecode
97
+ rather than trusted from the decompile alone): the "Brightness"
98
+ channel (VisualID.Brightness) is a master dimmer that multiplies
99
+ every OTHER channel -- confirmed via real hardware testing that this
100
+ was missing entirely: MoonlightBlue/White (and every other color
101
+ channel) were computed without ever being scaled by Brightness,
102
+ which the real app clearly does (a light showing ~1% in the app's
103
+ own "Current Intensities" display came back as ~25% from this
104
+ library at the same moment, with Brightness itself reading ~3.3% at
105
+ that point in its own ramp -- consistent with the missing
106
+ multiplication, not a lunar or scheduling bug).
107
+
108
+ Critically, this flattening happens to EACH bracketing point
109
+ SEPARATELY (each point's own non-Brightness channels multiplied by
110
+ that SAME point's own Brightness value) BEFORE interpolating between
111
+ the two already-flattened points -- not interpolate raw values first
112
+ and apply a single Brightness value at the end. These are NOT
113
+ mathematically equivalent whenever Brightness itself changes across
114
+ the segment (which it usually does, e.g. ramping 0->1000 during a
115
+ dusk/dawn transition) -- confirmed by the smali calling flatten() on
116
+ both point copies before the interpolation loop, not after it.
117
+
118
+ "Brightness" itself is deliberately NOT flattened to 1000 in the
119
+ returned dict the way the real flatten() call does internally --
120
+ unlike the app's own dashboard (which doesn't display Brightness as
121
+ its own value at all, only as the multiplier baked into every other
122
+ channel), this library's callers (e.g. a dedicated Brightness
123
+ sensor) want the actual current master-dimmer level itself, not a
124
+ constant 100%. Returned as the plain raw interpolation between the
125
+ two points' own Brightness values, same as before this fix.
91
126
  """
92
127
  if not points:
93
128
  return {}
@@ -109,12 +144,26 @@ def interpolate_light_schedule(points: list[SchedulePoint], minute_of_day: int)
109
144
  if t1 <= m <= t2:
110
145
  span = (t2 - t1) or 1
111
146
  frac = (m - t1) / span
147
+
148
+ # Each point's own Brightness value, defaulting to 1000 (a
149
+ # no-op multiplier) if that point doesn't have a Brightness
150
+ # channel at all -- matches flatten()'s own
151
+ # visuals().contains(Brightness) guard, which skips scaling
152
+ # entirely rather than treating an absent channel as 0.
153
+ b1 = p1.light.get(VisualID.Brightness) if VisualID.Brightness in p1.light.channels else 1000
154
+ b2 = p2.light.get(VisualID.Brightness) if VisualID.Brightness in p2.light.channels else 1000
155
+
112
156
  result = {}
113
157
  all_channels = set(p1.light.channels) | set(p2.light.channels)
114
158
  for ch in all_channels:
115
159
  v1 = p1.light.get(ch)
116
160
  v2 = p2.light.get(ch)
117
- result[ch] = v1 + (v2 - v1) * frac
161
+ if ch == VisualID.Brightness:
162
+ result[ch] = v1 + (v2 - v1) * frac
163
+ else:
164
+ flattened1 = v1 * b1 / 1000.0
165
+ flattened2 = v2 * b2 / 1000.0
166
+ result[ch] = flattened1 + (flattened2 - flattened1) * frac
118
167
  return result
119
168
  return {}
120
169
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-mobius
3
- Version: 0.3.0
3
+ Version: 0.3.1
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,4 +1,4 @@
1
- mobius/__init__.py,sha256=m_RB_zd21HCRyOSYovJeLFLScE8Gv9dPLjwdLALGRjk,5596
1
+ mobius/__init__.py,sha256=pUvLAuR2ubblIn1v_bfunHnaCosr7TJys_LNFbnYUHw,5596
2
2
  mobius/cli.py,sha256=s1zZa4P4rws-XRLLd1B_J67mjMbdImcfgNeDet44cYo,21494
3
3
  mobius/coap.py,sha256=n-_wBuSY88_c1TAjfXPZsPnpG0IcZZLFRjxTzd1c0Us,10859
4
4
  mobius/constants.py,sha256=N98whYfTAdzydP18kn0ycXQubbc6F-CJUSr-o_KlepU,24129
@@ -13,9 +13,9 @@ mobius/modifiers.py,sha256=TQD__OvHAvUO14Z8SNp2I4lb7XYSbw_iZT2D2DXaeJ4,7315
13
13
  mobius/power.py,sha256=cZBpfYh2yg4xhmOQ0ILpACYdJSd7jMvSrhxat0yaH-g,3851
14
14
  mobius/pump_status.py,sha256=vqJXFAb16S-4oyzAzZIcwR5if7lXoTj67qwBJdbH1gI,1604
15
15
  mobius/relay.py,sha256=YnIAtX0vHPPSazgRT_g8ocP2WJNyvW02JQOafabmsbM,16497
16
- mobius/schedule.py,sha256=kHr684TIKPZ2BplIySoeD-Yn1Xa_2bE6rfGUs-waWMQ,7483
17
- python_mobius-0.3.0.dist-info/METADATA,sha256=8Zxtj2NGCJFkLEm2yXnLs-9ioowAitxS3i3jIrJ9Xtk,5959
18
- python_mobius-0.3.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
19
- python_mobius-0.3.0.dist-info/entry_points.txt,sha256=Q2hlcek-bWm70zvd12v32essflPgC2su-dKDHAqbPoE,48
20
- python_mobius-0.3.0.dist-info/licenses/LICENSE,sha256=7a72Msu2Q-TnoiFxemxEGkwafJGObk1W3rw9hzmyM_Y,17984
21
- python_mobius-0.3.0.dist-info/RECORD,,
16
+ mobius/schedule.py,sha256=hKTlVoxw4eZpDcWUL9wpxShLacmoQZd7MR4kn6ZNvWs,10492
17
+ python_mobius-0.3.1.dist-info/METADATA,sha256=FV_rjO4y1wL8ews26uvabsG87XtNgjuH2ZLz9oK6LHo,5959
18
+ python_mobius-0.3.1.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
19
+ python_mobius-0.3.1.dist-info/entry_points.txt,sha256=Q2hlcek-bWm70zvd12v32essflPgC2su-dKDHAqbPoE,48
20
+ python_mobius-0.3.1.dist-info/licenses/LICENSE,sha256=7a72Msu2Q-TnoiFxemxEGkwafJGObk1W3rw9hzmyM_Y,17984
21
+ python_mobius-0.3.1.dist-info/RECORD,,