Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added time and day related evu events (related #38) #248 #249

Merged
merged 7 commits into from
Oct 5, 2024
1 change: 1 addition & 0 deletions custom_components/luxtronik/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,7 @@ class SensorAttrKey(StrEnum):
EVU_SECOND_START_TIME = "EVU_second_start_time"
EVU_SECOND_END_TIME = "EVU_second_end_time"
EVU_MINUTES_UNTIL_NEXT_EVENT = "EVU_minutes_until_next_event"
EVU_DAYS = "EVU_days"
TIMESTAMP = "timestamp"
CODE = "code"
CAUSE = "cause"
Expand Down
33 changes: 31 additions & 2 deletions custom_components/luxtronik/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from __future__ import annotations

from datetime import date, datetime, time, timezone
import calendar
from decimal import Decimal
from typing import Any

Expand Down Expand Up @@ -182,11 +183,12 @@ class LuxtronikStatusSensorEntity(LuxtronikSensorEntity, SensorEntity):
_coordinator: LuxtronikCoordinator
_last_state: StateType | date | datetime | Decimal = None

_attr_cache: dict[SA, time] = {}
_attr_cache: dict[SA, object] = {}
_attr_cache[SA.EVU_FIRST_START_TIME] = time.min
_attr_cache[SA.EVU_FIRST_END_TIME] = time.min
_attr_cache[SA.EVU_SECOND_START_TIME] = time.min
_attr_cache[SA.EVU_SECOND_END_TIME] = time.min
_attr_cache[SA.EVU_DAYS] = list()

_unrecorded_attributes = frozenset(
LuxtronikSensorEntity._unrecorded_attributes
Expand All @@ -198,6 +200,7 @@ class LuxtronikStatusSensorEntity(LuxtronikSensorEntity, SensorEntity):
SA.EVU_SECOND_START_TIME,
SA.EVU_SECOND_END_TIME,
SA.EVU_MINUTES_UNTIL_NEXT_EVENT,
SA.EVU_DAYS,
}
)

Expand All @@ -212,6 +215,7 @@ def _handle_coordinator_update(
super()._handle_coordinator_update(data)
time_now = time(datetime.now().hour, datetime.now().minute)
evu = LuxOperationMode.evu.value
weekday = datetime.today().weekday()
if self._attr_native_value is None or self._last_state is None:
pass
elif self._attr_native_value == evu and str(self._last_state) != evu:
Expand All @@ -228,6 +232,8 @@ def _handle_coordinator_update(
self._attr_cache[SA.EVU_FIRST_START_TIME] = time_now
else:
self._attr_cache[SA.EVU_SECOND_START_TIME] = time_now
if weekday not in self._attr_cache[SA.EVU_DAYS]:
self._attr_cache[SA.EVU_DAYS].append(weekday)
elif self._attr_native_value != evu and str(self._last_state) == evu:
# evu end
if (
Expand Down Expand Up @@ -319,6 +325,9 @@ def _handle_coordinator_update(
attr[SA.EVU_SECOND_END_TIME] = self._tm_txt(
self._attr_cache[SA.EVU_SECOND_END_TIME]
)
attr[SA.EVU_DAYS] = self._wd_txt(
self._attr_cache[SA.EVU_DAYS]
)
self._enrich_extra_attributes()
self.async_write_ha_state()

Expand Down Expand Up @@ -384,7 +393,19 @@ def _calc_next_evu_event_minutes(self) -> int | None:
if evu_time == time.min:
return None
evu_hours = (24 if evu_time < time_now else 0) + evu_time.hour
return (evu_hours - time_now.hour) * 60 + evu_time.minute - time_now.minute
weekday = datetime.today().weekday()
evu_pause = 0
if not self._attr_cache[SA.EVU_DAYS] and weekday not in self._attr_cache[SA.EVU_DAYS]:
evu_pause += (24 - datetime.now().hour)*60 - datetime.now().minute
for i in range(1, 7):
if weekday+i > 6:
i = -7+i
if weekday+i in self._attr_cache[SA.EVU_DAYS]:
return (evu_hours - time_now.hour) * 60 + evu_time.minute - time_now.minute + evu_pause
else:
evu_pause += 1440
else:
return (evu_hours - time_now.hour) * 60 + evu_time.minute - time_now.minute

def _get_next_evu_event_time(self) -> time:
event: time = time.min
Expand Down Expand Up @@ -415,6 +436,14 @@ def _get_next_evu_event_time(self) -> time:
def _tm_txt(self, value: time) -> str:
return "" if value == time.min else value.strftime("%H:%M")

def _wd_txt(self, value: list) -> str:
if not value:
return ""
days = []
for i in value:
days.append(calendar.day_name[i])
return ','.join(days)

def _restore_attr_value(self, value: Any | None) -> Any:
if value is None or ":" not in str(value):
return time.min
Expand Down
1 change: 1 addition & 0 deletions custom_components/luxtronik/sensor_entities_predefined.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
attr(SA.EVU_FIRST_END_TIME, LC.UNSET, None, True),
attr(SA.EVU_SECOND_START_TIME, LC.UNSET, None, True),
attr(SA.EVU_SECOND_END_TIME, LC.UNSET, None, True),
attr(SA.EVU_DAYS, LC.UNSET, None, True),
),
options=[e.value for e in LuxOperationMode],
update_interval=UPDATE_INTERVAL_NORMAL,
Expand Down