Skip to content

Commit

Permalink
fix: more dupe serial number fixes (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
firstof9 authored Jan 10, 2025
1 parent 34aa32d commit 07dffe5
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 28 deletions.
19 changes: 7 additions & 12 deletions custom_components/renogy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,16 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
if "serial" in device.keys() and device["serial"] != "":
serial = device["serial"]
else:
serial = device_id
serial = None

device_check = device_registry.async_get_device(identifiers=(DOMAIN, serial))
if device_check is not None:
# Device already exists or duplicate serial number
# swap to device_id instead
serial = device_id
via = (DOMAIN, hub) if device_id != hub and hub else None

via = (DOMAIN, hub) if serial != hub and hub else None
_LOGGER.debug("Using device: %s via %s", device_id, via)

device_registry.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(dr.CONNECTION_NETWORK_MAC, device["mac"])},
identifiers={(DOMAIN, serial)},
identifiers={(DOMAIN, device_id)},
serial_number=serial,
name=device["name"],
manufacturer="Renogy",
Expand All @@ -106,10 +102,9 @@ async def async_find_hub(coordinator) -> bool:
) in coordinator.data.items():
_LOGGER.debug("Looking for hub device...")
if device["connection"] == "Hub":
if "serial" in device.keys() and device["serial"] != "":
hub = device["serial"]
else:
hub = device_id
hub = device_id
_LOGGER.debug("Hub found: %s", hub)
break

return hub

