Add wallbox integration (#48082)

* Wallbox component added

* resolved mergeconflicts from upstream

* fixed an incorrect removal in CODEOWNERS file

* fixes for pullrequest automatic test

* clean up code after PR tests

* fixed strings.json

* fix config_flow error > wallbox

* fixed some formatting issues

* fix pylint warnings

* fixed error in number.py > set value

* pylint warnings fixed

* some more pylint fixes

* isort fixes

* fix unused_import pylint

* remove tests

* remove test requirements

* config flow test

* test errors resolved

* test file formatting

* isort on test file

* sensor test

* isort on test

* isort test const

* remove not working sensor test

* remove test const

* add switch, number and lock test

* docstrings for test classes

* sort test_number, create test_sensor

* additional tests

* fix test error

* reduced PR to 1 component

* newline in const

* ignore test coverage -> dependency on external device (wallbox)

* do not ignore config_flow

* add test for validate_input

* remove obsolete import

* additional test config flow

* change test sensor

* docstring

* add additional test for exceptions

* fix test_config

* more tests

* fix test_config_flow

* fixed http error test

* catch connectionerror and introduce testing for this error

* remove .coveragefile

* change comment

* Update homeassistant/components/wallbox/__init__.py

review suggestion by janiversen

Co-authored-by: jan iversen <jancasacondor@gmail.com>

* Update homeassistant/components/wallbox/__init__.py

review suggestion by janiversen (format only)

Co-authored-by: jan iversen <jancasacondor@gmail.com>

* Processed review comments, include more testing for sensor component

* Isolated the async_add_executor_job to make the solution more async

* add a config flow test

* Revert "add a config flow test"

This reverts commit 9c1af82fff.

* Revert "Isolated the async_add_executor_job to make the solution more async"

This reverts commit 0bf034c331.

* Make component more async and add config flow tests

* Changes based on review comments

* made _ methods in WallboxHub for the 'non-async' call to the API and try-catch. Stored the wallbox in the class.

* moved the coordinator to __init__ and pass it as part of the WallboxHub class

* removed obsolete function in __init__

* removed CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL

* fixed spelling and imports on test files

* did isort on component files

Co-authored-by: jan iversen <jancasacondor@gmail.com>
This commit is contained in:
hesselonline 2021-05-24 13:08:24 +02:00 committed by GitHub
parent be13a73db8
commit c497c0eadd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 805 additions and 0 deletions

View file

@ -544,6 +544,7 @@ homeassistant/components/vlc_telnet/* @rodripf @dmcc
homeassistant/components/volkszaehler/* @fabaff
homeassistant/components/volumio/* @OnFreund
homeassistant/components/wake_on_lan/* @ntilley905
homeassistant/components/wallbox/* @hesselonline
homeassistant/components/waqi/* @andrey-git
homeassistant/components/watson_tts/* @rutkai
homeassistant/components/weather/* @fabaff

View file

@ -0,0 +1,147 @@
"""The Wallbox integration."""
import asyncio
from datetime import timedelta
import logging
import requests
from wallbox import Wallbox
from homeassistant import exceptions
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import CONF_CONNECTIONS, CONF_ROUND, CONF_SENSOR_TYPES, CONF_STATION, DOMAIN
_LOGGER = logging.getLogger(__name__)
PLATFORMS = ["sensor"]
UPDATE_INTERVAL = 30
class WallboxHub:
"""Wallbox Hub class."""
def __init__(self, station, username, password, hass):
"""Initialize."""
self._station = station
self._username = username
self._password = password
self._wallbox = Wallbox(self._username, self._password)
self._hass = hass
self._coordinator = DataUpdateCoordinator(
hass,
_LOGGER,
# Name of the data. For logging purposes.
name="wallbox",
update_method=self.async_get_data,
# Polling interval. Will only be polled if there are subscribers.
update_interval=timedelta(seconds=UPDATE_INTERVAL),
)
def _authenticate(self):
"""Authenticate using Wallbox API."""
try:
self._wallbox.authenticate()
return True
except requests.exceptions.HTTPError as wallbox_connection_error:
if wallbox_connection_error.response.status_code == 403:
raise InvalidAuth from wallbox_connection_error
raise ConnectionError from wallbox_connection_error
def _get_data(self):
"""Get new sensor data for Wallbox component."""
try:
self._authenticate()
data = self._wallbox.getChargerStatus(self._station)
filtered_data = {k: data[k] for k in CONF_SENSOR_TYPES if k in data}
for key, value in filtered_data.items():
sensor_round = CONF_SENSOR_TYPES[key][CONF_ROUND]
if sensor_round:
try:
filtered_data[key] = round(value, sensor_round)
except TypeError:
_LOGGER.debug("Cannot format %s", key)
return filtered_data
except requests.exceptions.HTTPError as wallbox_connection_error:
raise ConnectionError from wallbox_connection_error
async def async_coordinator_first_refresh(self):
"""Refresh coordinator for the first time."""
await self._coordinator.async_config_entry_first_refresh()
async def async_authenticate(self) -> bool:
"""Authenticate using Wallbox API."""
return await self._hass.async_add_executor_job(self._authenticate)
async def async_get_data(self) -> bool:
"""Get new sensor data for Wallbox component."""
data = await self._hass.async_add_executor_job(self._get_data)
return data
@property
def coordinator(self):
"""Return the coordinator."""
return self._coordinator
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Set up Wallbox from a config entry."""
wallbox = WallboxHub(
entry.data[CONF_STATION],
entry.data[CONF_USERNAME],
entry.data[CONF_PASSWORD],
hass,
)
await wallbox.async_authenticate()
await wallbox.async_coordinator_first_refresh()
hass.data.setdefault(DOMAIN, {CONF_CONNECTIONS: {}})
hass.data[DOMAIN][CONF_CONNECTIONS][entry.entry_id] = wallbox
for platform in PLATFORMS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, platform)
)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Unload a config entry."""
unload_ok = all(
await asyncio.gather(
*[
hass.config_entries.async_forward_entry_unload(entry, platform)
for platform in PLATFORMS
]
)
)
if unload_ok:
hass.data[DOMAIN]["connections"].pop(entry.entry_id)
return unload_ok
class CannotConnect(exceptions.HomeAssistantError):
"""Error to indicate we cannot connect."""
def __init__(self, msg=""):
"""Create a log record."""
super().__init__()
_LOGGER.error("Cannot connect to Wallbox API. %s", msg)
class InvalidAuth(exceptions.HomeAssistantError):
"""Error to indicate there is invalid auth."""
def __init__(self, msg=""):
"""Create a log record."""
super().__init__()
_LOGGER.error("Cannot authenticate with Wallbox API. %s", msg)

View file

@ -0,0 +1,58 @@
"""Config flow for Wallbox integration."""
import voluptuous as vol
from homeassistant import config_entries, core
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from . import CannotConnect, InvalidAuth, WallboxHub
from .const import CONF_STATION, DOMAIN
COMPONENT_DOMAIN = DOMAIN
STEP_USER_DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_STATION): str,
vol.Required(CONF_USERNAME): str,
vol.Required(CONF_PASSWORD): str,
}
)
async def validate_input(hass: core.HomeAssistant, data):
"""Validate the user input allows to connect.
Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user.
"""
hub = WallboxHub(data["station"], data["username"], data["password"], hass)
await hub.async_get_data()
# Return info that you want to store in the config entry.
return {"title": "Wallbox Portal"}
class ConfigFlow(config_entries.ConfigFlow, domain=COMPONENT_DOMAIN):
"""Handle a config flow for Wallbox."""
async def async_step_user(self, user_input=None):
"""Handle the initial step."""
if user_input is None:
return self.async_show_form(
step_id="user",
data_schema=STEP_USER_DATA_SCHEMA,
)
errors = {}
try:
info = await validate_input(self.hass, user_input)
except CannotConnect:
errors["base"] = "cannot_connect"
except InvalidAuth:
errors["base"] = "invalid_auth"
else:
return self.async_create_entry(title=info["title"], data=user_input)
return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
)

View file

@ -0,0 +1,99 @@
"""Constants for the Wallbox integration."""
from homeassistant.const import (
CONF_ICON,
CONF_NAME,
CONF_UNIT_OF_MEASUREMENT,
ELECTRICAL_CURRENT_AMPERE,
ENERGY_KILO_WATT_HOUR,
LENGTH_KILOMETERS,
PERCENTAGE,
POWER_KILO_WATT,
STATE_UNAVAILABLE,
)
DOMAIN = "wallbox"
CONF_STATION = "station"
CONF_CONNECTIONS = "connections"
CONF_ROUND = "round"
CONF_SENSOR_TYPES = {
"charging_power": {
CONF_ICON: "mdi:ev-station",
CONF_NAME: "Charging Power",
CONF_ROUND: 2,
CONF_UNIT_OF_MEASUREMENT: POWER_KILO_WATT,
STATE_UNAVAILABLE: False,
},
"max_available_power": {
CONF_ICON: "mdi:ev-station",
CONF_NAME: "Max Available Power",
CONF_ROUND: 0,
CONF_UNIT_OF_MEASUREMENT: ELECTRICAL_CURRENT_AMPERE,
STATE_UNAVAILABLE: False,
},
"charging_speed": {
CONF_ICON: "mdi:speedometer",
CONF_NAME: "Charging Speed",
CONF_ROUND: 0,
CONF_UNIT_OF_MEASUREMENT: None,
STATE_UNAVAILABLE: False,
},
"added_range": {
CONF_ICON: "mdi:map-marker-distance",
CONF_NAME: "Added Range",
CONF_ROUND: 0,
CONF_UNIT_OF_MEASUREMENT: LENGTH_KILOMETERS,
STATE_UNAVAILABLE: False,
},
"added_energy": {
CONF_ICON: "mdi:battery-positive",
CONF_NAME: "Added Energy",
CONF_ROUND: 2,
CONF_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
STATE_UNAVAILABLE: False,
},
"charging_time": {
CONF_ICON: "mdi:timer",
CONF_NAME: "Charging Time",
CONF_ROUND: None,
CONF_UNIT_OF_MEASUREMENT: None,
STATE_UNAVAILABLE: False,
},
"cost": {
CONF_ICON: "mdi:ev-station",
CONF_NAME: "Cost",
CONF_ROUND: None,
CONF_UNIT_OF_MEASUREMENT: None,
STATE_UNAVAILABLE: False,
},
"state_of_charge": {
CONF_ICON: "mdi:battery-charging-80",
CONF_NAME: "State of Charge",
CONF_ROUND: None,
CONF_UNIT_OF_MEASUREMENT: PERCENTAGE,
STATE_UNAVAILABLE: False,
},
"current_mode": {
CONF_ICON: "mdi:ev-station",
CONF_NAME: "Current Mode",
CONF_ROUND: None,
CONF_UNIT_OF_MEASUREMENT: None,
STATE_UNAVAILABLE: False,
},
"depot_price": {
CONF_ICON: "mdi:ev-station",
CONF_NAME: "Depot Price",
CONF_ROUND: 2,
CONF_UNIT_OF_MEASUREMENT: None,
STATE_UNAVAILABLE: False,
},
"status_description": {
CONF_ICON: "mdi:ev-station",
CONF_NAME: "Status Description",
CONF_ROUND: None,
CONF_UNIT_OF_MEASUREMENT: None,
STATE_UNAVAILABLE: False,
},
}

View file

@ -0,0 +1,13 @@
{
"domain": "wallbox",
"name": "Wallbox",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/wallbox",
"requirements": ["wallbox==0.4.4"],
"ssdp": [],
"zeroconf": [],
"homekit": {},
"dependencies": [],
"codeowners": ["@hesselonline"],
"iot_class": "cloud_polling"
}

View file

@ -0,0 +1,61 @@
"""Home Assistant component for accessing the Wallbox Portal API. The sensor component creates multiple sensors regarding wallbox performance."""
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import (
CONF_CONNECTIONS,
CONF_ICON,
CONF_NAME,
CONF_SENSOR_TYPES,
CONF_UNIT_OF_MEASUREMENT,
DOMAIN,
)
CONF_STATION = "station"
UPDATE_INTERVAL = 30
async def async_setup_entry(hass, config, async_add_entities):
"""Create wallbox sensor entities in HASS."""
wallbox = hass.data[DOMAIN][CONF_CONNECTIONS][config.entry_id]
coordinator = wallbox.coordinator
async_add_entities(
WallboxSensor(coordinator, idx, ent, config)
for idx, ent in enumerate(coordinator.data)
)
class WallboxSensor(CoordinatorEntity, Entity):
"""Representation of the Wallbox portal."""
def __init__(self, coordinator, idx, ent, config):
"""Initialize a Wallbox sensor."""
super().__init__(coordinator)
self._properties = CONF_SENSOR_TYPES[ent]
self._name = f"{config.title} {self._properties[CONF_NAME]}"
self._icon = self._properties[CONF_ICON]
self._unit = self._properties[CONF_UNIT_OF_MEASUREMENT]
self._ent = ent
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def state(self):
"""Return the state of the sensor."""
return self.coordinator.data[self._ent]
@property
def unit_of_measurement(self):
"""Return the unit of the sensor."""
return self._unit
@property
def icon(self):
"""Return the icon of the sensor."""
return self._icon

View file

@ -0,0 +1,22 @@
{
"title": "Wallbox",
"config": {
"step": {
"user": {
"data": {
"station": "Station Serial Number",
"username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]"
}
}
},
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"unknown": "[%key:common::config_flow::error::unknown%]"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
}
}
}

View file

@ -0,0 +1,22 @@
{
"config": {
"abort": {
"already_configured": "Device is already configured"
},
"error": {
"cannot_connect": "Failed to connect",
"invalid_auth": "Invalid authentication",
"unknown": "Unexpected error"
},
"step": {
"user": {
"data": {
"station": "Station S/N",
"password": "Password",
"username": "Username"
}
}
}
},
"title": "MyWallbox"
}

View file

@ -275,6 +275,7 @@ FLOWS = [
"vilfo",
"vizio",
"volumio",
"wallbox",
"waze_travel_time",
"wemo",
"wiffi",

View file

@ -2332,6 +2332,9 @@ vultr==0.1.2
# homeassistant.components.wake_on_lan
wakeonlan==2.0.1
# homeassistant.components.wallbox
wallbox==0.4.4
# homeassistant.components.waqi
waqiasync==1.0.0

View file

@ -1256,6 +1256,9 @@ vultr==0.1.2
# homeassistant.components.wake_on_lan
wakeonlan==2.0.1
# homeassistant.components.wallbox
wallbox==0.4.4
# homeassistant.components.folder_watcher
watchdog==2.1.2

View file

@ -0,0 +1 @@
"""Tests for the Wallbox integration."""

View file

@ -0,0 +1,128 @@
"""Test the Wallbox config flow."""
from unittest.mock import patch
from voluptuous.schema_builder import raises
from homeassistant import config_entries, data_entry_flow
from homeassistant.components.wallbox import CannotConnect, InvalidAuth, config_flow
from homeassistant.components.wallbox.const import DOMAIN
from homeassistant.core import HomeAssistant
async def test_show_set_form(hass: HomeAssistant) -> None:
"""Test that the setup form is served."""
flow = config_flow.ConfigFlow()
flow.hass = hass
result = await flow.async_step_user(user_input=None)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user"
async def test_form_invalid_auth(hass):
"""Test we handle invalid auth."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.wallbox.config_flow.WallboxHub.async_authenticate",
side_effect=InvalidAuth,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"station": "12345",
"username": "test-username",
"password": "test-password",
},
)
assert result2["type"] == "form"
assert result2["errors"] == {"base": "invalid_auth"}
async def test_form_cannot_connect(hass):
"""Test we handle cannot connect error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.wallbox.config_flow.WallboxHub.async_authenticate",
side_effect=CannotConnect,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"station": "12345",
"username": "test-username",
"password": "test-password",
},
)
assert result2["type"] == "form"
assert result2["errors"] == {"base": "invalid_auth"}
async def test_validate_input(hass):
"""Test we can validate input."""
data = {
"station": "12345",
"username": "test-username",
"password": "test-password",
}
def alternate_authenticate_method():
return None
def alternate_get_charger_status_method(station):
data = '{"Temperature": 100, "Location": "Toronto", "Datetime": "2020-07-23", "Units": "Celsius"}'
return data
with patch(
"wallbox.Wallbox.authenticate",
side_effect=alternate_authenticate_method,
), patch(
"wallbox.Wallbox.getChargerStatus",
side_effect=alternate_get_charger_status_method,
):
result = await config_flow.validate_input(hass, data)
assert result == {"title": "Wallbox Portal"}
async def test_configflow_class():
"""Test configFlow class."""
configflow = config_flow.ConfigFlow()
assert configflow
with patch(
"homeassistant.components.wallbox.config_flow.validate_input",
side_effect=TypeError,
), raises(Exception):
assert await configflow.async_step_user(True)
with patch(
"homeassistant.components.wallbox.config_flow.validate_input",
side_effect=CannotConnect,
), raises(Exception):
assert await configflow.async_step_user(True)
with patch(
"homeassistant.components.wallbox.config_flow.validate_input",
), raises(Exception):
assert await configflow.async_step_user(True)
def test_cannot_connect_class():
"""Test cannot Connect class."""
cannot_connect = CannotConnect
assert cannot_connect
def test_invalid_auth_class():
"""Test invalid auth class."""
invalid_auth = InvalidAuth
assert invalid_auth

View file

@ -0,0 +1,165 @@
"""Test Wallbox Init Component."""
import json
import pytest
import requests_mock
from voluptuous.schema_builder import raises
from homeassistant.components import wallbox
from homeassistant.components.wallbox.const import CONF_STATION, DOMAIN
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.helpers.typing import HomeAssistantType
from tests.common import MockConfigEntry
entry = MockConfigEntry(
domain=DOMAIN,
data={
CONF_USERNAME: "test_username",
CONF_PASSWORD: "test_password",
CONF_STATION: "12345",
},
entry_id="testEntry",
)
test_response = json.loads(
'{"charging_power": 0,"max_available_power": 25,"charging_speed": 0,"added_range": 372,"added_energy": 44.697}'
)
test_response_rounding_error = json.loads(
'{"charging_power": "XX","max_available_power": "xx","charging_speed": 0,"added_range": "xx","added_energy": "XX"}'
)
async def test_wallbox_setup_entry(hass: HomeAssistantType):
"""Test Wallbox Setup."""
with requests_mock.Mocker() as m:
m.get(
"https://api.wall-box.com/auth/token/user",
text='{"jwt":"fakekeyhere","user_id":12345,"ttl":145656758,"error":false,"status":200}',
status_code=200,
)
m.get(
"https://api.wall-box.com/chargers/status/12345",
text='{"Temperature": 100, "Location": "Toronto", "Datetime": "2020-07-23", "Units": "Celsius"}',
status_code=200,
)
assert await wallbox.async_setup_entry(hass, entry)
with requests_mock.Mocker() as m, raises(ConnectionError):
m.get(
"https://api.wall-box.com/auth/token/user",
text='{"jwt":"fakekeyhere","user_id":12345,"ttl":145656758,"error":false,"status":404}',
status_code=404,
)
assert await wallbox.async_setup_entry(hass, entry) is False
async def test_wallbox_unload_entry(hass: HomeAssistantType):
"""Test Wallbox Unload."""
hass.data[DOMAIN] = {"connections": {entry.entry_id: entry}}
assert await wallbox.async_unload_entry(hass, entry)
hass.data[DOMAIN] = {"fail_entry": entry}
with pytest.raises(KeyError):
await wallbox.async_unload_entry(hass, entry)
async def test_get_data(hass: HomeAssistantType):
"""Test hub class, get_data."""
station = ("12345",)
username = ("test-username",)
password = "test-password"
hub = wallbox.WallboxHub(station, username, password, hass)
with requests_mock.Mocker() as m:
m.get(
"https://api.wall-box.com/auth/token/user",
text='{"jwt":"fakekeyhere","user_id":12345,"ttl":145656758,"error":false,"status":200}',
status_code=200,
)
m.get(
"https://api.wall-box.com/chargers/status/('12345',)",
json=test_response,
status_code=200,
)
assert await hub.async_get_data()
async def test_get_data_rounding_error(hass: HomeAssistantType):
"""Test hub class, get_data with rounding error."""
station = ("12345",)
username = ("test-username",)
password = "test-password"
hub = wallbox.WallboxHub(station, username, password, hass)
with requests_mock.Mocker() as m:
m.get(
"https://api.wall-box.com/auth/token/user",
text='{"jwt":"fakekeyhere","user_id":12345,"ttl":145656758,"error":false,"status":200}',
status_code=200,
)
m.get(
"https://api.wall-box.com/chargers/status/('12345',)",
json=test_response_rounding_error,
status_code=200,
)
assert await hub.async_get_data()
async def test_authentication_exception(hass: HomeAssistantType):
"""Test hub class, authentication raises exception."""
station = ("12345",)
username = ("test-username",)
password = "test-password"
hub = wallbox.WallboxHub(station, username, password, hass)
with requests_mock.Mocker() as m, raises(wallbox.InvalidAuth):
m.get("https://api.wall-box.com/auth/token/user", text="data", status_code=403)
assert await hub.async_authenticate()
with requests_mock.Mocker() as m, raises(ConnectionError):
m.get("https://api.wall-box.com/auth/token/user", text="data", status_code=404)
assert await hub.async_authenticate()
with requests_mock.Mocker() as m, raises(wallbox.InvalidAuth):
m.get("https://api.wall-box.com/auth/token/user", text="data", status_code=403)
m.get(
"https://api.wall-box.com/chargers/status/test",
json=test_response,
status_code=403,
)
assert await hub.async_get_data()
async def test_get_data_exception(hass: HomeAssistantType):
"""Test hub class, authentication raises exception."""
station = ("12345",)
username = ("test-username",)
password = "test-password"
hub = wallbox.WallboxHub(station, username, password, hass)
with requests_mock.Mocker() as m, raises(ConnectionError):
m.get(
"https://api.wall-box.com/auth/token/user",
text='{"jwt":"fakekeyhere","user_id":12345,"ttl":145656758,"error":false,"status":200}',
status_code=200,
)
m.get(
"https://api.wall-box.com/chargers/status/('12345',)",
text="data",
status_code=404,
)
assert await hub.async_get_data()

View file

@ -0,0 +1,81 @@
"""Test Wallbox Switch component."""
import json
from unittest.mock import MagicMock
from homeassistant.components.wallbox import sensor
from homeassistant.components.wallbox.const import CONF_STATION, DOMAIN
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from tests.common import MockConfigEntry
entry = MockConfigEntry(
domain=DOMAIN,
data={
CONF_USERNAME: "test_username",
CONF_PASSWORD: "test_password",
CONF_STATION: "12345",
},
entry_id="testEntry",
)
test_response = json.loads(
'{"charging_power": 0,"max_available_power": 25,"charging_speed": 0,"added_range": 372,"added_energy": 44.697}'
)
test_response_rounding_error = json.loads(
'{"charging_power": "XX","max_available_power": "xx","charging_speed": 0,"added_range": "xx","added_energy": "XX"}'
)
CONF_STATION = ("12345",)
CONF_USERNAME = ("test-username",)
CONF_PASSWORD = "test-password"
# wallbox = WallboxHub(CONF_STATION, CONF_USERNAME, CONF_PASSWORD, hass)
async def test_wallbox_sensor_class():
"""Test wallbox sensor class."""
coordinator = MagicMock(return_value="connected")
idx = 1
ent = "charging_power"
wallboxSensor = sensor.WallboxSensor(coordinator, idx, ent, entry)
assert wallboxSensor.icon == "mdi:ev-station"
assert wallboxSensor.unit_of_measurement == "kW"
assert wallboxSensor.name == "Mock Title Charging Power"
assert wallboxSensor.state
# async def test_wallbox_updater(hass: HomeAssistantType):
# """Test wallbox updater."""
# with requests_mock.Mocker() as m:
# m.get(
# "https://api.wall-box.com/auth/token/user",
# text='{"jwt":"fakekeyhere","user_id":12345,"ttl":145656758,"error":false,"status":200}',
# status_code=200,
# )
# m.get(
# "https://api.wall-box.com/chargers/status/('12345',)",
# json=test_response,
# status_code=200,
# )
# await sensor.wallbox_updater(wallbox, hass)
# async def test_wallbox_updater_rounding_error(hass: HomeAssistantType):
# """Test wallbox updater rounding error."""
# with requests_mock.Mocker() as m:
# m.get(
# "https://api.wall-box.com/auth/token/user",
# text='{"jwt":"fakekeyhere","user_id":12345,"ttl":145656758,"error":false,"status":200}',
# status_code=200,
# )
# m.get(
# "https://api.wall-box.com/chargers/status/('12345',)",
# json=test_response_rounding_error,
# status_code=200,
# )
# await sensor.wallbox_updater(wallbox, hass)