Bump iammeter to 0.2.1 (#95885)

* Bump iammeter to 0.2.1

* Refactor sensor.

* Add const.py to .coveragerc.

* Add id migration.

* Modify translation file.

* Fix ruff test error

* update asyncio.timeout import.

* Delete homeassistant/components/iammeter/translations directory

* Add strings.json
This commit is contained in:
yangbo 2023-12-14 17:01:29 +08:00 committed by GitHub
parent 0ec3a222e3
commit 82f0b28e89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 486 additions and 53 deletions

View File

@ -539,6 +539,7 @@ omit =
homeassistant/components/hvv_departures/binary_sensor.py homeassistant/components/hvv_departures/binary_sensor.py
homeassistant/components/hvv_departures/sensor.py homeassistant/components/hvv_departures/sensor.py
homeassistant/components/ialarm/alarm_control_panel.py homeassistant/components/ialarm/alarm_control_panel.py
homeassistant/components/iammeter/const.py
homeassistant/components/iammeter/sensor.py homeassistant/components/iammeter/sensor.py
homeassistant/components/iaqualink/binary_sensor.py homeassistant/components/iaqualink/binary_sensor.py
homeassistant/components/iaqualink/climate.py homeassistant/components/iaqualink/climate.py

View File

@ -1 +1 @@
"""Support for IamMeter Devices.""" """Iammeter integration."""

View File

@ -0,0 +1,11 @@
"""Constants for the Iammeter integration."""
from __future__ import annotations
DOMAIN = "iammeter"
# Default config for iammeter.
DEFAULT_IP = "192.168.2.15"
DEFAULT_NAME = "IamMeter"
DEVICE_3080 = "WEM3080"
DEVICE_3080T = "WEM3080T"
DEVICE_TYPES = [DEVICE_3080, DEVICE_3080T]

View File

@ -5,5 +5,5 @@
"documentation": "https://www.home-assistant.io/integrations/iammeter", "documentation": "https://www.home-assistant.io/integrations/iammeter",
"iot_class": "local_polling", "iot_class": "local_polling",
"loggers": ["iammeter"], "loggers": ["iammeter"],
"requirements": ["iammeter==0.1.7"] "requirements": ["iammeter==0.2.1"]
} }

View File

