-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from sangvikh/dev
v2.0.0
- Loading branch information
Showing
12 changed files
with
553 additions
and
128 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,41 @@ | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.config_entries import ConfigEntry | ||
from .services import register_services | ||
|
||
from .services import register_services | ||
from .device import register_device | ||
from .const import DOMAIN | ||
|
||
platforms = ['sensor', 'button', 'valve', 'select'] | ||
|
||
async def async_setup(hass: HomeAssistant, config: dict): | ||
return True | ||
|
||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): | ||
hass.data.setdefault(DOMAIN, {}) | ||
hass.data[DOMAIN][entry.entry_id] = entry.data | ||
|
||
# Register sensors | ||
hass.async_create_task( | ||
hass.config_entries.async_forward_entry_setup(entry, 'sensor') | ||
) | ||
# Register the device | ||
await register_device(hass, entry) | ||
|
||
# Register services | ||
await register_services(hass) | ||
|
||
# Register entities for each platform | ||
hass.async_create_task( | ||
hass.config_entries.async_forward_entry_setups(entry, platforms) | ||
) | ||
|
||
return True | ||
|
||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): | ||
await hass.config_entries.async_forward_entry_unload(entry, 'sensor') | ||
hass.data[DOMAIN].pop(entry.entry_id) | ||
return True | ||
# Unload each platform | ||
unload_ok = all( | ||
await hass.config_entries.async_forward_entry_unload(entry, platform) | ||
for platform in platforms | ||
) | ||
|
||
# Remove data related to this entry if everything is unloaded successfully | ||
if unload_ok: | ||
hass.data[DOMAIN].pop(entry.entry_id) | ||
|
||
return unload_ok |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# custom_components/hass_pontos/button.py | ||
import logging | ||
from homeassistant.components.button import ButtonEntity | ||
from homeassistant.util import slugify | ||
from .const import DOMAIN | ||
from .device import get_device_info | ||
|
||
LOGGER = logging.getLogger(__name__) | ||
|
||
async def async_setup_entry(hass, entry, async_add_entities): | ||
# Fetch device info | ||
device_info, _ = await get_device_info(hass, entry) | ||
|
||
# Instantiate button | ||
reset_button = PontosClearAlarmsButton(hass, entry, device_info) | ||
|
||
# Add entities | ||
async_add_entities([reset_button], True) | ||
|
||
class PontosClearAlarmsButton(ButtonEntity): | ||
"""Button to clear alarms on the Pontos Base device.""" | ||
|
||
def __init__(self, hass, entry, device_info): | ||
"""Initialize the button.""" | ||
self._hass = hass | ||
self._entry = entry | ||
self._attr_name = f"{device_info['name']} Clear alarms" | ||
self._attr_unique_id = slugify(f"{device_info['serial_number']}_clear_alarms") | ||
self._device_info = device_info | ||
|
||
async def async_press(self): | ||
"""Handle the button press to clear alarms.""" | ||
LOGGER.info("Clear Alarms button pressed") | ||
await self._hass.services.async_call( | ||
DOMAIN, | ||
"clear_alarms", # Assuming the service name for clearing alarms is "clear_alarms" | ||
service_data={"entry_id": self._entry.entry_id} | ||
) | ||
|
||
@property | ||
def unique_id(self): | ||
return self._attr_unique_id | ||
|
||
@property | ||
def device_info(self): | ||
return { | ||
"identifiers": self._device_info['identifiers'], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import logging | ||
import time | ||
from homeassistant.helpers.device_registry import async_get as async_get_device_registry | ||
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC | ||
|
||
from .const import DOMAIN, URL_LIST, CONF_IP_ADDRESS, FETCH_INTERVAL | ||
from .utils import fetch_data | ||
|
||
LOGGER = logging.getLogger(__name__) | ||
|
||
# Cache to store device data | ||
_device_cache = {} | ||
|
||
async def get_device_info(hass, entry): | ||
entry_id = entry.entry_id | ||
ip_address = entry.data[CONF_IP_ADDRESS] | ||
|
||
# Check if the data is already cached and not expired | ||
if entry_id in _device_cache: | ||
cache_entry = _device_cache[entry_id] | ||
cache_age = time.time() - cache_entry['timestamp'] | ||
if cache_age < FETCH_INTERVAL.total_seconds(): | ||
LOGGER.debug(f"Using cached data for device {entry_id} (age: {cache_age} seconds)") | ||
return cache_entry['device_info'], cache_entry['data'] | ||
else: | ||
LOGGER.debug(f"Cache expired for device {entry_id} (age: {cache_age} seconds)") | ||
|
||
LOGGER.debug(f"Fetching data for device {entry_id} from the device") | ||
|
||
# Fetching all relevant data from the device | ||
data = await fetch_data(ip_address, URL_LIST) | ||
|
||
# Assign data to variables | ||
mac_address = data.get("getMAC", "00:00:00:00:00:00:00:00") | ||
serial_number = data.get("getSRN", "") | ||
firmware_version = data.get("getVER", "") | ||
device_type = data.get("getTYP", "") | ||
|
||
device_info = { | ||
"identifiers": {(DOMAIN, "pontos_base")}, | ||
"connections": {(CONNECTION_NETWORK_MAC, mac_address)}, | ||
"name": "Pontos Base", | ||
"manufacturer": "Hansgrohe", | ||
"model": device_type, | ||
"sw_version": firmware_version, | ||
"serial_number": serial_number, | ||
} | ||
|
||
# Cache the device info and data | ||
_device_cache[entry_id] = { | ||
'device_info': device_info, | ||
'data': data, | ||
'timestamp': time.time() | ||
} | ||
|
||
return device_info, data | ||
|
||
async def register_device(hass, entry): | ||
entry_id = entry.entry_id | ||
|
||
# Create a device entry with fetched data | ||
device_registry = async_get_device_registry(hass) | ||
device_info, _ = await get_device_info(hass, entry) | ||
|
||
# Register device in the device registry | ||
device_registry.async_get_or_create( | ||
config_entry_id=entry_id, | ||
**device_info | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,14 @@ | ||
{ | ||
"domain": "hass_pontos", | ||
"name": "Hansgrohe Pontos", | ||
"domain": "hass_pontos", | ||
"name": "Hansgrohe Pontos", | ||
"codeowners": [ | ||
"@sangvikh" | ||
], | ||
"config_flow": true, | ||
"dependencies": [], | ||
"documentation": "https://github.com/sangvikh/hass-pontos", | ||
"iot_class": "local_polling", | ||
"issue_tracker": "https://github.com/sangvikh/hass-pontos/issues", | ||
"issue_tracker": "https://github.com/sangvikh/hass-pontos/issues", | ||
"requirements": [], | ||
"version": "1.0.4" | ||
} | ||
"version": "2.0.0" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import logging | ||
from homeassistant.components.select import SelectEntity | ||
from homeassistant.helpers import entity_registry as er | ||
from homeassistant.helpers.event import async_track_state_change_event | ||
from homeassistant.core import callback, Event | ||
from .device import get_device_info | ||
from .const import DOMAIN, PROFILE_CODES | ||
|
||
LOGGER = logging.getLogger(__name__) | ||
|
||
async def async_setup_entry(hass, entry, async_add_entities): | ||
"""Set up the custom profile select entity.""" | ||
device_info, data = await get_device_info(hass, entry) | ||
select_entity = PontosProfileSelect(hass, entry, device_info) | ||
async_add_entities([select_entity], True) | ||
|
||
class PontosProfileSelect(SelectEntity): | ||
"""Representation of a Select entity for setting profiles.""" | ||
|
||
def __init__(self, hass, entry, device_info): | ||
"""Initialize the profile select entity.""" | ||
self._hass = hass | ||
self._entry = entry | ||
self._attr_name = f"{device_info['name']} Profile" | ||
self._attr_unique_id = f"{device_info['serial_number']}_profile_select" | ||
self._sensor_unique_id = f"{device_info['serial_number']}_active_profile" | ||
self._attr_options = [ | ||
name if name else "Not Defined" | ||
for name in PROFILE_CODES.values() | ||
if name and name != "not defined" | ||
] | ||
self._attr_current_option = None | ||
self._device_info = device_info | ||
|
||
async def async_added_to_hass(self): | ||
"""When entity is added to hass.""" | ||
await super().async_added_to_hass() | ||
|
||
# Get the entity ID of the sensor using the unique ID | ||
entity_registry = er.async_get(self.hass) | ||
sensor_entity_id = entity_registry.async_get_entity_id("sensor", DOMAIN, self._sensor_unique_id) | ||
|
||
# Fetch the initial state from the sensor entity | ||
if sensor_entity_id: | ||
sensor_state = self.hass.states.get(sensor_entity_id) | ||
initial_state = sensor_state.state if sensor_state else None | ||
LOGGER.debug(f"Fetched initial profile state from sensor: {initial_state}") | ||
self._attr_current_option = initial_state | ||
self.async_write_ha_state() | ||
|
||
# Register state change listener | ||
LOGGER.debug(f"Registering state change listener for {sensor_entity_id}") | ||
async_track_state_change_event( | ||
self.hass, | ||
sensor_entity_id, | ||
self._sensor_state_changed | ||
) | ||
else: | ||
LOGGER.error(f"Sensor with unique ID {self._sensor_unique_id} not found") | ||
|
||
@callback | ||
def _sensor_state_changed(self, event: Event) -> None: | ||
"""Handle active profile sensor state changes.""" | ||
new_state = event.data.get('new_state') | ||
if new_state is not None: | ||
new_option = new_state.state | ||
if new_option != self._attr_current_option: | ||
LOGGER.debug(f"Profile state changed to: {new_option}") | ||
self.set_state(new_option) | ||
|
||
def set_state(self, state): | ||
"""Set the valve state and update Home Assistant.""" | ||
self._attr_current_option = state | ||
self.async_write_ha_state() | ||
|
||
async def async_select_option(self, option: str): | ||
"""Handle the user selecting an option.""" | ||
LOGGER.info(f"Setting profile to {option}") | ||
profile_number = self.map_profile_name_to_number(option) | ||
await self._hass.services.async_call( | ||
DOMAIN, | ||
"set_profile", | ||
service_data={"profile_number": profile_number, "ip_address": self._entry.data["ip_address"]} | ||
) | ||
self._attr_current_option = option | ||
self.async_write_ha_state() | ||
|
||
@property | ||
def device_info(self): | ||
"""Return device info to link this entity with the device.""" | ||
return { | ||
"identifiers": self._device_info['identifiers'], | ||
} | ||
|
||
def map_profile_name_to_number(self, profile_name): | ||
"""Map profile name to profile number.""" | ||
for number, name in PROFILE_CODES.items(): | ||
if name == profile_name: | ||
return int(number) | ||
return None |
Oops, something went wrong.