Skip to content

Commit 6796267

Browse files
committed
time
1 parent ab50ddd commit 6796267

6 files changed

Lines changed: 50 additions & 67 deletions

File tree

.github/workflows/lint.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ on:
77
pull_request:
88
branches:
99
- main
10-
schedule:
11-
- cron: "0 0 * * *"
10+
# schedule:
11+
# - cron: "0 0 * * *"
1212

1313
jobs:
1414
find:

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ dependencies = [
2626
"mqtt-entity[options]>=1.1",
2727
"prettytable>=3.17,<4",
2828
"pymodbus[serial]==3.11.4",
29-
"whenever>=0.9.5",
29+
"whenever>=0.10,<11",
3030
]
3131
optional-dependencies.solarman = [ "pysolarmanv5==3.0.6" ]
3232
optional-dependencies.umodbus = [ "async-modbus==0.2.3", "connio==0.2", "umodbus==1.0.4" ]

src/sunsynk/helpers.py

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import math
55
import struct
66
from collections.abc import Iterable
7+
from dataclasses import InitVar, dataclass
78

89
_LOG = logging.getLogger(__name__)
910

@@ -75,7 +76,7 @@ def ensure_tuple[T](val: T | tuple[T, ...]) -> tuple[T, ...]:
7576
return ()
7677
if isinstance(val, Iterable) and not isinstance(val, str):
7778
return tuple(val)
78-
return (val,)
79+
return (val,) # type: ignore[return-value]
7980

8081

8182
def int_round(val: NumType) -> NumType:
@@ -123,28 +124,20 @@ def patch_bitmask(value: int, patch: int, bitmask: int) -> int:
123124
return (patch & bitmask) + (value & (0xFFFF - bitmask))
124125

125126

127+
@dataclass
126128
class SSTime:
127129
"""Deals with inverter time format conversion complexities."""
128130

129131
minutes: int = 0
132+
strv: InitVar[str] = ""
133+
regv: InitVar[int] = 0
130134

131-
def __init__(
132-
self,
133-
*,
134-
minutes: int | None = None,
135-
register: int | None = None,
136-
string: str | None = None,
137-
) -> None:
138-
"""Init the time. All mutually exclusive."""
139-
if minutes is not None:
140-
assert register is None
141-
assert string is None
142-
self.minutes = minutes
143-
elif register is not None:
144-
assert string is None
145-
self.reg_value = register
146-
elif string is not None:
147-
self.str_value = string
135+
def __post_init__(self, strv: str, regv: int) -> None:
136+
"""Initialize from string or register value."""
137+
if strv:
138+
self.str_value = strv
139+
elif regv:
140+
self.reg_value = regv
148141

149142
@property
150143
def reg_value(self) -> int:
@@ -162,6 +155,7 @@ def reg_value(self, reg_value: int) -> None:
162155
def str_value(self) -> str:
163156
"""Get the value in hh:mm format."""
164157
hours, minutes = divmod(self.minutes, 60)
158+
hours = hours % 24
165159
return f"{hours}:{minutes:02}"
166160

167161
@str_value.setter

src/sunsynk/rwsensors.py

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import logging
66
import re
7-
from collections.abc import Generator
87
from dataclasses import dataclass, field
98
from typing import TYPE_CHECKING
109

@@ -230,19 +229,17 @@ class TimeRWSensor(RWSensor):
230229

231230
def available_values(self, step_minutes: int, state: InverterState) -> list[str]:
232231
"""Get the available values for this sensor."""
233-
full_day = 24 * 60
234-
235-
min_val = (
236-
SSTime(string=str(state.get(self.min, "0:00"))).minutes if self.min else 0
237-
)
238-
max_val = (
239-
SSTime(string=str(state.get(self.max, "24:00"))).minutes
240-
if self.max
241-
else full_day
242-
)
243-
val = SSTime(string=str(state.get(self, "0:00"))).minutes
244-
time_range = self._range(min_val, max_val, val, step_minutes, full_day)
245-
return list(map(lambda m: SSTime(minutes=m).str_value, time_range))
232+
day = list(range(0, 24 * 60, step_minutes))
233+
minv = SSTime(strv=str(state.get(self.min, "0:00"))).minutes if self.min else 0
234+
maxv = SSTime(strv=str(state.get(self.max, "0:00"))).minutes if self.max else 0
235+
if minv >= maxv:
236+
maxv += 24 * 60
237+
opt = [minv, *[v for v in day if (v > minv and v < maxv)], maxv]
238+
val = SSTime(strv=str(state.get(self, "0:00"))).minutes
239+
if val not in opt:
240+
opt.append(val)
241+
opt.sort()
242+
return [SSTime(minutes=m).str_value for m in opt]
246243

247244
@property
248245
def dependencies(self) -> list[Sensor]:
@@ -251,22 +248,10 @@ def dependencies(self) -> list[Sensor]:
251248

252249
def reg_to_value(self, regs: RegType) -> ValType:
253250
"""Decode the time from a register."""
254-
return SSTime(register=regs[0]).str_value
251+
return SSTime(regv=regs[0]).str_value
255252

256253
def value_to_reg(self, value: ValType, state: InverterState) -> RegType:
257254
"""Get the reg value from a display value."""
258255
if not self.address:
259256
raise NotImplementedError("Cannot write to a sensor with no address")
260-
return self.reg(SSTime(string=str(value)).reg_value)
261-
262-
@staticmethod
263-
def _range(
264-
start: int, end: int, val: int, step: int, modulo: int
265-
) -> Generator[int]:
266-
if val % step != 0:
267-
yield val
268-
stop = end if start <= end else end + modulo
269-
for i in range(start, stop, step):
270-
yield i % modulo
271-
if start == end or start != end % modulo:
272-
yield end
257+
return self.reg(SSTime(strv=str(value)).reg_value)

src/tests/sunsynk/test_rwsensors.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -223,26 +223,30 @@ def test_time_rw(state: InverterState) -> None:
223223

224224
state.update(
225225
{
226-
50: 2330,
227-
60: 2330,
228-
70: 30,
226+
50: 2300, # min
227+
60: 2330, # value
228+
70: 2400, # max
229229
}
230230
)
231231
assert s.available_values(15, state) == [
232+
"23:00",
233+
"23:15",
232234
"23:30",
233235
"23:45",
234236
"0:00",
235-
"0:15",
236-
"0:30",
237+
# "0:00",
238+
# "0:15",
239+
# "0:30",
237240
]
238241

239242
state.update(
240243
{
241-
50: 200,
242-
70: 200,
244+
50: 203,
245+
60: 210,
246+
70: 222,
243247
}
244248
)
245-
assert s.available_values(15, state) == ["2:00"]
249+
assert s.available_values(15, state) == ["2:03", "2:10", "2:15", "2:22"]
246250

247251

248252
# def test_update_sensor(caplog) -> None:

uv.lock

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)