diff --git a/custom_components/alfen_wallbox/__init__.py b/custom_components/alfen_wallbox/__init__.py index dd19f2c..4a1301b 100644 --- a/custom_components/alfen_wallbox/__init__.py +++ b/custom_components/alfen_wallbox/__init__.py @@ -32,7 +32,8 @@ Platform.BINARY_SENSOR, Platform.SWITCH, Platform.NUMBER, - Platform.BUTTON + Platform.BUTTON, + Platform.TEXT ] SCAN_INTERVAL = timedelta(seconds=60) diff --git a/custom_components/alfen_wallbox/alfen.py b/custom_components/alfen_wallbox/alfen.py index 3101471..5f4ab63 100644 --- a/custom_components/alfen_wallbox/alfen.py +++ b/custom_components/alfen_wallbox/alfen.py @@ -5,7 +5,7 @@ from datetime import timedelta from homeassistant.util import Throttle -from .const import CAT, CAT_GENERIC, CAT_GENERIC2, CAT_METER1, CAT_METER4, CAT_OCPP, CAT_STATES, CAT_TEMP,CAT_MBUS_TCP, CMD, DOMAIN, ALFEN_PRODUCT_MAP, ID, METHOD_GET, METHOD_POST, OFFSET, INFO, LOGIN, LOGOUT, PARAM_COMMAND, PARAM_PASSWORD, PARAM_USERNAME, PROP, PROPERTIES, TOTAL, VALUE +from .const import CAT, CAT_GENERIC, CAT_GENERIC2, CAT_METER1, CAT_METER4, CAT_OCPP, CAT_STATES, CAT_TEMP,CAT_MBUS_TCP,CAT_COMM, CMD, DOMAIN, ALFEN_PRODUCT_MAP, ID, METHOD_GET, METHOD_POST, OFFSET, INFO, LOGIN, LOGOUT, PARAM_COMMAND, PARAM_PASSWORD, PARAM_USERNAME, PROP, PROPERTIES, TOTAL, VALUE HEADER_JSON = {"content-type": "alfen/json; charset=utf-8"} POST_HEADER_JSON = {"content-type": "application/json"} @@ -124,7 +124,7 @@ async def _do_update(self): await self.login() properties = [] - for cat in (CAT_GENERIC, CAT_GENERIC2, CAT_METER1, CAT_STATES, CAT_TEMP, CAT_OCPP, CAT_METER4, CAT_MBUS_TCP): + for cat in (CAT_GENERIC, CAT_GENERIC2, CAT_METER1, CAT_STATES, CAT_TEMP, CAT_OCPP, CAT_METER4, CAT_MBUS_TCP, CAT_COMM): nextRequest = True offset = 0 while (nextRequest): diff --git a/custom_components/alfen_wallbox/const.py b/custom_components/alfen_wallbox/const.py index 95876e7..2f52f17 100644 --- a/custom_components/alfen_wallbox/const.py +++ b/custom_components/alfen_wallbox/const.py @@ -29,6 +29,7 @@ CAT_TEMP = "temp" CAT_OCPP = "ocpp" CAT_MBUS_TCP = "MbusTCP" +CAT_COMM = "comm" COMMAND_REBOOT = "reboot" diff --git a/custom_components/alfen_wallbox/number.py b/custom_components/alfen_wallbox/number.py index df246c4..3a3629d 100644 --- a/custom_components/alfen_wallbox/number.py +++ b/custom_components/alfen_wallbox/number.py @@ -14,6 +14,7 @@ PERCENTAGE, UnitOfElectricCurrent, UnitOfPower, + UnitOfTime, ) import voluptuous as vol @@ -165,6 +166,35 @@ class AlfenNumberDescription(NumberEntityDescription, AlfenNumberDescriptionMixi unit_of_measurement=UnitOfElectricCurrent.AMPERE, api_param="21B9_0", ), + AlfenNumberDescription( + key="auth_re_authorize_after_power_outage", + name="Auth. Re-authorize after Power Outage (s)", + state=None, + icon="mdi:timer-sand", + assumed_state=False, + device_class=None, + native_min_value=0, + native_max_value=30, + native_step=1, + custom_mode=None, + unit_of_measurement=UnitOfTime.SECONDS, + api_param="2169_0", + ), + AlfenNumberDescription( + key="auth_connection_timeout", + name="Auth. Connection Timeout (s)", + state=None, + icon="mdi:timer-sand", + assumed_state=False, + device_class=None, + native_min_value=0, + native_max_value=30, + native_step=1, + custom_mode=None, + unit_of_measurement=UnitOfTime.SECONDS, + api_param="2169_0", + ), + ) diff --git a/custom_components/alfen_wallbox/select.py b/custom_components/alfen_wallbox/select.py index 9486152..e07426b 100644 --- a/custom_components/alfen_wallbox/select.py +++ b/custom_components/alfen_wallbox/select.py @@ -55,19 +55,6 @@ class AlfenSelectDescription(SelectEntityDescription, AlfenSelectDescriptionMixi "L3,L2,L1": "L3L2L1", } -SAFE_AMPS_DICT: Final[dict[str, int]] = { - "1 A": 1, - "2 A": 2, - "3 A": 3, - "4 A": 4, - "5 A": 5, - "6 A": 6, - "7 A": 7, - "8 A": 8, - "9 A": 9, - "10 A": 10, -} - AUTH_MODE_DICT: Final[dict[str, int]] = { "Plug and Charge": 0, "RFID": 2 @@ -159,25 +146,16 @@ class AlfenSelectDescription(SelectEntityDescription, AlfenSelectDescriptionMixi ), AlfenSelectDescription( - key="alb_phase_connection", - name="Active Load Balancing Phase Connection", + key="lb_phase_connection", + name="Load Balancing Phase Connection", icon=None, options=list(PHASE_ROTATION_DICT), options_dict=PHASE_ROTATION_DICT, api_param="2069_0", ), - # AlfenSelectDescription( - # key="alb_safe_current", - # name="Active Load Balancing Safe Current", - # icon="mdi:current-ac", - # options=list(SAFE_AMPS_DICT), - # options_dict=SAFE_AMPS_DICT, - # api_param="2068_0", - # ), - AlfenSelectDescription( key="auth_mode", - name="Authorization Mode", + name="Auth. Mode", icon="mdi:key", options=list(AUTH_MODE_DICT), options_dict=AUTH_MODE_DICT, @@ -273,12 +251,12 @@ class AlfenSelectDescription(SelectEntityDescription, AlfenSelectDescriptionMixi api_param="2189_0", ), AlfenSelectDescription( - key="ps_installation_direct external suspend signal", + key="ps_installation_direct_external_suspend_signal", name="Installation Direct External Suspend Signal", icon="mdi:scale-balance", options=list(DIRECT_EXTERNAL_SUSPEND_SIGNAL), options_dict=DIRECT_EXTERNAL_SUSPEND_SIGNAL, - api_param="2189_0", + api_param="216C_0", ), ) diff --git a/custom_components/alfen_wallbox/switch.py b/custom_components/alfen_wallbox/switch.py index 6fceafd..e2b4b67 100644 --- a/custom_components/alfen_wallbox/switch.py +++ b/custom_components/alfen_wallbox/switch.py @@ -47,6 +47,26 @@ class AlfenSwitchDescription(SwitchEntityDescription, AlfenSwitchDescriptionMixi name="Solar Charging Boost", api_param="3280_4", ), + AlfenSwitchDescription( + key="auth_white_list", + name="Auth. Whitelist", + api_param="213B_0", + ), + AlfenSwitchDescription( + key="auth_local_list", + name="Auth. Whitelist", + api_param="213D_0", + ), + AlfenSwitchDescription( + key="auth_restart_after_power_outage", + name="Auth. Restart after Power Outage", + api_param="215E_0", + ), + AlfenSwitchDescription( + key="auth_remote_transaction_request", + name="Auth. Remote Transaction requests", + api_param="209B_0", + ), ) diff --git a/custom_components/alfen_wallbox/text.py b/custom_components/alfen_wallbox/text.py new file mode 100644 index 0000000..2ff3ec6 --- /dev/null +++ b/custom_components/alfen_wallbox/text.py @@ -0,0 +1,84 @@ +from __future__ import annotations +import logging + +from dataclasses import dataclass +from typing import Final + +from .const import ID +from homeassistant.components.counter import VALUE + +from .alfen import AlfenDevice +from .entity import AlfenEntity + + +from homeassistant.components.text import TextEntity, TextEntityDescription, TextMode +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.entity_platform import AddEntitiesCallback + +from . import DOMAIN as ALFEN_DOMAIN +from . import DOMAIN + +_LOGGER = logging.getLogger(__name__) + +@dataclass +class AlfenTextDescriptionMixin: + """Define an entity description mixin for text entities.""" + + api_param: str + +@dataclass +class AlfenTextDescription(TextEntityDescription, AlfenTextDescriptionMixin): + """Class to describe an Alfen text entity.""" + +ALFEN_TEXT_TYPES: Final[tuple[AlfenTextDescription,...]] = ( + AlfenTextDescription( + key="auth_plug_and_charge_id", + name="Auth. Plug & Charge ID", + icon="mdi:key", + api_param="2063_0" + ), +) + +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback +) -> None: + """Add Alfen Select from a config_entry""" + + device = hass.data[ALFEN_DOMAIN][entry.entry_id] + texts = [AlfenText(device, description) + for description in ALFEN_TEXT_TYPES] + + async_add_entities(texts) + +class AlfenText(AlfenEntity, TextEntity): + """Representation of a Alfen text entity.""" + + def __init__( + self, device: AlfenDevice, description: AlfenTextDescription + )->None: + super().__init__(device) + self._device = device + self._attr_name = f"{device.name} {description.name}" + + self._attr_unique_id = f"{self._device.id}_{description.key}" + self.entity_description = description + self._async_update_attrs() + + @callback + def _async_update_attrs(self) -> None: + """Update text attributes.""" + self._attr_native_value = self._get_current_value() + + def _get_current_value(self) -> str | None: + """Return the current value.""" + for prop in self._device.properties: + if prop[ID] == self.entity_description.api_param: + return prop[VALUE] + return None + + async def async_set_value(self, value: str) -> None: + """Update the value.""" + self._attr_native_value = value + await self.update_state(self.entity_description.api_param,value) + self.async_write_ha_state() \ No newline at end of file