-
Notifications
You must be signed in to change notification settings - Fork 75
defro drx pluse #156
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
base: main
Are you sure you want to change the base?
defro drx pluse #156
Changes from all commits
23c7262
3731c18
6788f52
2325a72
ae0d5be
4325e23
afcde62
b5965a8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldnt be here |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,24 +5,38 @@ | |
from homeassistant.components import binary_sensor | ||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.const import ( | ||
ATTR_IDENTIFIERS, | ||
ATTR_MANUFACTURER, | ||
CONF_MODEL, | ||
CONF_NAME, | ||
CONF_PARAMS, | ||
CONF_TYPE, | ||
STATE_OFF, | ||
STATE_ON, | ||
EntityCategory, | ||
) | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.helpers.device_registry import DeviceInfo | ||
from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||
from homeassistant.helpers.typing import StateType, UndefinedType | ||
from homeassistant.helpers.update_coordinator import CoordinatorEntity | ||
|
||
from . import TechCoordinator, assets | ||
from .const import ( | ||
CONTROLLER, | ||
DOMAIN, | ||
FILTER_ALARM_MAX_DAYS, | ||
INCLUDE_HUB_IN_NAME, | ||
MANUFACTURER, | ||
RECUPERATION_EXHAUST_FLOW, | ||
RECUPERATION_SUPPLY_FLOW, | ||
RECUPERATION_SUPPLY_FLOW_ALT, | ||
TYPE_ADDITIONAL_PUMP, | ||
TYPE_FIRE_SENSOR, | ||
TYPE_RELAY, | ||
TYPE_TEMPERATURE_CH, | ||
UDID, | ||
VER, | ||
VISIBILITY, | ||
) | ||
from .entity import TileEntity | ||
|
@@ -63,6 +77,28 @@ async def async_setup_entry( | |
if tile[CONF_TYPE] == TYPE_ADDITIONAL_PUMP: | ||
entities.append(RelaySensor(tile, coordinator, config_entry)) | ||
|
||
# Check if we have recuperation system for filter replacement sensor | ||
has_recuperation_flow = False | ||
for t in tiles: | ||
tile = tiles[t] | ||
if tile.get("type") == TYPE_TEMPERATURE_CH: | ||
widget1_txt_id = tile.get("params", {}).get("widget1", {}).get("txtId", 0) | ||
widget2_txt_id = tile.get("params", {}).get("widget2", {}).get("txtId", 0) | ||
for flow_sensor in [RECUPERATION_EXHAUST_FLOW, RECUPERATION_SUPPLY_FLOW, RECUPERATION_SUPPLY_FLOW_ALT]: | ||
if flow_sensor["txt_id"] in [widget1_txt_id, widget2_txt_id]: | ||
has_recuperation_flow = True | ||
break | ||
if has_recuperation_flow: | ||
break | ||
|
||
# Add recuperation binary sensors if system detected | ||
if has_recuperation_flow: | ||
_LOGGER.debug("Creating recuperation binary sensors") | ||
entities.extend([ | ||
FilterReplacementSensor(coordinator, config_entry), | ||
RecuperationSystemStatusSensor(coordinator, config_entry), | ||
]) | ||
|
||
async_add_entities(entities, True) | ||
|
||
|
||
|
@@ -109,3 +145,143 @@ def __init__( | |
def get_state(self, device): | ||
"""Get device state.""" | ||
return device[CONF_PARAMS]["workingStatus"] | ||
|
||
|
||
class FilterReplacementSensor(CoordinatorEntity, binary_sensor.BinarySensorEntity): | ||
"""Binary sensor to indicate when filter replacement is needed.""" | ||
|
||
_attr_has_entity_name = True | ||
_attr_device_class = binary_sensor.BinarySensorDeviceClass.PROBLEM | ||
_attr_icon = "mdi:air-filter-outline" | ||
|
||
def __init__( | ||
self, | ||
coordinator: TechCoordinator, | ||
config_entry: ConfigEntry, | ||
) -> None: | ||
"""Initialize the filter replacement sensor.""" | ||
super().__init__(coordinator) | ||
self._coordinator = coordinator | ||
self._config_entry = config_entry | ||
self._udid = config_entry.data[CONTROLLER][UDID] | ||
self._attr_unique_id = f"{self._udid}_filter_replacement_needed" | ||
|
||
self._name = ( | ||
self._config_entry.title + " " | ||
if self._config_entry.data[INCLUDE_HUB_IN_NAME] | ||
else "" | ||
) + "Filter Replacement Needed" | ||
|
||
@property | ||
def name(self) -> str: | ||
"""Return the name of the sensor.""" | ||
return self._name | ||
|
||
@property | ||
def is_on(self) -> bool | None: | ||
"""Return True if filter replacement is needed.""" | ||
# Calculate if filter replacement is needed based on usage days | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is source of max days and other constants? Does device record them or what will happen when those will be passed? |
||
if hasattr(self._coordinator, '_filter_reset_date') and self._coordinator._filter_reset_date: | ||
from datetime import datetime | ||
reset_date = datetime.fromisoformat(self._coordinator._filter_reset_date) | ||
current_date = datetime.now() | ||
days_since_reset = (current_date - reset_date).days | ||
return days_since_reset >= FILTER_ALARM_MAX_DAYS | ||
else: | ||
# No reset date stored, check if we're over the default max days | ||
# Assume filter is new if no reset date | ||
return False | ||
|
||
@property | ||
def entity_category(self): | ||
"""Return the entity category for diagnostic entities.""" | ||
return EntityCategory.DIAGNOSTIC | ||
|
||
@property | ||
def device_info(self) -> DeviceInfo | None: | ||
"""Returns device information in a dictionary format.""" | ||
return { | ||
ATTR_IDENTIFIERS: { | ||
(DOMAIN, f"{self._udid}_recuperation") | ||
}, | ||
CONF_NAME: f"{self._config_entry.title} Recuperation", | ||
CONF_MODEL: ( | ||
self._config_entry.data[CONTROLLER][CONF_NAME] | ||
+ ": " | ||
+ self._config_entry.data[CONTROLLER][VER] | ||
), | ||
ATTR_MANUFACTURER: MANUFACTURER, | ||
} | ||
|
||
|
||
class RecuperationSystemStatusSensor(CoordinatorEntity, binary_sensor.BinarySensorEntity): | ||
"""Binary sensor to indicate recuperation system operational status.""" | ||
|
||
_attr_has_entity_name = True | ||
_attr_device_class = binary_sensor.BinarySensorDeviceClass.RUNNING | ||
_attr_icon = "mdi:air-filter" | ||
|
||
def __init__( | ||
self, | ||
coordinator: TechCoordinator, | ||
config_entry: ConfigEntry, | ||
) -> None: | ||
"""Initialize the system status sensor.""" | ||
super().__init__(coordinator) | ||
self._coordinator = coordinator | ||
self._config_entry = config_entry | ||
self._udid = config_entry.data[CONTROLLER][UDID] | ||
self._attr_unique_id = f"{self._udid}_recuperation_running" | ||
|
||
self._name = ( | ||
self._config_entry.title + " " | ||
if self._config_entry.data[INCLUDE_HUB_IN_NAME] | ||
else "" | ||
) + "Recuperation Running" | ||
|
||
@property | ||
def name(self) -> str: | ||
"""Return the name of the sensor.""" | ||
return self._name | ||
|
||
@property | ||
def is_on(self) -> bool | None: | ||
"""Return True if recuperation system is running.""" | ||
# Check if any flow sensors show activity | ||
if self._coordinator.data and "tiles" in self._coordinator.data: | ||
for tile_id, tile_data in self._coordinator.data["tiles"].items(): | ||
if tile_data.get("type") == TYPE_TEMPERATURE_CH: | ||
# Check flow sensors for activity | ||
widget1_data = tile_data.get("params", {}).get("widget1", {}) | ||
widget2_data = tile_data.get("params", {}).get("widget2", {}) | ||
|
||
# Check if any flow sensor shows activity (> 0) | ||
for widget_data in [widget1_data, widget2_data]: | ||
widget_txt_id = widget_data.get("txtId", 0) | ||
for flow_sensor in [RECUPERATION_EXHAUST_FLOW, RECUPERATION_SUPPLY_FLOW, RECUPERATION_SUPPLY_FLOW_ALT]: | ||
if flow_sensor["txt_id"] == widget_txt_id: | ||
flow_value = widget_data.get("value", 0) | ||
if flow_value and flow_value > 0: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we dont need to check flow_value exists as above you always make it using: |
||
return True | ||
return False | ||
|
||
@property | ||
def entity_category(self): | ||
"""Return the entity category for diagnostic entities.""" | ||
return EntityCategory.DIAGNOSTIC | ||
|
||
@property | ||
def device_info(self) -> DeviceInfo | None: | ||
"""Returns device information in a dictionary format.""" | ||
return { | ||
ATTR_IDENTIFIERS: { | ||
(DOMAIN, f"{self._udid}_recuperation") | ||
}, | ||
CONF_NAME: f"{self._config_entry.title} Recuperation", | ||
CONF_MODEL: ( | ||
self._config_entry.data[CONTROLLER][CONF_NAME] | ||
+ ": " | ||
+ self._config_entry.data[CONTROLLER][VER] | ||
), | ||
ATTR_MANUFACTURER: MANUFACTURER, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this shouldnt be added