Update plugwise 0.16.2 (#65933)

This commit is contained in:
Franck Nijhof 2022-02-08 11:13:05 +01:00 committed by GitHub
parent 0ea82bdbfb
commit d12a392767
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 837 additions and 317 deletions

View File

@ -50,35 +50,33 @@ async def async_setup_entry(
config_entry.entry_id config_entry.entry_id
][COORDINATOR] ][COORDINATOR]
entities: list[BinarySensorEntity] = [] entities: list[PlugwiseBinarySensorEntity] = []
is_thermostat = api.single_master_thermostat() for device_id, device_properties in coordinator.data.devices.items():
all_devices = api.get_all_devices()
for dev_id, device_properties in all_devices.items():
if device_properties["class"] == "heater_central": if device_properties["class"] == "heater_central":
data = api.get_device_data(dev_id)
for description in BINARY_SENSORS: for description in BINARY_SENSORS:
if description.key not in data: if (
"binary_sensors" not in device_properties
or description.key not in device_properties["binary_sensors"]
):
continue continue
entities.append( entities.append(
PwBinarySensor( PlugwiseBinarySensorEntity(
api, api,
coordinator, coordinator,
device_properties["name"], device_properties["name"],
dev_id, device_id,
description, description,
) )
) )
if device_properties["class"] == "gateway" and is_thermostat is not None: if device_properties["class"] == "gateway":
entities.append( entities.append(
PwNotifySensor( PlugwiseNotifyBinarySensorEntity(
api, api,
coordinator, coordinator,
device_properties["name"], device_properties["name"],
dev_id, device_id,
BinarySensorEntityDescription( BinarySensorEntityDescription(
key="plugwise_notification", key="plugwise_notification",
name="Plugwise Notification", name="Plugwise Notification",
@ -89,7 +87,7 @@ async def async_setup_entry(
async_add_entities(entities, True) async_add_entities(entities, True)
class SmileBinarySensor(PlugwiseEntity, BinarySensorEntity): class PlugwiseBinarySensorEntity(PlugwiseEntity, BinarySensorEntity):
"""Represent Smile Binary Sensors.""" """Represent Smile Binary Sensors."""
def __init__( def __init__(
@ -106,36 +104,23 @@ class SmileBinarySensor(PlugwiseEntity, BinarySensorEntity):
self._attr_is_on = False self._attr_is_on = False
self._attr_unique_id = f"{dev_id}-{description.key}" self._attr_unique_id = f"{dev_id}-{description.key}"
if dev_id == self._api.heater_id: if dev_id == coordinator.data.gateway["heater_id"]:
self._entity_name = "Auxiliary" self._entity_name = "Auxiliary"
self._name = f"{self._entity_name} {description.name}" self._name = f"{self._entity_name} {description.name}"
if dev_id == self._api.gateway_id: if dev_id == coordinator.data.gateway["gateway_id"]:
self._entity_name = f"Smile {self._entity_name}" self._entity_name = f"Smile {self._entity_name}"
@callback @callback
def _async_process_data(self) -> None: def _async_process_data(self) -> None:
"""Update the entity.""" """Update the entity."""
raise NotImplementedError if not (data := self.coordinator.data.devices.get(self._dev_id)):
class PwBinarySensor(SmileBinarySensor):
"""Representation of a Plugwise binary_sensor."""
@callback
def _async_process_data(self) -> None:
"""Update the entity."""
if not (data := self._api.get_device_data(self._dev_id)):
LOGGER.error("Received no data for device %s", self._dev_id) LOGGER.error("Received no data for device %s", self._dev_id)
self.async_write_ha_state() self.async_write_ha_state()
return return
if self.entity_description.key not in data: self._attr_is_on = data["binary_sensors"].get(self.entity_description.key)
self.async_write_ha_state()
return
self._attr_is_on = data[self.entity_description.key]
if self.entity_description.key == "dhw_state": if self.entity_description.key == "dhw_state":
self._attr_icon = FLOW_ON_ICON if self._attr_is_on else FLOW_OFF_ICON self._attr_icon = FLOW_ON_ICON if self._attr_is_on else FLOW_OFF_ICON
@ -145,27 +130,15 @@ class PwBinarySensor(SmileBinarySensor):
self.async_write_ha_state() self.async_write_ha_state()
class PwNotifySensor(SmileBinarySensor): class PlugwiseNotifyBinarySensorEntity(PlugwiseBinarySensorEntity):
"""Representation of a Plugwise Notification binary_sensor.""" """Representation of a Plugwise Notification binary_sensor."""
def __init__(
self,
api: Smile,
coordinator: PlugwiseDataUpdateCoordinator,
name: str,
dev_id: str,
description: BinarySensorEntityDescription,
) -> None:
"""Set up the Plugwise API."""
super().__init__(api, coordinator, name, dev_id, description)
self._attr_extra_state_attributes = {}
@callback @callback
def _async_process_data(self) -> None: def _async_process_data(self) -> None:
"""Update the entity.""" """Update the entity."""
notify = self._api.notifications notify = self.coordinator.data.gateway["notifications"]
self._attr_extra_state_attributes = {}
for severity in SEVERITIES: for severity in SEVERITIES:
self._attr_extra_state_attributes[f"{severity}_msg"] = [] self._attr_extra_state_attributes[f"{severity}_msg"] = []

View File

@ -10,8 +10,9 @@ from homeassistant.components.climate.const import (
CURRENT_HVAC_HEAT, CURRENT_HVAC_HEAT,
CURRENT_HVAC_IDLE, CURRENT_HVAC_IDLE,
HVAC_MODE_AUTO, HVAC_MODE_AUTO,
HVAC_MODE_COOL,
HVAC_MODE_HEAT, HVAC_MODE_HEAT,
HVAC_MODE_HEAT_COOL, HVAC_MODE_OFF,
SUPPORT_PRESET_MODE, SUPPORT_PRESET_MODE,
SUPPORT_TARGET_TEMPERATURE, SUPPORT_TARGET_TEMPERATURE,
) )
@ -32,8 +33,8 @@ from .const import (
from .coordinator import PlugwiseDataUpdateCoordinator from .coordinator import PlugwiseDataUpdateCoordinator
from .entity import PlugwiseEntity from .entity import PlugwiseEntity
HVAC_MODES_HEAT_ONLY = [HVAC_MODE_HEAT, HVAC_MODE_AUTO] HVAC_MODES_HEAT_ONLY = [HVAC_MODE_HEAT, HVAC_MODE_AUTO, HVAC_MODE_OFF]
HVAC_MODES_HEAT_COOL = [HVAC_MODE_HEAT_COOL, HVAC_MODE_AUTO] HVAC_MODES_HEAT_COOL = [HVAC_MODE_HEAT, HVAC_MODE_COOL, HVAC_MODE_AUTO, HVAC_MODE_OFF]
async def async_setup_entry( async def async_setup_entry(
@ -45,24 +46,21 @@ async def async_setup_entry(
api = hass.data[DOMAIN][config_entry.entry_id]["api"] api = hass.data[DOMAIN][config_entry.entry_id]["api"]
coordinator = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR] coordinator = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR]
entities = [] entities: list[PlugwiseClimateEntity] = []
thermostat_classes = [ thermostat_classes = [
"thermostat", "thermostat",
"zone_thermostat", "zone_thermostat",
"thermostatic_radiator_valve", "thermostatic_radiator_valve",
] ]
all_devices = api.get_all_devices() for device_id, device_properties in coordinator.data.devices.items():
for dev_id, device_properties in all_devices.items():
if device_properties["class"] not in thermostat_classes: if device_properties["class"] not in thermostat_classes:
continue continue
thermostat = PwThermostat( thermostat = PlugwiseClimateEntity(
api, api,
coordinator, coordinator,
device_properties["name"], device_properties["name"],
dev_id, device_id,
device_properties["location"], device_properties["location"],
device_properties["class"], device_properties["class"],
) )
@ -72,7 +70,7 @@ async def async_setup_entry(
async_add_entities(entities, True) async_add_entities(entities, True)
class PwThermostat(PlugwiseEntity, ClimateEntity): class PlugwiseClimateEntity(PlugwiseEntity, ClimateEntity):
"""Representation of an Plugwise thermostat.""" """Representation of an Plugwise thermostat."""
_attr_hvac_mode = HVAC_MODE_HEAT _attr_hvac_mode = HVAC_MODE_HEAT
@ -90,21 +88,19 @@ class PwThermostat(PlugwiseEntity, ClimateEntity):
api: Smile, api: Smile,
coordinator: PlugwiseDataUpdateCoordinator, coordinator: PlugwiseDataUpdateCoordinator,
name: str, name: str,
dev_id: str, device_id: str,
loc_id: str, loc_id: str,
model: str, model: str,
) -> None: ) -> None:
"""Set up the Plugwise API.""" """Set up the Plugwise API."""
super().__init__(api, coordinator, name, dev_id) super().__init__(api, coordinator, name, device_id)
self._attr_extra_state_attributes = {} self._attr_extra_state_attributes = {}
self._attr_unique_id = f"{dev_id}-climate" self._attr_unique_id = f"{device_id}-climate"
self._api = api self._api = api
self._loc_id = loc_id self._loc_id = loc_id
self._model = model
self._presets = None self._presets = None
self._single_thermostat = self._api.single_master_thermostat()
async def async_set_temperature(self, **kwargs: Any) -> None: async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature.""" """Set new target temperature."""
@ -124,7 +120,7 @@ class PwThermostat(PlugwiseEntity, ClimateEntity):
async def async_set_hvac_mode(self, hvac_mode: str) -> None: async def async_set_hvac_mode(self, hvac_mode: str) -> None:
"""Set the hvac mode.""" """Set the hvac mode."""
state = SCHEDULE_OFF state = SCHEDULE_OFF
climate_data = self._api.get_device_data(self._dev_id) climate_data = self.coordinator.data.devices[self._dev_id]
if hvac_mode == HVAC_MODE_AUTO: if hvac_mode == HVAC_MODE_AUTO:
state = SCHEDULE_ON state = SCHEDULE_ON
@ -161,18 +157,20 @@ class PwThermostat(PlugwiseEntity, ClimateEntity):
@callback @callback
def _async_process_data(self) -> None: def _async_process_data(self) -> None:
"""Update the data for this climate device.""" """Update the data for this climate device."""
climate_data = self._api.get_device_data(self._dev_id) data = self.coordinator.data.devices[self._dev_id]
heater_central_data = self._api.get_device_data(self._api.heater_id) heater_central_data = self.coordinator.data.devices[
self.coordinator.data.gateway["heater_id"]
]
# Current & set temperatures # Current & set temperatures
if setpoint := climate_data.get("setpoint"): if setpoint := data["sensors"].get("setpoint"):
self._attr_target_temperature = setpoint self._attr_target_temperature = setpoint
if temperature := climate_data.get("temperature"): if temperature := data["sensors"].get("temperature"):
self._attr_current_temperature = temperature self._attr_current_temperature = temperature
# Presets handling # Presets handling
self._attr_preset_mode = climate_data.get("active_preset") self._attr_preset_mode = data.get("active_preset")
if presets := climate_data.get("presets"): if presets := data.get("presets"):
self._presets = presets self._presets = presets
self._attr_preset_modes = list(presets) self._attr_preset_modes = list(presets)
else: else:
@ -181,31 +179,22 @@ class PwThermostat(PlugwiseEntity, ClimateEntity):
# Determine current hvac action # Determine current hvac action
self._attr_hvac_action = CURRENT_HVAC_IDLE self._attr_hvac_action = CURRENT_HVAC_IDLE
if self._single_thermostat:
if heater_central_data.get("heating_state"): if heater_central_data.get("heating_state"):
self._attr_hvac_action = CURRENT_HVAC_HEAT self._attr_hvac_action = CURRENT_HVAC_HEAT
elif heater_central_data.get("cooling_state"): elif heater_central_data.get("cooling_state"):
self._attr_hvac_action = CURRENT_HVAC_COOL self._attr_hvac_action = CURRENT_HVAC_COOL
elif (
self.target_temperature is not None
and self.current_temperature is not None
and self.target_temperature > self.current_temperature
):
self._attr_hvac_action = CURRENT_HVAC_HEAT
# Determine hvac modes and current hvac mode # Determine hvac modes and current hvac mode
self._attr_hvac_mode = HVAC_MODE_HEAT
self._attr_hvac_modes = HVAC_MODES_HEAT_ONLY self._attr_hvac_modes = HVAC_MODES_HEAT_ONLY
if heater_central_data.get("compressor_state") is not None: if self.coordinator.data.gateway.get("cooling_present"):
self._attr_hvac_mode = HVAC_MODE_HEAT_COOL
self._attr_hvac_modes = HVAC_MODES_HEAT_COOL self._attr_hvac_modes = HVAC_MODES_HEAT_COOL
if climate_data.get("selected_schedule") is not None: if data.get("mode") in self._attr_hvac_modes:
self._attr_hvac_mode = HVAC_MODE_AUTO self._attr_hvac_mode = data["mode"]
# Extra attributes # Extra attributes
self._attr_extra_state_attributes = { self._attr_extra_state_attributes = {
"available_schemas": climate_data.get("available_schedules"), "available_schemas": data.get("available_schedules"),
"selected_schema": climate_data.get("selected_schedule"), "selected_schema": data.get("selected_schedule"),
} }
self.async_write_ha_state() self.async_write_ha_state()

View File

@ -1,17 +1,24 @@
"""DataUpdateCoordinator for Plugwise.""" """DataUpdateCoordinator for Plugwise."""
from datetime import timedelta from datetime import timedelta
from typing import Any, NamedTuple
import async_timeout
from plugwise import Smile from plugwise import Smile
from plugwise.exceptions import XMLDataMissingError from plugwise.exceptions import PlugwiseException, XMLDataMissingError
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DEFAULT_SCAN_INTERVAL, DEFAULT_TIMEOUT, DOMAIN, LOGGER from .const import DEFAULT_SCAN_INTERVAL, DOMAIN, LOGGER
class PlugwiseDataUpdateCoordinator(DataUpdateCoordinator[bool]): class PlugwiseData(NamedTuple):
"""Plugwise data stored in the DataUpdateCoordinator."""
gateway: dict[str, Any]
devices: dict[str, dict[str, Any]]
class PlugwiseDataUpdateCoordinator(DataUpdateCoordinator[PlugwiseData]):
"""Class to manage fetching Plugwise data from single endpoint.""" """Class to manage fetching Plugwise data from single endpoint."""
def __init__(self, hass: HomeAssistant, api: Smile) -> None: def __init__(self, hass: HomeAssistant, api: Smile) -> None:
@ -26,11 +33,14 @@ class PlugwiseDataUpdateCoordinator(DataUpdateCoordinator[bool]):
) )
self.api = api self.api = api
async def _async_update_data(self) -> bool: async def _async_update_data(self) -> PlugwiseData:
"""Fetch data from Plugwise.""" """Fetch data from Plugwise."""
try: try:
async with async_timeout.timeout(DEFAULT_TIMEOUT): data = await self.api.async_update()
await self.api.full_update_device()
except XMLDataMissingError as err: except XMLDataMissingError as err:
raise UpdateFailed("Smile update failed") from err raise UpdateFailed(
return True f"No XML data received for: {self.api.smile_name}"
) from err
except PlugwiseException as err:
raise UpdateFailed(f"Updated failed for: {self.api.smile_name}") from err
return PlugwiseData(*data)

View File

@ -14,14 +14,12 @@ from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN from .const import DOMAIN
from .coordinator import PlugwiseDataUpdateCoordinator from .coordinator import PlugwiseData, PlugwiseDataUpdateCoordinator
class PlugwiseEntity(CoordinatorEntity[bool]): class PlugwiseEntity(CoordinatorEntity[PlugwiseData]):
"""Represent a PlugWise Entity.""" """Represent a PlugWise Entity."""
_model: str | None = None
def __init__( def __init__(
self, self,
api: Smile, api: Smile,
@ -45,6 +43,7 @@ class PlugwiseEntity(CoordinatorEntity[bool]):
@property @property
def device_info(self) -> DeviceInfo: def device_info(self) -> DeviceInfo:
"""Return the device information.""" """Return the device information."""
data = self.coordinator.data.devices[self._dev_id]
device_information = DeviceInfo( device_information = DeviceInfo(
identifiers={(DOMAIN, self._dev_id)}, identifiers={(DOMAIN, self._dev_id)},
name=self._entity_name, name=self._entity_name,
@ -56,11 +55,14 @@ class PlugwiseEntity(CoordinatorEntity[bool]):
ATTR_CONFIGURATION_URL ATTR_CONFIGURATION_URL
] = f"http://{entry.data[CONF_HOST]}" ] = f"http://{entry.data[CONF_HOST]}"
if self._model is not None: if model := data.get("model"):
device_information[ATTR_MODEL] = self._model.replace("_", " ").title() device_information[ATTR_MODEL] = model
if self._dev_id != self._api.gateway_id: if self._dev_id != self.coordinator.data.gateway["gateway_id"]:
device_information[ATTR_VIA_DEVICE] = (DOMAIN, str(self._api.gateway_id)) device_information[ATTR_VIA_DEVICE] = (
DOMAIN,
str(self.coordinator.data.gateway["gateway_id"]),
)
return device_information return device_information

View File

@ -55,15 +55,14 @@ async def async_setup_entry_gw(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if not connected: if not connected:
raise ConfigEntryNotReady("Unable to connect to Smile") raise ConfigEntryNotReady("Unable to connect to Smile")
coordinator = PlugwiseDataUpdateCoordinator(hass, api)
await coordinator.async_config_entry_first_refresh()
api.get_all_devices() api.get_all_devices()
if entry.unique_id is None and api.smile_version[0] != "1.8.0": if entry.unique_id is None and api.smile_version[0] != "1.8.0":
hass.config_entries.async_update_entry(entry, unique_id=api.smile_hostname) hass.config_entries.async_update_entry(entry, unique_id=api.smile_hostname)
coordinator = PlugwiseDataUpdateCoordinator(hass, api)
await coordinator.async_config_entry_first_refresh()
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = { hass.data.setdefault(DOMAIN, {})[entry.entry_id] = {
"api": api, "api": api,
COORDINATOR: coordinator, COORDINATOR: coordinator,
@ -80,10 +79,8 @@ async def async_setup_entry_gw(hass: HomeAssistant, entry: ConfigEntry) -> bool:
sw_version=api.smile_version[0], sw_version=api.smile_version[0],
) )
single_master_thermostat = api.single_master_thermostat()
platforms = PLATFORMS_GATEWAY platforms = PLATFORMS_GATEWAY
if single_master_thermostat is None: if coordinator.data.gateway["single_master_thermostat"] is None:
platforms = SENSOR_PLATFORMS platforms = SENSOR_PLATFORMS
hass.config_entries.async_setup_platforms(entry, platforms) hass.config_entries.async_setup_platforms(entry, platforms)

View File

@ -2,7 +2,7 @@
"domain": "plugwise", "domain": "plugwise",
"name": "Plugwise", "name": "Plugwise",
"documentation": "https://www.home-assistant.io/integrations/plugwise", "documentation": "https://www.home-assistant.io/integrations/plugwise",
"requirements": ["plugwise==0.8.5"], "requirements": ["plugwise==0.16.2"],
"codeowners": ["@CoMPaTech", "@bouwew", "@brefra"], "codeowners": ["@CoMPaTech", "@bouwew", "@brefra"],
"zeroconf": ["_plugwise._tcp.local."], "zeroconf": ["_plugwise._tcp.local."],
"config_flow": true, "config_flow": true,

View File

@ -289,53 +289,37 @@ async def async_setup_entry(
api = hass.data[DOMAIN][config_entry.entry_id]["api"] api = hass.data[DOMAIN][config_entry.entry_id]["api"]
coordinator = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR] coordinator = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR]
entities: list[SmileSensor] = [] entities: list[PlugwiseSensorEnity] = []
all_devices = api.get_all_devices() for device_id, device_properties in coordinator.data.devices.items():
single_thermostat = api.single_master_thermostat()
for dev_id, device_properties in all_devices.items():
data = api.get_device_data(dev_id)
for description in SENSORS: for description in SENSORS:
if data.get(description.key) is None: if (
"sensors" not in device_properties
or device_properties["sensors"].get(description.key) is None
):
continue continue
if "power" in device_properties["types"]:
model = None
if "plug" in device_properties["types"]:
model = "Metered Switch"
entities.append( entities.append(
PwPowerSensor( PlugwiseSensorEnity(
api, api,
coordinator, coordinator,
device_properties["name"], device_properties["name"],
dev_id, device_id,
model,
description,
)
)
else:
entities.append(
PwThermostatSensor(
api,
coordinator,
device_properties["name"],
dev_id,
description, description,
) )
) )
if single_thermostat is False: if coordinator.data.gateway["single_master_thermostat"] is False:
# These sensors should actually be binary sensors.
for description in INDICATE_ACTIVE_LOCAL_DEVICE_SENSORS: for description in INDICATE_ACTIVE_LOCAL_DEVICE_SENSORS:
if description.key not in data: if description.key not in device_properties:
continue continue
entities.append( entities.append(
PwAuxDeviceSensor( PlugwiseAuxSensorEntity(
api, api,
coordinator, coordinator,
device_properties["name"], device_properties["name"],
dev_id, device_id,
description, description,
) )
) )
@ -344,47 +328,43 @@ async def async_setup_entry(
async_add_entities(entities, True) async_add_entities(entities, True)
class SmileSensor(PlugwiseEntity, SensorEntity): class PlugwiseSensorEnity(PlugwiseEntity, SensorEntity):
"""Represent Smile Sensors.""" """Represent Plugwise Sensors."""
def __init__( def __init__(
self, self,
api: Smile, api: Smile,
coordinator: PlugwiseDataUpdateCoordinator, coordinator: PlugwiseDataUpdateCoordinator,
name: str, name: str,
dev_id: str, device_id: str,
description: SensorEntityDescription, description: SensorEntityDescription,
) -> None: ) -> None:
"""Initialise the sensor.""" """Initialise the sensor."""
super().__init__(api, coordinator, name, dev_id) super().__init__(api, coordinator, name, device_id)
self.entity_description = description self.entity_description = description
self._attr_unique_id = f"{dev_id}-{description.key}" self._attr_unique_id = f"{device_id}-{description.key}"
if dev_id == self._api.heater_id: if device_id == coordinator.data.gateway["heater_id"]:
self._entity_name = "Auxiliary" self._entity_name = "Auxiliary"
self._name = f"{self._entity_name} {description.name}" self._name = f"{self._entity_name} {description.name}"
if dev_id == self._api.gateway_id: if device_id == coordinator.data.gateway["gateway_id"]:
self._entity_name = f"Smile {self._entity_name}" self._entity_name = f"Smile {self._entity_name}"
class PwThermostatSensor(SmileSensor):
"""Thermostat (or generic) sensor devices."""
@callback @callback
def _async_process_data(self) -> None: def _async_process_data(self) -> None:
"""Update the entity.""" """Update the entity."""
if not (data := self._api.get_device_data(self._dev_id)): if not (data := self.coordinator.data.devices.get(self._dev_id)):
LOGGER.error("Received no data for device %s", self._entity_name) LOGGER.error("Received no data for device %s", self._entity_name)
self.async_write_ha_state() self.async_write_ha_state()
return return
self._attr_native_value = data.get(self.entity_description.key) self._attr_native_value = data["sensors"].get(self.entity_description.key)
self.async_write_ha_state() self.async_write_ha_state()
class PwAuxDeviceSensor(SmileSensor): class PlugwiseAuxSensorEntity(PlugwiseSensorEnity):
"""Auxiliary Device Sensors.""" """Auxiliary Device Sensors."""
_cooling_state = False _cooling_state = False
@ -393,7 +373,7 @@ class PwAuxDeviceSensor(SmileSensor):
@callback @callback
def _async_process_data(self) -> None: def _async_process_data(self) -> None:
"""Update the entity.""" """Update the entity."""
if not (data := self._api.get_device_data(self._dev_id)): if not (data := self.coordinator.data.devices.get(self._dev_id)):
LOGGER.error("Received no data for device %s", self._entity_name) LOGGER.error("Received no data for device %s", self._entity_name)
self.async_write_ha_state() self.async_write_ha_state()
return return
@ -413,33 +393,3 @@ class PwAuxDeviceSensor(SmileSensor):
self._attr_icon = COOL_ICON self._attr_icon = COOL_ICON
self.async_write_ha_state() self.async_write_ha_state()
class PwPowerSensor(SmileSensor):
"""Power sensor entities."""
def __init__(
self,
api: Smile,
coordinator: PlugwiseDataUpdateCoordinator,
name: str,
dev_id: str,
model: str | None,
description: SensorEntityDescription,
) -> None:
"""Set up the Plugwise API."""
super().__init__(api, coordinator, name, dev_id, description)
self._model = model
if dev_id == self._api.gateway_id:
self._model = "P1 DSMR"
@callback
def _async_process_data(self) -> None:
"""Update the entity."""
if not (data := self._api.get_device_data(self._dev_id)):
LOGGER.error("Received no data for device %s", self._entity_name)
self.async_write_ha_state()
return
self._attr_native_value = data.get(self.entity_description.key)
self.async_write_ha_state()

View File

@ -25,34 +25,27 @@ async def async_setup_entry(
api = hass.data[DOMAIN][config_entry.entry_id]["api"] api = hass.data[DOMAIN][config_entry.entry_id]["api"]
coordinator = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR] coordinator = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR]
entities = [] entities: list[PlugwiseSwitchEntity] = []
switch_classes = ["plug", "switch_group"] for device_id, device_properties in coordinator.data.devices.items():
if (
all_devices = api.get_all_devices() "switches" not in device_properties
for dev_id, device_properties in all_devices.items(): or "relay" not in device_properties["switches"]
members = None
model = None
if any(
switch_class in device_properties["types"]
for switch_class in switch_classes
): ):
if "plug" in device_properties["types"]: continue
model = "Metered Switch"
if "switch_group" in device_properties["types"]:
members = device_properties["members"]
model = "Switch Group"
entities.append( entities.append(
GwSwitch( PlugwiseSwitchEntity(
api, coordinator, device_properties["name"], dev_id, members, model api,
coordinator,
device_properties["name"],
device_id,
) )
) )
async_add_entities(entities, True) async_add_entities(entities, True)
class GwSwitch(PlugwiseEntity, SwitchEntity): class PlugwiseSwitchEntity(PlugwiseEntity, SwitchEntity):
"""Representation of a Plugwise plug.""" """Representation of a Plugwise plug."""
_attr_icon = SWITCH_ICON _attr_icon = SWITCH_ICON
@ -62,24 +55,19 @@ class GwSwitch(PlugwiseEntity, SwitchEntity):
api: Smile, api: Smile,
coordinator: PlugwiseDataUpdateCoordinator, coordinator: PlugwiseDataUpdateCoordinator,
name: str, name: str,
dev_id: str, device_id: str,
members: list[str] | None,
model: str | None,
) -> None: ) -> None:
"""Set up the Plugwise API.""" """Set up the Plugwise API."""
super().__init__(api, coordinator, name, dev_id) super().__init__(api, coordinator, name, device_id)
self._attr_unique_id = f"{dev_id}-plug" self._attr_unique_id = f"{device_id}-plug"
self._members = coordinator.data.devices[device_id].get("members")
self._members = members
self._model = model
self._attr_is_on = False self._attr_is_on = False
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the device on.""" """Turn the device on."""
try: try:
state_on = await self._api.set_relay_state( state_on = await self._api.set_switch_state(
self._dev_id, self._members, "on" self._dev_id, self._members, "relay", "on"
) )
except PlugwiseException: except PlugwiseException:
LOGGER.error("Error while communicating to device") LOGGER.error("Error while communicating to device")
@ -91,8 +79,8 @@ class GwSwitch(PlugwiseEntity, SwitchEntity):
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the device off.""" """Turn the device off."""
try: try:
state_off = await self._api.set_relay_state( state_off = await self._api.set_switch_state(
self._dev_id, self._members, "off" self._dev_id, self._members, "relay", "off"
) )
except PlugwiseException: except PlugwiseException:
LOGGER.error("Error while communicating to device") LOGGER.error("Error while communicating to device")
@ -104,12 +92,10 @@ class GwSwitch(PlugwiseEntity, SwitchEntity):
@callback @callback
def _async_process_data(self) -> None: def _async_process_data(self) -> None:
"""Update the data from the Plugs.""" """Update the data from the Plugs."""
if not (data := self._api.get_device_data(self._dev_id)): if not (data := self.coordinator.data.devices.get(self._dev_id)):
LOGGER.error("Received no data for device %s", self._name) LOGGER.error("Received no data for device %s", self._name)
self.async_write_ha_state() self.async_write_ha_state()
return return
if "relay" in data: self._attr_is_on = data["switches"].get("relay")
self._attr_is_on = data["relay"]
self.async_write_ha_state() self.async_write_ha_state()

View File

@ -1264,7 +1264,7 @@ plexauth==0.0.6
plexwebsocket==0.0.13 plexwebsocket==0.0.13
# homeassistant.components.plugwise # homeassistant.components.plugwise
plugwise==0.8.5 plugwise==0.16.2
# homeassistant.components.plum_lightpad # homeassistant.components.plum_lightpad
plumlightpad==0.0.11 plumlightpad==0.0.11

View File

@ -10,7 +10,6 @@
codecov==2.1.12 codecov==2.1.12
coverage==6.3.1 coverage==6.3.1
freezegun==1.1.0 freezegun==1.1.0
jsonpickle==1.4.1
mock-open==1.4.0 mock-open==1.4.0
mypy==0.931 mypy==0.931
pre-commit==2.17.0 pre-commit==2.17.0

View File

@ -786,7 +786,7 @@ plexauth==0.0.6
plexwebsocket==0.0.13 plexwebsocket==0.0.13
# homeassistant.components.plugwise # homeassistant.components.plugwise
plugwise==0.8.5 plugwise==0.16.2
# homeassistant.components.plum_lightpad # homeassistant.components.plum_lightpad
plumlightpad==0.0.11 plumlightpad==0.0.11

View File

@ -3,7 +3,7 @@ PIP_CACHE=$1
# Number of existing dependency conflicts # Number of existing dependency conflicts
# Update if a PR resolve one! # Update if a PR resolve one!
DEPENDENCY_CONFLICTS=11 DEPENDENCY_CONFLICTS=10
PIP_CHECK=$(pip check --cache-dir=$PIP_CACHE) PIP_CHECK=$(pip check --cache-dir=$PIP_CACHE)
LINE_COUNT=$(echo "$PIP_CHECK" | wc -l) LINE_COUNT=$(echo "$PIP_CHECK" | wc -l)

View File

@ -4,10 +4,10 @@ from __future__ import annotations
from collections.abc import Generator from collections.abc import Generator
from functools import partial from functools import partial
from http import HTTPStatus from http import HTTPStatus
import json
import re import re
from unittest.mock import AsyncMock, MagicMock, Mock, patch from unittest.mock import AsyncMock, MagicMock, Mock, patch
import jsonpickle
from plugwise.exceptions import ( from plugwise.exceptions import (
ConnectionFailedError, ConnectionFailedError,
InvalidAuthentication, InvalidAuthentication,
@ -23,7 +23,7 @@ from tests.test_util.aiohttp import AiohttpClientMocker
def _read_json(environment, call): def _read_json(environment, call):
"""Undecode the json data.""" """Undecode the json data."""
fixture = load_fixture(f"plugwise/{environment}/{call}.json") fixture = load_fixture(f"plugwise/{environment}/{call}.json")
return jsonpickle.decode(fixture) return json.loads(fixture)
@pytest.fixture @pytest.fixture
@ -93,13 +93,11 @@ def mock_smile_adam():
smile_mock.return_value.smile_version = "3.0.15" smile_mock.return_value.smile_version = "3.0.15"
smile_mock.return_value.smile_type = "thermostat" smile_mock.return_value.smile_type = "thermostat"
smile_mock.return_value.smile_hostname = "smile98765" smile_mock.return_value.smile_hostname = "smile98765"
smile_mock.return_value.smile_name = "Adam"
smile_mock.return_value.notifications = _read_json(chosen_env, "notifications") smile_mock.return_value.notifications = _read_json(chosen_env, "notifications")
smile_mock.return_value.connect.side_effect = AsyncMock(return_value=True) smile_mock.return_value.connect.side_effect = AsyncMock(return_value=True)
smile_mock.return_value.full_update_device.side_effect = AsyncMock(
return_value=True
)
smile_mock.return_value.single_master_thermostat.side_effect = Mock( smile_mock.return_value.single_master_thermostat.side_effect = Mock(
return_value=False return_value=False
) )
@ -110,17 +108,13 @@ def mock_smile_adam():
smile_mock.return_value.set_temperature.side_effect = AsyncMock( smile_mock.return_value.set_temperature.side_effect = AsyncMock(
return_value=True return_value=True
) )
smile_mock.return_value.set_relay_state.side_effect = AsyncMock( smile_mock.return_value.async_update.side_effect = AsyncMock(
return_value=_read_json(chosen_env, "all_data")
)
smile_mock.return_value.set_switch_state.side_effect = AsyncMock(
return_value=True return_value=True
) )
smile_mock.return_value.get_all_devices.return_value = _read_json(
chosen_env, "get_all_devices"
)
smile_mock.return_value.get_device_data.side_effect = partial(
_get_device_data, chosen_env
)
yield smile_mock.return_value yield smile_mock.return_value
@ -138,13 +132,11 @@ def mock_smile_anna():
smile_mock.return_value.smile_version = "4.0.15" smile_mock.return_value.smile_version = "4.0.15"
smile_mock.return_value.smile_type = "thermostat" smile_mock.return_value.smile_type = "thermostat"
smile_mock.return_value.smile_hostname = "smile98765" smile_mock.return_value.smile_hostname = "smile98765"
smile_mock.return_value.smile_name = "Anna"
smile_mock.return_value.notifications = _read_json(chosen_env, "notifications") smile_mock.return_value.notifications = _read_json(chosen_env, "notifications")
smile_mock.return_value.connect.side_effect = AsyncMock(return_value=True) smile_mock.return_value.connect.side_effect = AsyncMock(return_value=True)
smile_mock.return_value.full_update_device.side_effect = AsyncMock(
return_value=True
)
smile_mock.return_value.single_master_thermostat.side_effect = Mock( smile_mock.return_value.single_master_thermostat.side_effect = Mock(
return_value=True return_value=True
) )
@ -155,12 +147,12 @@ def mock_smile_anna():
smile_mock.return_value.set_temperature.side_effect = AsyncMock( smile_mock.return_value.set_temperature.side_effect = AsyncMock(
return_value=True return_value=True
) )
smile_mock.return_value.set_relay_state.side_effect = AsyncMock( smile_mock.return_value.set_switch_state.side_effect = AsyncMock(
return_value=True return_value=True
) )
smile_mock.return_value.get_all_devices.return_value = _read_json( smile_mock.return_value.async_update.side_effect = AsyncMock(
chosen_env, "get_all_devices" return_value=_read_json(chosen_env, "all_data")
) )
smile_mock.return_value.get_device_data.side_effect = partial( smile_mock.return_value.get_device_data.side_effect = partial(
_get_device_data, chosen_env _get_device_data, chosen_env
@ -183,25 +175,24 @@ def mock_smile_p1():
smile_mock.return_value.smile_version = "3.3.9" smile_mock.return_value.smile_version = "3.3.9"
smile_mock.return_value.smile_type = "power" smile_mock.return_value.smile_type = "power"
smile_mock.return_value.smile_hostname = "smile98765" smile_mock.return_value.smile_hostname = "smile98765"
smile_mock.return_value.smile_name = "Smile P1"
smile_mock.return_value.notifications = _read_json(chosen_env, "notifications") smile_mock.return_value.notifications = _read_json(chosen_env, "notifications")
smile_mock.return_value.connect.side_effect = AsyncMock(return_value=True) smile_mock.return_value.connect.side_effect = AsyncMock(return_value=True)
smile_mock.return_value.full_update_device.side_effect = AsyncMock(
return_value=True
)
smile_mock.return_value.single_master_thermostat.side_effect = Mock( smile_mock.return_value.single_master_thermostat.side_effect = Mock(
return_value=None return_value=None
) )
smile_mock.return_value.get_all_devices.return_value = _read_json(
chosen_env, "get_all_devices"
)
smile_mock.return_value.get_device_data.side_effect = partial( smile_mock.return_value.get_device_data.side_effect = partial(
_get_device_data, chosen_env _get_device_data, chosen_env
) )
smile_mock.return_value.async_update.side_effect = AsyncMock(
return_value=_read_json(chosen_env, "all_data")
)
yield smile_mock.return_value yield smile_mock.return_value
@ -219,20 +210,18 @@ def mock_stretch():
smile_mock.return_value.smile_version = "3.1.11" smile_mock.return_value.smile_version = "3.1.11"
smile_mock.return_value.smile_type = "stretch" smile_mock.return_value.smile_type = "stretch"
smile_mock.return_value.smile_hostname = "stretch98765" smile_mock.return_value.smile_hostname = "stretch98765"
smile_mock.return_value.smile_name = "Stretch"
smile_mock.return_value.connect.side_effect = AsyncMock(return_value=True) smile_mock.return_value.connect.side_effect = AsyncMock(return_value=True)
smile_mock.return_value.full_update_device.side_effect = AsyncMock( smile_mock.return_value.set_switch_state.side_effect = AsyncMock(
return_value=True return_value=True
) )
smile_mock.return_value.set_relay_state.side_effect = AsyncMock(
return_value=True
)
smile_mock.return_value.get_all_devices.return_value = _read_json(
chosen_env, "get_all_devices"
)
smile_mock.return_value.get_device_data.side_effect = partial( smile_mock.return_value.get_device_data.side_effect = partial(
_get_device_data, chosen_env _get_device_data, chosen_env
) )
smile_mock.return_value.async_update.side_effect = AsyncMock(
return_value=_read_json(chosen_env, "all_data")
)
yield smile_mock.return_value yield smile_mock.return_value

View File

@ -0,0 +1,358 @@
[
{
"active_device": true,
"cooling_present": null,
"gateway_id": "fe799307f1624099878210aa0b9f1475",
"heater_id": "90986d591dcd426cae3ec3e8111ff730",
"single_master_thermostat": false,
"smile_name": "Adam",
"notifications": {
"af82e4ccf9c548528166d38e560662a4": {
"warning": "Node Plug (with MAC address 000D6F000D13CB01, in room 'n.a.') has been unreachable since 23:03 2020-01-18. Please check the connection and restart the device."
}
}
},
{
"df4a4a8169904cdb9c03d61a21f42140": {
"class": "zone_thermostat",
"fw": "2016-10-27T02:00:00+02:00",
"location": "12493538af164a409c6a1c79e38afe1c",
"model": "Lisa",
"name": "Zone Lisa Bios",
"vendor": "Plugwise",
"preset_modes": ["home", "asleep", "away", "vacation", "no_frost"],
"active_preset": "away",
"presets": {
"home": [20.0, 22.0],
"asleep": [17.0, 24.0],
"away": [15.0, 25.0],
"vacation": [15.0, 28.0],
"no_frost": [10.0, 30.0]
},
"available_schedules": [
"CV Roan",
"Bios Schema met Film Avond",
"GF7 Woonkamer",
"Badkamer Schema",
"CV Jessie"
],
"selected_schedule": "None",
"schedule_temperature": 15.0,
"last_used": "Badkamer Schema",
"mode": "off",
"sensors": { "temperature": 16.5, "setpoint": 13.0, "battery": 67 }
},
"b310b72a0e354bfab43089919b9a88bf": {
"class": "thermo_sensor",
"fw": "2019-03-27T01:00:00+01:00",
"location": "c50f167537524366a5af7aa3942feb1e",
"model": "Tom/Floor",
"name": "Floor kraan",
"vendor": "Plugwise",
"sensors": {
"temperature": 26.0,
"setpoint": 21.5,
"temperature_difference": 3.5,
"valve_position": 100
}
},
"a2c3583e0a6349358998b760cea82d2a": {
"class": "thermo_sensor",
"fw": "2019-03-27T01:00:00+01:00",
"location": "12493538af164a409c6a1c79e38afe1c",
"model": "Tom/Floor",
"name": "Bios Cv Thermostatic Radiator ",
"vendor": "Plugwise",
"sensors": {
"temperature": 17.2,
"setpoint": 13.0,
"battery": 62,
"temperature_difference": -0.2,
"valve_position": 0.0
}
},
"b59bcebaf94b499ea7d46e4a66fb62d8": {
"class": "zone_thermostat",
"fw": "2016-08-02T02:00:00+02:00",
"location": "c50f167537524366a5af7aa3942feb1e",
"model": "Lisa",
"name": "Zone Lisa WK",
"vendor": "Plugwise",
"preset_modes": ["home", "asleep", "away", "vacation", "no_frost"],
"active_preset": "home",
"presets": {
"home": [20.0, 22.0],
"asleep": [17.0, 24.0],
"away": [15.0, 25.0],
"vacation": [15.0, 28.0],
"no_frost": [10.0, 30.0]
},
"available_schedules": [
"CV Roan",
"Bios Schema met Film Avond",
"GF7 Woonkamer",
"Badkamer Schema",
"CV Jessie"
],
"selected_schedule": "GF7 Woonkamer",
"schedule_temperature": 20.0,
"last_used": "GF7 Woonkamer",
"mode": "auto",
"sensors": { "temperature": 20.9, "setpoint": 21.5, "battery": 34 }
},
"fe799307f1624099878210aa0b9f1475": {
"class": "gateway",
"fw": "3.0.15",
"location": "1f9dcf83fd4e4b66b72ff787957bfe5d",
"model": "Adam",
"name": "Adam",
"vendor": "Plugwise B.V.",
"binary_sensors": { "plugwise_notification": true },
"sensors": { "outdoor_temperature": 7.81 }
},
"d3da73bde12a47d5a6b8f9dad971f2ec": {
"class": "thermo_sensor",
"fw": "2019-03-27T01:00:00+01:00",
"location": "82fa13f017d240daa0d0ea1775420f24",
"model": "Tom/Floor",
"name": "Thermostatic Radiator Jessie",
"vendor": "Plugwise",
"sensors": {
"temperature": 17.1,
"setpoint": 15.0,
"battery": 62,
"temperature_difference": 0.1,
"valve_position": 0.0
}
},
"21f2b542c49845e6bb416884c55778d6": {
"class": "game_console",
"fw": "2019-06-21T02:00:00+02:00",
"location": "cd143c07248f491493cea0533bc3d669",
"model": "Plug",
"name": "Playstation Smart Plug",
"vendor": "Plugwise",
"sensors": {
"electricity_consumed": 82.6,
"electricity_consumed_interval": 8.6,
"electricity_produced": 0.0,
"electricity_produced_interval": 0.0
},
"switches": { "relay": true, "lock": false }
},
"78d1126fc4c743db81b61c20e88342a7": {
"class": "central_heating_pump",
"fw": "2019-06-21T02:00:00+02:00",
"location": "c50f167537524366a5af7aa3942feb1e",
"model": "Plug",
"name": "CV Pomp",
"vendor": "Plugwise",
"sensors": {
"electricity_consumed": 35.6,
"electricity_consumed_interval": 7.37,
"electricity_produced": 0.0,
"electricity_produced_interval": 0.0
},
"switches": { "relay": true }
},
"90986d591dcd426cae3ec3e8111ff730": {
"class": "heater_central",
"fw": null,
"location": "1f9dcf83fd4e4b66b72ff787957bfe5d",
"model": "Unknown",
"name": "OnOff",
"vendor": null,
"cooling_active": false,
"heating_state": true,
"sensors": {
"water_temperature": 70.0,
"intended_boiler_temperature": 70.0,
"modulation_level": 1,
"device_state": "heating"
}
},
"cd0ddb54ef694e11ac18ed1cbce5dbbd": {
"class": "vcr",
"fw": "2019-06-21T02:00:00+02:00",
"location": "cd143c07248f491493cea0533bc3d669",
"model": "Plug",
"name": "NAS",
"vendor": "Plugwise",
"sensors": {
"electricity_consumed": 16.5,
"electricity_consumed_interval": 0.5,
"electricity_produced": 0.0,
"electricity_produced_interval": 0.0
},
"switches": { "relay": true, "lock": true }
},
"4a810418d5394b3f82727340b91ba740": {
"class": "router",
"fw": "2019-06-21T02:00:00+02:00",
"location": "cd143c07248f491493cea0533bc3d669",
"model": "Plug",
"name": "USG Smart Plug",
"vendor": "Plugwise",
"sensors": {
"electricity_consumed": 8.5,
"electricity_consumed_interval": 0.0,
"electricity_produced": 0.0,
"electricity_produced_interval": 0.0
},
"switches": { "relay": true, "lock": true }
},
"02cf28bfec924855854c544690a609ef": {
"class": "vcr",
"fw": "2019-06-21T02:00:00+02:00",
"location": "cd143c07248f491493cea0533bc3d669",
"model": "Plug",
"name": "NVR",
"vendor": "Plugwise",
"sensors": {
"electricity_consumed": 34.0,
"electricity_consumed_interval": 9.15,
"electricity_produced": 0.0,
"electricity_produced_interval": 0.0
},
"switches": { "relay": true, "lock": true }
},
"a28f588dc4a049a483fd03a30361ad3a": {
"class": "settop",
"fw": "2019-06-21T02:00:00+02:00",
"location": "cd143c07248f491493cea0533bc3d669",
"model": "Plug",
"name": "Fibaro HC2",
"vendor": "Plugwise",
"sensors": {
"electricity_consumed": 12.5,
"electricity_consumed_interval": 3.8,
"electricity_produced": 0.0,
"electricity_produced_interval": 0.0
},
"switches": { "relay": true, "lock": true }
},
"6a3bf693d05e48e0b460c815a4fdd09d": {
"class": "zone_thermostat",
"fw": "2016-10-27T02:00:00+02:00",
"location": "82fa13f017d240daa0d0ea1775420f24",
"model": "Lisa",
"name": "Zone Thermostat Jessie",
"vendor": "Plugwise",
"preset_modes": ["home", "asleep", "away", "vacation", "no_frost"],
"active_preset": "asleep",
"presets": {
"home": [20.0, 22.0],
"asleep": [17.0, 24.0],
"away": [15.0, 25.0],
"vacation": [15.0, 28.0],
"no_frost": [10.0, 30.0]
},
"available_schedules": [
"CV Roan",
"Bios Schema met Film Avond",
"GF7 Woonkamer",
"Badkamer Schema",
"CV Jessie"
],
"selected_schedule": "CV Jessie",
"schedule_temperature": 15.0,
"last_used": "CV Jessie",
"mode": "auto",
"sensors": { "temperature": 17.2, "setpoint": 15.0, "battery": 37 }
},
"680423ff840043738f42cc7f1ff97a36": {
"class": "thermo_sensor",
"fw": "2019-03-27T01:00:00+01:00",
"location": "08963fec7c53423ca5680aa4cb502c63",
"model": "Tom/Floor",
"name": "Thermostatic Radiator Badkamer",
"vendor": "Plugwise",
"sensors": {
"temperature": 19.1,
"setpoint": 14.0,
"battery": 51,
"temperature_difference": -0.4,
"valve_position": 0.0
}
},
"f1fee6043d3642a9b0a65297455f008e": {
"class": "zone_thermostat",
"fw": "2016-10-27T02:00:00+02:00",
"location": "08963fec7c53423ca5680aa4cb502c63",
"model": "Lisa",
"name": "Zone Thermostat Badkamer",
"vendor": "Plugwise",
"preset_modes": ["home", "asleep", "away", "vacation", "no_frost"],
"active_preset": "away",
"presets": {
"home": [20.0, 22.0],
"asleep": [17.0, 24.0],
"away": [15.0, 25.0],
"vacation": [15.0, 28.0],
"no_frost": [10.0, 30.0]
},
"available_schedules": [
"CV Roan",
"Bios Schema met Film Avond",
"GF7 Woonkamer",
"Badkamer Schema",
"CV Jessie"
],
"selected_schedule": "Badkamer Schema",
"schedule_temperature": 15.0,
"last_used": "Badkamer Schema",
"mode": "auto",
"sensors": { "temperature": 18.9, "setpoint": 14.0, "battery": 92 }
},
"675416a629f343c495449970e2ca37b5": {
"class": "router",
"fw": "2019-06-21T02:00:00+02:00",
"location": "cd143c07248f491493cea0533bc3d669",
"model": "Plug",
"name": "Ziggo Modem",
"vendor": "Plugwise",
"sensors": {
"electricity_consumed": 12.2,
"electricity_consumed_interval": 2.97,
"electricity_produced": 0.0,
"electricity_produced_interval": 0.0
},
"switches": { "relay": true, "lock": true }
},
"e7693eb9582644e5b865dba8d4447cf1": {
"class": "thermostatic_radiator_valve",
"fw": "2019-03-27T01:00:00+01:00",
"location": "446ac08dd04d4eff8ac57489757b7314",
"model": "Tom/Floor",
"name": "CV Kraan Garage",
"vendor": "Plugwise",
"preset_modes": ["home", "asleep", "away", "vacation", "no_frost"],
"active_preset": "no_frost",
"presets": {
"home": [20.0, 22.0],
"asleep": [17.0, 24.0],
"away": [15.0, 25.0],
"vacation": [15.0, 28.0],
"no_frost": [10.0, 30.0]
},
"available_schedules": [
"CV Roan",
"Bios Schema met Film Avond",
"GF7 Woonkamer",
"Badkamer Schema",
"CV Jessie"
],
"selected_schedule": "None",
"schedule_temperature": 15.0,
"last_used": "Badkamer Schema",
"mode": "heat",
"sensors": {
"temperature": 15.6,
"setpoint": 5.5,
"battery": 68,
"temperature_difference": 0.0,
"valve_position": 0.0
}
}
}
]

View File

@ -1 +0,0 @@
{"df4a4a8169904cdb9c03d61a21f42140": {"name": "Zone Lisa Bios", "model": "Zone Thermostat", "types": {"py/set": ["thermostat"]}, "class": "zone_thermostat", "location": "12493538af164a409c6a1c79e38afe1c"}, "b310b72a0e354bfab43089919b9a88bf": {"name": "Floor kraan", "model": "Thermostatic Radiator Valve", "types": {"py/set": ["thermostat"]}, "class": "thermo_sensor", "location": "c50f167537524366a5af7aa3942feb1e"}, "a2c3583e0a6349358998b760cea82d2a": {"name": "Bios Cv Thermostatic Radiator ", "model": "Thermostatic Radiator Valve", "types": {"py/set": ["thermostat"]}, "class": "thermo_sensor", "location": "12493538af164a409c6a1c79e38afe1c"}, "b59bcebaf94b499ea7d46e4a66fb62d8": {"name": "Zone Lisa WK", "model": "Zone Thermostat", "types": {"py/set": ["thermostat"]}, "class": "zone_thermostat", "location": "c50f167537524366a5af7aa3942feb1e"}, "fe799307f1624099878210aa0b9f1475": {"name": "Adam", "model": "Smile Adam", "types": {"py/set": ["temperature", "thermostat", "home"]}, "class": "gateway", "location": "1f9dcf83fd4e4b66b72ff787957bfe5d"}, "d3da73bde12a47d5a6b8f9dad971f2ec": {"name": "Thermostatic Radiator Jessie", "model": "Thermostatic Radiator Valve", "types": {"py/set": ["thermostat"]}, "class": "thermo_sensor", "location": "82fa13f017d240daa0d0ea1775420f24"}, "21f2b542c49845e6bb416884c55778d6": {"name": "Playstation Smart Plug", "model": "Plug", "types": {"py/set": ["plug", "power"]}, "class": "game_console", "location": "cd143c07248f491493cea0533bc3d669"}, "78d1126fc4c743db81b61c20e88342a7": {"name": "CV Pomp", "model": "Plug", "types": {"py/set": ["plug", "power"]}, "class": "central_heating_pump", "location": "c50f167537524366a5af7aa3942feb1e"}, "90986d591dcd426cae3ec3e8111ff730": {"name": "Adam", "model": "Heater Central", "types": {"py/set": ["temperature", "thermostat", "home"]}, "class": "heater_central", "location": "1f9dcf83fd4e4b66b72ff787957bfe5d"}, "cd0ddb54ef694e11ac18ed1cbce5dbbd": {"name": "NAS", "model": "Plug", "types": {"py/set": ["plug", "power"]}, "class": "vcr", "location": "cd143c07248f491493cea0533bc3d669"}, "4a810418d5394b3f82727340b91ba740": {"name": "USG Smart Plug", "model": "Plug", "types": {"py/set": ["plug", "power"]}, "class": "router", "location": "cd143c07248f491493cea0533bc3d669"}, "02cf28bfec924855854c544690a609ef": {"name": "NVR", "model": "Plug", "types": {"py/set": ["plug", "power"]}, "class": "vcr", "location": "cd143c07248f491493cea0533bc3d669"}, "a28f588dc4a049a483fd03a30361ad3a": {"name": "Fibaro HC2", "model": "Plug", "types": {"py/set": ["plug", "power"]}, "class": "settop", "location": "cd143c07248f491493cea0533bc3d669"}, "6a3bf693d05e48e0b460c815a4fdd09d": {"name": "Zone Thermostat Jessie", "model": "Zone Thermostat", "types": {"py/set": ["thermostat"]}, "class": "zone_thermostat", "location": "82fa13f017d240daa0d0ea1775420f24"}, "680423ff840043738f42cc7f1ff97a36": {"name": "Thermostatic Radiator Badkamer", "model": "Thermostatic Radiator Valve", "types": {"py/set": ["thermostat"]}, "class": "thermo_sensor", "location": "08963fec7c53423ca5680aa4cb502c63"}, "f1fee6043d3642a9b0a65297455f008e": {"name": "Zone Thermostat Badkamer", "model": "Zone Thermostat", "types": {"py/set": ["thermostat"]}, "class": "zone_thermostat", "location": "08963fec7c53423ca5680aa4cb502c63"}, "675416a629f343c495449970e2ca37b5": {"name": "Ziggo Modem", "model": "Plug", "types": {"py/set": ["plug", "power"]}, "class": "router", "location": "cd143c07248f491493cea0533bc3d669"}, "e7693eb9582644e5b865dba8d4447cf1": {"name": "CV Kraan Garage", "model": "Thermostatic Radiator Valve", "types": {"py/set": ["thermostat"]}, "class": "thermostatic_radiator_valve", "location": "446ac08dd04d4eff8ac57489757b7314"}}

View File

@ -1 +0,0 @@
{"electricity_consumed": 34.0, "electricity_consumed_interval": 9.15, "electricity_produced": 0.0, "electricity_produced_interval": 0.0, "relay": true}

View File

@ -1 +0,0 @@
{"electricity_consumed": 82.6, "electricity_consumed_interval": 8.6, "electricity_produced": 0.0, "electricity_produced_interval": 0.0, "relay": true}

View File

@ -1 +0,0 @@
{"electricity_consumed": 8.5, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0, "relay": true}

View File

@ -1 +0,0 @@
{"electricity_consumed": 12.2, "electricity_consumed_interval": 2.97, "electricity_produced": 0.0, "electricity_produced_interval": 0.0, "relay": true}

View File

@ -1 +0,0 @@
{"temperature": 19.1, "setpoint": 14.0, "battery": 51, "temperature_difference": -0.4, "valve_position": 0.0}

View File

@ -1 +0,0 @@
{"temperature": 17.2, "setpoint": 15.0, "battery": 37, "active_preset": "asleep", "presets": {"home": [20.0, 22.0], "no_frost": [10.0, 30.0], "away": [12.0, 25.0], "vacation": [11.0, 28.0], "asleep": [16.0, 24.0]}, "schedule_temperature": 15.0, "available_schedules": ["CV Jessie"], "selected_schedule": "CV Jessie", "last_used": "CV Jessie"}

View File

@ -1 +0,0 @@
{"electricity_consumed": 35.6, "electricity_consumed_interval": 7.37, "electricity_produced": 0.0, "electricity_produced_interval": 0.0, "relay": true}

View File

@ -1 +0,0 @@
{"water_temperature": 70.0, "intended_boiler_temperature": 70.0, "modulation_level": 1, "heating_state": true}

View File

@ -1 +0,0 @@
{"electricity_consumed": 12.5, "electricity_consumed_interval": 3.8, "electricity_produced": 0.0, "electricity_produced_interval": 0.0, "relay": true}

View File

@ -1 +0,0 @@
{"temperature": 17.2, "setpoint": 13.0, "battery": 62, "temperature_difference": -0.2, "valve_position": 0.0}

View File

@ -1 +0,0 @@
{"temperature": 26.0, "setpoint": 21.5, "temperature_difference": 3.5, "valve_position": 100}

View File

@ -1 +0,0 @@
{"temperature": 20.9, "setpoint": 21.5, "battery": 34, "active_preset": "home", "presets": {"vacation": [15.0, 28.0], "asleep": [18.0, 24.0], "no_frost": [12.0, 30.0], "away": [17.0, 25.0], "home": [21.5, 22.0]}, "schedule_temperature": 21.5, "available_schedules": ["GF7 Woonkamer"], "selected_schedule": "GF7 Woonkamer", "last_used": "GF7 Woonkamer"}

View File

@ -1 +0,0 @@
{"electricity_consumed": 16.5, "electricity_consumed_interval": 0.5, "electricity_produced": 0.0, "electricity_produced_interval": 0.0, "relay": true}

View File

@ -1 +0,0 @@
{"temperature": 17.1, "setpoint": 15.0, "battery": 62, "temperature_difference": 0.1, "valve_position": 0.0}

View File

@ -1 +0,0 @@
{"temperature": 16.5, "setpoint": 13.0, "battery": 67, "active_preset": "away", "presets": {"home": [20.0, 22.0], "away": [12.0, 25.0], "vacation": [12.0, 28.0], "no_frost": [8.0, 30.0], "asleep": [15.0, 24.0]}, "schedule_temperature": null, "available_schedules": [], "selected_schedule": null, "last_used": null}

View File

@ -1 +0,0 @@
{"temperature": 15.6, "setpoint": 5.5, "battery": 68, "temperature_difference": 0.0, "valve_position": 0.0, "active_preset": "no_frost", "presets": {"home": [20.0, 22.0], "asleep": [17.0, 24.0], "away": [15.0, 25.0], "vacation": [15.0, 28.0], "no_frost": [10.0, 30.0]}, "schedule_temperature": null, "available_schedules": [], "selected_schedule": null, "last_used": null}

View File

@ -1 +0,0 @@
{"temperature": 18.9, "setpoint": 14.0, "battery": 92, "active_preset": "away", "presets": {"asleep": [17.0, 24.0], "no_frost": [10.0, 30.0], "away": [14.0, 25.0], "home": [21.0, 22.0], "vacation": [12.0, 28.0]}, "schedule_temperature": 14.0, "available_schedules": ["Badkamer Schema"], "selected_schedule": "Badkamer Schema", "last_used": "Badkamer Schema"}

View File

@ -1 +1,5 @@
{"af82e4ccf9c548528166d38e560662a4": {"warning": "Node Plug (with MAC address 000D6F000D13CB01, in room 'n.a.') has been unreachable since 23:03 2020-01-18. Please check the connection and restart the device."}} {
"af82e4ccf9c548528166d38e560662a4": {
"warning": "Node Plug (with MAC address 000D6F000D13CB01, in room 'n.a.') has been unreachable since 23:03 2020-01-18. Please check the connection and restart the device."
}
}

View File

@ -0,0 +1,79 @@
[
{
"active_device": true,
"cooling_present": true,
"gateway_id": "015ae9ea3f964e668e490fa39da3870b",
"heater_id": "1cbf783bb11e4a7c8a6843dee3a86927",
"single_master_thermostat": true,
"smile_name": "Anna",
"notifications": {}
},
{
"1cbf783bb11e4a7c8a6843dee3a86927": {
"class": "heater_central",
"fw": null,
"location": "a57efe5f145f498c9be62a9b63626fbf",
"model": "Generic heater",
"name": "OpenTherm",
"vendor": "Techneco",
"heating_state": true,
"compressor_state": true,
"cooling_state": false,
"cooling_active": false,
"binary_sensors": {
"dhw_state": false,
"slave_boiler_state": false,
"flame_state": false
},
"sensors": {
"outdoor_temperature": 3.0,
"water_temperature": 29.1,
"intended_boiler_temperature": 0.0,
"modulation_level": 52,
"return_temperature": 25.1,
"water_pressure": 1.57,
"device_state": "heating"
},
"switches": { "dhw_cm_switch": false }
},
"015ae9ea3f964e668e490fa39da3870b": {
"class": "gateway",
"fw": "4.0.15",
"location": "a57efe5f145f498c9be62a9b63626fbf",
"model": "Anna",
"name": "Anna",
"vendor": "Plugwise B.V.",
"binary_sensors": { "plugwise_notification": false },
"sensors": { "outdoor_temperature": 20.2 }
},
"3cb70739631c4d17a86b8b12e8a5161b": {
"class": "thermostat",
"fw": "2018-02-08T11:15:53+01:00",
"location": "c784ee9fdab44e1395b8dee7d7a497d5",
"model": "Anna",
"name": "Anna",
"vendor": "Plugwise",
"preset_modes": ["no_frost", "home", "away", "asleep", "vacation"],
"active_preset": "home",
"presets": {
"no_frost": [10.0, 30.0],
"home": [21.0, 22.0],
"away": [20.0, 25.0],
"asleep": [20.5, 24.0],
"vacation": [17.0, 28.0]
},
"available_schedules": ["None"],
"selected_schedule": "None",
"schedule_temperature": null,
"last_used": null,
"mode": "heat",
"sensors": {
"temperature": 19.3,
"setpoint": 21.0,
"illuminance": 86.0,
"cooling_activation_outdoor_temperature": 21.0,
"cooling_deactivation_threshold": 4
}
}
}
]

View File

@ -1 +0,0 @@
{"1cbf783bb11e4a7c8a6843dee3a86927": {"name": "Anna", "model": "Heater Central", "types": {"py/set": ["temperature", "thermostat", "home"]}, "class": "heater_central", "location": "a57efe5f145f498c9be62a9b63626fbf"}, "015ae9ea3f964e668e490fa39da3870b": {"name": "Anna", "model": "Smile Anna", "types": {"py/set": ["temperature", "thermostat", "home"]}, "class": "gateway", "location": "a57efe5f145f498c9be62a9b63626fbf"}, "3cb70739631c4d17a86b8b12e8a5161b": {"name": "Anna", "model": "Thermostat", "types": {"py/set": ["thermostat"]}, "class": "thermostat", "location": "c784ee9fdab44e1395b8dee7d7a497d5"}}

View File

@ -1 +0,0 @@
{"water_temperature": 29.1, "dhw_state": false, "intended_boiler_temperature": 0.0, "heating_state": false, "modulation_level": 52, "return_temperature": 25.1, "compressor_state": true, "cooling_state": false, "slave_boiler_state": false, "flame_state": false, "water_pressure": 1.57, "outdoor_temperature": 18.0}

View File

@ -1 +0,0 @@
{"temperature": 23.3, "setpoint": 21.0, "heating_state": false, "active_preset": "home", "presets": {"no_frost": [10.0, 30.0], "home": [21.0, 22.0], "away": [20.0, 25.0], "asleep": [20.5, 24.0], "vacation": [17.0, 28.0]}, "schedule_temperature": null, "available_schedules": ["standaard"], "selected_schedule": "standaard", "last_used": "standaard", "illuminance": 86.0}

View File

@ -0,0 +1,39 @@
[
{
"active_device": false,
"cooling_present": null,
"gateway_id": "e950c7d5e1ee407a858e2a8b5016c8b3",
"heater_id": null,
"single_master_thermostat": null,
"smile_name": "P1",
"notifications": {}
},
{
"e950c7d5e1ee407a858e2a8b5016c8b3": {
"class": "gateway",
"fw": "3.3.9",
"location": "cd3e822288064775a7c4afcdd70bdda2",
"model": "P1",
"name": "P1",
"vendor": "Plugwise B.V.",
"sensors": {
"net_electricity_point": -2816,
"electricity_consumed_peak_point": 0,
"electricity_consumed_off_peak_point": 0,
"net_electricity_cumulative": 442.972,
"electricity_consumed_peak_cumulative": 442.932,
"electricity_consumed_off_peak_cumulative": 551.09,
"electricity_consumed_peak_interval": 0,
"electricity_consumed_off_peak_interval": 0,
"electricity_produced_peak_point": 2816,
"electricity_produced_off_peak_point": 0,
"electricity_produced_peak_cumulative": 396.559,
"electricity_produced_off_peak_cumulative": 154.491,
"electricity_produced_peak_interval": 0,
"electricity_produced_off_peak_interval": 0,
"gas_consumed_cumulative": 584.85,
"gas_consumed_interval": 0.0
}
}
}
]

View File

@ -1 +0,0 @@
{"e950c7d5e1ee407a858e2a8b5016c8b3": {"name": "P1", "model": "Smile P1", "types": {"py/set": ["home", "power"]}, "class": "gateway", "location": "cd3e822288064775a7c4afcdd70bdda2"}}

View File

@ -1 +0,0 @@
{"net_electricity_point": -2761, "electricity_consumed_peak_point": 0, "electricity_consumed_off_peak_point": 0, "net_electricity_cumulative": 442.972, "electricity_consumed_peak_cumulative": 442.932, "electricity_consumed_off_peak_cumulative": 551.09, "net_electricity_interval": 0, "electricity_consumed_peak_interval": 0, "electricity_consumed_off_peak_interval": 0, "electricity_produced_peak_point": 2761, "electricity_produced_off_peak_point": 0, "electricity_produced_peak_cumulative": 396.559, "electricity_produced_off_peak_cumulative": 154.491, "electricity_produced_peak_interval": 0, "electricity_produced_off_peak_interval": 0, "gas_consumed_cumulative": 584.85, "gas_consumed_interval": 0.0}

View File

@ -0,0 +1,178 @@
[
{
"active_device": false,
"cooling_present": null,
"gateway_id": "0000aaaa0000aaaa0000aaaa0000aa00",
"heater_id": null,
"single_master_thermostat": null,
"smile_name": "Stretch",
"notifications": {}
},
{
"0000aaaa0000aaaa0000aaaa0000aa00": {
"class": "gateway",
"fw": "3.1.11",
"location": "0000aaaa0000aaaa0000aaaa0000aa00",
"vendor": "Plugwise B.V.",
"model": "Stretch",
"name": "Stretch"
},
"5ca521ac179d468e91d772eeeb8a2117": {
"class": "zz_misc",
"fw": null,
"location": "0000aaaa0000aaaa0000aaaa0000aa00",
"model": null,
"name": "Oven (793F84)",
"vendor": null,
"sensors": {
"electricity_consumed": 0.0,
"electricity_consumed_interval": 0.0,
"electricity_produced": 0.0,
"electricity_produced_interval": 0.0
},
"switches": { "relay": true, "lock": false }
},
"5871317346d045bc9f6b987ef25ee638": {
"class": "water_heater_vessel",
"fw": "2011-06-27T10:52:18+02:00",
"location": "0000aaaa0000aaaa0000aaaa0000aa00",
"model": "Circle type F",
"name": "Boiler (1EB31)",
"vendor": "Plugwise",
"sensors": {
"electricity_consumed": 1.19,
"electricity_consumed_interval": 0.0,
"electricity_produced": 0.0
},
"switches": { "relay": true, "lock": false }
},
"e1c884e7dede431dadee09506ec4f859": {
"class": "refrigerator",
"fw": "2011-06-27T10:47:37+02:00",
"location": "0000aaaa0000aaaa0000aaaa0000aa00",
"model": "Circle+ type F",
"name": "Koelkast (92C4A)",
"vendor": "Plugwise",
"sensors": {
"electricity_consumed": 50.5,
"electricity_consumed_interval": 0.08,
"electricity_produced": 0.0
},
"switches": { "relay": true, "lock": false }
},
"aac7b735042c4832ac9ff33aae4f453b": {
"class": "dishwasher",
"fw": "2011-06-27T10:52:18+02:00",
"location": "0000aaaa0000aaaa0000aaaa0000aa00",
"model": "Circle type F",
"name": "Vaatwasser (2a1ab)",
"vendor": "Plugwise",
"sensors": {
"electricity_consumed": 0.0,
"electricity_consumed_interval": 0.71,
"electricity_produced": 0.0
},
"switches": { "relay": true, "lock": false }
},
"cfe95cf3de1948c0b8955125bf754614": {
"class": "dryer",
"fw": "2011-06-27T10:52:18+02:00",
"location": "0000aaaa0000aaaa0000aaaa0000aa00",
"model": "Circle type F",
"name": "Droger (52559)",
"vendor": "Plugwise",
"sensors": {
"electricity_consumed": 0.0,
"electricity_consumed_interval": 0.0,
"electricity_produced": 0.0
},
"switches": { "relay": true, "lock": false }
},
"99f89d097be34fca88d8598c6dbc18ea": {
"class": "router",
"fw": null,
"location": "0000aaaa0000aaaa0000aaaa0000aa00",
"model": null,
"name": "Meterkast (787BFB)",
"vendor": null,
"sensors": {
"electricity_consumed": 27.6,
"electricity_consumed_interval": 28.2,
"electricity_produced": 0.0,
"electricity_produced_interval": 0.0
},
"switches": { "relay": true, "lock": true }
},
"059e4d03c7a34d278add5c7a4a781d19": {
"class": "washingmachine",
"fw": "2011-06-27T10:52:18+02:00",
"location": "0000aaaa0000aaaa0000aaaa0000aa00",
"model": "Circle type F",
"name": "Wasmachine (52AC1)",
"vendor": "Plugwise",
"sensors": {
"electricity_consumed": 0.0,
"electricity_consumed_interval": 0.0,
"electricity_produced": 0.0
},
"switches": { "relay": true, "lock": false }
},
"e309b52ea5684cf1a22f30cf0cd15051": {
"class": "computer_desktop",
"fw": null,
"location": "0000aaaa0000aaaa0000aaaa0000aa00",
"model": null,
"name": "Computer (788618)",
"vendor": null,
"sensors": {
"electricity_consumed": 156,
"electricity_consumed_interval": 163,
"electricity_produced": 0.0,
"electricity_produced_interval": 0.0
},
"switches": { "relay": true, "lock": true }
},
"71e1944f2a944b26ad73323e399efef0": {
"class": "switching",
"fw": null,
"location": null,
"model": "Switchgroup",
"name": "Test",
"members": ["5ca521ac179d468e91d772eeeb8a2117"],
"types": ["switch_group"],
"vendor": null,
"switches": { "relay": true }
},
"d950b314e9d8499f968e6db8d82ef78c": {
"class": "report",
"fw": null,
"location": null,
"model": "Switchgroup",
"name": "Stroomvreters",
"members": [
"059e4d03c7a34d278add5c7a4a781d19",
"5871317346d045bc9f6b987ef25ee638",
"aac7b735042c4832ac9ff33aae4f453b",
"cfe95cf3de1948c0b8955125bf754614",
"e1c884e7dede431dadee09506ec4f859"
],
"types": ["switch_group"],
"vendor": null,
"switches": { "relay": true }
},
"d03738edfcc947f7b8f4573571d90d2d": {
"class": "switching",
"fw": null,
"location": null,
"model": "Switchgroup",
"name": "Schakel",
"members": [
"059e4d03c7a34d278add5c7a4a781d19",
"cfe95cf3de1948c0b8955125bf754614"
],
"types": ["switch_group"],
"vendor": null,
"switches": { "relay": true }
}
}
]

View File

@ -1 +0,0 @@
{"5ca521ac179d468e91d772eeeb8a2117": {"name": "Oven (793F84)", "model": "Circle", "types": {"py/set": ["plug", "power"]}, "class": "zz_misc", "location": 0}, "5871317346d045bc9f6b987ef25ee638": {"name": "Boiler (1EB31)", "model": "Circle", "types": {"py/set": ["plug", "power"]}, "class": "water_heater_vessel", "location": 0}, "e1c884e7dede431dadee09506ec4f859": {"name": "Koelkast (92C4A)", "model": "Circle+", "types": {"py/set": ["plug", "power"]}, "class": "refrigerator", "location": 0}, "aac7b735042c4832ac9ff33aae4f453b": {"name": "Vaatwasser (2a1ab)", "model": "Circle", "types": {"py/set": ["plug", "power"]}, "class": "dishwasher", "location": 0}, "cfe95cf3de1948c0b8955125bf754614": {"name": "Droger (52559)", "model": "Circle", "types": {"py/set": ["plug", "power"]}, "class": "dryer", "location": 0}, "99f89d097be34fca88d8598c6dbc18ea": {"name": "Meterkast (787BFB)", "model": "Circle", "types": {"py/set": ["plug", "power"]}, "class": "router", "location": 0}, "059e4d03c7a34d278add5c7a4a781d19": {"name": "Wasmachine (52AC1)", "model": "Circle", "types": {"py/set": ["plug", "power"]}, "class": "washingmachine", "location": 0}, "e309b52ea5684cf1a22f30cf0cd15051": {"name": "Computer (788618)", "model": "Circle", "types": {"py/set": ["plug", "power"]}, "class": "computer_desktop", "location": 0}, "71e1944f2a944b26ad73323e399efef0": {"name": "Test", "model": "group_switch", "types": {"py/set": ["switch_group"]}, "class": "switching", "members": ["5ca521ac179d468e91d772eeeb8a2117"], "location": null}, "d950b314e9d8499f968e6db8d82ef78c": {"name": "Stroomvreters", "model": "group_switch", "types": {"py/set": ["switch_group"]}, "class": "report", "members": ["059e4d03c7a34d278add5c7a4a781d19", "5871317346d045bc9f6b987ef25ee638", "aac7b735042c4832ac9ff33aae4f453b", "cfe95cf3de1948c0b8955125bf754614", "e1c884e7dede431dadee09506ec4f859"], "location": null}, "d03738edfcc947f7b8f4573571d90d2d": {"name": "Schakel", "model": "group_switch", "types": {"py/set": ["switch_group"]}, "class": "switching", "members": ["059e4d03c7a34d278add5c7a4a781d19", "cfe95cf3de1948c0b8955125bf754614"], "location": null}}

View File

@ -1 +0,0 @@
{"electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "relay": true}

View File

@ -1 +0,0 @@
{"electricity_consumed": 1.19, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "relay": true}

View File

@ -1 +0,0 @@
{"electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "electricity_produced_interval": 0.0, "relay": true}

View File

@ -1 +0,0 @@
{"electricity_consumed": 27.6, "electricity_consumed_interval": 28.2, "electricity_produced": 0.0, "electricity_produced_interval": 0.0, "relay": true}

View File

@ -1 +0,0 @@
{"electricity_consumed": 0.0, "electricity_consumed_interval": 0.71, "electricity_produced": 0.0, "relay": true}

View File

@ -1 +0,0 @@
{"electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "relay": true}

View File

@ -1 +0,0 @@
{"electricity_consumed": 50.5, "electricity_consumed_interval": 0.08, "electricity_produced": 0.0, "relay": true}

View File

@ -1 +0,0 @@
{"electricity_consumed": 156, "electricity_consumed_interval": 163, "electricity_produced": 0.0, "electricity_produced_interval": 0.0, "relay": true}

View File

@ -2,7 +2,11 @@
from plugwise.exceptions import PlugwiseException from plugwise.exceptions import PlugwiseException
from homeassistant.components.climate.const import HVAC_MODE_AUTO, HVAC_MODE_HEAT from homeassistant.components.climate.const import (
HVAC_MODE_AUTO,
HVAC_MODE_HEAT,
HVAC_MODE_OFF,
)
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from tests.components.plugwise.common import async_init_integration from tests.components.plugwise.common import async_init_integration
@ -16,7 +20,7 @@ async def test_adam_climate_entity_attributes(hass, mock_smile_adam):
state = hass.states.get("climate.zone_lisa_wk") state = hass.states.get("climate.zone_lisa_wk")
attrs = state.attributes attrs = state.attributes
assert attrs["hvac_modes"] == [HVAC_MODE_HEAT, HVAC_MODE_AUTO] assert attrs["hvac_modes"] == [HVAC_MODE_HEAT, HVAC_MODE_AUTO, HVAC_MODE_OFF]
assert "preset_modes" in attrs assert "preset_modes" in attrs
assert "no_frost" in attrs["preset_modes"] assert "no_frost" in attrs["preset_modes"]
@ -32,7 +36,7 @@ async def test_adam_climate_entity_attributes(hass, mock_smile_adam):
state = hass.states.get("climate.zone_thermostat_jessie") state = hass.states.get("climate.zone_thermostat_jessie")
attrs = state.attributes attrs = state.attributes
assert attrs["hvac_modes"] == [HVAC_MODE_HEAT, HVAC_MODE_AUTO] assert attrs["hvac_modes"] == [HVAC_MODE_HEAT, HVAC_MODE_AUTO, HVAC_MODE_OFF]
assert "preset_modes" in attrs assert "preset_modes" in attrs
assert "no_frost" in attrs["preset_modes"] assert "no_frost" in attrs["preset_modes"]
@ -144,17 +148,17 @@ async def test_anna_climate_entity_attributes(hass, mock_smile_anna):
attrs = state.attributes attrs = state.attributes
assert "hvac_modes" in attrs assert "hvac_modes" in attrs
assert "heat_cool" in attrs["hvac_modes"] assert "heat" in attrs["hvac_modes"]
assert "preset_modes" in attrs assert "preset_modes" in attrs
assert "no_frost" in attrs["preset_modes"] assert "no_frost" in attrs["preset_modes"]
assert "home" in attrs["preset_modes"] assert "home" in attrs["preset_modes"]
assert attrs["current_temperature"] == 23.3 assert attrs["current_temperature"] == 19.3
assert attrs["temperature"] == 21.0 assert attrs["temperature"] == 21.0
assert state.state == HVAC_MODE_AUTO assert state.state == HVAC_MODE_HEAT
assert attrs["hvac_action"] == "idle" assert attrs["hvac_action"] == "heating"
assert attrs["preset_mode"] == "home" assert attrs["preset_mode"] == "home"
assert attrs["supported_features"] == 17 assert attrs["supported_features"] == 17

View File

@ -39,7 +39,7 @@ async def test_smile_timeout(hass, mock_smile_notconnect):
async def test_smile_adam_xmlerror(hass, mock_smile_adam): async def test_smile_adam_xmlerror(hass, mock_smile_adam):
"""Detect malformed XML by Smile in Adam environment.""" """Detect malformed XML by Smile in Adam environment."""
mock_smile_adam.full_update_device.side_effect = XMLDataMissingError mock_smile_adam.async_update.side_effect = XMLDataMissingError
entry = await async_init_integration(hass, mock_smile_adam) entry = await async_init_integration(hass, mock_smile_adam)
assert entry.state is ConfigEntryState.SETUP_RETRY assert entry.state is ConfigEntryState.SETUP_RETRY

View File

@ -37,7 +37,7 @@ async def test_anna_as_smt_climate_sensor_entities(hass, mock_smile_anna):
assert entry.state is ConfigEntryState.LOADED assert entry.state is ConfigEntryState.LOADED
state = hass.states.get("sensor.auxiliary_outdoor_temperature") state = hass.states.get("sensor.auxiliary_outdoor_temperature")
assert float(state.state) == 18.0 assert float(state.state) == 3.0
state = hass.states.get("sensor.auxiliary_water_temperature") state = hass.states.get("sensor.auxiliary_water_temperature")
assert float(state.state) == 29.1 assert float(state.state) == 29.1
@ -53,7 +53,7 @@ async def test_anna_climate_sensor_entities(hass, mock_smile_anna):
assert entry.state is ConfigEntryState.LOADED assert entry.state is ConfigEntryState.LOADED
state = hass.states.get("sensor.auxiliary_outdoor_temperature") state = hass.states.get("sensor.auxiliary_outdoor_temperature")
assert float(state.state) == 18.0 assert float(state.state) == 3.0
async def test_p1_dsmr_sensor_entities(hass, mock_smile_p1): async def test_p1_dsmr_sensor_entities(hass, mock_smile_p1):
@ -62,13 +62,13 @@ async def test_p1_dsmr_sensor_entities(hass, mock_smile_p1):
assert entry.state is ConfigEntryState.LOADED assert entry.state is ConfigEntryState.LOADED
state = hass.states.get("sensor.p1_net_electricity_point") state = hass.states.get("sensor.p1_net_electricity_point")
assert float(state.state) == -2761.0 assert float(state.state) == -2816.0
state = hass.states.get("sensor.p1_electricity_consumed_off_peak_cumulative") state = hass.states.get("sensor.p1_electricity_consumed_off_peak_cumulative")
assert float(state.state) == 551.09 assert float(state.state) == 551.09
state = hass.states.get("sensor.p1_electricity_produced_peak_point") state = hass.states.get("sensor.p1_electricity_produced_peak_point")
assert float(state.state) == 2761.0 assert float(state.state) == 2816.0
state = hass.states.get("sensor.p1_electricity_consumed_peak_cumulative") state = hass.states.get("sensor.p1_electricity_consumed_peak_cumulative")
assert float(state.state) == 442.932 assert float(state.state) == 442.932

View File

@ -21,7 +21,7 @@ async def test_adam_climate_switch_entities(hass, mock_smile_adam):
async def test_adam_climate_switch_negative_testing(hass, mock_smile_adam): async def test_adam_climate_switch_negative_testing(hass, mock_smile_adam):
"""Test exceptions of climate related switch entities.""" """Test exceptions of climate related switch entities."""
mock_smile_adam.set_relay_state.side_effect = PlugwiseException mock_smile_adam.set_switch_state.side_effect = PlugwiseException
entry = await async_init_integration(hass, mock_smile_adam) entry = await async_init_integration(hass, mock_smile_adam)
assert entry.state is ConfigEntryState.LOADED assert entry.state is ConfigEntryState.LOADED