170 lines
5.5 KiB
Python
170 lines
5.5 KiB
Python
"""Support for Blue Current switches."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
from dataclasses import dataclass
|
|
from typing import Any
|
|
|
|
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
|
|
from homeassistant.core import HomeAssistant, callback
|
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
|
|
|
from . import PLUG_AND_CHARGE, BlueCurrentConfigEntry, Connector
|
|
from .const import (
|
|
AVAILABLE,
|
|
BLOCK,
|
|
LINKED_CHARGE_CARDS,
|
|
PUBLIC_CHARGING,
|
|
UNAVAILABLE,
|
|
VALUE,
|
|
)
|
|
from .entity import ChargepointEntity
|
|
|
|
|
|
@dataclass(kw_only=True, frozen=True)
|
|
class BlueCurrentSwitchEntityDescription(SwitchEntityDescription):
|
|
"""Describes a Blue Current switch entity."""
|
|
|
|
function: Callable[[Connector, str, bool], Any]
|
|
|
|
turn_on_off_fn: Callable[[str, Connector], tuple[bool, bool]]
|
|
"""Update the switch based on the latest data received from the websocket. The first returned boolean is _attr_is_on, the second one has_value."""
|
|
|
|
|
|
def update_on_value_and_activity(
|
|
key: str, evse_id: str, connector: Connector, reverse_is_on: bool = False
|
|
) -> tuple[bool, bool]:
|
|
"""Return the updated state of the switch based on received chargepoint data and activity."""
|
|
|
|
data_object = connector.charge_points[evse_id].get(key)
|
|
is_on = data_object[VALUE] if data_object is not None else None
|
|
activity = connector.charge_points[evse_id].get("activity")
|
|
|
|
if is_on is not None and activity == AVAILABLE:
|
|
return is_on if not reverse_is_on else not is_on, True
|
|
return False, False
|
|
|
|
|
|
def update_block_switch(evse_id: str, connector: Connector) -> tuple[bool, bool]:
|
|
"""Return the updated data for a block switch."""
|
|
activity = connector.charge_points[evse_id].get("activity")
|
|
return activity == UNAVAILABLE, activity in [AVAILABLE, UNAVAILABLE]
|
|
|
|
|
|
def update_charge_point(
|
|
key: str, evse_id: str, connector: Connector, new_switch_value: bool
|
|
) -> None:
|
|
"""Change charge point data when the state of the switch changes."""
|
|
data_objects = connector.charge_points[evse_id].get(key)
|
|
if data_objects is not None:
|
|
data_objects[VALUE] = new_switch_value
|
|
|
|
|
|
async def set_plug_and_charge(connector: Connector, evse_id: str, value: bool) -> None:
|
|
"""Toggle the plug and charge setting for a specific charging point."""
|
|
await connector.client.set_plug_and_charge(evse_id, value)
|
|
update_charge_point(PLUG_AND_CHARGE, evse_id, connector, value)
|
|
|
|
|
|
async def set_linked_charge_cards(
|
|
connector: Connector, evse_id: str, value: bool
|
|
) -> None:
|
|
"""Toggle the plug and charge setting for a specific charging point."""
|
|
await connector.client.set_linked_charge_cards_only(evse_id, value)
|
|
update_charge_point(PUBLIC_CHARGING, evse_id, connector, not value)
|
|
|
|
|
|
SWITCHES = (
|
|
BlueCurrentSwitchEntityDescription(
|
|
key=PLUG_AND_CHARGE,
|
|
translation_key=PLUG_AND_CHARGE,
|
|
function=set_plug_and_charge,
|
|
turn_on_off_fn=lambda evse_id, connector: (
|
|
update_on_value_and_activity(PLUG_AND_CHARGE, evse_id, connector)
|
|
),
|
|
),
|
|
BlueCurrentSwitchEntityDescription(
|
|
key=LINKED_CHARGE_CARDS,
|
|
translation_key=LINKED_CHARGE_CARDS,
|
|
function=set_linked_charge_cards,
|
|
turn_on_off_fn=lambda evse_id, connector: (
|
|
update_on_value_and_activity(
|
|
PUBLIC_CHARGING, evse_id, connector, reverse_is_on=True
|
|
)
|
|
),
|
|
),
|
|
BlueCurrentSwitchEntityDescription(
|
|
key=BLOCK,
|
|
translation_key=BLOCK,
|
|
function=lambda connector, evse_id, value: connector.client.block(
|
|
evse_id, value
|
|
),
|
|
turn_on_off_fn=update_block_switch,
|
|
),
|
|
)
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
entry: BlueCurrentConfigEntry,
|
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
|
) -> None:
|
|
"""Set up Blue Current switches."""
|
|
connector = entry.runtime_data
|
|
|
|
async_add_entities(
|
|
ChargePointSwitch(
|
|
connector,
|
|
evse_id,
|
|
switch,
|
|
)
|
|
for evse_id in connector.charge_points
|
|
for switch in SWITCHES
|
|
)
|
|
|
|
|
|
class ChargePointSwitch(ChargepointEntity, SwitchEntity):
|
|
"""Base charge point switch."""
|
|
|
|
has_value = True
|
|
entity_description: BlueCurrentSwitchEntityDescription
|
|
|
|
def __init__(
|
|
self,
|
|
connector: Connector,
|
|
evse_id: str,
|
|
switch: BlueCurrentSwitchEntityDescription,
|
|
) -> None:
|
|
"""Initialize the switch."""
|
|
super().__init__(connector, evse_id)
|
|
|
|
self.key = switch.key
|
|
self.entity_description = switch
|
|
self.evse_id = evse_id
|
|
self._attr_available = True
|
|
self._attr_unique_id = f"{switch.key}_{evse_id}"
|
|
|
|
async def call_function(self, value: bool) -> None:
|
|
"""Call the function to set setting."""
|
|
await self.entity_description.function(self.connector, self.evse_id, value)
|
|
|
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
|
"""Turn the entity on."""
|
|
await self.call_function(True)
|
|
self._attr_is_on = True
|
|
self.async_write_ha_state()
|
|
|
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
|
"""Turn the entity on."""
|
|
await self.call_function(False)
|
|
self._attr_is_on = False
|
|
self.async_write_ha_state()
|
|
|
|
@callback
|
|
def update_from_latest_data(self) -> None:
|
|
"""Fetch new state data for the switch."""
|
|
new_state = self.entity_description.turn_on_off_fn(self.evse_id, self.connector)
|
|
self._attr_is_on = new_state[0]
|
|
self.has_value = new_state[1]
|