@ -2,26 +2,44 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
from datetime import timedelta from asyncio import timeout
from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime, timedelta
import logging import logging
from iammeter import real_time_api from iammeter.client import IamMeter
from iammeter.power_meter import IamMeterError
import voluptuous as vol import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity from homeassistant.components.sensor import (
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT PLATFORM_SCHEMA,
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.const import (
CONF_HOST,
CONF_NAME,
CONF_PORT,
PERCENTAGE,
Platform,
UnitOfElectricCurrent,
UnitOfElectricPotential,
UnitOfEnergy,
UnitOfFrequency,
UnitOfPower,
)
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import PlatformNotReady from homeassistant.exceptions import PlatformNotReady
from homeassistant.helpers import debounce from homeassistant.helpers import debounce, entity_registry as er, update_coordinator
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.helpers.update_coordinator import ( from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
CoordinatorEntity,
DataUpdateCoordinator, from .const import DEVICE_3080, DOMAIN
UpdateFailed,
)
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -40,6 +58,51 @@ SCAN_INTERVAL = timedelta(seconds=30)
PLATFORM_TIMEOUT = 8 PLATFORM_TIMEOUT = 8
def _migrate_to_new_unique_id(
hass: HomeAssistant, model: str, serial_number: str
) -> None:
"""Migrate old unique ids to new unique ids."""
ent_reg = er.async_get(hass)
name_list = [
"Voltage",
"Current",
"Power",
"ImportEnergy",
"ExportGrid",
"Frequency",
"PF",
]
phase_list = ["A", "B", "C", "NET"]
id_phase_range = 1 if model == DEVICE_3080 else 4
id_name_range = 5 if model == DEVICE_3080 else 7
for row in range(0, id_phase_range):
for idx in range(0, id_name_range):
old_unique_id = f"{serial_number}-{row}-{idx}"
new_unique_id = (
f"{serial_number}_{name_list[idx]}"
if model == DEVICE_3080
else f"{serial_number}_{name_list[idx]}_{phase_list[row]}"
)
entity_id = ent_reg.async_get_entity_id(
Platform.SENSOR, DOMAIN, old_unique_id
)
if entity_id is not None:
try:
ent_reg.async_update_entity(entity_id, new_unique_id=new_unique_id)
except ValueError:
_LOGGER.warning(
"Skip migration of id [%s] to [%s] because it already exists",
old_unique_id,
new_unique_id,
)
else:
_LOGGER.debug(
"Migrating unique_id from [%s] to [%s]",
old_unique_id,
new_unique_id,
)
async def async_setup_platform( async def async_setup_platform(
hass: HomeAssistant, hass: HomeAssistant,
config: ConfigType, config: ConfigType,
@ -51,23 +114,24 @@ async def async_setup_platform(
config_port = config[CONF_PORT] config_port = config[CONF_PORT]
config_name = config[CONF_NAME] config_name = config[CONF_NAME]
try: try:
async with asyncio.timeout(PLATFORM_TIMEOUT): api = await hass.async_add_executor_job(
api = await real_time_api(config_host, config_port) IamMeter, config_host, config_port, config_name
except (IamMeterError, asyncio.TimeoutError) as err: )
except asyncio.TimeoutError as err:
_LOGGER.error("Device is not ready") _LOGGER.error("Device is not ready")
raise PlatformNotReady from err raise PlatformNotReady from err
async def async_update_data(): async def async_update_data():
try: try:
async with asyncio.timeout(PLATFORM_TIMEOUT): async with timeout(PLATFORM_TIMEOUT):
return await api.get_data() return await hass.async_add_executor_job(api.client.get_data)
except (IamMeterError, asyncio.TimeoutError) as err: except asyncio.TimeoutError as err:
raise UpdateFailed from err raise UpdateFailed from err
coordinator = DataUpdateCoordinator( coordinator = DataUpdateCoordinator(
hass, hass,
_LOGGER, _LOGGER,
name=DEFAULT_DEVICE_NAME, name=config_name,
update_method=async_update_data, update_method=async_update_data,
update_interval=SCAN_INTERVAL, update_interval=SCAN_INTERVAL,
request_refresh_debouncer=debounce.Debouncer( request_refresh_debouncer=debounce.Debouncer(
@ -75,46 +139,334 @@ async def async_setup_platform(
), ),
) )
await coordinator.async_refresh() await coordinator.async_refresh()
entities = [] model = coordinator.data["Model"]
for sensor_name, (row, idx, unit) in api.iammeter.sensor_map().items(): serial_number = coordinator.data["sn"]
serial_number = api.iammeter.serial_number _migrate_to_new_unique_id(hass, model, serial_number)
uid = f"{serial_number}-{row}-{idx}" if model == DEVICE_3080:
entities.append(IamMeter(coordinator, uid, sensor_name, unit, config_name)) async_add_entities(
async_add_entities(entities) IammeterSensor(coordinator, description)
for description in SENSOR_TYPES_3080
)
else: # DEVICE_3080T:
async_add_entities(
IammeterSensor(coordinator, description)
for description in SENSOR_TYPES_3080T
)
class IamMeter(CoordinatorEntity, SensorEntity): class IammeterSensor(update_coordinator.CoordinatorEntity, SensorEntity):
"""Class for a sensor.""" """Representation of a Sensor."""
def __init__(self, coordinator, uid, sensor_name, unit, dev_name): entity_description: IammeterSensorEntityDescription
"""Initialize an iammeter sensor.""" _attr_has_entity_name = True
_attr_name = None
def __init__(
self,
coordinator: DataUpdateCoordinator,
description: IammeterSensorEntityDescription,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator) super().__init__(coordinator)
self.uid = uid self.entity_description = description
self.sensor_name = sensor_name self._attr_unique_id = f"{coordinator.data['sn']}_{description.key}"
self.unit = unit self._attr_device_info = DeviceInfo(
self.dev_name = dev_name identifiers={(DOMAIN, coordinator.data["sn"])},
manufacturer="IamMeter",
name=coordinator.name,
)
@property @property
def native_value(self): def native_value(self):
"""Return the state of the sensor.""" """Return the native sensor value."""
return self.coordinator.data.data[self.sensor_name] raw_attr = self.coordinator.data.get(self.entity_description.key, None)
if self.entity_description.value:
return self.entity_description.value(raw_attr)
return raw_attr
@property
def unique_id(self):
"""Return unique id."""
return self.uid
@property @dataclass
def name(self): class IammeterSensorEntityDescription(SensorEntityDescription):
"""Name of this iammeter attribute.""" """Describes Iammeter sensor entity."""
return f"{self.dev_name} {self.sensor_name}"
@property value: Callable[[float | int], float] | Callable[[datetime], datetime] | None = None
def icon(self):
"""Icon for each sensor."""
return "mdi:flash"
@property
def native_unit_of_measurement(self): SENSOR_TYPES_3080: tuple[IammeterSensorEntityDescription, ...] = (
"""Return the unit of measurement.""" IammeterSensorEntityDescription(
return self.unit key="Voltage",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="Current",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.CURRENT,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="Power",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
),
IammeterSensorEntityDescription(
key="ImportEnergy",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
IammeterSensorEntityDescription(
key="ExportGrid",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
)
SENSOR_TYPES_3080T: tuple[IammeterSensorEntityDescription, ...] = (
IammeterSensorEntityDescription(
key="Voltage_A",
translation_key="voltage_a",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="Current_A",
translation_key="current_a",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.CURRENT,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="Power_A",
translation_key="power_a",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
),
IammeterSensorEntityDescription(
key="ImportEnergy_A",
translation_key="import_energy_a",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
IammeterSensorEntityDescription(
key="ExportGrid_A",
translation_key="export_grid_a",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
IammeterSensorEntityDescription(
key="Frequency_A",
translation_key="frequency_a",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfFrequency.HERTZ,
device_class=SensorDeviceClass.FREQUENCY,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="PF_A",
translation_key="pf_a",
icon="mdi:solar-power",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.POWER_FACTOR,
value=lambda value: value * 100,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="Voltage_B",
translation_key="voltage_b",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="Current_B",
translation_key="current_b",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.CURRENT,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="Power_B",
translation_key="power_b",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
),
IammeterSensorEntityDescription(
key="ImportEnergy_B",
translation_key="import_energy_b",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
IammeterSensorEntityDescription(
key="ExportGrid_B",
translation_key="export_grid_b",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
IammeterSensorEntityDescription(
key="Frequency_B",
translation_key="frequency_b",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfFrequency.HERTZ,
device_class=SensorDeviceClass.FREQUENCY,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="PF_B",
translation_key="pf_b",
icon="mdi:solar-power",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.POWER_FACTOR,
value=lambda value: value * 100,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="Voltage_C",
translation_key="voltage_c",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="Current_C",
translation_key="current_c",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.CURRENT,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="Power_C",
translation_key="power_c",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
),
IammeterSensorEntityDescription(
key="ImportEnergy_C",
translation_key="import_energy_c",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
IammeterSensorEntityDescription(
key="ExportGrid_C",
translation_key="export_grid_c",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
IammeterSensorEntityDescription(
key="Frequency_C",
translation_key="frequency_c",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfFrequency.HERTZ,
device_class=SensorDeviceClass.FREQUENCY,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="PF_C",
translation_key="pf_c",
icon="mdi:solar-power",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.POWER_FACTOR,
value=lambda value: value * 100,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="Voltage_Net",
translation_key="voltage_net",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="Power_Net",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="ImportEnergy_Net",
translation_key="import_energy_net",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="ExportGrid_Net",
translation_key="export_grid_net",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="Frequency_Net",
translation_key="frequency_net",
icon="mdi:solar-power",
native_unit_of_measurement=UnitOfFrequency.HERTZ,
device_class=SensorDeviceClass.FREQUENCY,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=False,
),
IammeterSensorEntityDescription(
key="PF_Net",
translation_key="pf_net",
icon="mdi:solar-power",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.POWER_FACTOR,
value=lambda value: value * 100,
entity_registry_enabled_default=False,
),
)

View File

@ -0,0 +1,69 @@
{
"entity": {
"sensor": {
"voltage_a": {
"name": "Voltage A"
},
"voltage_b": {
"name": "Voltage B"
},
"voltage_c": {
"name": "Voltage C"
},
"current_a": {
"name": "Current A"
},
"current_b": {
"name": "Current B"
},
"current_c": {
"name": "Current C"
},
"power_a": {
"name": "Power A"
},
"power_b": {
"name": "Power B"
},
"power_c": {
"name": "Power C"
},
"import_energy_a": {
"name": "ImportEnergy A"
},
"import_energy_b": {
"name": "ImportEnergy B"
},
"import_energy_c": {
"name": "ImportEnergy C"
},
"export_grid_a": {
"name": "ExportGrid A"
},
"export_grid_b": {
"name": "ExportGrid B"
},
"export_grid_c": {
"name": "ExportGrid C"
},
"frequency_a": {
"name": "Frequency A"
},
"frequency_b": {
"name": "Frequency B"
},
"frequency_c": {
"name": "Frequency C"
},
"pf_a": {
"name": "PF A"
},
"pf_b": {
"name": "PF B"
},
"pf_c": {
"name": "PF C"
}
}
}
}

View File

@ -1051,7 +1051,7 @@ huawei-lte-api==1.7.3
hyperion-py==0.7.5 hyperion-py==0.7.5
# homeassistant.components.iammeter # homeassistant.components.iammeter
iammeter==0.1.7 iammeter==0.2.1
# homeassistant.components.iaqualink # homeassistant.components.iaqualink
iaqualink==0.5.0 iaqualink==0.5.0