Add switch platform to the Lektrico integration (#126721)

This commit is contained in:
Lektri.co 2024-10-23 17:20:08 +03:00 committed by GitHub
parent 9ec4881d8d
commit 90547da007
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 271 additions and 9 deletions

View File

@ -15,6 +15,7 @@ CHARGERS_PLATFORMS: list[Platform] = [
Platform.BUTTON,
Platform.NUMBER,
Platform.SENSOR,
Platform.SWITCH,
]
# List the platforms that load balancer device supports.

View File

@ -62,11 +62,13 @@ SENSORS_FOR_CHARGERS: tuple[LektricoSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.ENUM,
options=[
"available",
"charging",
"connected",
"error",
"locked",
"need_auth",
"paused",
"charging",
"error",
"paused_by_scheduler",
"updating_firmware",
],
translation_key="state",

View File

@ -54,11 +54,13 @@
"name": "State",
"state": {
"available": "Available",
"charging": "Charging",
"connected": "Connected",
"error": "Error",
"locked": "Locked",
"need_auth": "Waiting for authentication",
"paused": "Paused",
"charging": "Charging",
"error": "Error",
"paused_by_scheduler": "Paused by scheduler",
"updating_firmware": "Updating firmware"
}
},
@ -126,6 +128,17 @@
"pf_l3": {
"name": "Power factor L3"
}
},
"switch": {
"authentication": {
"name": "Authentication"
},
"force_single_phase": {
"name": "Force single phase"
},
"lock": {
"name": "Lock"
}
}
}
}

View File

@ -0,0 +1,116 @@
"""Support for Lektrico switch entities."""
from collections.abc import Callable, Coroutine
from dataclasses import dataclass
from typing import Any
from lektricowifi import Device
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.const import ATTR_SERIAL_NUMBER, CONF_TYPE, EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import LektricoConfigEntry, LektricoDeviceDataUpdateCoordinator
from .entity import LektricoEntity
@dataclass(frozen=True, kw_only=True)
class LektricoSwitchEntityDescription(SwitchEntityDescription):
"""Describes Lektrico switch entity."""
value_fn: Callable[[dict[str, Any]], bool]
set_value_fn: Callable[[Device, dict[Any, Any], bool], Coroutine[Any, Any, Any]]
SWITCHS_FOR_ALL_CHARGERS: tuple[LektricoSwitchEntityDescription, ...] = (
LektricoSwitchEntityDescription(
key="authentication",
translation_key="authentication",
entity_category=EntityCategory.CONFIG,
value_fn=lambda data: bool(data["require_auth"]),
set_value_fn=lambda device, data, value: device.set_auth(not value),
),
LektricoSwitchEntityDescription(
key="lock",
translation_key="lock",
entity_category=EntityCategory.CONFIG,
value_fn=lambda data: str(data["charger_state"]) == "locked",
set_value_fn=lambda device, data, value: device.set_charger_locked(value),
),
)
SWITCHS_FOR_3_PHASE_CHARGERS: tuple[LektricoSwitchEntityDescription, ...] = (
LektricoSwitchEntityDescription(
key="force_single_phase",
translation_key="force_single_phase",
entity_category=EntityCategory.CONFIG,
value_fn=lambda data: data["relay_mode"] == 1,
set_value_fn=lambda device, data, value: (
device.set_relay_mode(data["dynamic_current"], 1)
if value
else device.set_relay_mode(data["dynamic_current"], 3)
),
),
)
async def async_setup_entry(
hass: HomeAssistant,
entry: LektricoConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Lektrico switch entities based on a config entry."""
coordinator = entry.runtime_data
switchs_to_be_used: tuple[LektricoSwitchEntityDescription, ...]
if coordinator.device_type == Device.TYPE_3P22K:
switchs_to_be_used = SWITCHS_FOR_ALL_CHARGERS + SWITCHS_FOR_3_PHASE_CHARGERS
else:
switchs_to_be_used = SWITCHS_FOR_ALL_CHARGERS
async_add_entities(
LektricoSwitch(
description,
coordinator,
f"{entry.data[CONF_TYPE]}_{entry.data[ATTR_SERIAL_NUMBER]}",
)
for description in switchs_to_be_used
)
class LektricoSwitch(LektricoEntity, SwitchEntity):
"""Defines a Lektrico switch entity."""
entity_description: LektricoSwitchEntityDescription
def __init__(
self,
description: LektricoSwitchEntityDescription,
coordinator: LektricoDeviceDataUpdateCoordinator,
device_name: str,
) -> None:
"""Initialize Lektrico switch."""
super().__init__(coordinator, device_name)
self.entity_description = description
self._attr_unique_id = f"{coordinator.serial_number}_{description.key}"
@property
def is_on(self) -> bool:
"""Return the state of the switch."""
return self.entity_description.value_fn(self.coordinator.data)
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the switch on."""
await self.entity_description.set_value_fn(
self.coordinator.device, self.coordinator.data, True
)
await self.coordinator.async_request_refresh()
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the switch off."""
await self.entity_description.set_value_fn(
self.coordinator.device, self.coordinator.data, False
)
await self.coordinator.async_request_refresh()

View File

@ -13,5 +13,6 @@
"led_max_brightness": 20,
"dynamic_current": 32,
"user_current": 32,
"lb_mode": 0
"lb_mode": 0,
"require_auth": true
}

View File

@ -381,11 +381,13 @@
'capabilities': dict({
'options': list([
'available',
'charging',
'connected',
'error',
'locked',
'need_auth',
'paused',
'charging',
'error',
'paused_by_scheduler',
'updating_firmware',
]),
}),
@ -423,11 +425,13 @@
'friendly_name': '1p7k_500006 State',
'options': list([
'available',
'charging',
'connected',
'error',
'locked',
'need_auth',
'paused',
'charging',
'error',
'paused_by_scheduler',
'updating_firmware',
]),
}),

View File

@ -0,0 +1,93 @@
# serializer version: 1
# name: test_all_entities[switch.1p7k_500006_authentication-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.1p7k_500006_authentication',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Authentication',
'platform': 'lektrico',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'authentication',
'unique_id': '500006_authentication',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[switch.1p7k_500006_authentication-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': '1p7k_500006 Authentication',
}),
'context': <ANY>,
'entity_id': 'switch.1p7k_500006_authentication',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_all_entities[switch.1p7k_500006_lock-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.1p7k_500006_lock',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Lock',
'platform': 'lektrico',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'lock',
'unique_id': '500006_lock',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[switch.1p7k_500006_lock-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': '1p7k_500006 Lock',
}),
'context': <ANY>,
'entity_id': 'switch.1p7k_500006_lock',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---

View File

@ -0,0 +1,32 @@
"""Tests for the Lektrico switch platform."""
from unittest.mock import AsyncMock, patch
from syrupy import SnapshotAssertion
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from . import setup_integration
from tests.common import MockConfigEntry, snapshot_platform
async def test_all_entities(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
mock_device: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
) -> None:
"""Test all entities."""
with patch.multiple(
"homeassistant.components.lektrico",
CHARGERS_PLATFORMS=[Platform.SWITCH],
LB_DEVICES_PLATFORMS=[Platform.SWITCH],
):
await setup_integration(hass, mock_config_entry)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)