diff --git a/custom_components/battery_notes/config_flow.py b/custom_components/battery_notes/config_flow.py index 81b4448b..41ad636e 100644 --- a/custom_components/battery_notes/config_flow.py +++ b/custom_components/battery_notes/config_flow.py @@ -23,7 +23,7 @@ CONF_DEVICE_ID, ) -from .library import Library +from .library import Library, ModelInfo from .library_updater import LibraryUpdater from .const import ( @@ -134,21 +134,23 @@ async def async_step_user( device_entry = device_registry.async_get(device_id) _LOGGER.debug( - "Looking up device %s %s", device_entry.manufacturer, device_entry.model + "Looking up device %s %s %s", device_entry.manufacturer, device_entry.model, device_entry.hw_version ) + model_info = ModelInfo(device_entry.manufacturer, device_entry.model, device_entry.hw_version) + library = Library.factory(self.hass) # Set defaults if not found in library self.data[CONF_BATTERY_QUANTITY] = 1 device_battery_details = await library.get_device_battery_details( - device_entry.manufacturer, device_entry.model + model_info ) if device_battery_details and not device_battery_details.is_manual: _LOGGER.debug( - "Found device %s %s", device_entry.manufacturer, device_entry.model + "Found device %s %s %s", device_entry.manufacturer, device_entry.model, device_entry.hw_version ) self.data[CONF_BATTERY_TYPE] = device_battery_details.battery_type diff --git a/custom_components/battery_notes/discovery.py b/custom_components/battery_notes/discovery.py index 5e0bca7f..92d6efa2 100644 --- a/custom_components/battery_notes/discovery.py +++ b/custom_components/battery_notes/discovery.py @@ -55,11 +55,12 @@ async def get_model_information( manufacturer = device_entry.manufacturer model = device_entry.model + hw_version = device_entry.hw_version if not manufacturer or not model: return None - return ModelInfo(manufacturer, model) + return ModelInfo(manufacturer, model, hw_version) class DiscoveryManager: @@ -98,7 +99,7 @@ async def start_discovery(self) -> None: continue device_battery_details = await library.get_device_battery_details( - model_info.manufacturer, model_info.model + model_info ) if not device_battery_details: diff --git a/custom_components/battery_notes/library.py b/custom_components/battery_notes/library.py index 99c7c541..d1b73ad7 100644 --- a/custom_components/battery_notes/library.py +++ b/custom_components/battery_notes/library.py @@ -88,26 +88,68 @@ def factory(hass: HomeAssistant) -> Library: async def get_device_battery_details( self, - manufacturer: str, - model: str, + model_info: ModelInfo, ) -> DeviceBatteryDetails | None: """Create a battery details object from the JSON devices data.""" if self._devices is not None: - for device in self._devices: - if ( - str(device["manufacturer"] or "").casefold() - == str(manufacturer or "").casefold() - and str(device["model"] or "").casefold() - == str(model or "").casefold() - ): - device_battery_details = DeviceBatteryDetails( - manufacturer=device["manufacturer"], - model=device["model"], - battery_type=device["battery_type"], - battery_quantity=device.get("battery_quantity", 1), - ) - return device_battery_details + + # If a hw_version is present try find that first + if model_info.hw_version: + matching_devices = [] + + # Find all devices that match the manufacturer and model + for device in self._devices: + if ( + str(device["manufacturer"] or "").casefold() + == str(model_info.manufacturer or "").casefold() + and str(device["model"] or "").casefold() + == str(model_info.model or "").casefold() + ): + matching_devices.append(device) + + # Check if any matching devices have specified hw_version + for device in matching_devices: + if device.get("hw_version", "").casefold() == str(model_info.hw_version or "").casefold(): + matched_device = device + device_battery_details = DeviceBatteryDetails( + manufacturer=matched_device["manufacturer"], + model=matched_device["model"], + hw_version=matched_device["hw_version"], + battery_type=matched_device["battery_type"], + battery_quantity=matched_device.get("battery_quantity", 1), + ) + break + else: + # Return first item in list, the non hw_version one + matched_device = matching_devices[0] + + device_battery_details = DeviceBatteryDetails( + manufacturer=matched_device["manufacturer"], + model=matched_device["model"], + hw_version=matched_device.get("hw_version", None), + battery_type=matched_device["battery_type"], + battery_quantity=matched_device.get("battery_quantity", 1), + ) + return device_battery_details + + else: + # For devices that don't have hw_version + for device in self._devices: + if ( + str(device["manufacturer"] or "").casefold() + == str(model_info.manufacturer or "").casefold() + and str(device["model"] or "").casefold() + == str(model_info.model or "").casefold() + ): + device_battery_details = DeviceBatteryDetails( + manufacturer=device["manufacturer"], + model=device["model"], + hw_version=device.get("hw_version", None), + battery_type=device["battery_type"], + battery_quantity=device.get("battery_quantity", 1), + ) + return device_battery_details return None @@ -121,6 +163,7 @@ class DeviceBatteryDetails(NamedTuple): manufacturer: str model: str + hw_version: str battery_type: str battery_quantity: int @@ -152,3 +195,4 @@ class ModelInfo(NamedTuple): manufacturer: str model: str + hw_version: str diff --git a/docs/library.md b/docs/library.md index a91a0d26..477d1260 100644 --- a/docs/library.md +++ b/docs/library.md @@ -31,8 +31,9 @@ For the example image below, your JSON entry will look like this: { "manufacturer": "Philips", "model": "Hue motion sensor (9290012607)", + "hw_version": "Some specific hardware detail", < Optional, only use if two devices have the same model and the hw_version are different. "battery_type": "AAA", - "battery_quantity": 2 + "battery_quantity": 2 < Only use if more than 1 battery }, ``` diff --git a/library.md b/library.md index 2a4d4677..293059c2 100644 --- a/library.md +++ b/library.md @@ -604,6 +604,8 @@ Request new devices to be added to the library [here](https://github.com/andrew- |Somfy |Somfy Smoke Detector |2× AA | |SOMFY |Sonesse 28 WF Li-Ion Roller |Rechargeable | |SOMFY |Sonesse 28 WF Li-Ion Roller |MANUAL | +|SOMFY |Sonesse 28 WF Li-Ion Roller |Rechargeable | +|SOMFY |Sonesse 28 WF Li-Ion Roller |MANUAL | |Sonoff |Contact sensor (SNZB-04) |CR2032 | |SONOFF |DW2-Wi-Fi |2× AAA | |SONOFF |DW2-WI-FI-L |2× AAA |