Expand Down
8 changes: 2 additions & 6 deletions custom_components/renogy/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@ async def async_setup_entry(hass, entry, async_add_devices):
for (
binary_sensor
) in BINARY_SENSORS: # pylint: disable=consider-using-dict-items
unique_id = device["serial"] or device_id
temp_obj = RenogyBinarySensor(
BINARY_SENSORS[binary_sensor],
unique_id,
device_id,
coordinator,
entry,
Expand All @@ -53,7 +51,6 @@ class RenogyBinarySensor(CoordinatorEntity, BinarySensorEntity):
def __init__(
self,
sensor_description: BinarySensorEntityDescription,
unique_id: str,
device_id: str,
coordinator: DataUpdateCoordinator,
config: ConfigEntry,
Expand All @@ -65,17 +62,16 @@ def __init__(
self.entity_description = sensor_description
self._name = sensor_description.name
self._type = sensor_description.key
self._unique_id = unique_id
self._device_id = device_id

self._attr_name = f"{coordinator.data[device_id]["name"]} {self._name}"
self._attr_unique_id = f"{self._name}_{self._unique_id}"
self._attr_unique_id = f"{self._name}_{device_id}"

@property
def device_info(self) -> dict:
"""Return a port description for device registry."""
info = {
"identifiers": {(DOMAIN, self._unique_id)},
"identifiers": {(DOMAIN, self._device_id)},
}

return info
Expand Down
14 changes: 4 additions & 10 deletions custom_components/renogy/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,22 @@
2: "Eco",
}


async def async_setup_entry(hass, entry, async_add_entities):
"""Set up the OpenEVSE sensors."""
coordinator = hass.data[DOMAIN][entry.entry_id][COORDINATOR]

sensors = []
for device_id, device in coordinator.data.items():
for sensor in SENSOR_TYPES: # pylint: disable=consider-using-dict-items
if sensor in device.keys(): # pylint: disable=consider-using-dict-items
unique_id = device["serial"] or device_id
sensors.append(
RenogySensor(
SENSOR_TYPES[sensor], unique_id, device_id, coordinator, entry
SENSOR_TYPES[sensor], device_id, coordinator, entry
)
)
if sensor in device["data"].keys():
unique_id = device["serial"] or device_id
sensors.append(
RenogySensor(
SENSOR_TYPES[sensor], unique_id, device_id, coordinator, entry
SENSOR_TYPES[sensor], device_id, coordinator, entry
)
)

Expand All @@ -54,7 +50,6 @@ class RenogySensor(CoordinatorEntity, SensorEntity):
def __init__(
self,
sensor_description: SensorEntityDescription,
unique_id: str,
device_id: str,
coordinator: str,
config: ConfigEntry,
Expand All @@ -66,20 +61,19 @@ def __init__(
self.entity_description = sensor_description
self._name = sensor_description.name
self._type = sensor_description.key
self._unique_id = unique_id
self._data = coordinator.data
self.coordinator = coordinator
self._state = None

self._attr_icon = sensor_description.icon
self._attr_name = f"{coordinator.data[device_id]["name"]} {self._name}"
self._attr_unique_id = f"{self._name}_{self._unique_id}"
self._attr_unique_id = f"{self._name}_{device_id}"

@property
def device_info(self) -> dict:
"""Return a port description for device registry."""
info = {
"identifiers": {(DOMAIN, self._unique_id)},
"identifiers": {(DOMAIN, self._device_id)},
}
return info

Expand Down
10 changes: 10 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from aioresponses import aioresponses

from .common import load_fixture
from .const import DUPE_SERIAL

BASE_URL = "https://openapi.renogy.com"
DEVICE_LIST = "/device/list"
Expand Down Expand Up @@ -107,3 +108,12 @@ def mock_api_no_devices(mock_aioclient):
body=load_fixture("realtime_data.json"),
repeat=True,
)

@pytest.fixture(name="mock_coordinator")
def mock_coord():
"""Mock charger data."""
with patch(
"custom_components.renogy.RenogyUpdateCoordinator._async_update_data"
) as mock_value:
mock_value.return_value = DUPE_SERIAL
yield
81 changes: 81 additions & 0 deletions tests/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,84 @@
"status": "online",
},
}

DUPE_SERIAL = {
"230314043002434307": {
"deviceId": "230314043002434307",
"name": "Renogy ONE M1",
"mac": "",
"firmware": "V1.3.99",
"status": "online",
"connection": "Hub",
"serial": "23RMG3523812001099",
"model": "RMS-LP4-G2",
"data": {}
},
"250101091000725004": {
"deviceId": "250101091000725004",
"name": "Temp & RH Sensor",
"mac": "",
"firmware": "",
"status": "online",
"connection": "Zigbee",
"serial": "00124B0024CCDB0F",
"model": "TH01",
"data": {
"temperature": "10.8",
"humidity": "58",
"lowbattery": "57"
}
},
"230703112949819001": {
"deviceId": "230703112949819001",
"name": "RBT100LFP12S-G1",
"mac": "31",
"firmware": "",
"status": "online",
"connection": "Bluetooth",
"serial": "BT-TH-66EDEF65",
"model": "RBT100LFP12S-G1",
"data": {
"communicationMethod": None,
"presentCapacity": None,
"error": None,
"remainingTime": None,
"heatingModeStatus": None,
"temperature": "4.0",
"presentVolts": "13.50",
"cellVolts": None,
"maximumCapacity": "100.00",
"totalMaximumCapacity": "100.00",
"firmwareVersion": "0022",
"sku": None,
"batteryLevel": "99.66",
"presentAmps": "0.00"
}
},
"220327070523454002": {
"deviceId": "220327070523454002",
"name": "RBT100LFP12S-G1",
"mac": "30",
"firmware": "",
"status": "online",
"connection": "Bluetooth",
"serial": "BT-TH-66EDEF65",
"model": "RBT100LFP12S-G1",
"data": {
"communicationMethod": None,
"presentCapacity": None,
"error": None,
"remainingTime": None,
"heatingModeStatus": None,
"temperature": "4.0",
"presentVolts": "13.50",
"cellVolts": None,
"maximumCapacity": "100.00",
"totalMaximumCapacity": "100.00",
"firmwareVersion": "0026",
"sku": None,
"batteryLevel": "99.59",
"presentAmps": "0.00"
}
},
}
18 changes: 18 additions & 0 deletions tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,21 @@ async def test_setup_and_unload_entry(hass, mock_api, caplog):
await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(BINARY_SENSOR_DOMAIN)) == 0
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 0

async def test_duplicate_serials(hass, mock_api, mock_coordinator, device_registry: dr.DeviceRegistry, caplog):
"""Test setup_entry."""
entry = MockConfigEntry(
domain=DOMAIN,
title=DEVICE_NAME,
data=CONFIG_DATA,
)

with caplog.at_level(logging.DEBUG):
entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()

assert len(hass.states.async_entity_ids(BINARY_SENSOR_DOMAIN)) == 6
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 19
entries = hass.config_entries.async_entries(DOMAIN)
assert len(entries) == 1

0 comments on commit 07dffe5

Please sign in to comment.