Skip to content

Commit 7857a75

Browse files
committed
Resolve state/last_state issues
- Fix type object singleton issues - Add deep copy functionality to new_object - Ensure proper isolation between current and last values
1 parent ffab8f3 commit 7857a75

File tree

4 files changed

+39
-18
lines changed

4 files changed

+39
-18
lines changed

inelsmqtt/devices/__init__.py

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,14 @@
1818
TOPIC_FRAGMENTS,
1919
VERSION,
2020
)
21-
from inelsmqtt.utils.core import DUMMY_VAL, DeviceClassProtocol, DeviceTypeNotFound, DeviceValue, ProtocolHandlerMapper
21+
from inelsmqtt.utils.core import (
22+
DUMMY_VAL,
23+
DeviceClassProtocol,
24+
DeviceTypeNotFound,
25+
DeviceValue,
26+
LastHAValue,
27+
ProtocolHandlerMapper,
28+
)
2229

2330
_LOGGER = logging.getLogger(__name__)
2431

@@ -234,24 +241,23 @@ def values(self) -> Optional[DeviceValue]:
234241
return self.__values
235242

236243
@property
237-
def last_values(self) -> DeviceValue:
244+
def last_values(self) -> LastHAValue:
238245
"""Get last value of the device
239246
240247
Returns:
241-
DeviceValue: latest values in many formats
248+
LastHAValue: Container for the previous Home Assistant value.
242249
"""
243-
try:
244-
if hasattr(self.__values.last_value.ha_value, "__dict__"):
245-
return self.__values.last_value
246-
raise AttributeError
247-
except AttributeError:
250+
if self.__values: # previous state exists
251+
return self.__values.last_value
252+
else:
248253
val = self.__mqtt.last_value(self.__state_topic)
249-
return DeviceValue(
254+
device_value = DeviceValue(
250255
self.__device_type,
251256
self.__inels_type,
252257
self.__device_class,
253258
inels_value=val.decode() if val is not None else None, # type: ignore[attr-defined]
254259
)
260+
return LastHAValue(device_value.ha_value)
255261

256262
@property
257263
def mqtt(self) -> InelsMqtt:
@@ -270,10 +276,9 @@ def __get_value(self, val: Any) -> DeviceValue:
270276
self.__inels_type,
271277
self.__device_class,
272278
inels_value=(val.decode() if val is not None else None),
273-
# last_value=self.last_values,
274-
last_value=self.__values, # because it is already the last value at this moment
279+
last_value=LastHAValue(self.__values.ha_value) if self.__values else self.last_values,
275280
)
276-
self.__state = dev_value.ha_value
281+
self.__state = dev_value.ha_value.copy() if dev_value.ha_value is not DUMMY_VAL else DUMMY_VAL
277282
self.__values = dev_value
278283

279284
return dev_value
@@ -302,12 +307,11 @@ def set_ha_value(self, value: Any) -> bool:
302307
self.__inels_type,
303308
self.__device_class,
304309
ha_value=value,
305-
# last_value=self.__state,
306-
last_value=self.__values, # because the last_value will be accessible
310+
last_value=LastHAValue(self.__values.ha_value if self.__values else None),
307311
)
308312

309-
self.__state = dev.ha_value
310-
self.__values = dev
313+
# self.__state = dev.ha_value
314+
# self.__values = dev
311315

312316
ret = False
313317
if self.__set_topic is not None:

inelsmqtt/utils/common.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import copy
12
import json
23
from dataclasses import dataclass
34
from operator import itemgetter
@@ -96,7 +97,15 @@ class DALILight(SimpleLight):
9697

9798
def new_object(**kwargs: Any) -> Any:
9899
"""Create new anonymous object."""
99-
return type("Object", (), kwargs)
100+
cls = type("Object", (), kwargs)
101+
cls.copy = staticmethod(
102+
lambda: type(
103+
"Object",
104+
(),
105+
copy.deepcopy({k: v for k, v in dict(cls.__dict__).items() if not k.startswith("__") and k != "copy"}),
106+
)
107+
)
108+
return cls
100109

101110

102111
def break_into_bytes(line: str) -> List[str]:

inelsmqtt/utils/core.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import logging
6+
from dataclasses import dataclass
67
from typing import Any, List, Optional, Protocol
78

89
from inelsmqtt.protocols import cu3, elanrf
@@ -149,6 +150,13 @@ def get_handler(device_type: str) -> type[DeviceClassProtocol]:
149150
return handler
150151

151152

153+
@dataclass
154+
class LastHAValue:
155+
"""Store the last known ha_value without creating reference chains."""
156+
157+
ha_value: Any
158+
159+
152160
class DeviceValue:
153161
"""Device value interpretation object."""
154162

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
setup(
66
name="elkoep-mqtt",
7-
version="0.2.33.beta.15",
7+
version="0.2.33.beta.16",
88
url="https://github.com/epdevlab/elkoep-mqtt",
99
license="MIT",
1010
author="Elko EP s.r.o.",

0 commit comments

Comments
 (0)