Skip to content

Commit cad0856

Browse files
authored
Merge pull request #57 from eMeF1/fix/delivery-time-recursion-error
Fix RecursionError in DeliveryTime sensor
2 parents c7dc064 + 55ffa31 commit cad0856

1 file changed

Lines changed: 60 additions & 15 deletions

File tree

custom_components/rohlikcz/sensor.py

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,29 +65,38 @@ async def async_setup_entry(
6565

6666
async_add_entities(entities)
6767

68-
class DeliveryInfo(BaseEntity, SensorEntity):
68+
class DeliveryInfo(BaseEntity, SensorEntity, RestoreEntity):
6969
"""Sensor for showing delivery information."""
7070

7171
_attr_translation_key = "delivery_info"
7272
_attr_should_poll = False
7373

74+
def __init__(self, rohlik_account: RohlikAccount) -> None:
75+
"""Initialize the delivery info sensor."""
76+
super().__init__(rohlik_account)
77+
self._last_value: str | None = None
78+
self._last_attributes: Mapping[str, Any] | None = None
79+
7480
@property
7581
def native_value(self) -> str | None:
7682
"""Returns text of announcement."""
7783
delivery_info: list = self._rohlik_account.data["delivery_announcements"]["data"]["announcements"]
7884
if len(delivery_info) > 0:
7985
clean_text = re.sub(r'<[^>]+>', '', delivery_info[0]["content"])
86+
self._last_value = clean_text
8087
return clean_text
8188
else:
82-
return None
83-
89+
# If announcements stopped but order still exists, preserve last value
90+
if self._rohlik_account.is_ordered and self._last_value is not None:
91+
return self._last_value
92+
else:
93+
return None
8494

8595
@property
8696
def extra_state_attributes(self) -> Mapping[str, Any] | None:
8797
""" Get extra state attributes. """
8898
delivery_info: list = self._rohlik_account.data["delivery_announcements"]["data"]["announcements"]
8999
if len(delivery_info) > 0:
90-
91100
delivery_time = extract_delivery_datetime(delivery_info[0].get("content", ""))
92101

93102
if delivery_info[0].get("additionalContent", None):
@@ -96,54 +105,90 @@ def extra_state_attributes(self) -> Mapping[str, Any] | None:
96105
else:
97106
additional_info = None
98107

99-
return {
108+
attrs = {
100109
"Delivery time (deprecated, use new entity)": delivery_time,
101110
"Order Id": str(delivery_info[0].get("id")),
102111
"Updated At": datetime.fromisoformat(delivery_info[0].get("updatedAt")),
103112
"Title": delivery_info[0].get("title"),
104113
"Additional Content": additional_info
105114
}
106-
115+
self._last_attributes = attrs
116+
return attrs
107117
else:
108-
return None
118+
# If announcements stopped but order still exists, preserve last attributes
119+
if self._rohlik_account.is_ordered and self._last_attributes is not None:
120+
return self._last_attributes
121+
else:
122+
return None
109123

110124
@property
111125
def icon(self) -> str:
112126
return ICON_INFO
113127

114128
async def async_added_to_hass(self) -> None:
129+
"""Restore state when added to HA."""
130+
await super().async_added_to_hass()
131+
132+
# Restore last state if available
133+
if (last_state := await self.async_get_last_state()) is not None:
134+
if last_state.state not in (STATE_UNAVAILABLE, "unknown", "None"):
135+
self._last_value = last_state.state
136+
if last_state.attributes:
137+
self._last_attributes = dict(last_state.attributes)
138+
115139
self._rohlik_account.register_callback(self.async_write_ha_state)
116140

117141
async def async_will_remove_from_hass(self) -> None:
118142
self._rohlik_account.remove_callback(self.async_write_ha_state)
119143

120-
class DeliveryTime(BaseEntity, SensorEntity):
144+
class DeliveryTime(BaseEntity, SensorEntity, RestoreEntity):
121145
"""Sensor for showing delivery time."""
122146

123147
_attr_translation_key = "delivery_time"
124148
_attr_should_poll = False
125149
_attr_device_class = SensorDeviceClass.TIMESTAMP
126150

151+
def __init__(self, rohlik_account: RohlikAccount) -> None:
152+
"""Initialize the delivery time sensor."""
153+
super().__init__(rohlik_account)
154+
self._last_value: datetime | None = None
155+
127156
@property
128-
def native_value(self) -> str | None:
157+
def native_value(self) -> datetime | None:
129158
"""Returns time of delivery."""
130159
delivery_info: list = self._rohlik_account.data["delivery_announcements"]["data"]["announcements"]
131160
if len(delivery_info) > 0:
132-
133-
return extract_delivery_datetime(delivery_info[0].get("content", ""))
134-
161+
delivery_time = extract_delivery_datetime(delivery_info[0].get("content", ""))
162+
self._last_value = delivery_time
163+
return delivery_time
135164
else:
136-
if self._rohlik_account.is_ordered:
137-
return self.native_value
165+
# If announcements stopped but order still exists, preserve last value
166+
if self._rohlik_account.is_ordered and self._last_value is not None:
167+
return self._last_value
138168
else:
139169
return None
140170

141-
142171
@property
143172
def icon(self) -> str:
144173
return ICON_DELIVERY_TIME
145174

146175
async def async_added_to_hass(self) -> None:
176+
"""Restore state when added to HA."""
177+
await super().async_added_to_hass()
178+
179+
# Restore last state if available
180+
if (last_state := await self.async_get_last_state()) is not None:
181+
if last_state.state not in (STATE_UNAVAILABLE, "unknown", "None"):
182+
# Try to parse the restored state
183+
try:
184+
if isinstance(last_state.state, datetime):
185+
self._last_value = last_state.state
186+
elif isinstance(last_state.state, str):
187+
# Try to parse ISO format
188+
self._last_value = datetime.fromisoformat(last_state.state.replace('Z', '+00:00'))
189+
except (ValueError, AttributeError):
190+
pass
191+
147192
self._rohlik_account.register_callback(self.async_write_ha_state)
148193

149194
async def async_will_remove_from_hass(self) -> None:

0 commit comments

Comments
 (0)