mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Add support for V2C Trydan 2.1.7 (#117147)
* Support for firmware 2.1.7 * add device ID as unique_id * add device ID as unique_id * add test device id as unique_id * backward compatibility * move outside try * Sensor return type Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * not needed * make slave error enum state * fix enum * Update homeassistant/components/v2c/sensor.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update homeassistant/components/v2c/strings.json Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update homeassistant/components/v2c/strings.json Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * simplify tests * fix misspellings from upstream library * add sensor tests * just enough coverage for enum sensor * Refactor V2C tests (#117264) * Refactor V2C tests * fix rebase issues * ruff * review * fix https://github.com/home-assistant/core/issues/117296 --------- Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
parent
486c72db73
commit
e6e017dab7
@ -1534,7 +1534,6 @@ omit =
|
|||||||
homeassistant/components/v2c/coordinator.py
|
homeassistant/components/v2c/coordinator.py
|
||||||
homeassistant/components/v2c/entity.py
|
homeassistant/components/v2c/entity.py
|
||||||
homeassistant/components/v2c/number.py
|
homeassistant/components/v2c/number.py
|
||||||
homeassistant/components/v2c/sensor.py
|
|
||||||
homeassistant/components/v2c/switch.py
|
homeassistant/components/v2c/switch.py
|
||||||
homeassistant/components/vallox/__init__.py
|
homeassistant/components/vallox/__init__.py
|
||||||
homeassistant/components/vallox/coordinator.py
|
homeassistant/components/vallox/coordinator.py
|
||||||
|
@ -31,6 +31,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
|
|
||||||
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator
|
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator
|
||||||
|
|
||||||
|
if coordinator.data.ID and entry.unique_id != coordinator.data.ID:
|
||||||
|
hass.config_entries.async_update_entry(entry, unique_id=coordinator.data.ID)
|
||||||
|
|
||||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -41,13 +41,18 @@ class V2CConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await evse.get_data()
|
data = await evse.get_data()
|
||||||
|
|
||||||
except TrydanError:
|
except TrydanError:
|
||||||
errors["base"] = "cannot_connect"
|
errors["base"] = "cannot_connect"
|
||||||
except Exception:
|
except Exception:
|
||||||
_LOGGER.exception("Unexpected exception")
|
_LOGGER.exception("Unexpected exception")
|
||||||
errors["base"] = "unknown"
|
errors["base"] = "unknown"
|
||||||
else:
|
else:
|
||||||
|
if data.ID:
|
||||||
|
await self.async_set_unique_id(data.ID)
|
||||||
|
self._abort_if_unique_id_configured()
|
||||||
|
|
||||||
return self.async_create_entry(
|
return self.async_create_entry(
|
||||||
title=f"EVSE {user_input[CONF_HOST]}", data=user_input
|
title=f"EVSE {user_input[CONF_HOST]}", data=user_input
|
||||||
)
|
)
|
||||||
|
@ -15,6 +15,12 @@
|
|||||||
},
|
},
|
||||||
"fv_power": {
|
"fv_power": {
|
||||||
"default": "mdi:solar-power-variant"
|
"default": "mdi:solar-power-variant"
|
||||||
|
},
|
||||||
|
"slave_error": {
|
||||||
|
"default": "mdi:alert"
|
||||||
|
},
|
||||||
|
"battery_power": {
|
||||||
|
"default": "mdi:home-battery"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"switch": {
|
"switch": {
|
||||||
|
@ -5,5 +5,5 @@
|
|||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/v2c",
|
"documentation": "https://www.home-assistant.io/integrations/v2c",
|
||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
"requirements": ["pytrydan==0.6.0"]
|
"requirements": ["pytrydan==0.6.1"]
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ from dataclasses import dataclass
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from pytrydan import TrydanData
|
from pytrydan import TrydanData
|
||||||
|
from pytrydan.models.trydan import SlaveCommunicationState
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
SensorDeviceClass,
|
SensorDeviceClass,
|
||||||
@ -18,6 +19,7 @@ from homeassistant.config_entries import ConfigEntry
|
|||||||
from homeassistant.const import UnitOfEnergy, UnitOfPower, UnitOfTime
|
from homeassistant.const import UnitOfEnergy, UnitOfPower, UnitOfTime
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.typing import StateType
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .coordinator import V2CUpdateCoordinator
|
from .coordinator import V2CUpdateCoordinator
|
||||||
@ -30,9 +32,11 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
class V2CSensorEntityDescription(SensorEntityDescription):
|
class V2CSensorEntityDescription(SensorEntityDescription):
|
||||||
"""Describes an EVSE Power sensor entity."""
|
"""Describes an EVSE Power sensor entity."""
|
||||||
|
|
||||||
value_fn: Callable[[TrydanData], float]
|
value_fn: Callable[[TrydanData], StateType]
|
||||||
|
|
||||||
|
|
||||||
|
_SLAVE_ERROR_OPTIONS = [error.name.lower() for error in SlaveCommunicationState]
|
||||||
|
|
||||||
TRYDAN_SENSORS = (
|
TRYDAN_SENSORS = (
|
||||||
V2CSensorEntityDescription(
|
V2CSensorEntityDescription(
|
||||||
key="charge_power",
|
key="charge_power",
|
||||||
@ -75,6 +79,23 @@ TRYDAN_SENSORS = (
|
|||||||
device_class=SensorDeviceClass.POWER,
|
device_class=SensorDeviceClass.POWER,
|
||||||
value_fn=lambda evse_data: evse_data.fv_power,
|
value_fn=lambda evse_data: evse_data.fv_power,
|
||||||
),
|
),
|
||||||
|
V2CSensorEntityDescription(
|
||||||
|
key="slave_error",
|
||||||
|
translation_key="slave_error",
|
||||||
|
value_fn=lambda evse_data: evse_data.slave_error.name.lower(),
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
device_class=SensorDeviceClass.ENUM,
|
||||||
|
options=_SLAVE_ERROR_OPTIONS,
|
||||||
|
),
|
||||||
|
V2CSensorEntityDescription(
|
||||||
|
key="battery_power",
|
||||||
|
translation_key="battery_power",
|
||||||
|
native_unit_of_measurement=UnitOfPower.WATT,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
device_class=SensorDeviceClass.POWER,
|
||||||
|
value_fn=lambda evse_data: evse_data.battery_power,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -108,6 +129,6 @@ class V2CSensorBaseEntity(V2CBaseEntity, SensorEntity):
|
|||||||
self._attr_unique_id = f"{entry_id}_{description.key}"
|
self._attr_unique_id = f"{entry_id}_{description.key}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def native_value(self) -> float | None:
|
def native_value(self) -> StateType:
|
||||||
"""Return the state of the sensor."""
|
"""Return the state of the sensor."""
|
||||||
return self.entity_description.value_fn(self.data)
|
return self.entity_description.value_fn(self.data)
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||||
|
},
|
||||||
"step": {
|
"step": {
|
||||||
"user": {
|
"user": {
|
||||||
"data": {
|
"data": {
|
||||||
@ -47,6 +50,49 @@
|
|||||||
},
|
},
|
||||||
"fv_power": {
|
"fv_power": {
|
||||||
"name": "Photovoltaic power"
|
"name": "Photovoltaic power"
|
||||||
|
},
|
||||||
|
"battery_power": {
|
||||||
|
"name": "Battery power"
|
||||||
|
},
|
||||||
|
"slave_error": {
|
||||||
|
"name": "Slave error",
|
||||||
|
"state": {
|
||||||
|
"no_error": "No error",
|
||||||
|
"communication": "Communication",
|
||||||
|
"reading": "Reading",
|
||||||
|
"slave": "Slave",
|
||||||
|
"waiting_wifi": "Waiting for Wi-Fi",
|
||||||
|
"waiting_communication": "Waiting communication",
|
||||||
|
"wrong_ip": "Wrong IP",
|
||||||
|
"slave_not_found": "Slave not found",
|
||||||
|
"wrong_slave": "Wrong slave",
|
||||||
|
"no_response": "No response",
|
||||||
|
"clamp_not_connected": "Clamp not connected",
|
||||||
|
"illegal_function": "Illegal function",
|
||||||
|
"illegal_data_address": "Illegal data address",
|
||||||
|
"illegal_data_value": "Illegal data value",
|
||||||
|
"server_device_failure": "Server device failure",
|
||||||
|
"acknowledge": "Acknowledge",
|
||||||
|
"server_device_busy": "Server device busy",
|
||||||
|
"negative_acknowledge": "Negative acknowledge",
|
||||||
|
"memory_parity_error": "Memory parity error",
|
||||||
|
"gateway_path_unavailable": "Gateway path unavailable",
|
||||||
|
"gateway_target_no_resp": "Gateway target no response",
|
||||||
|
"server_rtu_inactive244_timeout": "Server RTU inactive/timeout",
|
||||||
|
"invalid_server": "Invalid server",
|
||||||
|
"crc_error": "CRC error",
|
||||||
|
"fc_mismatch": "FC mismatch",
|
||||||
|
"server_id_mismatch": "Server id mismatch",
|
||||||
|
"packet_length_error": "Packet length error",
|
||||||
|
"parameter_count_error": "Parameter count error",
|
||||||
|
"parameter_limit_error": "Parameter limit error",
|
||||||
|
"request_queue_full": "Request queue full",
|
||||||
|
"illegal_ip_or_port": "Illegal IP or port",
|
||||||
|
"ip_connection_failed": "IP connection failed",
|
||||||
|
"tcp_head_mismatch": "TCP head mismatch",
|
||||||
|
"empty_message": "Empty message",
|
||||||
|
"undefined_error": "Undefined error"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"switch": {
|
"switch": {
|
||||||
|
@ -2352,7 +2352,7 @@ pytradfri[async]==9.0.1
|
|||||||
pytrafikverket==0.3.10
|
pytrafikverket==0.3.10
|
||||||
|
|
||||||
# homeassistant.components.v2c
|
# homeassistant.components.v2c
|
||||||
pytrydan==0.6.0
|
pytrydan==0.6.1
|
||||||
|
|
||||||
# homeassistant.components.usb
|
# homeassistant.components.usb
|
||||||
pyudev==0.24.1
|
pyudev==0.24.1
|
||||||
|
@ -1831,7 +1831,7 @@ pytradfri[async]==9.0.1
|
|||||||
pytrafikverket==0.3.10
|
pytrafikverket==0.3.10
|
||||||
|
|
||||||
# homeassistant.components.v2c
|
# homeassistant.components.v2c
|
||||||
pytrydan==0.6.0
|
pytrydan==0.6.1
|
||||||
|
|
||||||
# homeassistant.components.usb
|
# homeassistant.components.usb
|
||||||
pyudev==0.24.1
|
pyudev==0.24.1
|
||||||
|
@ -48,4 +48,5 @@ def mock_v2c_client() -> Generator[AsyncMock, None, None]:
|
|||||||
client = mock_client.return_value
|
client = mock_client.return_value
|
||||||
get_data_json = load_json_object_fixture("get_data.json", DOMAIN)
|
get_data_json = load_json_object_fixture("get_data.json", DOMAIN)
|
||||||
client.get_data.return_value = TrydanData.from_api(get_data_json)
|
client.get_data.return_value = TrydanData.from_api(get_data_json)
|
||||||
|
client.firmware_version = get_data_json["FirmwareVersion"]
|
||||||
yield client
|
yield client
|
||||||
|
@ -1,4 +1,340 @@
|
|||||||
# serializer version: 1
|
# serializer version: 1
|
||||||
|
# name: test_sensor
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'device_class': 'power',
|
||||||
|
'friendly_name': 'EVSE 1.1.1.1 Photovoltaic power',
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'sensor.evse_1_1_1_1_photovoltaic_power',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': '0.0',
|
||||||
|
})
|
||||||
|
list([
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'sensor',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'sensor.evse_1_1_1_1_charge_power',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||||
|
'original_icon': 'mdi:ev-station',
|
||||||
|
'original_name': 'Charge power',
|
||||||
|
'platform': 'v2c',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'charge_power',
|
||||||
|
'unique_id': '45a36e55aaddb2137c5f6602e0c38e72_charge_power',
|
||||||
|
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
|
||||||
|
}),
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'sensor',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'sensor.evse_1_1_1_1_charge_energy',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <SensorDeviceClass.ENERGY: 'energy'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Charge energy',
|
||||||
|
'platform': 'v2c',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'charge_energy',
|
||||||
|
'unique_id': '45a36e55aaddb2137c5f6602e0c38e72_charge_energy',
|
||||||
|
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||||
|
}),
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'sensor',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'sensor.evse_1_1_1_1_charge_time',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Charge time',
|
||||||
|
'platform': 'v2c',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'charge_time',
|
||||||
|
'unique_id': '45a36e55aaddb2137c5f6602e0c38e72_charge_time',
|
||||||
|
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||||
|
}),
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'sensor',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'sensor.evse_1_1_1_1_house_power',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'House power',
|
||||||
|
'platform': 'v2c',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'house_power',
|
||||||
|
'unique_id': '45a36e55aaddb2137c5f6602e0c38e72_house_power',
|
||||||
|
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
|
||||||
|
}),
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'sensor',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'sensor.evse_1_1_1_1_photovoltaic_power',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Photovoltaic power',
|
||||||
|
'platform': 'v2c',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'fv_power',
|
||||||
|
'unique_id': '45a36e55aaddb2137c5f6602e0c38e72_fv_power',
|
||||||
|
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
|
||||||
|
}),
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'options': list([
|
||||||
|
'no_error',
|
||||||
|
'communication',
|
||||||
|
'reading',
|
||||||
|
'slave',
|
||||||
|
'waiting_wifi',
|
||||||
|
'waiting_communication',
|
||||||
|
'wrong_ip',
|
||||||
|
'slave_not_found',
|
||||||
|
'wrong_slave',
|
||||||
|
'no_response',
|
||||||
|
'clamp_not_connected',
|
||||||
|
'illegal_function',
|
||||||
|
'illegal_data_address',
|
||||||
|
'illegal_data_value',
|
||||||
|
'server_device_failure',
|
||||||
|
'acknowledge',
|
||||||
|
'server_device_busy',
|
||||||
|
'negative_acknowledge',
|
||||||
|
'memory_parity_error',
|
||||||
|
'gateway_path_unavailable',
|
||||||
|
'gateway_target_no_resp',
|
||||||
|
'server_rtu_inactive244_timeout',
|
||||||
|
'invalid_server',
|
||||||
|
'crc_error',
|
||||||
|
'fc_missmatch',
|
||||||
|
'server_id_missmatch',
|
||||||
|
'packet_length_error',
|
||||||
|
'parameter_count_error',
|
||||||
|
'parameter_limit_error',
|
||||||
|
'request_queue_full',
|
||||||
|
'illegal_ip_or_port',
|
||||||
|
'ip_connection_failed',
|
||||||
|
'tcp_head_missmatch',
|
||||||
|
'empty_message',
|
||||||
|
'undefined_error',
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': <RegistryEntryDisabler.INTEGRATION: 'integration'>,
|
||||||
|
'domain': 'sensor',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'sensor.evse_1_1_1_1_slave_error',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Slave error',
|
||||||
|
'platform': 'v2c',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'slave_error',
|
||||||
|
'unique_id': '45a36e55aaddb2137c5f6602e0c38e72_slave_error',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
}),
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': <RegistryEntryDisabler.INTEGRATION: 'integration'>,
|
||||||
|
'domain': 'sensor',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'sensor.evse_1_1_1_1_battery_power',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Battery power',
|
||||||
|
'platform': 'v2c',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'battery_power',
|
||||||
|
'unique_id': '45a36e55aaddb2137c5f6602e0c38e72_battery_power',
|
||||||
|
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
# ---
|
||||||
|
# name: test_sensor[sensor.evse_1_1_1_1_battery_power-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'sensor',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'sensor.evse_1_1_1_1_battery_power',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Battery power',
|
||||||
|
'platform': 'v2c',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'battery_power',
|
||||||
|
'unique_id': 'da58ee91f38c2406c2a36d0a1a7f8569_battery_power',
|
||||||
|
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_sensor[sensor.evse_1_1_1_1_battery_power-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'device_class': 'power',
|
||||||
|
'friendly_name': 'EVSE 1.1.1.1 Battery power',
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'sensor.evse_1_1_1_1_battery_power',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': '0.0',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
# name: test_sensor[sensor.evse_1_1_1_1_charge_energy-entry]
|
# name: test_sensor[sensor.evse_1_1_1_1_charge_energy-entry]
|
||||||
EntityRegistryEntrySnapshot({
|
EntityRegistryEntrySnapshot({
|
||||||
'aliases': set({
|
'aliases': set({
|
||||||
@ -255,3 +591,125 @@
|
|||||||
'state': '0.0',
|
'state': '0.0',
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
|
# name: test_sensor[sensor.evse_1_1_1_1_slave_error-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'options': list([
|
||||||
|
'no_error',
|
||||||
|
'communication',
|
||||||
|
'reading',
|
||||||
|
'slave',
|
||||||
|
'waiting_wifi',
|
||||||
|
'waiting_communication',
|
||||||
|
'wrong_ip',
|
||||||
|
'slave_not_found',
|
||||||
|
'wrong_slave',
|
||||||
|
'no_response',
|
||||||
|
'clamp_not_connected',
|
||||||
|
'illegal_function',
|
||||||
|
'illegal_data_address',
|
||||||
|
'illegal_data_value',
|
||||||
|
'server_device_failure',
|
||||||
|
'acknowledge',
|
||||||
|
'server_device_busy',
|
||||||
|
'negative_acknowledge',
|
||||||
|
'memory_parity_error',
|
||||||
|
'gateway_path_unavailable',
|
||||||
|
'gateway_target_no_resp',
|
||||||
|
'server_rtu_inactive244_timeout',
|
||||||
|
'invalid_server',
|
||||||
|
'crc_error',
|
||||||
|
'fc_mismatch',
|
||||||
|
'server_id_mismatch',
|
||||||
|
'packet_length_error',
|
||||||
|
'parameter_count_error',
|
||||||
|
'parameter_limit_error',
|
||||||
|
'request_queue_full',
|
||||||
|
'illegal_ip_or_port',
|
||||||
|
'ip_connection_failed',
|
||||||
|
'tcp_head_mismatch',
|
||||||
|
'empty_message',
|
||||||
|
'undefined_error',
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'sensor',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'sensor.evse_1_1_1_1_slave_error',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Slave error',
|
||||||
|
'platform': 'v2c',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'slave_error',
|
||||||
|
'unique_id': 'da58ee91f38c2406c2a36d0a1a7f8569_slave_error',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_sensor[sensor.evse_1_1_1_1_slave_error-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'device_class': 'enum',
|
||||||
|
'friendly_name': 'EVSE 1.1.1.1 Slave error',
|
||||||
|
'options': list([
|
||||||
|
'no_error',
|
||||||
|
'communication',
|
||||||
|
'reading',
|
||||||
|
'slave',
|
||||||
|
'waiting_wifi',
|
||||||
|
'waiting_communication',
|
||||||
|
'wrong_ip',
|
||||||
|
'slave_not_found',
|
||||||
|
'wrong_slave',
|
||||||
|
'no_response',
|
||||||
|
'clamp_not_connected',
|
||||||
|
'illegal_function',
|
||||||
|
'illegal_data_address',
|
||||||
|
'illegal_data_value',
|
||||||
|
'server_device_failure',
|
||||||
|
'acknowledge',
|
||||||
|
'server_device_busy',
|
||||||
|
'negative_acknowledge',
|
||||||
|
'memory_parity_error',
|
||||||
|
'gateway_path_unavailable',
|
||||||
|
'gateway_target_no_resp',
|
||||||
|
'server_rtu_inactive244_timeout',
|
||||||
|
'invalid_server',
|
||||||
|
'crc_error',
|
||||||
|
'fc_mismatch',
|
||||||
|
'server_id_mismatch',
|
||||||
|
'packet_length_error',
|
||||||
|
'parameter_count_error',
|
||||||
|
'parameter_limit_error',
|
||||||
|
'request_queue_full',
|
||||||
|
'illegal_ip_or_port',
|
||||||
|
'ip_connection_failed',
|
||||||
|
'tcp_head_mismatch',
|
||||||
|
'empty_message',
|
||||||
|
'undefined_error',
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'sensor.evse_1_1_1_1_slave_error',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'waiting_wifi',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
@ -25,3 +25,43 @@ async def test_sensor(
|
|||||||
with patch("homeassistant.components.v2c.PLATFORMS", [Platform.SENSOR]):
|
with patch("homeassistant.components.v2c.PLATFORMS", [Platform.SENSOR]):
|
||||||
await init_integration(hass, mock_config_entry)
|
await init_integration(hass, mock_config_entry)
|
||||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||||
|
|
||||||
|
from homeassistant.components.v2c.sensor import _SLAVE_ERROR_OPTIONS
|
||||||
|
|
||||||
|
assert [
|
||||||
|
"no_error",
|
||||||
|
"communication",
|
||||||
|
"reading",
|
||||||
|
"slave",
|
||||||
|
"waiting_wifi",
|
||||||
|
"waiting_communication",
|
||||||
|
"wrong_ip",
|
||||||
|
"slave_not_found",
|
||||||
|
"wrong_slave",
|
||||||
|
"no_response",
|
||||||
|
"clamp_not_connected",
|
||||||
|
"illegal_function",
|
||||||
|
"illegal_data_address",
|
||||||
|
"illegal_data_value",
|
||||||
|
"server_device_failure",
|
||||||
|
"acknowledge",
|
||||||
|
"server_device_busy",
|
||||||
|
"negative_acknowledge",
|
||||||
|
"memory_parity_error",
|
||||||
|
"gateway_path_unavailable",
|
||||||
|
"gateway_target_no_resp",
|
||||||
|
"server_rtu_inactive244_timeout",
|
||||||
|
"invalid_server",
|
||||||
|
"crc_error",
|
||||||
|
"fc_mismatch",
|
||||||
|
"server_id_mismatch",
|
||||||
|
"packet_length_error",
|
||||||
|
"parameter_count_error",
|
||||||
|
"parameter_limit_error",
|
||||||
|
"request_queue_full",
|
||||||
|
"illegal_ip_or_port",
|
||||||
|
"ip_connection_failed",
|
||||||
|
"tcp_head_mismatch",
|
||||||
|
"empty_message",
|
||||||
|
"undefined_error",
|
||||||
|
] == _SLAVE_ERROR_OPTIONS
|
||||||
|
Loading…
x
Reference in New Issue
Block a user