mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Add Huisbaasje integration (#42716)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io> Co-authored-by: Franck Nijhof <frenck@frenck.nl>
This commit is contained in:
parent
b4af17e02d
commit
8d572af77a
@ -203,6 +203,7 @@ homeassistant/components/http/* @home-assistant/core
|
||||
homeassistant/components/huawei_lte/* @scop @fphammerle
|
||||
homeassistant/components/huawei_router/* @abmantis
|
||||
homeassistant/components/hue/* @balloob @frenck
|
||||
homeassistant/components/huisbaasje/* @denniss17
|
||||
homeassistant/components/humidifier/* @home-assistant/core @Shulyaka
|
||||
homeassistant/components/hunterdouglas_powerview/* @bdraco
|
||||
homeassistant/components/hvv_departures/* @vigonotion
|
||||
|
168
homeassistant/components/huisbaasje/__init__.py
Normal file
168
homeassistant/components/huisbaasje/__init__.py
Normal file
@ -0,0 +1,168 @@
|
||||
"""The Huisbaasje integration."""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
import async_timeout
|
||||
from huisbaasje import Huisbaasje, HuisbaasjeException
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import (
|
||||
DATA_COORDINATOR,
|
||||
DOMAIN,
|
||||
FETCH_TIMEOUT,
|
||||
POLLING_INTERVAL,
|
||||
SENSOR_TYPE_RATE,
|
||||
SENSOR_TYPE_THIS_DAY,
|
||||
SENSOR_TYPE_THIS_MONTH,
|
||||
SENSOR_TYPE_THIS_WEEK,
|
||||
SENSOR_TYPE_THIS_YEAR,
|
||||
SOURCE_TYPES,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: dict):
|
||||
"""Set up the Huisbaasje component."""
|
||||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry):
|
||||
"""Set up Huisbaasje from a config entry."""
|
||||
# Create the Huisbaasje client
|
||||
huisbaasje = Huisbaasje(
|
||||
username=config_entry.data[CONF_USERNAME],
|
||||
password=config_entry.data[CONF_PASSWORD],
|
||||
source_types=SOURCE_TYPES,
|
||||
request_timeout=FETCH_TIMEOUT,
|
||||
)
|
||||
|
||||
# Attempt authentication. If this fails, an exception is thrown
|
||||
try:
|
||||
await huisbaasje.authenticate()
|
||||
except HuisbaasjeException as exception:
|
||||
_LOGGER.error("Authentication failed: %s", str(exception))
|
||||
return False
|
||||
|
||||
async def async_update_data():
|
||||
return await async_update_huisbaasje(huisbaasje)
|
||||
|
||||
# Create a coordinator for polling updates
|
||||
coordinator = DataUpdateCoordinator(
|
||||
hass,
|
||||
_LOGGER,
|
||||
name="sensor",
|
||||
update_method=async_update_data,
|
||||
update_interval=timedelta(seconds=POLLING_INTERVAL),
|
||||
)
|
||||
|
||||
await coordinator.async_refresh()
|
||||
|
||||
if not coordinator.last_update_success:
|
||||
raise ConfigEntryNotReady
|
||||
|
||||
# Load the client in the data of home assistant
|
||||
hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = {
|
||||
DATA_COORDINATOR: coordinator
|
||||
}
|
||||
|
||||
# Offload the loading of entities to the platform
|
||||
hass.async_create_task(
|
||||
hass.config_entries.async_forward_entry_setup(config_entry, "sensor")
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry):
|
||||
"""Unload a config entry."""
|
||||
# Forward the unloading of the entry to the platform
|
||||
unload_ok = await hass.config_entries.async_forward_entry_unload(
|
||||
config_entry, "sensor"
|
||||
)
|
||||
|
||||
# If successful, unload the Huisbaasje client
|
||||
if unload_ok:
|
||||
hass.data[DOMAIN].pop(config_entry.entry_id)
|
||||
|
||||
return unload_ok
|
||||
|
||||
|
||||
async def async_update_huisbaasje(huisbaasje):
|
||||
"""Update the data by performing a request to Huisbaasje."""
|
||||
try:
|
||||
# Note: asyncio.TimeoutError and aiohttp.ClientError are already
|
||||
# handled by the data update coordinator.
|
||||
async with async_timeout.timeout(FETCH_TIMEOUT):
|
||||
if not huisbaasje.is_authenticated():
|
||||
_LOGGER.warning("Huisbaasje is unauthenticated. Reauthenticating...")
|
||||
await huisbaasje.authenticate()
|
||||
|
||||
current_measurements = await huisbaasje.current_measurements()
|
||||
|
||||
return {
|
||||
source_type: {
|
||||
SENSOR_TYPE_RATE: _get_measurement_rate(
|
||||
current_measurements, source_type
|
||||
),
|
||||
SENSOR_TYPE_THIS_DAY: _get_cumulative_value(
|
||||
current_measurements, source_type, SENSOR_TYPE_THIS_DAY
|
||||
),
|
||||
SENSOR_TYPE_THIS_WEEK: _get_cumulative_value(
|
||||
current_measurements, source_type, SENSOR_TYPE_THIS_WEEK
|
||||
),
|
||||
SENSOR_TYPE_THIS_MONTH: _get_cumulative_value(
|
||||
current_measurements, source_type, SENSOR_TYPE_THIS_MONTH
|
||||
),
|
||||
SENSOR_TYPE_THIS_YEAR: _get_cumulative_value(
|
||||
current_measurements, source_type, SENSOR_TYPE_THIS_YEAR
|
||||
),
|
||||
}
|
||||
for source_type in SOURCE_TYPES
|
||||
}
|
||||
except HuisbaasjeException as exception:
|
||||
raise UpdateFailed(f"Error communicating with API: {exception}") from exception
|
||||
|
||||
|
||||
def _get_cumulative_value(
|
||||
current_measurements: dict,
|
||||
source_type: str,
|
||||
period_type: str,
|
||||
):
|
||||
"""
|
||||
Get the cumulative energy consumption for a certain period.
|
||||
|
||||
:param current_measurements: The result from the Huisbaasje client
|
||||
:param source_type: The source of energy (electricity or gas)
|
||||
:param period_type: The period for which cumulative value should be given.
|
||||
"""
|
||||
if source_type in current_measurements.keys():
|
||||
if (
|
||||
period_type in current_measurements[source_type]
|
||||
and current_measurements[source_type][period_type] is not None
|
||||
):
|
||||
return current_measurements[source_type][period_type]["value"]
|
||||
else:
|
||||
_LOGGER.error(
|
||||
"Source type %s not present in %s", source_type, current_measurements
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
def _get_measurement_rate(current_measurements: dict, source_type: str):
|
||||
if source_type in current_measurements:
|
||||
if (
|
||||
"measurement" in current_measurements[source_type]
|
||||
and current_measurements[source_type]["measurement"] is not None
|
||||
):
|
||||
return current_measurements[source_type]["measurement"]["rate"]
|
||||
else:
|
||||
_LOGGER.error(
|
||||
"Source type %s not present in %s", source_type, current_measurements
|
||||
)
|
||||
return None
|
84
homeassistant/components/huisbaasje/config_flow.py
Normal file
84
homeassistant/components/huisbaasje/config_flow.py
Normal file
@ -0,0 +1,84 @@
|
||||
"""Config flow for Huisbaasje integration."""
|
||||
import logging
|
||||
|
||||
from huisbaasje import Huisbaasje, HuisbaasjeConnectionException, HuisbaasjeException
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_ID, CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.data_entry_flow import AbortFlow
|
||||
|
||||
from .const import DOMAIN # pylint: disable=unused-import
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DATA_SCHEMA = vol.Schema(
|
||||
{vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str}
|
||||
)
|
||||
|
||||
|
||||
class HuisbaasjeConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for Huisbaasje."""
|
||||
|
||||
VERSION = 1
|
||||
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Handle a flow initiated by the user."""
|
||||
if user_input is None:
|
||||
return await self._show_setup_form(user_input)
|
||||
|
||||
errors = {}
|
||||
|
||||
try:
|
||||
user_id = await self._validate_input(user_input)
|
||||
|
||||
_LOGGER.info("Input for Huisbaasje is valid!")
|
||||
|
||||
# Set user id as unique id
|
||||
await self.async_set_unique_id(user_id)
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
# Create entry
|
||||
return self.async_create_entry(
|
||||
title=user_input[CONF_USERNAME],
|
||||
data={
|
||||
CONF_ID: user_id,
|
||||
CONF_USERNAME: user_input[CONF_USERNAME],
|
||||
CONF_PASSWORD: user_input[CONF_PASSWORD],
|
||||
},
|
||||
)
|
||||
except HuisbaasjeConnectionException as exception:
|
||||
_LOGGER.warning(exception)
|
||||
errors["base"] = "connection_exception"
|
||||
except HuisbaasjeException as exception:
|
||||
_LOGGER.warning(exception)
|
||||
errors["base"] = "invalid_auth"
|
||||
except AbortFlow as exception:
|
||||
raise exception
|
||||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.exception("Unexpected exception")
|
||||
errors["base"] = "unknown"
|
||||
|
||||
return await self._show_setup_form(user_input, errors)
|
||||
|
||||
async def _show_setup_form(self, user_input, errors=None):
|
||||
return self.async_show_form(
|
||||
step_id="user", data_schema=DATA_SCHEMA, errors=errors or {}
|
||||
)
|
||||
|
||||
async def _validate_input(self, user_input):
|
||||
"""Validate the user input allows us to connect.
|
||||
|
||||
Data has the keys from DATA_SCHEMA with values provided by the user.
|
||||
"""
|
||||
|
||||
username = user_input[CONF_USERNAME]
|
||||
password = user_input[CONF_PASSWORD]
|
||||
|
||||
huisbaasje = Huisbaasje(username, password)
|
||||
|
||||
# Attempt authentication. If this fails, an HuisbaasjeException will be thrown
|
||||
await huisbaasje.authenticate()
|
||||
|
||||
return huisbaasje.get_user_id()
|
142
homeassistant/components/huisbaasje/const.py
Normal file
142
homeassistant/components/huisbaasje/const.py
Normal file
@ -0,0 +1,142 @@
|
||||
"""Constants for the Huisbaasje integration."""
|
||||
from huisbaasje.const import (
|
||||
SOURCE_TYPE_ELECTRICITY,
|
||||
SOURCE_TYPE_ELECTRICITY_IN,
|
||||
SOURCE_TYPE_ELECTRICITY_IN_LOW,
|
||||
SOURCE_TYPE_ELECTRICITY_OUT,
|
||||
SOURCE_TYPE_ELECTRICITY_OUT_LOW,
|
||||
SOURCE_TYPE_GAS,
|
||||
)
|
||||
|
||||
from homeassistant.const import (
|
||||
DEVICE_CLASS_POWER,
|
||||
ENERGY_KILO_WATT_HOUR,
|
||||
TIME_HOURS,
|
||||
VOLUME_CUBIC_METERS,
|
||||
)
|
||||
|
||||
DATA_COORDINATOR = "coordinator"
|
||||
|
||||
DOMAIN = "huisbaasje"
|
||||
|
||||
FLOW_CUBIC_METERS_PER_HOUR = f"{VOLUME_CUBIC_METERS}/{TIME_HOURS}"
|
||||
|
||||
"""Interval in seconds between polls to huisbaasje."""
|
||||
POLLING_INTERVAL = 20
|
||||
|
||||
"""Timeout for fetching sensor data"""
|
||||
FETCH_TIMEOUT = 10
|
||||
|
||||
SENSOR_TYPE_RATE = "rate"
|
||||
SENSOR_TYPE_THIS_DAY = "thisDay"
|
||||
SENSOR_TYPE_THIS_WEEK = "thisWeek"
|
||||
SENSOR_TYPE_THIS_MONTH = "thisMonth"
|
||||
SENSOR_TYPE_THIS_YEAR = "thisYear"
|
||||
|
||||
SOURCE_TYPES = [
|
||||
SOURCE_TYPE_ELECTRICITY,
|
||||
SOURCE_TYPE_ELECTRICITY_IN,
|
||||
SOURCE_TYPE_ELECTRICITY_IN_LOW,
|
||||
SOURCE_TYPE_ELECTRICITY_OUT,
|
||||
SOURCE_TYPE_ELECTRICITY_OUT_LOW,
|
||||
SOURCE_TYPE_GAS,
|
||||
]
|
||||
|
||||
SENSORS_INFO = [
|
||||
{
|
||||
"name": "Huisbaasje Current Power",
|
||||
"device_class": DEVICE_CLASS_POWER,
|
||||
"source_type": SOURCE_TYPE_ELECTRICITY,
|
||||
},
|
||||
{
|
||||
"name": "Huisbaasje Current Power In",
|
||||
"device_class": DEVICE_CLASS_POWER,
|
||||
"source_type": SOURCE_TYPE_ELECTRICITY_IN,
|
||||
},
|
||||
{
|
||||
"name": "Huisbaasje Current Power In Low",
|
||||
"device_class": DEVICE_CLASS_POWER,
|
||||
"source_type": SOURCE_TYPE_ELECTRICITY_IN_LOW,
|
||||
},
|
||||
{
|
||||
"name": "Huisbaasje Current Power Out",
|
||||
"device_class": DEVICE_CLASS_POWER,
|
||||
"source_type": SOURCE_TYPE_ELECTRICITY_OUT,
|
||||
},
|
||||
{
|
||||
"name": "Huisbaasje Current Power Out Low",
|
||||
"device_class": DEVICE_CLASS_POWER,
|
||||
"source_type": SOURCE_TYPE_ELECTRICITY_OUT_LOW,
|
||||
},
|
||||
{
|
||||
"name": "Huisbaasje Energy Today",
|
||||
"unit_of_measurement": ENERGY_KILO_WATT_HOUR,
|
||||
"source_type": SOURCE_TYPE_ELECTRICITY,
|
||||
"sensor_type": SENSOR_TYPE_THIS_DAY,
|
||||
"icon": "mdi:counter",
|
||||
"precision": 1,
|
||||
},
|
||||
{
|
||||
"name": "Huisbaasje Energy This Week",
|
||||
"unit_of_measurement": ENERGY_KILO_WATT_HOUR,
|
||||
"source_type": SOURCE_TYPE_ELECTRICITY,
|
||||
"sensor_type": SENSOR_TYPE_THIS_WEEK,
|
||||
"icon": "mdi:counter",
|
||||
"precision": 1,
|
||||
},
|
||||
{
|
||||
"name": "Huisbaasje Energy This Month",
|
||||
"unit_of_measurement": ENERGY_KILO_WATT_HOUR,
|
||||
"source_type": SOURCE_TYPE_ELECTRICITY,
|
||||
"sensor_type": SENSOR_TYPE_THIS_MONTH,
|
||||
"icon": "mdi:counter",
|
||||
"precision": 1,
|
||||
},
|
||||
{
|
||||
"name": "Huisbaasje Energy This Year",
|
||||
"unit_of_measurement": ENERGY_KILO_WATT_HOUR,
|
||||
"source_type": SOURCE_TYPE_ELECTRICITY,
|
||||
"sensor_type": SENSOR_TYPE_THIS_YEAR,
|
||||
"icon": "mdi:counter",
|
||||
"precision": 1,
|
||||
},
|
||||
{
|
||||
"name": "Huisbaasje Current Gas",
|
||||
"unit_of_measurement": FLOW_CUBIC_METERS_PER_HOUR,
|
||||
"source_type": SOURCE_TYPE_GAS,
|
||||
"icon": "mdi:fire",
|
||||
"precision": 1,
|
||||
},
|
||||
{
|
||||
"name": "Huisbaasje Gas Today",
|
||||
"unit_of_measurement": VOLUME_CUBIC_METERS,
|
||||
"source_type": SOURCE_TYPE_GAS,
|
||||
"sensor_type": SENSOR_TYPE_THIS_DAY,
|
||||
"icon": "mdi:counter",
|
||||
"precision": 1,
|
||||
},
|
||||
{
|
||||
"name": "Huisbaasje Gas This Week",
|
||||
"unit_of_measurement": VOLUME_CUBIC_METERS,
|
||||
"source_type": SOURCE_TYPE_GAS,
|
||||
"sensor_type": SENSOR_TYPE_THIS_WEEK,
|
||||
"icon": "mdi:counter",
|
||||
"precision": 1,
|
||||
},
|
||||
{
|
||||
"name": "Huisbaasje Gas This Month",
|
||||
"unit_of_measurement": VOLUME_CUBIC_METERS,
|
||||
"source_type": SOURCE_TYPE_GAS,
|
||||
"sensor_type": SENSOR_TYPE_THIS_MONTH,
|
||||
"icon": "mdi:counter",
|
||||
"precision": 1,
|
||||
},
|
||||
{
|
||||
"name": "Huisbaasje Gas This Year",
|
||||
"unit_of_measurement": VOLUME_CUBIC_METERS,
|
||||
"source_type": SOURCE_TYPE_GAS,
|
||||
"sensor_type": SENSOR_TYPE_THIS_YEAR,
|
||||
"icon": "mdi:counter",
|
||||
"precision": 1,
|
||||
},
|
||||
]
|
10
homeassistant/components/huisbaasje/manifest.json
Normal file
10
homeassistant/components/huisbaasje/manifest.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"domain": "huisbaasje",
|
||||
"name": "Huisbaasje",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/huisbaasje",
|
||||
"requirements": [
|
||||
"huisbaasje-client==0.1.0"
|
||||
],
|
||||
"codeowners": ["@denniss17"]
|
||||
}
|
95
homeassistant/components/huisbaasje/sensor.py
Normal file
95
homeassistant/components/huisbaasje/sensor.py
Normal file
@ -0,0 +1,95 @@
|
||||
"""Platform for sensor integration."""
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_ID, POWER_WATT
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import (
|
||||
CoordinatorEntity,
|
||||
DataUpdateCoordinator,
|
||||
)
|
||||
|
||||
from .const import DATA_COORDINATOR, DOMAIN, SENSOR_TYPE_RATE, SENSORS_INFO
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities
|
||||
):
|
||||
"""Set up the sensor platform."""
|
||||
coordinator = hass.data[DOMAIN][config_entry.entry_id][DATA_COORDINATOR]
|
||||
user_id = config_entry.data[CONF_ID]
|
||||
|
||||
async_add_entities(
|
||||
HuisbaasjeSensor(coordinator, user_id=user_id, **sensor_info)
|
||||
for sensor_info in SENSORS_INFO
|
||||
)
|
||||
|
||||
|
||||
class HuisbaasjeSensor(CoordinatorEntity):
|
||||
"""Defines a Huisbaasje sensor."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: DataUpdateCoordinator,
|
||||
user_id: str,
|
||||
name: str,
|
||||
source_type: str,
|
||||
device_class: str = None,
|
||||
sensor_type: str = SENSOR_TYPE_RATE,
|
||||
unit_of_measurement: str = POWER_WATT,
|
||||
icon: str = "mdi:lightning-bolt",
|
||||
precision: int = 0,
|
||||
):
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(coordinator)
|
||||
self._user_id = user_id
|
||||
self._name = name
|
||||
self._device_class = device_class
|
||||
self._unit_of_measurement = unit_of_measurement
|
||||
self._source_type = source_type
|
||||
self._sensor_type = sensor_type
|
||||
self._icon = icon
|
||||
self._precision = precision
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return an unique id for the sensor."""
|
||||
return f"{DOMAIN}_{self._user_id}_{self._source_type}_{self._sensor_type}"
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of the sensor."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def device_class(self) -> str:
|
||||
"""Return the device class of the sensor."""
|
||||
return self._device_class
|
||||
|
||||
@property
|
||||
def icon(self) -> str:
|
||||
"""Return the icon to use for the sensor."""
|
||||
return self._icon
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the sensor."""
|
||||
if self.coordinator.data[self._source_type][self._sensor_type] is not None:
|
||||
return round(
|
||||
self.coordinator.data[self._source_type][self._sensor_type],
|
||||
self._precision,
|
||||
)
|
||||
return None
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self) -> str:
|
||||
"""Return the unit of measurement."""
|
||||
return self._unit_of_measurement
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return if entity is available."""
|
||||
return (
|
||||
super().available
|
||||
and self.coordinator.data
|
||||
and self._source_type in self.coordinator.data
|
||||
and self.coordinator.data[self._source_type]
|
||||
)
|
21
homeassistant/components/huisbaasje/strings.json
Normal file
21
homeassistant/components/huisbaasje/strings.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"username": "[%key:common::config_flow::data::username%]",
|
||||
"password": "[%key:common::config_flow::data::password%]"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||
"unauthenticated_exception": "[%key:common::config_flow::error::invalid_auth%]",
|
||||
"connection_exception": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||
}
|
||||
}
|
||||
}
|
@ -94,6 +94,7 @@ FLOWS = [
|
||||
"homematicip_cloud",
|
||||
"huawei_lte",
|
||||
"hue",
|
||||
"huisbaasje",
|
||||
"hunterdouglas_powerview",
|
||||
"hvv_departures",
|
||||
"hyperion",
|
||||
|
@ -786,6 +786,9 @@ httplib2==0.18.1
|
||||
# homeassistant.components.huawei_lte
|
||||
huawei-lte-api==1.4.17
|
||||
|
||||
# homeassistant.components.huisbaasje
|
||||
huisbaasje-client==0.1.0
|
||||
|
||||
# homeassistant.components.hydrawise
|
||||
hydrawiser==0.2
|
||||
|
||||
|
@ -415,6 +415,9 @@ httplib2==0.18.1
|
||||
# homeassistant.components.huawei_lte
|
||||
huawei-lte-api==1.4.17
|
||||
|
||||
# homeassistant.components.huisbaasje
|
||||
huisbaasje-client==0.1.0
|
||||
|
||||
# homeassistant.components.hyperion
|
||||
hyperion-py==0.7.0
|
||||
|
||||
|
1
tests/components/huisbaasje/__init__.py
Normal file
1
tests/components/huisbaasje/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""Tests for the Huisbaasje integration."""
|
157
tests/components/huisbaasje/test_config_flow.py
Normal file
157
tests/components/huisbaasje/test_config_flow.py
Normal file
@ -0,0 +1,157 @@
|
||||
"""Test the Huisbaasje config flow."""
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant import config_entries, data_entry_flow, setup
|
||||
from homeassistant.components.huisbaasje.config_flow import (
|
||||
HuisbaasjeConnectionException,
|
||||
HuisbaasjeException,
|
||||
)
|
||||
from homeassistant.components.huisbaasje.const import DOMAIN
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_form(hass):
|
||||
"""Test we get the form."""
|
||||
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["errors"] == {}
|
||||
|
||||
with patch(
|
||||
"huisbaasje.Huisbaasje.authenticate", return_value=None
|
||||
) as mock_authenticate, patch(
|
||||
"huisbaasje.Huisbaasje.get_user_id",
|
||||
return_value="test-id",
|
||||
) as mock_get_user_id, patch(
|
||||
"homeassistant.components.huisbaasje.async_setup", return_value=True
|
||||
) as mock_setup, patch(
|
||||
"homeassistant.components.huisbaasje.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry:
|
||||
form_result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"username": "test-username",
|
||||
"password": "test-password",
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert form_result["type"] == "create_entry"
|
||||
assert form_result["title"] == "test-username"
|
||||
assert form_result["data"] == {
|
||||
"id": "test-id",
|
||||
"username": "test-username",
|
||||
"password": "test-password",
|
||||
}
|
||||
assert len(mock_authenticate.mock_calls) == 1
|
||||
assert len(mock_get_user_id.mock_calls) == 1
|
||||
assert len(mock_setup.mock_calls) == 1
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
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(
|
||||
"huisbaasje.Huisbaasje.authenticate",
|
||||
side_effect=HuisbaasjeException,
|
||||
):
|
||||
form_result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"username": "test-username",
|
||||
"password": "test-password",
|
||||
},
|
||||
)
|
||||
|
||||
assert form_result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert form_result["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(
|
||||
"huisbaasje.Huisbaasje.authenticate",
|
||||
side_effect=HuisbaasjeConnectionException,
|
||||
):
|
||||
form_result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"username": "test-username",
|
||||
"password": "test-password",
|
||||
},
|
||||
)
|
||||
|
||||
assert form_result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert form_result["errors"] == {"base": "connection_exception"}
|
||||
|
||||
|
||||
async def test_form_unknown_error(hass):
|
||||
"""Test we handle an unknown error."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
with patch(
|
||||
"huisbaasje.Huisbaasje.authenticate",
|
||||
side_effect=Exception,
|
||||
):
|
||||
form_result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"username": "test-username",
|
||||
"password": "test-password",
|
||||
},
|
||||
)
|
||||
|
||||
assert form_result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert form_result["errors"] == {"base": "unknown"}
|
||||
|
||||
|
||||
async def test_form_entry_exists(hass):
|
||||
"""Test we handle an already existing entry."""
|
||||
MockConfigEntry(
|
||||
unique_id="test-id",
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
"id": "test-id",
|
||||
"username": "test-username",
|
||||
"password": "test-password",
|
||||
},
|
||||
title="test-username",
|
||||
).add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
with patch("huisbaasje.Huisbaasje.authenticate", return_value=None), patch(
|
||||
"huisbaasje.Huisbaasje.get_user_id",
|
||||
return_value="test-id",
|
||||
), patch(
|
||||
"homeassistant.components.huisbaasje.async_setup", return_value=True
|
||||
), patch(
|
||||
"homeassistant.components.huisbaasje.async_setup_entry",
|
||||
return_value=True,
|
||||
):
|
||||
form_result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"username": "test-username",
|
||||
"password": "test-password",
|
||||
},
|
||||
)
|
||||
|
||||
assert form_result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||
assert form_result["reason"] == "already_configured"
|
79
tests/components/huisbaasje/test_data.py
Normal file
79
tests/components/huisbaasje/test_data.py
Normal file
@ -0,0 +1,79 @@
|
||||
"""Test data for the tests of the Huisbaasje integration."""
|
||||
MOCK_CURRENT_MEASUREMENTS = {
|
||||
"electricity": {
|
||||
"measurement": {
|
||||
"time": "2020-11-18T15:17:24.000Z",
|
||||
"rate": 1011.6666666666667,
|
||||
"value": 0.0033333333333333335,
|
||||
"costPerHour": 0.20233333333333337,
|
||||
"counterValue": 409.17166666631937,
|
||||
},
|
||||
"thisDay": {"value": 3.296665869, "cost": 0.6593331738},
|
||||
"thisWeek": {"value": 17.509996085, "cost": 3.5019992170000003},
|
||||
"thisMonth": {"value": 103.28830788, "cost": 20.657661576000002},
|
||||
"thisYear": {"value": 672.9781177300001, "cost": 134.595623546},
|
||||
},
|
||||
"electricityIn": {
|
||||
"measurement": {
|
||||
"time": "2020-11-18T15:17:24.000Z",
|
||||
"rate": 1011.6666666666667,
|
||||
"value": 0.0033333333333333335,
|
||||
"costPerHour": 0.20233333333333337,
|
||||
"counterValue": 409.17166666631937,
|
||||
},
|
||||
"thisDay": {"value": 2.669999453, "cost": 0.5339998906},
|
||||
"thisWeek": {"value": 15.328330291, "cost": 3.0656660582},
|
||||
"thisMonth": {"value": 72.986651896, "cost": 14.5973303792},
|
||||
"thisYear": {"value": 409.214880212, "cost": 81.84297604240001},
|
||||
},
|
||||
"electricityInLow": {
|
||||
"measurement": None,
|
||||
"thisDay": {"value": 0.6266664160000001, "cost": 0.1253332832},
|
||||
"thisWeek": {"value": 2.181665794, "cost": 0.43633315880000006},
|
||||
"thisMonth": {"value": 30.301655984000003, "cost": 6.060331196800001},
|
||||
"thisYear": {"value": 263.76323751800004, "cost": 52.75264750360001},
|
||||
},
|
||||
"electricityOut": {
|
||||
"measurement": None,
|
||||
"thisDay": {"value": 0.0, "cost": 0.0},
|
||||
"thisWeek": {"value": 0.0, "cost": 0.0},
|
||||
"thisMonth": {"value": 0.0, "cost": 0.0},
|
||||
"thisYear": {"value": 0.0, "cost": 0.0},
|
||||
},
|
||||
"electricityOutLow": {
|
||||
"measurement": None,
|
||||
"thisDay": {"value": 0.0, "cost": 0.0},
|
||||
"thisWeek": {"value": 0.0, "cost": 0.0},
|
||||
"thisMonth": {"value": 0.0, "cost": 0.0},
|
||||
"thisYear": {"value": 0.0, "cost": 0.0},
|
||||
},
|
||||
"gas": {
|
||||
"measurement": {
|
||||
"time": "2020-11-18T15:17:29.000Z",
|
||||
"rate": 0.0,
|
||||
"value": 0.0,
|
||||
"costPerHour": 0.0,
|
||||
"counterValue": 116.73000000002281,
|
||||
},
|
||||
"thisDay": {"value": 1.07, "cost": 0.642},
|
||||
"thisWeek": {"value": 5.634224386000001, "cost": 3.3805346316000007},
|
||||
"thisMonth": {"value": 39.14, "cost": 23.483999999999998},
|
||||
"thisYear": {"value": 116.73, "cost": 70.038},
|
||||
},
|
||||
}
|
||||
|
||||
MOCK_LIMITED_CURRENT_MEASUREMENTS = {
|
||||
"electricity": {
|
||||
"measurement": {
|
||||
"time": "2020-11-18T15:17:24.000Z",
|
||||
"rate": 1011.6666666666667,
|
||||
"value": 0.0033333333333333335,
|
||||
"costPerHour": 0.20233333333333337,
|
||||
"counterValue": 409.17166666631937,
|
||||
},
|
||||
"thisDay": {"value": 3.296665869, "cost": 0.6593331738},
|
||||
"thisWeek": {"value": 17.509996085, "cost": 3.5019992170000003},
|
||||
"thisMonth": {"value": 103.28830788, "cost": 20.657661576000002},
|
||||
"thisYear": {"value": 672.9781177300001, "cost": 134.595623546},
|
||||
}
|
||||
}
|
153
tests/components/huisbaasje/test_init.py
Normal file
153
tests/components/huisbaasje/test_init.py
Normal file
@ -0,0 +1,153 @@
|
||||
"""Test cases for the initialisation of the Huisbaasje integration."""
|
||||
from unittest.mock import patch
|
||||
|
||||
from huisbaasje import HuisbaasjeException
|
||||
|
||||
from homeassistant.components import huisbaasje
|
||||
from homeassistant.config_entries import (
|
||||
CONN_CLASS_CLOUD_POLL,
|
||||
ENTRY_STATE_LOADED,
|
||||
ENTRY_STATE_NOT_LOADED,
|
||||
ENTRY_STATE_SETUP_ERROR,
|
||||
ConfigEntry,
|
||||
)
|
||||
from homeassistant.const import CONF_ID, CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.components.huisbaasje.test_data import MOCK_CURRENT_MEASUREMENTS
|
||||
|
||||
|
||||
async def test_setup(hass: HomeAssistant):
|
||||
"""Test for successfully setting up the platform."""
|
||||
assert await async_setup_component(hass, huisbaasje.DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
assert huisbaasje.DOMAIN in hass.config.components
|
||||
|
||||
|
||||
async def test_setup_entry(hass: HomeAssistant):
|
||||
"""Test for successfully setting a config entry."""
|
||||
with patch(
|
||||
"huisbaasje.Huisbaasje.authenticate", return_value=None
|
||||
) as mock_authenticate, patch(
|
||||
"huisbaasje.Huisbaasje.is_authenticated", return_value=True
|
||||
) as mock_is_authenticated, patch(
|
||||
"huisbaasje.Huisbaasje.current_measurements",
|
||||
return_value=MOCK_CURRENT_MEASUREMENTS,
|
||||
) as mock_current_measurements:
|
||||
hass.config.components.add(huisbaasje.DOMAIN)
|
||||
config_entry = ConfigEntry(
|
||||
1,
|
||||
huisbaasje.DOMAIN,
|
||||
"userId",
|
||||
{
|
||||
CONF_ID: "userId",
|
||||
CONF_USERNAME: "username",
|
||||
CONF_PASSWORD: "password",
|
||||
},
|
||||
"test",
|
||||
CONN_CLASS_CLOUD_POLL,
|
||||
system_options={},
|
||||
)
|
||||
hass.config_entries._entries.append(config_entry)
|
||||
|
||||
assert config_entry.state == ENTRY_STATE_NOT_LOADED
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Assert integration is loaded
|
||||
assert config_entry.state == ENTRY_STATE_LOADED
|
||||
assert huisbaasje.DOMAIN in hass.config.components
|
||||
assert huisbaasje.DOMAIN in hass.data
|
||||
assert config_entry.entry_id in hass.data[huisbaasje.DOMAIN]
|
||||
|
||||
# Assert entities are loaded
|
||||
entities = hass.states.async_entity_ids("sensor")
|
||||
assert len(entities) == 14
|
||||
|
||||
# Assert mocks are called
|
||||
assert len(mock_authenticate.mock_calls) == 1
|
||||
assert len(mock_is_authenticated.mock_calls) == 1
|
||||
assert len(mock_current_measurements.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_setup_entry_error(hass: HomeAssistant):
|
||||
"""Test for successfully setting a config entry."""
|
||||
with patch(
|
||||
"huisbaasje.Huisbaasje.authenticate", side_effect=HuisbaasjeException
|
||||
) as mock_authenticate:
|
||||
hass.config.components.add(huisbaasje.DOMAIN)
|
||||
config_entry = ConfigEntry(
|
||||
1,
|
||||
huisbaasje.DOMAIN,
|
||||
"userId",
|
||||
{
|
||||
CONF_ID: "userId",
|
||||
CONF_USERNAME: "username",
|
||||
CONF_PASSWORD: "password",
|
||||
},
|
||||
"test",
|
||||
CONN_CLASS_CLOUD_POLL,
|
||||
system_options={},
|
||||
)
|
||||
hass.config_entries._entries.append(config_entry)
|
||||
|
||||
assert config_entry.state == ENTRY_STATE_NOT_LOADED
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Assert integration is loaded with error
|
||||
assert config_entry.state == ENTRY_STATE_SETUP_ERROR
|
||||
assert huisbaasje.DOMAIN not in hass.data
|
||||
|
||||
# Assert entities are not loaded
|
||||
entities = hass.states.async_entity_ids("sensor")
|
||||
assert len(entities) == 0
|
||||
|
||||
# Assert mocks are called
|
||||
assert len(mock_authenticate.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_unload_entry(hass: HomeAssistant):
|
||||
"""Test for successfully unloading the config entry."""
|
||||
with patch(
|
||||
"huisbaasje.Huisbaasje.authenticate", return_value=None
|
||||
) as mock_authenticate, patch(
|
||||
"huisbaasje.Huisbaasje.is_authenticated", return_value=True
|
||||
) as mock_is_authenticated, patch(
|
||||
"huisbaasje.Huisbaasje.current_measurements",
|
||||
return_value=MOCK_CURRENT_MEASUREMENTS,
|
||||
) as mock_current_measurements:
|
||||
hass.config.components.add(huisbaasje.DOMAIN)
|
||||
config_entry = ConfigEntry(
|
||||
1,
|
||||
huisbaasje.DOMAIN,
|
||||
"userId",
|
||||
{
|
||||
CONF_ID: "userId",
|
||||
CONF_USERNAME: "username",
|
||||
CONF_PASSWORD: "password",
|
||||
},
|
||||
"test",
|
||||
CONN_CLASS_CLOUD_POLL,
|
||||
system_options={},
|
||||
)
|
||||
hass.config_entries._entries.append(config_entry)
|
||||
|
||||
# Load config entry
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert config_entry.state == ENTRY_STATE_LOADED
|
||||
entities = hass.states.async_entity_ids("sensor")
|
||||
assert len(entities) == 14
|
||||
|
||||
# Unload config entry
|
||||
await hass.config_entries.async_unload(config_entry.entry_id)
|
||||
assert config_entry.state == ENTRY_STATE_NOT_LOADED
|
||||
entities = hass.states.async_entity_ids("sensor")
|
||||
assert len(entities) == 0
|
||||
|
||||
# Assert mocks are called
|
||||
assert len(mock_authenticate.mock_calls) == 1
|
||||
assert len(mock_is_authenticated.mock_calls) == 1
|
||||
assert len(mock_current_measurements.mock_calls) == 1
|
120
tests/components/huisbaasje/test_sensor.py
Normal file
120
tests/components/huisbaasje/test_sensor.py
Normal file
@ -0,0 +1,120 @@
|
||||
"""Test cases for the sensors of the Huisbaasje integration."""
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components import huisbaasje
|
||||
from homeassistant.config_entries import CONN_CLASS_CLOUD_POLL, ConfigEntry
|
||||
from homeassistant.const import CONF_ID, CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from tests.components.huisbaasje.test_data import (
|
||||
MOCK_CURRENT_MEASUREMENTS,
|
||||
MOCK_LIMITED_CURRENT_MEASUREMENTS,
|
||||
)
|
||||
|
||||
|
||||
async def test_setup_entry(hass: HomeAssistant):
|
||||
"""Test for successfully loading sensor states."""
|
||||
with patch(
|
||||
"huisbaasje.Huisbaasje.authenticate", return_value=None
|
||||
) as mock_authenticate, patch(
|
||||
"huisbaasje.Huisbaasje.is_authenticated", return_value=True
|
||||
) as mock_is_authenticated, patch(
|
||||
"huisbaasje.Huisbaasje.current_measurements",
|
||||
return_value=MOCK_CURRENT_MEASUREMENTS,
|
||||
) as mock_current_measurements:
|
||||
|
||||
hass.config.components.add(huisbaasje.DOMAIN)
|
||||
config_entry = ConfigEntry(
|
||||
1,
|
||||
huisbaasje.DOMAIN,
|
||||
"userId",
|
||||
{
|
||||
CONF_ID: "userId",
|
||||
CONF_USERNAME: "username",
|
||||
CONF_PASSWORD: "password",
|
||||
},
|
||||
"test",
|
||||
CONN_CLASS_CLOUD_POLL,
|
||||
system_options={},
|
||||
)
|
||||
hass.config_entries._entries.append(config_entry)
|
||||
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Assert data is loaded
|
||||
assert hass.states.get("sensor.huisbaasje_current_power").state == "1012.0"
|
||||
assert hass.states.get("sensor.huisbaasje_current_power_in").state == "1012.0"
|
||||
assert (
|
||||
hass.states.get("sensor.huisbaasje_current_power_in_low").state == "unknown"
|
||||
)
|
||||
assert hass.states.get("sensor.huisbaasje_current_power_out").state == "unknown"
|
||||
assert (
|
||||
hass.states.get("sensor.huisbaasje_current_power_out_low").state
|
||||
== "unknown"
|
||||
)
|
||||
assert hass.states.get("sensor.huisbaasje_current_gas").state == "0.0"
|
||||
assert hass.states.get("sensor.huisbaasje_energy_today").state == "3.3"
|
||||
assert hass.states.get("sensor.huisbaasje_energy_this_week").state == "17.5"
|
||||
assert hass.states.get("sensor.huisbaasje_energy_this_month").state == "103.3"
|
||||
assert hass.states.get("sensor.huisbaasje_energy_this_year").state == "673.0"
|
||||
assert hass.states.get("sensor.huisbaasje_gas_today").state == "1.1"
|
||||
assert hass.states.get("sensor.huisbaasje_gas_this_week").state == "5.6"
|
||||
assert hass.states.get("sensor.huisbaasje_gas_this_month").state == "39.1"
|
||||
assert hass.states.get("sensor.huisbaasje_gas_this_year").state == "116.7"
|
||||
|
||||
# Assert mocks are called
|
||||
assert len(mock_authenticate.mock_calls) == 1
|
||||
assert len(mock_is_authenticated.mock_calls) == 1
|
||||
assert len(mock_current_measurements.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_setup_entry_absent_measurement(hass: HomeAssistant):
|
||||
"""Test for successfully loading sensor states when response does not contain all measurements."""
|
||||
with patch(
|
||||
"huisbaasje.Huisbaasje.authenticate", return_value=None
|
||||
) as mock_authenticate, patch(
|
||||
"huisbaasje.Huisbaasje.is_authenticated", return_value=True
|
||||
) as mock_is_authenticated, patch(
|
||||
"huisbaasje.Huisbaasje.current_measurements",
|
||||
return_value=MOCK_LIMITED_CURRENT_MEASUREMENTS,
|
||||
) as mock_current_measurements:
|
||||
|
||||
hass.config.components.add(huisbaasje.DOMAIN)
|
||||
config_entry = ConfigEntry(
|
||||
1,
|
||||
huisbaasje.DOMAIN,
|
||||
"userId",
|
||||
{
|
||||
CONF_ID: "userId",
|
||||
CONF_USERNAME: "username",
|
||||
CONF_PASSWORD: "password",
|
||||
},
|
||||
"test",
|
||||
CONN_CLASS_CLOUD_POLL,
|
||||
system_options={},
|
||||
)
|
||||
hass.config_entries._entries.append(config_entry)
|
||||
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Assert data is loaded
|
||||
assert hass.states.get("sensor.huisbaasje_current_power").state == "1012.0"
|
||||
assert hass.states.get("sensor.huisbaasje_current_power_in").state == "unknown"
|
||||
assert (
|
||||
hass.states.get("sensor.huisbaasje_current_power_in_low").state == "unknown"
|
||||
)
|
||||
assert hass.states.get("sensor.huisbaasje_current_power_out").state == "unknown"
|
||||
assert (
|
||||
hass.states.get("sensor.huisbaasje_current_power_out_low").state
|
||||
== "unknown"
|
||||
)
|
||||
assert hass.states.get("sensor.huisbaasje_current_gas").state == "unknown"
|
||||
assert hass.states.get("sensor.huisbaasje_energy_today").state == "3.3"
|
||||
assert hass.states.get("sensor.huisbaasje_gas_today").state == "unknown"
|
||||
|
||||
# Assert mocks are called
|
||||
assert len(mock_authenticate.mock_calls) == 1
|
||||
assert len(mock_is_authenticated.mock_calls) == 1
|
||||
assert len(mock_current_measurements.mock_calls) == 1
|
Loading…
x
Reference in New Issue
Block a user