From 51d09319eaf6e5b6bf13cd50f5c66f951e8f7e5d Mon Sep 17 00:00:00 2001 From: Anko Hanse Date: Sat, 4 Jan 2025 20:01:09 +1300 Subject: [PATCH] Show mac_address and sw_version in device info --- custom_components/dabpumps/__init__.py | 5 +- custom_components/dabpumps/binary_sensor.py | 7 +- custom_components/dabpumps/const.py | 6 ++ custom_components/dabpumps/coordinator.py | 74 +++++++++++++++++++-- custom_components/dabpumps/manifest.json | 2 +- custom_components/dabpumps/number.py | 5 -- custom_components/dabpumps/select.py | 5 -- custom_components/dabpumps/sensor.py | 5 -- custom_components/dabpumps/switch.py | 5 -- 9 files changed, 82 insertions(+), 32 deletions(-) diff --git a/custom_components/dabpumps/__init__.py b/custom_components/dabpumps/__init__.py index 749781c..6c6affa 100644 --- a/custom_components/dabpumps/__init__.py +++ b/custom_components/dabpumps/__init__.py @@ -84,7 +84,10 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b # await coordinator.async_config_entry_first_refresh() - # Forward to all platforms (sensor, switch, ...) + # Create devices + await coordinator.async_create_devices(config_entry) + + # Create entities for all platforms (sensor, switch, ...) await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) # Reload entry when it is updated diff --git a/custom_components/dabpumps/binary_sensor.py b/custom_components/dabpumps/binary_sensor.py index 8f743ea..a33b405 100644 --- a/custom_components/dabpumps/binary_sensor.py +++ b/custom_components/dabpumps/binary_sensor.py @@ -158,15 +158,10 @@ def _update_attributes(self, status, is_create): self._attr_name = self._get_string(status.key) self._name = status.key - self._attr_device_class = self._get_device_class() + self._attr_device_class = self._get_device_class() self._attr_device_info = DeviceInfo( identifiers = {(DOMAIN, self._device.serial)}, - name = self._device.name, - manufacturer = self._device.vendor, - model = self._device.product, - serial_number = self._device.serial, - hw_version = self._device.version, ) changed = True diff --git a/custom_components/dabpumps/const.py b/custom_components/dabpumps/const.py index f056de2..ef272b0 100644 --- a/custom_components/dabpumps/const.py +++ b/custom_components/dabpumps/const.py @@ -77,6 +77,12 @@ # "": "Thai" } +# Extra device attributes that are not in install info, but retrieved from statusses +DEVICE_ATTR_EXTRA = { + "mac_address": ['MacWlan'], + "sw_version": ['LvFwVersion', 'ucVersion'] +} + LANGUAGE_TEXT_AUTO ="Auto (use system setting: {0})" LANGUAGE_TEXT_FALLBACK ="Auto (use default: {0})" diff --git a/custom_components/dabpumps/coordinator.py b/custom_components/dabpumps/coordinator.py index 632a21b..fee9613 100644 --- a/custom_components/dabpumps/coordinator.py +++ b/custom_components/dabpumps/coordinator.py @@ -18,6 +18,8 @@ from homeassistant.core import HomeAssistant from homeassistant.core import async_get_hass from homeassistant.exceptions import ConfigEntryAuthFailed +from homeassistant.helpers import device_registry +from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.storage import Store from homeassistant.helpers.update_coordinator import ( @@ -59,6 +61,7 @@ COORDINATOR_RETRY_DELAY, COORDINATOR_TIMEOUT, COORDINATOR_CACHE_WRITE_PERIOD, + DEVICE_ATTR_EXTRA, SIMULATE_MULTI_INSTALL, SIMULATE_SUFFIX_ID, SIMULATE_SUFFIX_NAME, @@ -68,7 +71,7 @@ _LOGGER = logging.getLogger(__name__) DabPumpsInstall = namedtuple('DabPumpsInstall', 'id, name, description, company, address, role, devices') -DabPumpsDevice = namedtuple('DabPumpsDevice', 'id, serial, name, vendor, product, version, config_id, install_id') +DabPumpsDevice = namedtuple('DabPumpsDevice', 'id, serial, name, vendor, product, hw_version, sw_version, config_id, install_id, mac_address') DabPumpsConfig = namedtuple('DabPumpsConfig', 'id, label, description, meta_params') DabPumpsParams = namedtuple('DabPumpsParams', 'key, type, unit, weight, values, min, max, family, group, view, change, log, report') DabPumpsStatus = namedtuple('DabPumpsStatus', 'serial, unique_id, key, val') @@ -215,7 +218,34 @@ async def async_config_flow_data(self): #_LOGGER.debug(f"install_map: {self._install_map}") return (self._install_map) - + + async def async_create_devices(self, config_entry: ConfigEntry): + """ + Add all detected devices to the hass device_registry + """ + + install_id = config_entry.data[CONF_INSTALL_ID] + install_name = config_entry.data[CONF_INSTALL_NAME] + + _LOGGER.info(f"Create devices for installation '{install_name}' ({install_id})") + dr = device_registry.async_get(self.hass) + + for device in self._device_map.values(): + _LOGGER.debug(f"Create device {device.serial} ({DabPumpsCoordinator.create_id(device.name)})") + + dr.async_get_or_create( + config_entry_id = config_entry.entry_id, + identifiers = {(DOMAIN, device.serial)}, + connections = {(CONNECTION_NETWORK_MAC, device.mac_address)} if device.mac_address else None, + name = device.name, + manufacturer = device.vendor, + model = device.product, + serial_number = device.serial, + hw_version = device.hw_version, + sw_version = device.sw_version, + ) + + async def _async_update_data(self): """ Fetch sensor data from API. @@ -348,6 +378,9 @@ async def _async_detect_data(self): # Attempt to refresh the list of installations (once a day, just for diagnostocs) await self._async_detect_installations(ignore_exception=True) + # Update device parameters that are derived from statusses instead of install_details + self._update_devices() + # Keep track of how many retries were needed and duration self._update_statistics(retries = retry, duration = datetime.now()-ts_start) return True @@ -683,7 +716,7 @@ async def _async_process_install_data(self, data): dum_serial = dum.get('serial', None) or '' dum_name = dum.get('name', None) or dum.get('ProductName', None) or f"device {dum_idx}" dum_product = dum.get('ProductName', None) or f"device {dum_idx}" - dum_version = dum.get('configuration_name', None) or '' + dum_hw_version = dum.get('configuration_name', None) or '' dum_config = dum.get('configuration_id', None) or '' if not dum_serial: @@ -701,9 +734,12 @@ async def _async_process_install_data(self, data): id = device_id, serial = device_serial, product = dum_product, - version = dum_version, + hw_version = dum_hw_version, config_id = dum_config, install_id = install_id, + # Not retrieved from install details, but added later from statusses + mac_address = None, + sw_version = None, ) device_map[device_serial] = device @@ -882,6 +918,36 @@ async def _async_fetch_from_cache(self, context): return self._cache.get(context, {}) else: return {} + + + def _update_devices(self): + """ + Update device_map with extra attributes derived from statusses + """ + + for device_serial in list(self._device_map.keys()): + + device = self._device_map[device_serial] + device_dict = device._asdict() + device_changed = False + + # Search for specific statusses + for attr,status_keys in DEVICE_ATTR_EXTRA.items(): + for status_key in status_keys: + + # Try to find a status for this key and device + entity_id = DabPumpsCoordinator.create_id(device_serial, status_key) + status = self._status_map.get(entity_id, None) + + if status is not None and status.val is not None: + # Found it. Update the device attribute (workaround via dict because it is a namedtuple) + if getattr(device, attr) != status.val: + _LOGGER.debug(f"Found extra device attribute {device.serial} {attr} = {status.val}") + device_dict[attr] = status.val + device_changed = True + + if device_changed: + self._device_map[device_serial] = DabPumpsDevice(**device_dict) async def async_get_diagnostics(self) -> dict[str, Any]: diff --git a/custom_components/dabpumps/manifest.json b/custom_components/dabpumps/manifest.json index 5118cf6..b44b672 100644 --- a/custom_components/dabpumps/manifest.json +++ b/custom_components/dabpumps/manifest.json @@ -10,5 +10,5 @@ "issue_tracker": "https://github.com/ankohanse/hass-dab-pumps/issues", "loggers": ["custom_components.dabpumps"], "requirements": [], - "version": "2025.01.1" + "version": "2025.01.2" } \ No newline at end of file diff --git a/custom_components/dabpumps/number.py b/custom_components/dabpumps/number.py index 017340e..088d571 100644 --- a/custom_components/dabpumps/number.py +++ b/custom_components/dabpumps/number.py @@ -156,11 +156,6 @@ def _update_attributes(self, status, is_create): self._attr_device_info = DeviceInfo( identifiers = {(DOMAIN, self._device.serial)}, - name = self._device.name, - manufacturer = self._device.vendor, - model = self._device.product, - serial_number = self._device.serial, - hw_version = self._device.version, ) changed = True diff --git a/custom_components/dabpumps/select.py b/custom_components/dabpumps/select.py index d76c508..b1c2eb4 100644 --- a/custom_components/dabpumps/select.py +++ b/custom_components/dabpumps/select.py @@ -141,11 +141,6 @@ def _update_attributes(self, status, is_create): self._attr_device_class = None self._attr_device_info = DeviceInfo( identifiers = {(DOMAIN, self._device.serial)}, - name = self._device.name, - manufacturer = self._device.vendor, - model = self._device.product, - serial_number = self._device.serial, - hw_version = self._device.version, ) changed = True diff --git a/custom_components/dabpumps/sensor.py b/custom_components/dabpumps/sensor.py index a8739ec..c516061 100644 --- a/custom_components/dabpumps/sensor.py +++ b/custom_components/dabpumps/sensor.py @@ -165,11 +165,6 @@ def _update_attributes(self, status, is_create): self._attr_device_class = self.get_sensor_device_class() self._attr_device_info = DeviceInfo( identifiers = {(DOMAIN, self._device.serial)}, - name = self._device.name, - manufacturer = self._device.vendor, - model = self._device.product, - serial_number = self._device.serial, - hw_version = self._device.version, ) changed = True diff --git a/custom_components/dabpumps/switch.py b/custom_components/dabpumps/switch.py index 13a93e7..1efcc09 100644 --- a/custom_components/dabpumps/switch.py +++ b/custom_components/dabpumps/switch.py @@ -156,11 +156,6 @@ def _update_attributes(self, status, is_create): self._attr_device_info = DeviceInfo( identifiers = {(DOMAIN, self._device.serial)}, - name = self._device.name, - manufacturer = self._device.vendor, - model = self._device.product, - serial_number = self._device.serial, - hw_version = self._device.version, ) changed = True