Add new number component for setting the wallbox ICP current (#125209)
* Add new number component for setting the wallbox ICP current * feat: Add number component for wallbox ICP current controlpull/124925/head
parent
4b111008df
commit
b5d7eba4f6
|
@ -22,11 +22,15 @@ CHARGER_CURRENCY_KEY = "currency"
|
|||
CHARGER_DATA_KEY = "config_data"
|
||||
CHARGER_DEPOT_PRICE_KEY = "depot_price"
|
||||
CHARGER_ENERGY_PRICE_KEY = "energy_price"
|
||||
CHARGER_FEATURES_KEY = "features"
|
||||
CHARGER_SERIAL_NUMBER_KEY = "serial_number"
|
||||
CHARGER_PART_NUMBER_KEY = "part_number"
|
||||
CHARGER_PLAN_KEY = "plan"
|
||||
CHARGER_POWER_BOOST_KEY = "POWER_BOOST"
|
||||
CHARGER_SOFTWARE_KEY = "software"
|
||||
CHARGER_MAX_AVAILABLE_POWER_KEY = "max_available_power"
|
||||
CHARGER_MAX_CHARGING_CURRENT_KEY = "max_charging_current"
|
||||
CHARGER_MAX_ICP_CURRENT_KEY = "icp_max_current"
|
||||
CHARGER_PAUSE_RESUME_KEY = "paused"
|
||||
CHARGER_LOCKED_UNLOCKED_KEY = "locked"
|
||||
CHARGER_NAME_KEY = "name"
|
||||
|
|
|
@ -19,8 +19,12 @@ from .const import (
|
|||
CHARGER_CURRENCY_KEY,
|
||||
CHARGER_DATA_KEY,
|
||||
CHARGER_ENERGY_PRICE_KEY,
|
||||
CHARGER_FEATURES_KEY,
|
||||
CHARGER_LOCKED_UNLOCKED_KEY,
|
||||
CHARGER_MAX_CHARGING_CURRENT_KEY,
|
||||
CHARGER_MAX_ICP_CURRENT_KEY,
|
||||
CHARGER_PLAN_KEY,
|
||||
CHARGER_POWER_BOOST_KEY,
|
||||
CHARGER_STATUS_DESCRIPTION_KEY,
|
||||
CHARGER_STATUS_ID_KEY,
|
||||
CODE_KEY,
|
||||
|
@ -130,6 +134,16 @@ class WallboxCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||
data[CHARGER_ENERGY_PRICE_KEY] = data[CHARGER_DATA_KEY][
|
||||
CHARGER_ENERGY_PRICE_KEY
|
||||
]
|
||||
# Only show max_icp_current if power_boost is available in the wallbox unit:
|
||||
if (
|
||||
data[CHARGER_DATA_KEY].get(CHARGER_MAX_ICP_CURRENT_KEY, 0) > 0
|
||||
and CHARGER_POWER_BOOST_KEY
|
||||
in data[CHARGER_DATA_KEY][CHARGER_PLAN_KEY][CHARGER_FEATURES_KEY]
|
||||
):
|
||||
data[CHARGER_MAX_ICP_CURRENT_KEY] = data[CHARGER_DATA_KEY][
|
||||
CHARGER_MAX_ICP_CURRENT_KEY
|
||||
]
|
||||
|
||||
data[CHARGER_CURRENCY_KEY] = (
|
||||
f"{data[CHARGER_DATA_KEY][CHARGER_CURRENCY_KEY][CODE_KEY]}/kWh"
|
||||
)
|
||||
|
@ -160,6 +174,21 @@ class WallboxCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||
)
|
||||
await self.async_request_refresh()
|
||||
|
||||
@_require_authentication
|
||||
def _set_icp_current(self, icp_current: float) -> None:
|
||||
"""Set maximum icp current for Wallbox."""
|
||||
try:
|
||||
self._wallbox.setIcpMaxCurrent(self._station, icp_current)
|
||||
except requests.exceptions.HTTPError as wallbox_connection_error:
|
||||
if wallbox_connection_error.response.status_code == 403:
|
||||
raise InvalidAuth from wallbox_connection_error
|
||||
raise
|
||||
|
||||
async def async_set_icp_current(self, icp_current: float) -> None:
|
||||
"""Set maximum icp current for Wallbox."""
|
||||
await self.hass.async_add_executor_job(self._set_icp_current, icp_current)
|
||||
await self.async_request_refresh()
|
||||
|
||||
@_require_authentication
|
||||
def _set_energy_cost(self, energy_cost: float) -> None:
|
||||
"""Set energy cost for Wallbox."""
|
||||
|
|
|
@ -21,6 +21,7 @@ from .const import (
|
|||
CHARGER_ENERGY_PRICE_KEY,
|
||||
CHARGER_MAX_AVAILABLE_POWER_KEY,
|
||||
CHARGER_MAX_CHARGING_CURRENT_KEY,
|
||||
CHARGER_MAX_ICP_CURRENT_KEY,
|
||||
CHARGER_PART_NUMBER_KEY,
|
||||
CHARGER_SERIAL_NUMBER_KEY,
|
||||
DOMAIN,
|
||||
|
@ -67,6 +68,16 @@ NUMBER_TYPES: dict[str, WallboxNumberEntityDescription] = {
|
|||
set_value_fn=lambda coordinator: coordinator.async_set_energy_cost,
|
||||
native_step=0.01,
|
||||
),
|
||||
CHARGER_MAX_ICP_CURRENT_KEY: WallboxNumberEntityDescription(
|
||||
key=CHARGER_MAX_ICP_CURRENT_KEY,
|
||||
translation_key="maximum_icp_current",
|
||||
max_value_fn=lambda coordinator: cast(
|
||||
float, coordinator.data[CHARGER_MAX_AVAILABLE_POWER_KEY]
|
||||
),
|
||||
min_value_fn=lambda _: 6,
|
||||
set_value_fn=lambda coordinator: coordinator.async_set_icp_current,
|
||||
native_step=1,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ from .const import (
|
|||
CHARGER_ENERGY_PRICE_KEY,
|
||||
CHARGER_MAX_AVAILABLE_POWER_KEY,
|
||||
CHARGER_MAX_CHARGING_CURRENT_KEY,
|
||||
CHARGER_MAX_ICP_CURRENT_KEY,
|
||||
CHARGER_SERIAL_NUMBER_KEY,
|
||||
CHARGER_STATE_OF_CHARGE_KEY,
|
||||
CHARGER_STATUS_DESCRIPTION_KEY,
|
||||
|
@ -145,6 +146,13 @@ SENSOR_TYPES: dict[str, WallboxSensorEntityDescription] = {
|
|||
device_class=SensorDeviceClass.CURRENT,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
CHARGER_MAX_ICP_CURRENT_KEY: WallboxSensorEntityDescription(
|
||||
key=CHARGER_MAX_ICP_CURRENT_KEY,
|
||||
translation_key=CHARGER_MAX_ICP_CURRENT_KEY,
|
||||
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
|
||||
device_class=SensorDeviceClass.CURRENT,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
},
|
||||
"energy_price": {
|
||||
"name": "Energy price"
|
||||
},
|
||||
"maximum_icp_current": {
|
||||
"name": "Maximum ICP current"
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
|
@ -79,6 +82,9 @@
|
|||
},
|
||||
"max_charging_current": {
|
||||
"name": "Max charging current"
|
||||
},
|
||||
"icp_max_current": {
|
||||
"name": "Max ICP current"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
|
|
|
@ -14,11 +14,15 @@ from homeassistant.components.wallbox.const import (
|
|||
CHARGER_CURRENT_VERSION_KEY,
|
||||
CHARGER_DATA_KEY,
|
||||
CHARGER_ENERGY_PRICE_KEY,
|
||||
CHARGER_FEATURES_KEY,
|
||||
CHARGER_LOCKED_UNLOCKED_KEY,
|
||||
CHARGER_MAX_AVAILABLE_POWER_KEY,
|
||||
CHARGER_MAX_CHARGING_CURRENT_KEY,
|
||||
CHARGER_MAX_ICP_CURRENT_KEY,
|
||||
CHARGER_NAME_KEY,
|
||||
CHARGER_PART_NUMBER_KEY,
|
||||
CHARGER_PLAN_KEY,
|
||||
CHARGER_POWER_BOOST_KEY,
|
||||
CHARGER_SERIAL_NUMBER_KEY,
|
||||
CHARGER_SOFTWARE_KEY,
|
||||
CHARGER_STATUS_ID_KEY,
|
||||
|
@ -45,6 +49,8 @@ test_response = {
|
|||
CHARGER_PART_NUMBER_KEY: "PLP1-0-2-4-9-002-E",
|
||||
CHARGER_SOFTWARE_KEY: {CHARGER_CURRENT_VERSION_KEY: "5.5.10"},
|
||||
CHARGER_CURRENCY_KEY: {"code": "EUR/kWh"},
|
||||
CHARGER_MAX_ICP_CURRENT_KEY: 20,
|
||||
CHARGER_PLAN_KEY: {CHARGER_FEATURES_KEY: [CHARGER_POWER_BOOST_KEY]},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -64,6 +70,8 @@ test_response_bidir = {
|
|||
CHARGER_PART_NUMBER_KEY: "QSP1-0-2-4-9-002-E",
|
||||
CHARGER_SOFTWARE_KEY: {CHARGER_CURRENT_VERSION_KEY: "5.5.10"},
|
||||
CHARGER_CURRENCY_KEY: {"code": "EUR/kWh"},
|
||||
CHARGER_MAX_ICP_CURRENT_KEY: 20,
|
||||
CHARGER_PLAN_KEY: {CHARGER_FEATURES_KEY: [CHARGER_POWER_BOOST_KEY]},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ STATUS = "status"
|
|||
|
||||
MOCK_NUMBER_ENTITY_ID = "number.wallbox_wallboxname_maximum_charging_current"
|
||||
MOCK_NUMBER_ENTITY_ENERGY_PRICE_ID = "number.wallbox_wallboxname_energy_price"
|
||||
MOCK_NUMBER_ENTITY_ICP_CURRENT_ID = "number.wallbox_wallboxname_maximum_icp_current"
|
||||
MOCK_LOCK_ENTITY_ID = "lock.wallbox_wallboxname_lock"
|
||||
MOCK_SENSOR_CHARGING_SPEED_ID = "sensor.wallbox_wallboxname_charging_speed"
|
||||
MOCK_SENSOR_CHARGING_POWER_ID = "sensor.wallbox_wallboxname_charging_power"
|
||||
|
|
|
@ -6,9 +6,12 @@ import pytest
|
|||
import requests_mock
|
||||
|
||||
from homeassistant.components.input_number import ATTR_VALUE, SERVICE_SET_VALUE
|
||||
from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN
|
||||
from homeassistant.components.wallbox import InvalidAuth
|
||||
from homeassistant.components.wallbox.const import (
|
||||
CHARGER_ENERGY_PRICE_KEY,
|
||||
CHARGER_MAX_CHARGING_CURRENT_KEY,
|
||||
CHARGER_MAX_ICP_CURRENT_KEY,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
@ -20,7 +23,11 @@ from . import (
|
|||
setup_integration_bidir,
|
||||
setup_integration_platform_not_ready,
|
||||
)
|
||||
from .const import MOCK_NUMBER_ENTITY_ENERGY_PRICE_ID, MOCK_NUMBER_ENTITY_ID
|
||||
from .const import (
|
||||
MOCK_NUMBER_ENTITY_ENERGY_PRICE_ID,
|
||||
MOCK_NUMBER_ENTITY_ICP_CURRENT_ID,
|
||||
MOCK_NUMBER_ENTITY_ID,
|
||||
)
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
@ -212,3 +219,99 @@ async def test_wallbox_number_class_platform_not_ready(
|
|||
assert state is None
|
||||
|
||||
await hass.config_entries.async_unload(entry.entry_id)
|
||||
|
||||
|
||||
async def test_wallbox_number_class_icp_energy(
|
||||
hass: HomeAssistant, entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test wallbox sensor class."""
|
||||
|
||||
await setup_integration(hass, entry)
|
||||
|
||||
with requests_mock.Mocker() as mock_request:
|
||||
mock_request.get(
|
||||
"https://user-api.wall-box.com/users/signin",
|
||||
json=authorisation_response,
|
||||
status_code=200,
|
||||
)
|
||||
|
||||
mock_request.post(
|
||||
"https://api.wall-box.com/chargers/config/12345",
|
||||
json={CHARGER_MAX_ICP_CURRENT_KEY: 10},
|
||||
status_code=200,
|
||||
)
|
||||
|
||||
await hass.services.async_call(
|
||||
NUMBER_DOMAIN,
|
||||
SERVICE_SET_VALUE,
|
||||
{
|
||||
ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ICP_CURRENT_ID,
|
||||
ATTR_VALUE: 10,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.config_entries.async_unload(entry.entry_id)
|
||||
|
||||
|
||||
async def test_wallbox_number_class_icp_energy_auth_error(
|
||||
hass: HomeAssistant, entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test wallbox sensor class."""
|
||||
|
||||
await setup_integration(hass, entry)
|
||||
|
||||
with requests_mock.Mocker() as mock_request:
|
||||
mock_request.get(
|
||||
"https://user-api.wall-box.com/users/signin",
|
||||
json=authorisation_response,
|
||||
status_code=200,
|
||||
)
|
||||
mock_request.post(
|
||||
"https://api.wall-box.com/chargers/config/12345",
|
||||
json={CHARGER_MAX_ICP_CURRENT_KEY: 10},
|
||||
status_code=403,
|
||||
)
|
||||
|
||||
with pytest.raises(InvalidAuth):
|
||||
await hass.services.async_call(
|
||||
NUMBER_DOMAIN,
|
||||
SERVICE_SET_VALUE,
|
||||
{
|
||||
ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ICP_CURRENT_ID,
|
||||
ATTR_VALUE: 10,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.config_entries.async_unload(entry.entry_id)
|
||||
|
||||
|
||||
async def test_wallbox_number_class_icp_energy_connection_error(
|
||||
hass: HomeAssistant, entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test wallbox sensor class."""
|
||||
|
||||
await setup_integration(hass, entry)
|
||||
|
||||
with requests_mock.Mocker() as mock_request:
|
||||
mock_request.get(
|
||||
"https://user-api.wall-box.com/users/signin",
|
||||
json=authorisation_response,
|
||||
status_code=200,
|
||||
)
|
||||
mock_request.post(
|
||||
"https://api.wall-box.com/chargers/config/12345",
|
||||
json={CHARGER_MAX_ICP_CURRENT_KEY: 10},
|
||||
status_code=404,
|
||||
)
|
||||
|
||||
with pytest.raises(ConnectionError):
|
||||
await hass.services.async_call(
|
||||
NUMBER_DOMAIN,
|
||||
SERVICE_SET_VALUE,
|
||||
{
|
||||
ATTR_ENTITY_ID: MOCK_NUMBER_ENTITY_ICP_CURRENT_ID,
|
||||
ATTR_VALUE: 10,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.config_entries.async_unload(entry.entry_id)
|
||||
|
|
Loading…
Reference in New Issue