From 2d05d3b7a5144bb59dc58e976bca7b3ab6650112 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Thu, 17 Nov 2022 18:37:35 +0100 Subject: [PATCH 1/2] Diagnostic entities for Record --- custom_components/energy_id/energy_id/api.py | 8 +- .../energy_id/energy_id/record.py | 148 +++++++++++++++++- .../energy_id/meter_reading_sensor.py | 6 +- .../energy_id/record_diagnostic_entity.py | 50 ++++++ custom_components/energy_id/sensor.py | 134 ++++++++++++++-- 5 files changed, 321 insertions(+), 25 deletions(-) create mode 100644 custom_components/energy_id/record_diagnostic_entity.py diff --git a/custom_components/energy_id/energy_id/api.py b/custom_components/energy_id/energy_id/api.py index 97defd2..7f3648e 100644 --- a/custom_components/energy_id/energy_id/api.py +++ b/custom_components/energy_id/energy_id/api.py @@ -16,7 +16,7 @@ def __init__(self, host: str, api_key: str): self._host = host self._api_key = api_key - def get_record(self, record: str, expand: list = None): + def get_record(self, record: str, expand: list = None) -> EnergyIDRecord: params = None if expand is not None: params = { @@ -29,11 +29,7 @@ def get_record(self, record: str, expand: list = None): params=params ) - return EnergyIDRecord( - response['id'], - response['recordNumber'], - response['displayName'] - ) + return EnergyIDRecord.from_json(response) def get_record_meters(self, record: str, expand: list = None): params = None diff --git a/custom_components/energy_id/energy_id/record.py b/custom_components/energy_id/energy_id/record.py index 697b37f..999063a 100644 --- a/custom_components/energy_id/energy_id/record.py +++ b/custom_components/energy_id/energy_id/record.py @@ -1,10 +1,146 @@ +from homeassistant.helpers.entity import DeviceInfo +from ..const import DOMAIN + +import datetime + + +class EnergyIDAddress: + def __init__( + self, + street: str = None, + postal_code: str = None, + city: str = None, + country: str = None, + ): + self.street = street + self.postal_code = postal_code + self.city = city + self.country = country + + class EnergyIDRecord: def __init__( self, - id: str, - number: str, - name: str, + created: datetime, + display_name: str, + record_id: str, + owner_id: str, + record_number: str, + record_type: str, + time_zone: str, + last_submission: datetime = None, + address: EnergyIDAddress = None, + category: str = None, + tags: list = None, + dwelling_type: str = None, + principal_residence: bool = None, + occupants: int = None, + occupier_type: str = None, + heating_on: str = None, + auxiliary_heating_on: str = None, + cooking_on: str = None, + hot_water_on: str = None, + floor_surface: float = None, + year_of_construction: int = None, + year_of_renovation: int = None, + energy_performance: float = None, + energy_rating: float = None, + energy_efficiency: str = None, + installations: list = None, + plan: str = None, + errors: int = None, + benchmarking_enabled: bool = None, + premium_features: list = None, ): - self.id = id - self.number = number - self.name = name + self.created = created + self.display_name = display_name + self.record_id = record_id + self.owner_id = owner_id + self.record_number = record_number + self.record_type = record_type + self.time_zone = time_zone + self.last_submission = last_submission + self.address = address + self.category = category + self.tags = tags + self.dwelling_type = dwelling_type + self.principal_residence = principal_residence + self.occupants = occupants + self.occupier_type = occupier_type + self.heating_on = heating_on + self.auxiliary_heating_on = auxiliary_heating_on + self.cooking_on = cooking_on + self.hot_water_on = hot_water_on + self.floor_surface = floor_surface + self.year_of_construction = year_of_construction + self.year_of_renovation = year_of_renovation + self.energy_performance = energy_performance + self.energy_rating = energy_rating + self.energy_efficiency = energy_efficiency + self.installations = installations + self.plan = plan + self.errors = errors + self.benchmarking_enabled = benchmarking_enabled + self.premium_features = premium_features + + @classmethod + def from_json(cls, json): + address = None + if 'address' in json: + address = EnergyIDAddress( + json['address']['streetAddress'], + json['address']['postalCode'], + json['address']['city'], + json['address']['country'] + ) + + created = None + if 'created' in json and json['created']: + created = datetime.datetime.strptime(json['created'], '%Y-%m-%dT%H:%M:%S.%fZ') + + last_submission = None + if 'lastSubmission' in json and json['lastSubmission'] is not None: + last_submission = datetime.datetime.strptime(json['lastSubmission'], '%Y-%m-%dT%H:%M:%SZ') + + return cls( + created=created, + display_name=json['displayName'], + record_id=json['id'], + owner_id=json['ownerId'], + record_number=json['recordNumber'], + record_type=json['recordType'], + time_zone=json['timeZone'], + last_submission=last_submission, + address=address, + category=json['category'] if 'category' in json else None, + tags=json['tags'] if 'tags' in json else None, + dwelling_type=json['dwellingType'] if 'dwellingType' in json else None, + principal_residence=json['principalResidence'] if 'principalResidence' in json else None, + occupants=json['occupants'] if 'occupants' in json else None, + occupier_type=json['occupierType'] if 'occupierType' in json else None, + heating_on=json['heatingOn'] if 'heatingOn' in json else None, + auxiliary_heating_on=json['auxiliaryHeatingOn'] if 'auxiliaryHeatingOn' in json else None, + cooking_on=json['cookingOn'] if 'cookingOn' in json else None, + hot_water_on=json['hotWaterOn'] if 'hotWaterOn' in json else None, + floor_surface=json['floorSurface'] if 'floorSurface' in json else None, + year_of_construction=json['yearOfConstruction'] if 'yearOfConstruction' in json else None, + year_of_renovation=json['yearOfRenovation'] if 'yearOfRenovation' in json else None, + energy_performance=json['energyPerformance'] if 'energyPerformance' in json else None, + energy_rating=json['energyRating'] if 'energyRating' in json else None, + energy_efficiency=json['energyEfficiency'] if 'energyEfficiency' in json else None, + installations=json['installations'] if 'installations' in json else None, + plan=json['plan'] if 'plan' in json else None, + errors=json['errors'] if 'errors' in json else None, + benchmarking_enabled=json['benchmarkingEnabled'] if 'benchmarkingEnabled' in json else None, + premium_features=json['premiumFeatures'] if 'premiumFeatures' in json else None, + ) + + @property + def device_info(self) -> DeviceInfo: + return DeviceInfo( + configuration_url=f'https://app.energyid.eu/record/{self.record_number}/facility', + identifiers={(DOMAIN, f'record-{self.record_id}')}, + name=self.display_name, + manufacturer="EnergyID", + model="Record", + ) diff --git a/custom_components/energy_id/meter_reading_sensor.py b/custom_components/energy_id/meter_reading_sensor.py index 0689bdc..5d9fc8e 100644 --- a/custom_components/energy_id/meter_reading_sensor.py +++ b/custom_components/energy_id/meter_reading_sensor.py @@ -35,7 +35,7 @@ def __init__( @property def name(self): - return f'{self._record.name}: {self._meter.name} - {self._attribute} reading' + return f'{self._record.display_name}: {self._meter.name} - {self._attribute} reading' @property def device_class(self) -> str: @@ -100,11 +100,11 @@ def device_class(self) -> str: @property def device_info(self) -> DeviceInfo: return DeviceInfo( - configuration_url=f'https://app.energyid.eu/record/{self._record.number}/meters/{self._meter.id}/properties', + configuration_url=f'https://app.energyid.eu/record/{self._record.record_number}/meters/{self._meter.id}/properties', identifiers={(DOMAIN, f'meter-{self._meter.id}')}, name=f'{self._meter.name}', model=self._meter.meter_type, - via_device=(DOMAIN, f'record-{self._record.id}') + via_device=(DOMAIN, f'record-{self._record.record_id}') ) @property diff --git a/custom_components/energy_id/record_diagnostic_entity.py b/custom_components/energy_id/record_diagnostic_entity.py new file mode 100644 index 0000000..84eaa03 --- /dev/null +++ b/custom_components/energy_id/record_diagnostic_entity.py @@ -0,0 +1,50 @@ +from homeassistant.helpers.entity import Entity, EntityCategory, DeviceInfo + +from .energy_id.record import EnergyIDRecord + +from .const import DOMAIN + + +class EnergyIDRecordDiagnosticEntity(Entity): + def __init__( + self, + record: EnergyIDRecord, + name: str, + attribute: str, + value, + icon: str = None, + ): + """Initialize the entity""" + self._record = record + self._name = name + self._attribute = attribute + self._value = value + self._icon = icon + + @property + def unique_id(self) -> str: + return f'{DOMAIN}-{self._record.record_id}-{self._attribute}' + + @property + def name(self) -> str: + return f'{self._record.display_name} - {self._name}' + + @property + def state(self): + return self._value + + @property + def device_info(self) -> DeviceInfo: + return self._record.device_info + + @property + def entity_category(self) -> str: + return EntityCategory.DIAGNOSTIC + + @property + def should_poll(self) -> bool: + return False + + @property + def icon(self) -> str: + return self._icon diff --git a/custom_components/energy_id/sensor.py b/custom_components/energy_id/sensor.py index a090aaf..2e43ece 100644 --- a/custom_components/energy_id/sensor.py +++ b/custom_components/energy_id/sensor.py @@ -1,12 +1,13 @@ """EnergyID sensors.""" from homeassistant.core import HomeAssistant from homeassistant.config_entries import ConfigEntry -from homeassistant.helpers import device_registry as dr from .const import DOMAIN, CONF_RECORD, CONF_API_KEY, CONF_ENERGY_ID_API_HOST, CONF_METER_IDS from .meter_reading_coordinator import EnergyIDMeterReadingCoordinator from .energy_id.api import EnergyIDApi from .meter_reading_sensor import EnergyIDMeterReading +from .record_diagnostic_entity import EnergyIDRecordDiagnosticEntity +from .energy_id.record import EnergyIDRecord import logging @@ -27,15 +28,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn record_config[CONF_RECORD] ) - device_registry = dr.async_get(hass) - device_registry.async_get_or_create( - config_entry_id=config_entry.entry_id, - configuration_url=f'https://app.energyid.eu/record/{record.number}/facility', - identifiers={(DOMAIN, f'record-{record.id}')}, - manufacturer='EnergyID', - name=record.name, - model='Record' - ) + async_add_entities(_entities_for_record(record)) meters = await hass.async_add_executor_job( api.get_record_meters, @@ -54,3 +47,124 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn async_add_entities(entities) await coordinator.async_config_entry_first_refresh() + + +def _entities_for_record(record: EnergyIDRecord) -> list: + entities_to_add = [ + EnergyIDRecordDiagnosticEntity(record, 'Created', 'created', record.created), + EnergyIDRecordDiagnosticEntity(record, 'Display name', 'display_name', record.display_name), + EnergyIDRecordDiagnosticEntity(record, 'Record ID', 'record_id', record.record_id), + EnergyIDRecordDiagnosticEntity(record, 'Owner ID', 'owner_id', record.owner_id), + EnergyIDRecordDiagnosticEntity(record, 'Record number', 'record_number', record.record_number), + EnergyIDRecordDiagnosticEntity(record, 'Record Type', 'record_type', record.record_type), + EnergyIDRecordDiagnosticEntity(record, 'Timezone', 'timezone', record.time_zone, 'mdi:map-clock'), + ] + + if record.last_submission is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Last submission', 'last_submission', record.last_submission)) + + if record.address is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Address Street', 'address_street', record.address.street)) + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Address Country', 'address_country', record.address.country)) + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Address Postal code', 'address_postal_code', + record.address.postal_code)) + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Address City', 'address_city', record.address.city, 'mdi:city')) + + if record.category is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Category', 'category', record.category)) + + if record.tags is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Tags', 'tags', ', '.join(record.tags), 'mdi:tag-multiple')) + + if record.dwelling_type is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Dwelling type', 'dwelling_type', record.dwelling_type)) + + if record.principal_residence is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Principal residence', 'principal_residence', + record.principal_residence)) + + if record.occupants is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Occupants', 'occupants', record.occupants)) + + if record.occupier_type is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Occupier type', 'occupier_type', record.occupier_type)) + + if record.heating_on is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Heating on', 'heating_on', record.heating_on)) + + if record.auxiliary_heating_on is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Auxiliary heating on', 'auxiliary_heating_on', + record.auxiliary_heating_on)) + + if record.cooking_on is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Cooking on', 'cooking_on', record.cooking_on)) + + if record.hot_water_on is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Hot water on', 'hot_water_on', record.hot_water_on)) + + if record.floor_surface is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Floor surface', 'floor_surface', record.floor_surface)) + + if record.year_of_construction is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Year of construction', 'year_of_construction', + record.year_of_construction)) + + if record.year_of_renovation is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Year of renovation', 'year_of_renovation', + record.year_of_renovation)) + + if record.energy_performance is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Energy performance', 'energy_performance', + record.energy_performance)) + + if record.energy_rating is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Energy rating', 'energy_rating', record.energy_rating)) + + if record.energy_efficiency is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Energy efficiency', 'energy_efficiency', + record.energy_efficiency)) + + if record.installations is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Installations', 'installations', + ', '.join(record.installations))) + + if record.plan is not None: + entities_to_add.append(EnergyIDRecordDiagnosticEntity(record, 'Plan', 'plan', record.plan)) + + if record.errors is not None: + entities_to_add.append(EnergyIDRecordDiagnosticEntity(record, 'Errors', 'errors', record.errors, + 'mdi:alert')) + + if record.benchmarking_enabled is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Benchmarking enabled', 'benchmarking_enabled', + record.benchmarking_enabled)) + + if record.premium_features is not None: + entities_to_add.append( + EnergyIDRecordDiagnosticEntity(record, 'Premium features', 'premium_features', + ', '.join(record.premium_features))) + + return entities_to_add From e3e504a7b72c08b823b676e9c8580fd1a8f92662 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Fri, 18 Nov 2022 13:23:04 +0100 Subject: [PATCH 2/2] Diagnostic entities for Meter --- ...gnostic_entity.py => diagnostic_entity.py} | 26 ++-- custom_components/energy_id/energy_id/api.py | 14 +- .../energy_id/energy_id/meter.py | 120 ++++++++++++++++-- .../energy_id/meter_reading_coordinator.py | 6 +- .../energy_id/meter_reading_sensor.py | 16 +-- custom_components/energy_id/sensor.py | 79 +++++++++++- 6 files changed, 212 insertions(+), 49 deletions(-) rename custom_components/energy_id/{record_diagnostic_entity.py => diagnostic_entity.py} (64%) diff --git a/custom_components/energy_id/record_diagnostic_entity.py b/custom_components/energy_id/diagnostic_entity.py similarity index 64% rename from custom_components/energy_id/record_diagnostic_entity.py rename to custom_components/energy_id/diagnostic_entity.py index 84eaa03..c4391f4 100644 --- a/custom_components/energy_id/record_diagnostic_entity.py +++ b/custom_components/energy_id/diagnostic_entity.py @@ -5,29 +5,25 @@ from .const import DOMAIN -class EnergyIDRecordDiagnosticEntity(Entity): +class EnergyIDDiagnosticEntity(Entity): def __init__( self, - record: EnergyIDRecord, + device, name: str, attribute: str, value, icon: str = None, ): """Initialize the entity""" - self._record = record + self._device = device self._name = name self._attribute = attribute self._value = value self._icon = icon - @property - def unique_id(self) -> str: - return f'{DOMAIN}-{self._record.record_id}-{self._attribute}' - @property def name(self) -> str: - return f'{self._record.display_name} - {self._name}' + return f'{self._device.display_name} - {self._name}' @property def state(self): @@ -35,7 +31,7 @@ def state(self): @property def device_info(self) -> DeviceInfo: - return self._record.device_info + return self._device.device_info @property def entity_category(self) -> str: @@ -48,3 +44,15 @@ def should_poll(self) -> bool: @property def icon(self) -> str: return self._icon + + +class EnergyIDRecordDiagnosticEntity(EnergyIDDiagnosticEntity): + @property + def unique_id(self) -> str: + return f'{DOMAIN}-{self._device.record_id}-{self._attribute}' + + +class EnergyIDMeterDiagnosticEntity(EnergyIDDiagnosticEntity): + @property + def unique_id(self) -> str: + return f'{DOMAIN}-{self._device.meter_id}-{self._attribute}' diff --git a/custom_components/energy_id/energy_id/api.py b/custom_components/energy_id/energy_id/api.py index 7f3648e..69924e1 100644 --- a/custom_components/energy_id/energy_id/api.py +++ b/custom_components/energy_id/energy_id/api.py @@ -46,19 +46,7 @@ def get_record_meters(self, record: str, expand: list = None): data = [] for meter_data in response: - data.append( - EnergyIDMeter( - meter_data['id'], - meter_data['recordId'], - meter_data['displayName'], - meter_data['meterType'], - meter_data['metric'], - meter_data['multiplier'], - meter_data['readingType'], - meter_data['theme'], - meter_data['unit'] - ) - ) + data.append(EnergyIDMeter.from_json(meter_data)) return data diff --git a/custom_components/energy_id/energy_id/meter.py b/custom_components/energy_id/energy_id/meter.py index 789cf05..544365c 100644 --- a/custom_components/energy_id/energy_id/meter.py +++ b/custom_components/energy_id/energy_id/meter.py @@ -1,25 +1,125 @@ +from homeassistant.helpers.entity import DeviceInfo +from ..const import DOMAIN + +import datetime + + class EnergyIDMeter: def __init__( self, - id: str, - record_id: str, - name: str, + automatic: bool, + display_name: str, + exclude_from_reports: bool, + hidden: bool, + meter_id: str, meter_type: str, metric: str, multiplier: float, reading_type: str, + record_id: str, theme: str, - unit: str + unit: str, + integration_id: str = None, + activated: datetime = None, + deactivated: datetime = None, + comments: str = None, + confirmed: bool = None, + installation_number: str = None, + connection_number: str = None, + supplier: str = None, + renewable: bool = None, + brand_name: str = None, + model_name: str = None, + peak_power: float = None, + meter_number: str = None, + stock_capacity: int = None, + interval: str = None, + qr_key: str = None, + qr_type: str = None ): - self.id = id - self.record_id = record_id - self.name = name + self.automatic = automatic + self.display_name = display_name + self.exclude_from_reports = exclude_from_reports + self.hidden = hidden + self.meter_id = meter_id self.meter_type = meter_type self.metric = metric self.multiplier = multiplier self.reading_type = reading_type + self.record_id = record_id self.theme = theme self.unit = unit - self.state = None - self.last_updated = None - self.last_updated_str = None + self.integration_id = integration_id + self.activated = activated + self.deactivated = deactivated + self.comments = comments + self.confirmed = confirmed + self.installation_number = installation_number + self.connection_number = connection_number + self.supplier = supplier + self.renewable = renewable + self.brand_name = brand_name + self.model_name = model_name + self.peak_power = peak_power + self.meter_number = meter_number + self.stock_capacity = stock_capacity + self.interval = interval + self.qr_key = qr_key + self.qr_type = qr_type + + @classmethod + def from_json(cls, json): + return cls( + automatic=json['automatic'], + display_name=json['displayName'], + exclude_from_reports=json['excludeFromReports'], + hidden=json['hidden'], + meter_id=json['id'], + meter_type=json['meterType'], + metric=json['metric'], + multiplier=json['multiplier'], + reading_type=json['readingType'], + record_id=json['recordId'], + theme=json['theme'], + unit=json['unit'], + integration_id=json['integrationId'] if 'integrationId' in json else None, + activated=json['activated'] if 'activated' in json else None, + deactivated=json['deactivated'] if 'deactivated' in json else None, + comments=json['comments'] if 'comments' in json else None, + confirmed=json['confirmed'] if 'confirmed' in json else None, + installation_number=json['installationNumber'] if 'installationNumber' in json else None, + connection_number=json['connectionNumber'] if 'connectionNumber' in json else None, + supplier=json['supplier'] if 'supplier' in json else None, + renewable=json['renewable'] if 'renewable' in json else None, + brand_name=json['brandName'] if 'brandName' in json else None, + model_name=json['modelName'] if 'modelName' in json else None, + peak_power=json['peakPower'] if 'peakPower' in json else None, + meter_number=json['meterNumber'] if 'meterNumber' in json else None, + stock_capacity=json['stockCapacity'] if 'stockCapacity' in json else None, + interval=json['interval'] if 'interval' in json else None, + qr_key=json['qrKey'] if 'qrKey' in json else None, + qr_type=json['qrType'] if 'qrType' in json else None + ) + + @property + def device_info(self) -> DeviceInfo: + manufacturer = 'EnergyID' + + if self.supplier is not None: + manufacturer = self.supplier + + if self.brand_name is not None: + manufacturer = self.brand_name + + model = self.meter_type + if self.model_name is not None: + model = self.meter_type + " " + self.model_name + + return DeviceInfo( + configuration_url=f'https://app.energyid.eu/record/{self.record_id}/meters/{self.meter_id}/properties', + identifiers={(DOMAIN, f'meter-{self.meter_id}')}, + name=self.display_name, + manufacturer=manufacturer, + model=model, + via_device=(DOMAIN, f'record-{self.record_id}') + ) diff --git a/custom_components/energy_id/meter_reading_coordinator.py b/custom_components/energy_id/meter_reading_coordinator.py index 834ce94..67f8bed 100644 --- a/custom_components/energy_id/meter_reading_coordinator.py +++ b/custom_components/energy_id/meter_reading_coordinator.py @@ -36,11 +36,11 @@ def fix_datetime_offset(match): for meter in self.meters: response = await self.hass.async_add_executor_job( self.api.get_meter_readings, - meter.id, + meter.meter_id, 2 ) - data[meter.id] = {} + data[meter.meter_id] = {} reading_data = { 'last': None, 'previous': None, @@ -67,6 +67,6 @@ def fix_datetime_offset(match): last_timestamp = timestamp - data[meter.id][RESPONSE_ATTRIBUTE_READINGS] = reading_data + data[meter.meter_id][RESPONSE_ATTRIBUTE_READINGS] = reading_data return data diff --git a/custom_components/energy_id/meter_reading_sensor.py b/custom_components/energy_id/meter_reading_sensor.py index 5d9fc8e..2fdd3d9 100644 --- a/custom_components/energy_id/meter_reading_sensor.py +++ b/custom_components/energy_id/meter_reading_sensor.py @@ -35,7 +35,7 @@ def __init__( @property def name(self): - return f'{self._record.display_name}: {self._meter.name} - {self._attribute} reading' + return f'{self._record.display_name}: {self._meter.display_name} - {self._attribute} reading' @property def device_class(self) -> str: @@ -99,17 +99,11 @@ def device_class(self) -> str: @property def device_info(self) -> DeviceInfo: - return DeviceInfo( - configuration_url=f'https://app.energyid.eu/record/{self._record.record_number}/meters/{self._meter.id}/properties', - identifiers={(DOMAIN, f'meter-{self._meter.id}')}, - name=f'{self._meter.name}', - model=self._meter.meter_type, - via_device=(DOMAIN, f'record-{self._record.record_id}') - ) + return self._meter.device_info @property def unique_id(self) -> str: - return f'meter-{self._meter.id}-{self._attribute}-reading' + return f'meter-{self._meter.meter_id}-{self._attribute}-reading' @property def native_unit_of_measurement(self) -> str: @@ -157,8 +151,8 @@ def state(self) -> float: @callback def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" - reading = self.coordinator.data[self._meter.id][RESPONSE_ATTRIBUTE_READINGS][self._attribute] - _LOGGER.debug(f'Updating meter {self._meter.id} reading {self._attribute} to {reading}') + reading = self.coordinator.data[self._meter.meter_id][RESPONSE_ATTRIBUTE_READINGS][self._attribute] + _LOGGER.debug(f'Updating meter {self._meter.meter_id} reading {self._attribute} to {reading}') if reading is not None and reading[RESPONSE_ATTRIBUTE_IGNORE] is False: self._value = reading[RESPONSE_ATTRIBUTE_VALUE] diff --git a/custom_components/energy_id/sensor.py b/custom_components/energy_id/sensor.py index 2e43ece..af2f786 100644 --- a/custom_components/energy_id/sensor.py +++ b/custom_components/energy_id/sensor.py @@ -6,8 +6,9 @@ from .meter_reading_coordinator import EnergyIDMeterReadingCoordinator from .energy_id.api import EnergyIDApi from .meter_reading_sensor import EnergyIDMeterReading -from .record_diagnostic_entity import EnergyIDRecordDiagnosticEntity +from .diagnostic_entity import EnergyIDRecordDiagnosticEntity, EnergyIDMeterDiagnosticEntity from .energy_id.record import EnergyIDRecord +from .energy_id.meter import EnergyIDMeter import logging @@ -40,7 +41,8 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn record_config[CONF_METER_IDS] = [] entities = [] for meter in meters: - record_config[CONF_METER_IDS].append(meter.id) + record_config[CONF_METER_IDS].append(meter.meter_id) + async_add_entities(_entities_for_meter(meter)) entities.append(EnergyIDMeterReading(coordinator, meter, record, 'last')) entities.append(EnergyIDMeterReading(coordinator, meter, record, 'previous')) @@ -56,7 +58,7 @@ def _entities_for_record(record: EnergyIDRecord) -> list: EnergyIDRecordDiagnosticEntity(record, 'Record ID', 'record_id', record.record_id), EnergyIDRecordDiagnosticEntity(record, 'Owner ID', 'owner_id', record.owner_id), EnergyIDRecordDiagnosticEntity(record, 'Record number', 'record_number', record.record_number), - EnergyIDRecordDiagnosticEntity(record, 'Record Type', 'record_type', record.record_type), + EnergyIDRecordDiagnosticEntity(record, 'Record type', 'record_type', record.record_type), EnergyIDRecordDiagnosticEntity(record, 'Timezone', 'timezone', record.time_zone, 'mdi:map-clock'), ] @@ -168,3 +170,74 @@ def _entities_for_record(record: EnergyIDRecord) -> list: ', '.join(record.premium_features))) return entities_to_add + + +def _entities_for_meter(meter: EnergyIDMeter) -> list: + entities_to_add = [ + EnergyIDMeterDiagnosticEntity(meter, 'Automatic', 'automatic', meter.automatic), + EnergyIDMeterDiagnosticEntity(meter, 'Display name', 'display_name', meter.display_name), + EnergyIDMeterDiagnosticEntity(meter, 'Exclude from reports', 'exclude_from_reports', meter.exclude_from_reports), + EnergyIDMeterDiagnosticEntity(meter, 'Hidden', 'hidden', meter.hidden), + EnergyIDMeterDiagnosticEntity(meter, 'Meter ID', 'meter_id', meter.meter_id), + EnergyIDMeterDiagnosticEntity(meter, 'Meter type', 'meter_type', meter.meter_type), + EnergyIDMeterDiagnosticEntity(meter, 'Metric', 'metric', meter.metric), + EnergyIDMeterDiagnosticEntity(meter, 'Multiplier', 'multiplier', meter.multiplier), + EnergyIDMeterDiagnosticEntity(meter, 'Reading type', 'reading_type', meter.reading_type), + EnergyIDMeterDiagnosticEntity(meter, 'Record ID', 'record_id', meter.record_id), + EnergyIDMeterDiagnosticEntity(meter, 'Theme', 'theme', meter.theme), + EnergyIDMeterDiagnosticEntity(meter, 'Unit', 'unit', meter.unit), + ] + + if meter.integration_id is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'Integration ID', 'integration_id', meter.integration_id)) + if meter.activated is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'Activated', 'activated', meter.activated)) + if meter.deactivated is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'Deactivated', 'deactivated', meter.deactivated)) + if meter.comments is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'Comments', 'comments', meter.comments)) + if meter.confirmed is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'Confirmed', 'confirmed', meter.confirmed)) + if meter.installation_number is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'Installation number', 'installation_number', meter.installation_number)) + if meter.connection_number is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'Connection number', 'connection_number', meter.connection_number)) + if meter.supplier is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'Supplier', 'supplier', meter.supplier)) + if meter.renewable is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'Renewable', 'renewable', meter.renewable)) + if meter.brand_name is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'Brand name', 'brand_name', meter.brand_name)) + if meter.model_name is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'Model name', 'model_name', meter.model_name)) + if meter.peak_power is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'Peak power', 'peak_power', meter.peak_power)) + if meter.meter_number is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'Meter number', 'meter_number', meter.meter_number)) + if meter.stock_capacity is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'Stock capacity', 'stock_capacity', meter.stock_capacity)) + if meter.interval is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'Interval', 'interval', meter.interval)) + if meter.qr_key is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'QR key', 'qr_key', meter.qr_key)) + if meter.qr_type is not None: + entities_to_add.append( + EnergyIDMeterDiagnosticEntity(meter, 'QR type', 'qr_type', meter.qr_type)) + + return entities_to_add