mirror of
https://github.com/home-assistant/core.git
synced 2025-07-29 08:07:45 +00:00
Add switches for blue current integration. (#146210)
This commit is contained in:
parent
6d3872252b
commit
1c8ae8a21b
@ -15,23 +15,31 @@ from bluecurrent_api.exceptions import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import ATTR_NAME, CONF_API_TOKEN, Platform
|
from homeassistant.const import CONF_API_TOKEN, Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
|
|
||||||
from .const import DOMAIN, EVSE_ID, LOGGER, MODEL_TYPE
|
from .const import (
|
||||||
|
CHARGEPOINT_SETTINGS,
|
||||||
|
CHARGEPOINT_STATUS,
|
||||||
|
DOMAIN,
|
||||||
|
EVSE_ID,
|
||||||
|
LOGGER,
|
||||||
|
PLUG_AND_CHARGE,
|
||||||
|
VALUE,
|
||||||
|
)
|
||||||
|
|
||||||
type BlueCurrentConfigEntry = ConfigEntry[Connector]
|
type BlueCurrentConfigEntry = ConfigEntry[Connector]
|
||||||
|
|
||||||
PLATFORMS = [Platform.BUTTON, Platform.SENSOR]
|
PLATFORMS = [Platform.BUTTON, Platform.SENSOR, Platform.SWITCH]
|
||||||
CHARGE_POINTS = "CHARGE_POINTS"
|
CHARGE_POINTS = "CHARGE_POINTS"
|
||||||
DATA = "data"
|
DATA = "data"
|
||||||
DELAY = 5
|
DELAY = 5
|
||||||
|
|
||||||
GRID = "GRID"
|
GRID = "GRID"
|
||||||
OBJECT = "object"
|
OBJECT = "object"
|
||||||
VALUE_TYPES = ["CH_STATUS"]
|
VALUE_TYPES = [CHARGEPOINT_STATUS, CHARGEPOINT_SETTINGS]
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
@ -94,7 +102,7 @@ class Connector:
|
|||||||
elif object_name in VALUE_TYPES:
|
elif object_name in VALUE_TYPES:
|
||||||
value_data: dict = message[DATA]
|
value_data: dict = message[DATA]
|
||||||
evse_id = value_data.pop(EVSE_ID)
|
evse_id = value_data.pop(EVSE_ID)
|
||||||
self.update_charge_point(evse_id, value_data)
|
self.update_charge_point(evse_id, object_name, value_data)
|
||||||
|
|
||||||
# gets grid key / values
|
# gets grid key / values
|
||||||
elif GRID in object_name:
|
elif GRID in object_name:
|
||||||
@ -106,26 +114,37 @@ class Connector:
|
|||||||
"""Handle incoming chargepoint data."""
|
"""Handle incoming chargepoint data."""
|
||||||
await asyncio.gather(
|
await asyncio.gather(
|
||||||
*(
|
*(
|
||||||
self.handle_charge_point(
|
self.handle_charge_point(entry[EVSE_ID], entry)
|
||||||
entry[EVSE_ID], entry[MODEL_TYPE], entry[ATTR_NAME]
|
|
||||||
)
|
|
||||||
for entry in charge_points_data
|
for entry in charge_points_data
|
||||||
),
|
),
|
||||||
self.client.get_grid_status(charge_points_data[0][EVSE_ID]),
|
self.client.get_grid_status(charge_points_data[0][EVSE_ID]),
|
||||||
)
|
)
|
||||||
|
|
||||||
async def handle_charge_point(self, evse_id: str, model: str, name: str) -> None:
|
async def handle_charge_point(
|
||||||
|
self, evse_id: str, charge_point: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
"""Add the chargepoint and request their data."""
|
"""Add the chargepoint and request their data."""
|
||||||
self.add_charge_point(evse_id, model, name)
|
self.add_charge_point(evse_id, charge_point)
|
||||||
await self.client.get_status(evse_id)
|
await self.client.get_status(evse_id)
|
||||||
|
|
||||||
def add_charge_point(self, evse_id: str, model: str, name: str) -> None:
|
def add_charge_point(self, evse_id: str, charge_point: dict[str, Any]) -> None:
|
||||||
"""Add a charge point to charge_points."""
|
"""Add a charge point to charge_points."""
|
||||||
self.charge_points[evse_id] = {MODEL_TYPE: model, ATTR_NAME: name}
|
self.charge_points[evse_id] = charge_point
|
||||||
|
|
||||||
def update_charge_point(self, evse_id: str, data: dict) -> None:
|
def update_charge_point(self, evse_id: str, update_type: str, data: dict) -> None:
|
||||||
"""Update the charge point data."""
|
"""Update the charge point data."""
|
||||||
self.charge_points[evse_id].update(data)
|
charge_point = self.charge_points[evse_id]
|
||||||
|
if update_type == CHARGEPOINT_SETTINGS:
|
||||||
|
# Update the plug and charge object. The library parses this object to a bool instead of an object.
|
||||||
|
plug_and_charge = charge_point.get(PLUG_AND_CHARGE)
|
||||||
|
if plug_and_charge is not None:
|
||||||
|
plug_and_charge[VALUE] = data[PLUG_AND_CHARGE]
|
||||||
|
|
||||||
|
# Remove the plug and charge object from the data list before updating.
|
||||||
|
del data[PLUG_AND_CHARGE]
|
||||||
|
|
||||||
|
charge_point.update(data)
|
||||||
|
|
||||||
self.dispatch_charge_point_update_signal(evse_id)
|
self.dispatch_charge_point_update_signal(evse_id)
|
||||||
|
|
||||||
def dispatch_charge_point_update_signal(self, evse_id: str) -> None:
|
def dispatch_charge_point_update_signal(self, evse_id: str) -> None:
|
||||||
|
@ -8,3 +8,14 @@ LOGGER = logging.getLogger(__package__)
|
|||||||
|
|
||||||
EVSE_ID = "evse_id"
|
EVSE_ID = "evse_id"
|
||||||
MODEL_TYPE = "model_type"
|
MODEL_TYPE = "model_type"
|
||||||
|
PLUG_AND_CHARGE = "plug_and_charge"
|
||||||
|
VALUE = "value"
|
||||||
|
PERMISSION = "permission"
|
||||||
|
CHARGEPOINT_STATUS = "CH_STATUS"
|
||||||
|
CHARGEPOINT_SETTINGS = "CH_SETTINGS"
|
||||||
|
BLOCK = "block"
|
||||||
|
UNAVAILABLE = "unavailable"
|
||||||
|
AVAILABLE = "available"
|
||||||
|
LINKED_CHARGE_CARDS = "linked_charge_cards_only"
|
||||||
|
PUBLIC_CHARGING = "public_charging"
|
||||||
|
ACTIVITY = "activity"
|
||||||
|
@ -30,6 +30,17 @@
|
|||||||
"stop_charge_session": {
|
"stop_charge_session": {
|
||||||
"default": "mdi:stop"
|
"default": "mdi:stop"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"switch": {
|
||||||
|
"plug_and_charge": {
|
||||||
|
"default": "mdi:ev-plug-type2"
|
||||||
|
},
|
||||||
|
"linked_charge_cards": {
|
||||||
|
"default": "mdi:account-group"
|
||||||
|
},
|
||||||
|
"block": {
|
||||||
|
"default": "mdi:lock"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,17 @@
|
|||||||
"reset": {
|
"reset": {
|
||||||
"name": "Reset"
|
"name": "Reset"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"switch": {
|
||||||
|
"plug_and_charge": {
|
||||||
|
"name": "Plug & Charge"
|
||||||
|
},
|
||||||
|
"linked_charge_cards_only": {
|
||||||
|
"name": "Linked charging cards only"
|
||||||
|
},
|
||||||
|
"block": {
|
||||||
|
"name": "Block charge point"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
169
homeassistant/components/blue_current/switch.py
Normal file
169
homeassistant/components/blue_current/switch.py
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
"""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]
|
@ -4,18 +4,28 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from asyncio import Event, Future
|
from asyncio import Event, Future
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from typing import Any
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
from bluecurrent_api import Client
|
from bluecurrent_api import Client
|
||||||
|
|
||||||
|
from homeassistant.components.blue_current import EVSE_ID, PLUG_AND_CHARGE
|
||||||
|
from homeassistant.components.blue_current.const import PUBLIC_CHARGING
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
DEFAULT_CHARGE_POINT_OPTIONS = {
|
||||||
|
PLUG_AND_CHARGE: {"value": False, "permission": "write"},
|
||||||
|
PUBLIC_CHARGING: {"value": True, "permission": "write"},
|
||||||
|
}
|
||||||
|
|
||||||
DEFAULT_CHARGE_POINT = {
|
DEFAULT_CHARGE_POINT = {
|
||||||
"evse_id": "101",
|
"evse_id": "101",
|
||||||
"model_type": "",
|
"model_type": "",
|
||||||
"name": "",
|
"name": "",
|
||||||
|
"activity": "available",
|
||||||
|
**DEFAULT_CHARGE_POINT_OPTIONS,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -77,11 +87,20 @@ def create_client_mock(
|
|||||||
"""Send the grid status to the callback."""
|
"""Send the grid status to the callback."""
|
||||||
await client_mock.receiver({"object": "GRID_STATUS", "data": grid})
|
await client_mock.receiver({"object": "GRID_STATUS", "data": grid})
|
||||||
|
|
||||||
|
async def update_charge_point(
|
||||||
|
evse_id: str, event_object: str, settings: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Update the charge point data by sending an event."""
|
||||||
|
await client_mock.receiver(
|
||||||
|
{"object": event_object, "data": {EVSE_ID: evse_id, **settings}}
|
||||||
|
)
|
||||||
|
|
||||||
client_mock.connect.side_effect = connect
|
client_mock.connect.side_effect = connect
|
||||||
client_mock.wait_for_charge_points.side_effect = wait_for_charge_points
|
client_mock.wait_for_charge_points.side_effect = wait_for_charge_points
|
||||||
client_mock.get_charge_points.side_effect = get_charge_points
|
client_mock.get_charge_points.side_effect = get_charge_points
|
||||||
client_mock.get_status.side_effect = get_status
|
client_mock.get_status.side_effect = get_status
|
||||||
client_mock.get_grid_status.side_effect = get_grid_status
|
client_mock.get_grid_status.side_effect = get_grid_status
|
||||||
|
client_mock.update_charge_point = update_charge_point
|
||||||
|
|
||||||
return client_mock
|
return client_mock
|
||||||
|
|
||||||
|
@ -7,17 +7,10 @@ import pytest
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
|
||||||
from . import init_integration
|
from . import DEFAULT_CHARGE_POINT, init_integration
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
charge_point = {
|
|
||||||
"evse_id": "101",
|
|
||||||
"model_type": "",
|
|
||||||
"name": "",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
charge_point_status = {
|
charge_point_status = {
|
||||||
"actual_v1": 14,
|
"actual_v1": 14,
|
||||||
"actual_v2": 18,
|
"actual_v2": 18,
|
||||||
@ -97,7 +90,7 @@ async def test_sensors_created(
|
|||||||
hass,
|
hass,
|
||||||
config_entry,
|
config_entry,
|
||||||
"sensor",
|
"sensor",
|
||||||
charge_point,
|
DEFAULT_CHARGE_POINT,
|
||||||
charge_point_status | charge_point_status_timestamps,
|
charge_point_status | charge_point_status_timestamps,
|
||||||
grid,
|
grid,
|
||||||
)
|
)
|
||||||
@ -116,7 +109,7 @@ async def test_sensors(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test the underlying sensors."""
|
"""Test the underlying sensors."""
|
||||||
await init_integration(
|
await init_integration(
|
||||||
hass, config_entry, "sensor", charge_point, charge_point_status, grid
|
hass, config_entry, "sensor", DEFAULT_CHARGE_POINT, charge_point_status, grid
|
||||||
)
|
)
|
||||||
|
|
||||||
for entity_id, key in charge_point_entity_ids.items():
|
for entity_id, key in charge_point_entity_ids.items():
|
||||||
|
152
tests/components/blue_current/test_switch.py
Normal file
152
tests/components/blue_current/test_switch.py
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
"""The tests for Bluecurrent switches."""
|
||||||
|
|
||||||
|
from homeassistant.components.blue_current import CHARGEPOINT_SETTINGS, PLUG_AND_CHARGE
|
||||||
|
from homeassistant.components.blue_current.const import (
|
||||||
|
ACTIVITY,
|
||||||
|
CHARGEPOINT_STATUS,
|
||||||
|
PUBLIC_CHARGING,
|
||||||
|
UNAVAILABLE,
|
||||||
|
)
|
||||||
|
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE, Platform
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
from homeassistant.helpers.entity_registry import EntityRegistry
|
||||||
|
|
||||||
|
from . import DEFAULT_CHARGE_POINT, init_integration
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
|
async def test_switches(
|
||||||
|
hass: HomeAssistant, config_entry: MockConfigEntry, entity_registry: EntityRegistry
|
||||||
|
) -> None:
|
||||||
|
"""Test the underlying switches."""
|
||||||
|
|
||||||
|
await init_integration(hass, config_entry, Platform.SWITCH)
|
||||||
|
|
||||||
|
entity_entries = er.async_entries_for_config_entry(
|
||||||
|
entity_registry, config_entry.entry_id
|
||||||
|
)
|
||||||
|
|
||||||
|
for switch in entity_entries:
|
||||||
|
state = hass.states.get(switch.entity_id)
|
||||||
|
|
||||||
|
assert state and state.state == STATE_OFF
|
||||||
|
entry = entity_registry.async_get(switch.entity_id)
|
||||||
|
assert entry and entry.unique_id == switch.unique_id
|
||||||
|
|
||||||
|
|
||||||
|
async def test_switches_offline(
|
||||||
|
hass: HomeAssistant, config_entry: MockConfigEntry, entity_registry: EntityRegistry
|
||||||
|
) -> None:
|
||||||
|
"""Test if switches are disabled when needed."""
|
||||||
|
charge_point = DEFAULT_CHARGE_POINT.copy()
|
||||||
|
charge_point[ACTIVITY] = "offline"
|
||||||
|
|
||||||
|
await init_integration(hass, config_entry, Platform.SWITCH, charge_point)
|
||||||
|
|
||||||
|
entity_entries = er.async_entries_for_config_entry(
|
||||||
|
entity_registry, config_entry.entry_id
|
||||||
|
)
|
||||||
|
|
||||||
|
for switch in entity_entries:
|
||||||
|
state = hass.states.get(switch.entity_id)
|
||||||
|
|
||||||
|
assert state and state.state == UNAVAILABLE
|
||||||
|
entry = entity_registry.async_get(switch.entity_id)
|
||||||
|
assert entry and entry.entity_id == switch.entity_id
|
||||||
|
|
||||||
|
|
||||||
|
async def test_block_switch_availability(
|
||||||
|
hass: HomeAssistant, config_entry: MockConfigEntry, entity_registry: EntityRegistry
|
||||||
|
) -> None:
|
||||||
|
"""Test if the block switch is unavailable when charging."""
|
||||||
|
charge_point = DEFAULT_CHARGE_POINT.copy()
|
||||||
|
charge_point[ACTIVITY] = "charging"
|
||||||
|
|
||||||
|
await init_integration(hass, config_entry, Platform.SWITCH, charge_point)
|
||||||
|
|
||||||
|
state = hass.states.get("switch.101_block_charge_point")
|
||||||
|
assert state and state.state == UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
|
async def test_toggle(
|
||||||
|
hass: HomeAssistant, config_entry: MockConfigEntry, entity_registry: EntityRegistry
|
||||||
|
) -> None:
|
||||||
|
"""Test the on / off methods and if the switch gets updated."""
|
||||||
|
await init_integration(hass, config_entry, Platform.SWITCH)
|
||||||
|
|
||||||
|
entity_entries = er.async_entries_for_config_entry(
|
||||||
|
entity_registry, config_entry.entry_id
|
||||||
|
)
|
||||||
|
|
||||||
|
for switch in entity_entries:
|
||||||
|
state = hass.states.get(switch.entity_id)
|
||||||
|
|
||||||
|
assert state and state.state == STATE_OFF
|
||||||
|
await hass.services.async_call(
|
||||||
|
"switch",
|
||||||
|
"turn_on",
|
||||||
|
{"entity_id": switch.entity_id},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
state = hass.states.get(switch.entity_id)
|
||||||
|
assert state and state.state == STATE_ON
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"switch",
|
||||||
|
"turn_off",
|
||||||
|
{"entity_id": switch.entity_id},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
state = hass.states.get(switch.entity_id)
|
||||||
|
assert state and state.state == STATE_OFF
|
||||||
|
|
||||||
|
|
||||||
|
async def test_setting_change(
|
||||||
|
hass: HomeAssistant, config_entry: MockConfigEntry, entity_registry: EntityRegistry
|
||||||
|
) -> None:
|
||||||
|
"""Test if the state of the switches are updated when an update message from the websocket comes in."""
|
||||||
|
integration = await init_integration(hass, config_entry, Platform.SWITCH)
|
||||||
|
client_mock = integration[0]
|
||||||
|
|
||||||
|
entity_entries = er.async_entries_for_config_entry(
|
||||||
|
entity_registry, config_entry.entry_id
|
||||||
|
)
|
||||||
|
|
||||||
|
for switch in entity_entries:
|
||||||
|
state = hass.states.get(switch.entity_id)
|
||||||
|
assert state.state == STATE_OFF
|
||||||
|
|
||||||
|
await client_mock.update_charge_point(
|
||||||
|
"101",
|
||||||
|
CHARGEPOINT_SETTINGS,
|
||||||
|
{
|
||||||
|
PLUG_AND_CHARGE: True,
|
||||||
|
PUBLIC_CHARGING: {"value": False, "permission": "write"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
charge_cards_only_switch = hass.states.get("switch.101_linked_charging_cards_only")
|
||||||
|
assert charge_cards_only_switch.state == STATE_ON
|
||||||
|
|
||||||
|
plug_and_charge_switch = hass.states.get("switch.101_plug_charge")
|
||||||
|
assert plug_and_charge_switch.state == STATE_ON
|
||||||
|
|
||||||
|
plug_and_charge_switch = hass.states.get("switch.101_block_charge_point")
|
||||||
|
assert plug_and_charge_switch.state == STATE_OFF
|
||||||
|
|
||||||
|
await client_mock.update_charge_point(
|
||||||
|
"101", CHARGEPOINT_STATUS, {ACTIVITY: UNAVAILABLE}
|
||||||
|
)
|
||||||
|
|
||||||
|
charge_cards_only_switch = hass.states.get("switch.101_linked_charging_cards_only")
|
||||||
|
assert charge_cards_only_switch.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
plug_and_charge_switch = hass.states.get("switch.101_plug_charge")
|
||||||
|
assert plug_and_charge_switch.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
switch = hass.states.get("switch.101_block_charge_point")
|
||||||
|
assert switch.state == STATE_ON
|
Loading…
x
Reference in New Issue
Block a user