Refactor home --> hap for Homematic IP Cloud (#27368)

* Refactor home to hap for Homematic IP Cloud

* Add some tests

* Rename ha_entity --> ha_state

* use asynctest.Mock
This commit is contained in:
SukramJ 2019-10-11 16:36:46 +02:00 committed by Martin Hjelmare
parent 0c8e208fd8
commit 8bbf261302
17 changed files with 872 additions and 289 deletions

View file

@ -2,7 +2,6 @@
import logging
from homematicip.aio.group import AsyncSecurityZoneGroup
from homematicip.aio.home import AsyncHome
from homematicip.base.enums import WindowState
from homeassistant.components.alarm_control_panel import AlarmControlPanel
@ -16,6 +15,7 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID
from .hap import HomematicipHAP
_LOGGER = logging.getLogger(__name__)
@ -31,15 +31,15 @@ async def async_setup_entry(
hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP alrm control panel from a config entry."""
home = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]].home
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
devices = []
security_zones = []
for group in home.groups:
for group in hap.home.groups:
if isinstance(group, AsyncSecurityZoneGroup):
security_zones.append(group)
if security_zones:
devices.append(HomematicipAlarmControlPanel(home, security_zones))
devices.append(HomematicipAlarmControlPanel(hap, security_zones))
if devices:
async_add_entities(devices)
@ -48,9 +48,9 @@ async def async_setup_entry(
class HomematicipAlarmControlPanel(AlarmControlPanel):
"""Representation of an alarm control panel."""
def __init__(self, home: AsyncHome, security_zones) -> None:
def __init__(self, hap: HomematicipHAP, security_zones) -> None:
"""Initialize the alarm control panel."""
self._home = home
self._home = hap.home
self.alarm_state = STATE_ALARM_DISARMED
for security_zone in security_zones:

View file

@ -20,7 +20,6 @@ from homematicip.aio.device import (
AsyncWeatherSensorPro,
)
from homematicip.aio.group import AsyncSecurityGroup, AsyncSecurityZoneGroup
from homematicip.aio.home import AsyncHome
from homematicip.base.enums import SmokeDetectorAlarmType, WindowState
from homeassistant.components.binary_sensor import (
@ -41,6 +40,7 @@ from homeassistant.core import HomeAssistant
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice
from .device import ATTR_GROUP_MEMBER_UNREACHABLE
from .hap import HomematicipHAP
_LOGGER = logging.getLogger(__name__)
@ -85,18 +85,18 @@ async def async_setup_entry(
hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP Cloud binary sensor from a config entry."""
home = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]].home
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
devices = []
for device in home.devices:
for device in hap.home.devices:
if isinstance(device, AsyncAccelerationSensor):
devices.append(HomematicipAccelerationSensor(home, device))
devices.append(HomematicipAccelerationSensor(hap, device))
if isinstance(device, (AsyncContactInterface, AsyncFullFlushContactInterface)):
devices.append(HomematicipContactInterface(home, device))
devices.append(HomematicipContactInterface(hap, device))
if isinstance(
device,
(AsyncShutterContact, AsyncShutterContactMagnetic, AsyncRotaryHandleSensor),
):
devices.append(HomematicipShutterContact(home, device))
devices.append(HomematicipShutterContact(hap, device))
if isinstance(
device,
(
@ -105,28 +105,28 @@ async def async_setup_entry(
AsyncMotionDetectorPushButton,
),
):
devices.append(HomematicipMotionDetector(home, device))
devices.append(HomematicipMotionDetector(hap, device))
if isinstance(device, AsyncPresenceDetectorIndoor):
devices.append(HomematicipPresenceDetector(home, device))
devices.append(HomematicipPresenceDetector(hap, device))
if isinstance(device, AsyncSmokeDetector):
devices.append(HomematicipSmokeDetector(home, device))
devices.append(HomematicipSmokeDetector(hap, device))
if isinstance(device, AsyncWaterSensor):
devices.append(HomematicipWaterDetector(home, device))
devices.append(HomematicipWaterDetector(hap, device))
if isinstance(device, (AsyncWeatherSensorPlus, AsyncWeatherSensorPro)):
devices.append(HomematicipRainSensor(home, device))
devices.append(HomematicipRainSensor(hap, device))
if isinstance(
device, (AsyncWeatherSensor, AsyncWeatherSensorPlus, AsyncWeatherSensorPro)
):
devices.append(HomematicipStormSensor(home, device))
devices.append(HomematicipSunshineSensor(home, device))
devices.append(HomematicipStormSensor(hap, device))
devices.append(HomematicipSunshineSensor(hap, device))
if isinstance(device, AsyncDevice) and device.lowBat is not None:
devices.append(HomematicipBatterySensor(home, device))
devices.append(HomematicipBatterySensor(hap, device))
for group in home.groups:
for group in hap.home.groups:
if isinstance(group, AsyncSecurityGroup):
devices.append(HomematicipSecuritySensorGroup(home, group))
devices.append(HomematicipSecuritySensorGroup(hap, group))
elif isinstance(group, AsyncSecurityZoneGroup):
devices.append(HomematicipSecurityZoneSensorGroup(home, group))
devices.append(HomematicipSecurityZoneSensorGroup(hap, group))
if devices:
async_add_entities(devices)
@ -249,9 +249,9 @@ class HomematicipWaterDetector(HomematicipGenericDevice, BinarySensorDevice):
class HomematicipStormSensor(HomematicipGenericDevice, BinarySensorDevice):
"""Representation of a HomematicIP Cloud storm sensor."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize storm sensor."""
super().__init__(home, device, "Storm")
super().__init__(hap, device, "Storm")
@property
def icon(self) -> str:
@ -267,9 +267,9 @@ class HomematicipStormSensor(HomematicipGenericDevice, BinarySensorDevice):
class HomematicipRainSensor(HomematicipGenericDevice, BinarySensorDevice):
"""Representation of a HomematicIP Cloud rain sensor."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize rain sensor."""
super().__init__(home, device, "Raining")
super().__init__(hap, device, "Raining")
@property
def device_class(self) -> str:
@ -285,9 +285,9 @@ class HomematicipRainSensor(HomematicipGenericDevice, BinarySensorDevice):
class HomematicipSunshineSensor(HomematicipGenericDevice, BinarySensorDevice):
"""Representation of a HomematicIP Cloud sunshine sensor."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize sunshine sensor."""
super().__init__(home, device, "Sunshine")
super().__init__(hap, device, "Sunshine")
@property
def device_class(self) -> str:
@ -314,9 +314,9 @@ class HomematicipSunshineSensor(HomematicipGenericDevice, BinarySensorDevice):
class HomematicipBatterySensor(HomematicipGenericDevice, BinarySensorDevice):
"""Representation of a HomematicIP Cloud low battery sensor."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize battery sensor."""
super().__init__(home, device, "Battery")
super().__init__(hap, device, "Battery")
@property
def device_class(self) -> str:
@ -332,10 +332,10 @@ class HomematicipBatterySensor(HomematicipGenericDevice, BinarySensorDevice):
class HomematicipSecurityZoneSensorGroup(HomematicipGenericDevice, BinarySensorDevice):
"""Representation of a HomematicIP Cloud security zone group."""
def __init__(self, home: AsyncHome, device, post: str = "SecurityZone") -> None:
def __init__(self, hap: HomematicipHAP, device, post: str = "SecurityZone") -> None:
"""Initialize security zone group."""
device.modelType = f"HmIP-{post}"
super().__init__(home, device, post)
super().__init__(hap, device, post)
@property
def device_class(self) -> str:
@ -389,9 +389,9 @@ class HomematicipSecuritySensorGroup(
):
"""Representation of a HomematicIP security group."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize security group."""
super().__init__(home, device, "Sensors")
super().__init__(hap, device, "Sensors")
@property
def device_state_attributes(self):

View file

@ -4,7 +4,6 @@ from typing import Awaitable
from homematicip.aio.device import AsyncHeatingThermostat, AsyncHeatingThermostatCompact
from homematicip.aio.group import AsyncHeatingGroup
from homematicip.aio.home import AsyncHome
from homematicip.base.enums import AbsenceType
from homematicip.functionalHomes import IndoorClimateHome
@ -24,6 +23,7 @@ from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
from homeassistant.core import HomeAssistant
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice
from .hap import HomematicipHAP
_LOGGER = logging.getLogger(__name__)
@ -41,11 +41,11 @@ async def async_setup_entry(
hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP climate from a config entry."""
home = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]].home
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
devices = []
for device in home.groups:
for device in hap.home.groups:
if isinstance(device, AsyncHeatingGroup):
devices.append(HomematicipHeatingGroup(home, device))
devices.append(HomematicipHeatingGroup(hap, device))
if devices:
async_add_entities(devices)
@ -54,13 +54,13 @@ async def async_setup_entry(
class HomematicipHeatingGroup(HomematicipGenericDevice, ClimateDevice):
"""Representation of a HomematicIP heating group."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize heating group."""
device.modelType = "Group-Heating"
self._simple_heating = None
if device.actualTemperature is None:
self._simple_heating = _get_first_heating_thermostat(device)
super().__init__(home, device)
super().__init__(hap, device)
@property
def temperature_unit(self) -> str:

View file

@ -31,13 +31,13 @@ async def async_setup_entry(
hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP cover from a config entry."""
home = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]].home
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
devices = []
for device in home.devices:
for device in hap.home.devices:
if isinstance(device, AsyncFullFlushBlind):
devices.append(HomematicipCoverSlats(home, device))
devices.append(HomematicipCoverSlats(hap, device))
elif isinstance(device, AsyncFullFlushShutter):
devices.append(HomematicipCoverShutter(home, device))
devices.append(HomematicipCoverShutter(hap, device))
if devices:
async_add_entities(devices)

View file

@ -4,17 +4,17 @@ from typing import Optional
from homematicip.aio.device import AsyncDevice
from homematicip.aio.group import AsyncGroup
from homematicip.aio.home import AsyncHome
from homeassistant.components import homematicip_cloud
from homeassistant.core import callback
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.entity import Entity
from .hap import HomematicipHAP
_LOGGER = logging.getLogger(__name__)
ATTR_MODEL_TYPE = "model_type"
ATTR_GROUP_ID = "group_id"
ATTR_ID = "id"
ATTR_IS_GROUP = "is_group"
# RSSI HAP -> Device
@ -46,15 +46,16 @@ DEVICE_ATTRIBUTES = {
"id": ATTR_ID,
}
GROUP_ATTRIBUTES = {"modelType": ATTR_MODEL_TYPE, "id": ATTR_GROUP_ID}
GROUP_ATTRIBUTES = {"modelType": ATTR_MODEL_TYPE}
class HomematicipGenericDevice(Entity):
"""Representation of an HomematicIP generic device."""
def __init__(self, home: AsyncHome, device, post: Optional[str] = None) -> None:
def __init__(self, hap: HomematicipHAP, device, post: Optional[str] = None) -> None:
"""Initialize the generic device."""
self._home = home
self._hap = hap
self._home = hap.home
self._device = device
self.post = post
# Marker showing that the HmIP device hase been removed.
@ -81,6 +82,7 @@ class HomematicipGenericDevice(Entity):
async def async_added_to_hass(self):
"""Register callbacks."""
self._hap.hmip_device_by_entity_id[self.entity_id] = self._device
self._device.on_update(self._async_device_changed)
self._device.on_remove(self._async_device_removed)
@ -104,6 +106,7 @@ class HomematicipGenericDevice(Entity):
# Only go further if the device/entity should be removed from registries
# due to a removal of the HmIP device.
if self.hmip_device_removed:
del self._hap.hmip_device_by_entity_id[self.entity_id]
await self.async_remove_from_registries()
async def async_remove_from_registries(self) -> None:

View file

@ -79,6 +79,7 @@ class HomematicipHAP:
self._retry_task = None
self._tries = 0
self._accesspoint_connected = True
self.hmip_device_by_entity_id = {}
async def async_setup(self, tries: int = 0):
"""Initialize connection."""

View file

@ -9,7 +9,6 @@ from homematicip.aio.device import (
AsyncFullFlushDimmer,
AsyncPluggableDimmer,
)
from homematicip.aio.home import AsyncHome
from homematicip.base.enums import RGBColorState
from homematicip.base.functionalChannels import NotificationLightChannel
@ -25,6 +24,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice
from .hap import HomematicipHAP
_LOGGER = logging.getLogger(__name__)
@ -41,26 +41,26 @@ async def async_setup_entry(
hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP Cloud lights from a config entry."""
home = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]].home
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
devices = []
for device in home.devices:
for device in hap.home.devices:
if isinstance(device, AsyncBrandSwitchMeasuring):
devices.append(HomematicipLightMeasuring(home, device))
devices.append(HomematicipLightMeasuring(hap, device))
elif isinstance(device, AsyncBrandSwitchNotificationLight):
devices.append(HomematicipLight(home, device))
devices.append(HomematicipLight(hap, device))
devices.append(
HomematicipNotificationLight(home, device, device.topLightChannelIndex)
HomematicipNotificationLight(hap, device, device.topLightChannelIndex)
)
devices.append(
HomematicipNotificationLight(
home, device, device.bottomLightChannelIndex
hap, device, device.bottomLightChannelIndex
)
)
elif isinstance(
device,
(AsyncDimmer, AsyncPluggableDimmer, AsyncBrandDimmer, AsyncFullFlushDimmer),
):
devices.append(HomematicipDimmer(home, device))
devices.append(HomematicipDimmer(hap, device))
if devices:
async_add_entities(devices)
@ -69,9 +69,9 @@ async def async_setup_entry(
class HomematicipLight(HomematicipGenericDevice, Light):
"""Representation of a HomematicIP Cloud light device."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the light device."""
super().__init__(home, device)
super().__init__(hap, device)
@property
def is_on(self) -> bool:
@ -107,9 +107,9 @@ class HomematicipLightMeasuring(HomematicipLight):
class HomematicipDimmer(HomematicipGenericDevice, Light):
"""Representation of HomematicIP Cloud dimmer light device."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the dimmer light device."""
super().__init__(home, device)
super().__init__(hap, device)
@property
def is_on(self) -> bool:
@ -143,13 +143,13 @@ class HomematicipDimmer(HomematicipGenericDevice, Light):
class HomematicipNotificationLight(HomematicipGenericDevice, Light):
"""Representation of HomematicIP Cloud dimmer light device."""
def __init__(self, home: AsyncHome, device, channel: int) -> None:
def __init__(self, hap: HomematicipHAP, device, channel: int) -> None:
"""Initialize the dimmer light device."""
self.channel = channel
if self.channel == 2:
super().__init__(home, device, "Top")
super().__init__(hap, device, "Top")
else:
super().__init__(home, device, "Bottom")
super().__init__(hap, device, "Bottom")
self._color_switcher = {
RGBColorState.WHITE: [0.0, 0.0],

View file

@ -20,7 +20,6 @@ from homematicip.aio.device import (
AsyncWeatherSensorPlus,
AsyncWeatherSensorPro,
)
from homematicip.aio.home import AsyncHome
from homematicip.base.enums import ValveState
from homeassistant.config_entries import ConfigEntry
@ -36,6 +35,7 @@ from homeassistant.core import HomeAssistant
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice
from .device import ATTR_IS_GROUP, ATTR_MODEL_TYPE
from .hap import HomematicipHAP
_LOGGER = logging.getLogger(__name__)
@ -55,12 +55,12 @@ async def async_setup_entry(
hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP Cloud sensors from a config entry."""
home = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]].home
devices = [HomematicipAccesspointStatus(home)]
for device in home.devices:
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
devices = [HomematicipAccesspointStatus(hap)]
for device in hap.home.devices:
if isinstance(device, (AsyncHeatingThermostat, AsyncHeatingThermostatCompact)):
devices.append(HomematicipHeatingThermostat(home, device))
devices.append(HomematicipTemperatureSensor(home, device))
devices.append(HomematicipHeatingThermostat(hap, device))
devices.append(HomematicipTemperatureSensor(hap, device))
if isinstance(
device,
(
@ -72,8 +72,8 @@ async def async_setup_entry(
AsyncWeatherSensorPro,
),
):
devices.append(HomematicipTemperatureSensor(home, device))
devices.append(HomematicipHumiditySensor(home, device))
devices.append(HomematicipTemperatureSensor(hap, device))
devices.append(HomematicipHumiditySensor(hap, device))
if isinstance(
device,
(
@ -87,7 +87,7 @@ async def async_setup_entry(
AsyncWeatherSensorPro,
),
):
devices.append(HomematicipIlluminanceSensor(home, device))
devices.append(HomematicipIlluminanceSensor(hap, device))
if isinstance(
device,
(
@ -96,15 +96,15 @@ async def async_setup_entry(
AsyncFullFlushSwitchMeasuring,
),
):
devices.append(HomematicipPowerSensor(home, device))
devices.append(HomematicipPowerSensor(hap, device))
if isinstance(
device, (AsyncWeatherSensor, AsyncWeatherSensorPlus, AsyncWeatherSensorPro)
):
devices.append(HomematicipWindspeedSensor(home, device))
devices.append(HomematicipWindspeedSensor(hap, device))
if isinstance(device, (AsyncWeatherSensorPlus, AsyncWeatherSensorPro)):
devices.append(HomematicipTodayRainSensor(home, device))
devices.append(HomematicipTodayRainSensor(hap, device))
if isinstance(device, AsyncPassageDetector):
devices.append(HomematicipPassageDetectorDeltaCounter(home, device))
devices.append(HomematicipPassageDetectorDeltaCounter(hap, device))
if devices:
async_add_entities(devices)
@ -113,9 +113,9 @@ async def async_setup_entry(
class HomematicipAccesspointStatus(HomematicipGenericDevice):
"""Representation of an HomeMaticIP Cloud access point."""
def __init__(self, home: AsyncHome) -> None:
def __init__(self, hap: HomematicipHAP) -> None:
"""Initialize access point device."""
super().__init__(home, home)
super().__init__(hap, hap.home)
@property
def device_info(self):
@ -162,9 +162,9 @@ class HomematicipAccesspointStatus(HomematicipGenericDevice):
class HomematicipHeatingThermostat(HomematicipGenericDevice):
"""Representation of a HomematicIP heating thermostat device."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize heating thermostat device."""
super().__init__(home, device, "Heating")
super().__init__(hap, device, "Heating")
@property
def icon(self) -> str:
@ -191,9 +191,9 @@ class HomematicipHeatingThermostat(HomematicipGenericDevice):
class HomematicipHumiditySensor(HomematicipGenericDevice):
"""Representation of a HomematicIP Cloud humidity device."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the thermometer device."""
super().__init__(home, device, "Humidity")
super().__init__(hap, device, "Humidity")
@property
def device_class(self) -> str:
@ -214,9 +214,9 @@ class HomematicipHumiditySensor(HomematicipGenericDevice):
class HomematicipTemperatureSensor(HomematicipGenericDevice):
"""Representation of a HomematicIP Cloud thermometer device."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the thermometer device."""
super().__init__(home, device, "Temperature")
super().__init__(hap, device, "Temperature")
@property
def device_class(self) -> str:
@ -251,9 +251,9 @@ class HomematicipTemperatureSensor(HomematicipGenericDevice):
class HomematicipIlluminanceSensor(HomematicipGenericDevice):
"""Representation of a HomematicIP Illuminance device."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the device."""
super().__init__(home, device, "Illuminance")
super().__init__(hap, device, "Illuminance")
@property
def device_class(self) -> str:
@ -277,9 +277,9 @@ class HomematicipIlluminanceSensor(HomematicipGenericDevice):
class HomematicipPowerSensor(HomematicipGenericDevice):
"""Representation of a HomematicIP power measuring device."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the device."""
super().__init__(home, device, "Power")
super().__init__(hap, device, "Power")
@property
def device_class(self) -> str:
@ -300,9 +300,9 @@ class HomematicipPowerSensor(HomematicipGenericDevice):
class HomematicipWindspeedSensor(HomematicipGenericDevice):
"""Representation of a HomematicIP wind speed sensor."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the device."""
super().__init__(home, device, "Windspeed")
super().__init__(hap, device, "Windspeed")
@property
def state(self) -> float:
@ -333,9 +333,9 @@ class HomematicipWindspeedSensor(HomematicipGenericDevice):
class HomematicipTodayRainSensor(HomematicipGenericDevice):
"""Representation of a HomematicIP rain counter of a day sensor."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the device."""
super().__init__(home, device, "Today Rain")
super().__init__(hap, device, "Today Rain")
@property
def state(self) -> float:
@ -351,10 +351,6 @@ class HomematicipTodayRainSensor(HomematicipGenericDevice):
class HomematicipPassageDetectorDeltaCounter(HomematicipGenericDevice):
"""Representation of a HomematicIP passage detector delta counter."""
def __init__(self, home: AsyncHome, device) -> None:
"""Initialize the device."""
super().__init__(home, device)
@property
def state(self) -> int:
"""Representation of the HomematicIP passage detector delta counter value."""

View file

@ -12,7 +12,6 @@ from homematicip.aio.device import (
AsyncPrintedCircuitBoardSwitchBattery,
)
from homematicip.aio.group import AsyncSwitchingGroup
from homematicip.aio.home import AsyncHome
from homeassistant.components.switch import SwitchDevice
from homeassistant.config_entries import ConfigEntry
@ -20,6 +19,7 @@ from homeassistant.core import HomeAssistant
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice
from .device import ATTR_GROUP_MEMBER_UNREACHABLE
from .hap import HomematicipHAP
_LOGGER = logging.getLogger(__name__)
@ -33,9 +33,9 @@ async def async_setup_entry(
hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP switch from a config entry."""
home = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]].home
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
devices = []
for device in home.devices:
for device in hap.home.devices:
if isinstance(device, AsyncBrandSwitchMeasuring):
# BrandSwitchMeasuring inherits PlugableSwitchMeasuring
# This device is implemented in the light platform and will
@ -44,24 +44,24 @@ async def async_setup_entry(
elif isinstance(
device, (AsyncPlugableSwitchMeasuring, AsyncFullFlushSwitchMeasuring)
):
devices.append(HomematicipSwitchMeasuring(home, device))
devices.append(HomematicipSwitchMeasuring(hap, device))
elif isinstance(
device, (AsyncPlugableSwitch, AsyncPrintedCircuitBoardSwitchBattery)
):
devices.append(HomematicipSwitch(home, device))
devices.append(HomematicipSwitch(hap, device))
elif isinstance(device, AsyncOpenCollector8Module):
for channel in range(1, 9):
devices.append(HomematicipMultiSwitch(home, device, channel))
devices.append(HomematicipMultiSwitch(hap, device, channel))
elif isinstance(device, AsyncMultiIOBox):
for channel in range(1, 3):
devices.append(HomematicipMultiSwitch(home, device, channel))
devices.append(HomematicipMultiSwitch(hap, device, channel))
elif isinstance(device, AsyncPrintedCircuitBoardSwitch2):
for channel in range(1, 3):
devices.append(HomematicipMultiSwitch(home, device, channel))
devices.append(HomematicipMultiSwitch(hap, device, channel))
for group in home.groups:
for group in hap.home.groups:
if isinstance(group, AsyncSwitchingGroup):
devices.append(HomematicipGroupSwitch(home, group))
devices.append(HomematicipGroupSwitch(hap, group))
if devices:
async_add_entities(devices)
@ -70,9 +70,9 @@ async def async_setup_entry(
class HomematicipSwitch(HomematicipGenericDevice, SwitchDevice):
"""representation of a HomematicIP Cloud switch device."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the switch device."""
super().__init__(home, device)
super().__init__(hap, device)
@property
def is_on(self) -> bool:
@ -91,10 +91,10 @@ class HomematicipSwitch(HomematicipGenericDevice, SwitchDevice):
class HomematicipGroupSwitch(HomematicipGenericDevice, SwitchDevice):
"""representation of a HomematicIP switching group."""
def __init__(self, home: AsyncHome, device, post: str = "Group") -> None:
def __init__(self, hap: HomematicipHAP, device, post: str = "Group") -> None:
"""Initialize switching group."""
device.modelType = f"HmIP-{post}"
super().__init__(home, device, post)
super().__init__(hap, device, post)
@property
def is_on(self) -> bool:
@ -148,10 +148,10 @@ class HomematicipSwitchMeasuring(HomematicipSwitch):
class HomematicipMultiSwitch(HomematicipGenericDevice, SwitchDevice):
"""Representation of a HomematicIP Cloud multi switch device."""
def __init__(self, home: AsyncHome, device, channel: int):
def __init__(self, hap: HomematicipHAP, device, channel: int):
"""Initialize the multi switch device."""
self.channel = channel
super().__init__(home, device, f"Channel{channel}")
super().__init__(hap, device, f"Channel{channel}")
@property
def unique_id(self) -> str:

View file

@ -6,7 +6,6 @@ from homematicip.aio.device import (
AsyncWeatherSensorPlus,
AsyncWeatherSensorPro,
)
from homematicip.aio.home import AsyncHome
from homematicip.base.enums import WeatherCondition
from homeassistant.components.weather import WeatherEntity
@ -15,6 +14,7 @@ from homeassistant.const import TEMP_CELSIUS
from homeassistant.core import HomeAssistant
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice
from .hap import HomematicipHAP
_LOGGER = logging.getLogger(__name__)
@ -46,15 +46,15 @@ async def async_setup_entry(
hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP weather sensor from a config entry."""
home = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]].home
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
devices = []
for device in home.devices:
for device in hap.home.devices:
if isinstance(device, AsyncWeatherSensorPro):
devices.append(HomematicipWeatherSensorPro(home, device))
devices.append(HomematicipWeatherSensorPro(hap, device))
elif isinstance(device, (AsyncWeatherSensor, AsyncWeatherSensorPlus)):
devices.append(HomematicipWeatherSensor(home, device))
devices.append(HomematicipWeatherSensor(hap, device))
devices.append(HomematicipHomeWeather(home))
devices.append(HomematicipHomeWeather(hap))
if devices:
async_add_entities(devices)
@ -63,9 +63,9 @@ async def async_setup_entry(
class HomematicipWeatherSensor(HomematicipGenericDevice, WeatherEntity):
"""representation of a HomematicIP Cloud weather sensor plus & basic."""
def __init__(self, home: AsyncHome, device) -> None:
def __init__(self, hap: HomematicipHAP, device) -> None:
"""Initialize the weather sensor."""
super().__init__(home, device)
super().__init__(hap, device)
@property
def name(self) -> str:
@ -121,10 +121,10 @@ class HomematicipWeatherSensorPro(HomematicipWeatherSensor):
class HomematicipHomeWeather(HomematicipGenericDevice, WeatherEntity):
"""representation of a HomematicIP Cloud home weather."""
def __init__(self, home: AsyncHome) -> None:
def __init__(self, hap: HomematicipHAP) -> None:
"""Initialize the home weather."""
home.modelType = "HmIP-Home-Weather"
super().__init__(home, home)
hap.home.modelType = "HmIP-Home-Weather"
super().__init__(hap, hap.home)
@property
def available(self) -> bool:

View file

@ -6,10 +6,14 @@ import pytest
from homeassistant import config_entries
from homeassistant.components.homematicip_cloud import (
CONF_ACCESSPOINT,
CONF_AUTHTOKEN,
DOMAIN as HMIPC_DOMAIN,
async_setup as hmip_async_setup,
const as hmipc,
hap as hmip_hap,
)
from homeassistant.const import CONF_NAME
from homeassistant.core import HomeAssistant
from .helper import AUTH_TOKEN, HAPID, HomeTemplate
@ -19,7 +23,7 @@ from tests.common import MockConfigEntry, mock_coro
@pytest.fixture(name="mock_connection")
def mock_connection_fixture():
"""Return a mockked connection."""
"""Return a mocked connection."""
connection = MagicMock(spec=AsyncConnection)
def _rest_call_side_effect(path, body=None):
@ -39,7 +43,7 @@ def default_mock_home_fixture(mock_connection):
@pytest.fixture(name="hmip_config_entry")
def hmip_config_entry_fixture():
"""Create a fake config entriy for homematic ip cloud."""
"""Create a mock config entriy for homematic ip cloud."""
entry_data = {
hmipc.HMIPC_HAPID: HAPID,
hmipc.HMIPC_AUTHTOKEN: AUTH_TOKEN,
@ -67,9 +71,32 @@ async def default_mock_hap_fixture(
hap = hmip_hap.HomematicipHAP(hass, hmip_config_entry)
with patch.object(hap, "get_hap", return_value=mock_coro(default_mock_home)):
assert await hap.async_setup() is True
default_mock_home.on_update(hap.async_update)
default_mock_home.on_create(hap.async_create_entity)
hass.data[HMIPC_DOMAIN] = {HAPID: hap}
await hass.async_block_till_done()
return hap
@pytest.fixture(name="hmip_config")
def hmip_config_fixture():
"""Create a config for homematic ip cloud."""
entry_data = {CONF_ACCESSPOINT: HAPID, CONF_AUTHTOKEN: AUTH_TOKEN, CONF_NAME: ""}
return {hmipc.DOMAIN: [entry_data]}
@pytest.fixture(name="mock_hap_with_service")
async def mock_hap_with_service_fixture(
hass: HomeAssistant, default_mock_hap, hmip_config
):
"""Create a fake homematic access point with hass services."""
await hmip_async_setup(hass, hmip_config)
await hass.async_block_till_done()
hass.data[HMIPC_DOMAIN] = {HAPID: default_mock_hap}
return default_mock_hap

View file

@ -1,18 +1,25 @@
"""Helper for HomematicIP Cloud Tests."""
import json
from unittest.mock import Mock
from asynctest import Mock
from homematicip.aio.class_maps import (
TYPE_CLASS_MAP,
TYPE_GROUP_MAP,
TYPE_SECURITY_EVENT_MAP,
)
from homematicip.aio.device import AsyncDevice
from homematicip.aio.group import AsyncGroup
from homematicip.aio.home import AsyncHome
from homematicip.home import Home
from homeassistant.components.homematicip_cloud.device import (
ATTR_IS_GROUP,
ATTR_MODEL_TYPE,
)
from tests.common import load_fixture
HAPID = "Mock_HAP"
HAPID = "3014F7110000000000000001"
AUTH_TOKEN = "1234"
HOME_JSON = "homematicip_cloud.json"
@ -21,28 +28,38 @@ def get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
):
"""Get and test basic device."""
ha_entity = hass.states.get(entity_id)
assert ha_entity is not None
assert ha_entity.attributes["model_type"] == device_model
assert ha_entity.name == entity_name
ha_state = hass.states.get(entity_id)
assert ha_state is not None
if device_model:
assert ha_state.attributes[ATTR_MODEL_TYPE] == device_model
assert ha_state.name == entity_name
hmip_device = default_mock_hap.home.template.search_mock_device_by_id(
ha_entity.attributes["id"]
)
assert hmip_device is not None
return ha_entity, hmip_device
hmip_device = default_mock_hap.hmip_device_by_entity_id.get(entity_id)
if hmip_device:
if isinstance(hmip_device, AsyncDevice):
assert ha_state.attributes[ATTR_IS_GROUP] is False
elif isinstance(hmip_device, AsyncGroup):
assert ha_state.attributes[ATTR_IS_GROUP] is True
return ha_state, hmip_device
async def async_manipulate_test_data(
hass, hmip_device, attribute, new_value, channel=1
hass, hmip_device, attribute, new_value, channel=1, fire_device=None
):
"""Set new value on hmip device."""
if channel == 1:
setattr(hmip_device, attribute, new_value)
functional_channel = hmip_device.functionalChannels[channel]
setattr(functional_channel, attribute, new_value)
if hasattr(hmip_device, "functionalChannels"):
functional_channel = hmip_device.functionalChannels[channel]
setattr(functional_channel, attribute, new_value)
fire_target = hmip_device if fire_device is None else fire_device
if isinstance(fire_target, AsyncHome):
fire_target.fire_update_event(fire_target._rawJSONData) # pylint: disable=W0212
else:
fire_target.fire_update_event()
hmip_device.fire_update_event()
await hass.async_block_till_done()
@ -66,8 +83,8 @@ class HomeTemplate(Home):
def __init__(self, connection=None):
"""Init template with connection."""
super().__init__(connection=connection)
self.mock_devices = []
self.mock_groups = []
self.label = "Access Point"
self.model_type = "HmIP-HAP"
def init_home(self, json_path=HOME_JSON):
"""Init template with json."""
@ -78,24 +95,15 @@ class HomeTemplate(Home):
def _generate_mocks(self):
"""Generate mocks for groups and devices."""
mock_devices = []
for device in self.devices:
self.mock_devices.append(_get_mock(device))
mock_devices.append(_get_mock(device))
self.devices = mock_devices
mock_groups = []
for group in self.groups:
self.mock_groups.append(_get_mock(group))
def search_mock_device_by_id(self, device_id):
"""Search a device by given id."""
for device in self.mock_devices:
if device.id == device_id:
return device
return None
def search_mock_group_by_id(self, group_id):
"""Search a group by given id."""
for group in self.mock_groups:
if group.id == group_id:
return group
return None
mock_groups.append(_get_mock(group))
self.groups = mock_groups
def get_async_home_mock(self):
"""
@ -105,19 +113,11 @@ class HomeTemplate(Home):
and sets reuired attributes.
"""
mock_home = Mock(
check_connection=self._connection,
id=HAPID,
connected=True,
dutyCycle=self.dutyCycle,
devices=self.mock_devices,
groups=self.mock_groups,
weather=self.weather,
location=self.location,
label="home label",
template=self,
spec=AsyncHome,
spec=AsyncHome, wraps=self, label="Access Point", modelType="HmIP-HAP"
)
mock_home.__dict__.update(self.__dict__)
mock_home.name = ""
return mock_home

View file

@ -0,0 +1,289 @@
"""Tests for HomematicIP Cloud binary sensor."""
from homematicip.base.enums import SmokeDetectorAlarmType, WindowState
from homeassistant.components.homematicip_cloud.binary_sensor import (
ATTR_ACCELERATION_SENSOR_MODE,
ATTR_ACCELERATION_SENSOR_NEUTRAL_POSITION,
ATTR_ACCELERATION_SENSOR_SENSITIVITY,
ATTR_ACCELERATION_SENSOR_TRIGGER_ANGLE,
ATTR_LOW_BATTERY,
ATTR_MOTION_DETECTED,
)
from homeassistant.const import STATE_OFF, STATE_ON
from .helper import async_manipulate_test_data, get_and_check_entity_basics
async def test_hmip_acceleration_sensor(hass, default_mock_hap):
"""Test HomematicipAccelerationSensor."""
entity_id = "binary_sensor.garagentor"
entity_name = "Garagentor"
device_model = "HmIP-SAM"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_ON
assert ha_state.attributes[ATTR_ACCELERATION_SENSOR_MODE] == "FLAT_DECT"
assert ha_state.attributes[ATTR_ACCELERATION_SENSOR_NEUTRAL_POSITION] == "VERTICAL"
assert (
ha_state.attributes[ATTR_ACCELERATION_SENSOR_SENSITIVITY] == "SENSOR_RANGE_4G"
)
assert ha_state.attributes[ATTR_ACCELERATION_SENSOR_TRIGGER_ANGLE] == 45
service_call_counter = len(hmip_device.mock_calls)
await async_manipulate_test_data(
hass, hmip_device, "accelerationSensorTriggered", False
)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_OFF
assert len(hmip_device.mock_calls) == service_call_counter + 1
await async_manipulate_test_data(
hass, hmip_device, "accelerationSensorTriggered", True
)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
assert len(hmip_device.mock_calls) == service_call_counter + 2
async def test_hmip_contact_interface(hass, default_mock_hap):
"""Test HomematicipContactInterface."""
entity_id = "binary_sensor.kontakt_schnittstelle_unterputz_1_fach"
entity_name = "Kontakt-Schnittstelle Unterputz 1-fach"
device_model = "HmIP-FCI1"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_OFF
await async_manipulate_test_data(hass, hmip_device, "windowState", WindowState.OPEN)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
await async_manipulate_test_data(hass, hmip_device, "windowState", None)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_OFF
async def test_hmip_shutter_contact(hass, default_mock_hap):
"""Test HomematicipShutterContact."""
entity_id = "binary_sensor.fenstergriffsensor"
entity_name = "Fenstergriffsensor"
device_model = "HmIP-SRH"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_ON
await async_manipulate_test_data(
hass, hmip_device, "windowState", WindowState.CLOSED
)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_OFF
await async_manipulate_test_data(hass, hmip_device, "windowState", None)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_OFF
async def test_hmip_motion_detector(hass, default_mock_hap):
"""Test HomematicipMotionDetector."""
entity_id = "binary_sensor.bewegungsmelder_fur_55er_rahmen_innen"
entity_name = "Bewegungsmelder für 55er Rahmen innen"
device_model = "HmIP-SMI55"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_OFF
await async_manipulate_test_data(hass, hmip_device, "motionDetected", True)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
async def test_hmip_presence_detector(hass, default_mock_hap):
"""Test HomematicipPresenceDetector."""
entity_id = "binary_sensor.spi_1"
entity_name = "SPI_1"
device_model = "HmIP-SPI"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_OFF
await async_manipulate_test_data(hass, hmip_device, "presenceDetected", True)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
async def test_hmip_smoke_detector(hass, default_mock_hap):
"""Test HomematicipSmokeDetector."""
entity_id = "binary_sensor.rauchwarnmelder"
entity_name = "Rauchwarnmelder"
device_model = "HmIP-SWSD"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_OFF
await async_manipulate_test_data(
hass,
hmip_device,
"smokeDetectorAlarmType",
SmokeDetectorAlarmType.PRIMARY_ALARM,
)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
async def test_hmip_water_detector(hass, default_mock_hap):
"""Test HomematicipWaterDetector."""
entity_id = "binary_sensor.wassersensor"
entity_name = "Wassersensor"
device_model = "HmIP-SWD"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_OFF
await async_manipulate_test_data(hass, hmip_device, "waterlevelDetected", True)
await async_manipulate_test_data(hass, hmip_device, "moistureDetected", False)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
await async_manipulate_test_data(hass, hmip_device, "waterlevelDetected", True)
await async_manipulate_test_data(hass, hmip_device, "moistureDetected", True)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
await async_manipulate_test_data(hass, hmip_device, "waterlevelDetected", False)
await async_manipulate_test_data(hass, hmip_device, "moistureDetected", True)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
await async_manipulate_test_data(hass, hmip_device, "waterlevelDetected", False)
await async_manipulate_test_data(hass, hmip_device, "moistureDetected", False)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_OFF
async def test_hmip_storm_sensor(hass, default_mock_hap):
"""Test HomematicipStormSensor."""
entity_id = "binary_sensor.weather_sensor_plus_storm"
entity_name = "Weather Sensor plus Storm"
device_model = "HmIP-SWO-PL"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_OFF
await async_manipulate_test_data(hass, hmip_device, "storm", True)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
async def test_hmip_rain_sensor(hass, default_mock_hap):
"""Test HomematicipRainSensor."""
entity_id = "binary_sensor.wettersensor_pro_raining"
entity_name = "Wettersensor - pro Raining"
device_model = "HmIP-SWO-PR"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_OFF
await async_manipulate_test_data(hass, hmip_device, "raining", True)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
async def test_hmip_sunshine_sensor(hass, default_mock_hap):
"""Test HomematicipSunshineSensor."""
entity_id = "binary_sensor.wettersensor_pro_sunshine"
entity_name = "Wettersensor - pro Sunshine"
device_model = "HmIP-SWO-PR"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_ON
assert ha_state.attributes["today_sunshine_duration_in_minutes"] == 100
await async_manipulate_test_data(hass, hmip_device, "sunshine", False)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_OFF
async def test_hmip_battery_sensor(hass, default_mock_hap):
"""Test HomematicipSunshineSensor."""
entity_id = "binary_sensor.wohnungsture_battery"
entity_name = "Wohnungstüre Battery"
device_model = "HMIP-SWDO"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_OFF
await async_manipulate_test_data(hass, hmip_device, "lowBat", True)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
async def test_hmip_security_zone_sensor_group(hass, default_mock_hap):
"""Test HomematicipSecurityZoneSensorGroup."""
entity_id = "binary_sensor.internal_securityzone"
entity_name = "INTERNAL SecurityZone"
device_model = "HmIP-SecurityZone"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_OFF
await async_manipulate_test_data(hass, hmip_device, "motionDetected", True)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
assert ha_state.attributes[ATTR_MOTION_DETECTED] is True
async def test_hmip_security_sensor_group(hass, default_mock_hap):
"""Test HomematicipSecuritySensorGroup."""
entity_id = "binary_sensor.buro_sensors"
entity_name = "Büro Sensors"
device_model = None
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_OFF
assert not ha_state.attributes.get("low_bat")
await async_manipulate_test_data(hass, hmip_device, "lowBat", True)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
assert ha_state.attributes[ATTR_LOW_BATTERY] is True
await async_manipulate_test_data(hass, hmip_device, "lowBat", False)
await async_manipulate_test_data(
hass,
hmip_device,
"smokeDetectorAlarmType",
SmokeDetectorAlarmType.PRIMARY_ALARM,
)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
assert (
ha_state.attributes["smoke_detector_alarm"]
== SmokeDetectorAlarmType.PRIMARY_ALARM
)

View file

@ -1,41 +0,0 @@
"""Tests for HomematicIP Cloud lights."""
import logging
from tests.components.homematicip_cloud.helper import (
async_manipulate_test_data,
get_and_check_entity_basics,
)
_LOGGER = logging.getLogger(__name__)
async def test_hmip_sam(hass, default_mock_hap):
"""Test HomematicipLight."""
entity_id = "binary_sensor.garagentor"
entity_name = "Garagentor"
device_model = "HmIP-SAM"
ha_entity, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_entity.state == "on"
assert ha_entity.attributes["acceleration_sensor_mode"] == "FLAT_DECT"
assert ha_entity.attributes["acceleration_sensor_neutral_position"] == "VERTICAL"
assert ha_entity.attributes["acceleration_sensor_sensitivity"] == "SENSOR_RANGE_4G"
assert ha_entity.attributes["acceleration_sensor_trigger_angle"] == 45
service_call_counter = len(hmip_device.mock_calls)
await async_manipulate_test_data(
hass, hmip_device, "accelerationSensorTriggered", False
)
ha_entity = hass.states.get(entity_id)
assert ha_entity.state == "off"
assert len(hmip_device.mock_calls) == service_call_counter + 1
await async_manipulate_test_data(
hass, hmip_device, "accelerationSensorTriggered", True
)
ha_entity = hass.states.get(entity_id)
assert ha_entity.state == "on"
assert len(hmip_device.mock_calls) == service_call_counter + 2

View file

@ -0,0 +1,196 @@
"""Tests for HomematicIP Cloud light."""
from homematicip.base.enums import RGBColorState
from homeassistant.components.homematicip_cloud.light import (
ATTR_ENERGY_COUNTER,
ATTR_POWER_CONSUMPTION,
)
from homeassistant.components.light import ATTR_BRIGHTNESS, ATTR_COLOR_NAME
from homeassistant.const import STATE_OFF, STATE_ON
from .helper import async_manipulate_test_data, get_and_check_entity_basics
async def test_hmip_light(hass, default_mock_hap):
"""Test HomematicipLight."""
entity_id = "light.treppe"
entity_name = "Treppe"
device_model = "HmIP-BSL"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_ON
service_call_counter = len(hmip_device.mock_calls)
await hass.services.async_call(
"light", "turn_off", {"entity_id": entity_id}, blocking=True
)
assert len(hmip_device.mock_calls) == service_call_counter + 1
assert hmip_device.mock_calls[-1][0] == "turn_off"
assert hmip_device.mock_calls[-1][1] == ()
await async_manipulate_test_data(hass, hmip_device, "on", False)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_OFF
await hass.services.async_call(
"light", "turn_on", {"entity_id": entity_id}, blocking=True
)
assert len(hmip_device.mock_calls) == service_call_counter + 3
assert hmip_device.mock_calls[-1][0] == "turn_on"
assert hmip_device.mock_calls[-1][1] == ()
await async_manipulate_test_data(hass, hmip_device, "on", True)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
async def test_hmip_notification_light(hass, default_mock_hap):
"""Test HomematicipNotificationLight."""
entity_id = "light.treppe_top_notification"
entity_name = "Treppe Top Notification"
device_model = "HmIP-BSL"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_OFF
service_call_counter = len(hmip_device.mock_calls)
# Send all color via service call.
await hass.services.async_call(
"light", "turn_on", {"entity_id": entity_id}, blocking=True
)
assert hmip_device.mock_calls[-1][0] == "set_rgb_dim_level"
assert hmip_device.mock_calls[-1][1] == (2, RGBColorState.RED, 1.0)
color_list = {
RGBColorState.WHITE: [0.0, 0.0],
RGBColorState.RED: [0.0, 100.0],
RGBColorState.YELLOW: [60.0, 100.0],
RGBColorState.GREEN: [120.0, 100.0],
RGBColorState.TURQUOISE: [180.0, 100.0],
RGBColorState.BLUE: [240.0, 100.0],
RGBColorState.PURPLE: [300.0, 100.0],
}
for color, hs_color in color_list.items():
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": entity_id, "hs_color": hs_color},
blocking=True,
)
assert hmip_device.mock_calls[-1][0] == "set_rgb_dim_level"
assert hmip_device.mock_calls[-1][1] == (2, color, 0.0392156862745098)
assert len(hmip_device.mock_calls) == service_call_counter + 8
assert hmip_device.mock_calls[-1][0] == "set_rgb_dim_level"
assert hmip_device.mock_calls[-1][1] == (
2,
RGBColorState.PURPLE,
0.0392156862745098,
)
await async_manipulate_test_data(hass, hmip_device, "dimLevel", 1, 2)
await async_manipulate_test_data(
hass, hmip_device, "simpleRGBColorState", RGBColorState.PURPLE, 2
)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
assert ha_state.attributes[ATTR_COLOR_NAME] == RGBColorState.PURPLE
assert ha_state.attributes[ATTR_BRIGHTNESS] == 255
await hass.services.async_call(
"light", "turn_off", {"entity_id": entity_id}, blocking=True
)
assert len(hmip_device.mock_calls) == service_call_counter + 11
assert hmip_device.mock_calls[-1][0] == "set_rgb_dim_level"
assert hmip_device.mock_calls[-1][1] == (2, RGBColorState.PURPLE, 0.0)
await async_manipulate_test_data(hass, hmip_device, "dimLevel", 0, 2)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_OFF
async def test_hmip_dimmer(hass, default_mock_hap):
"""Test HomematicipDimmer."""
entity_id = "light.schlafzimmerlicht"
entity_name = "Schlafzimmerlicht"
device_model = "HmIP-BDT"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_OFF
service_call_counter = len(hmip_device.mock_calls)
await hass.services.async_call(
"light", "turn_on", {"entity_id": entity_id}, blocking=True
)
assert hmip_device.mock_calls[-1][0] == "set_dim_level"
assert hmip_device.mock_calls[-1][1] == (1,)
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": entity_id, "brightness_pct": "100"},
blocking=True,
)
assert len(hmip_device.mock_calls) == service_call_counter + 2
assert hmip_device.mock_calls[-1][0] == "set_dim_level"
assert hmip_device.mock_calls[-1][1] == (1.0,)
await async_manipulate_test_data(hass, hmip_device, "dimLevel", 1)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
assert ha_state.attributes[ATTR_BRIGHTNESS] == 255
await hass.services.async_call(
"light", "turn_off", {"entity_id": entity_id}, blocking=True
)
assert len(hmip_device.mock_calls) == service_call_counter + 4
assert hmip_device.mock_calls[-1][0] == "set_dim_level"
assert hmip_device.mock_calls[-1][1] == (0,)
await async_manipulate_test_data(hass, hmip_device, "dimLevel", 0)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_OFF
async def test_hmip_light_measuring(hass, default_mock_hap):
"""Test HomematicipLightMeasuring."""
entity_id = "light.flur_oben"
entity_name = "Flur oben"
device_model = "HmIP-BSM"
ha_state, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_OFF
service_call_counter = len(hmip_device.mock_calls)
await hass.services.async_call(
"light", "turn_on", {"entity_id": entity_id}, blocking=True
)
assert len(hmip_device.mock_calls) == service_call_counter + 1
assert hmip_device.mock_calls[-1][0] == "turn_on"
assert hmip_device.mock_calls[-1][1] == ()
await async_manipulate_test_data(hass, hmip_device, "on", True)
await async_manipulate_test_data(hass, hmip_device, "currentPowerConsumption", 50)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
assert ha_state.attributes[ATTR_POWER_CONSUMPTION] == 50
assert ha_state.attributes[ATTR_ENERGY_COUNTER] == 6.33
await hass.services.async_call(
"light", "turn_off", {"entity_id": entity_id}, blocking=True
)
assert len(hmip_device.mock_calls) == service_call_counter + 4
assert hmip_device.mock_calls[-1][0] == "turn_off"
assert hmip_device.mock_calls[-1][1] == ()
await async_manipulate_test_data(hass, hmip_device, "on", False)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_OFF

View file

@ -1,77 +0,0 @@
"""Tests for HomematicIP Cloud lights."""
import logging
from tests.components.homematicip_cloud.helper import (
async_manipulate_test_data,
get_and_check_entity_basics,
)
_LOGGER = logging.getLogger(__name__)
async def test_hmip_light(hass, default_mock_hap):
"""Test HomematicipLight."""
entity_id = "light.treppe"
entity_name = "Treppe"
device_model = "HmIP-BSL"
ha_entity, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_entity.state == "on"
service_call_counter = len(hmip_device.mock_calls)
await hass.services.async_call(
"light", "turn_off", {"entity_id": entity_id}, blocking=True
)
assert len(hmip_device.mock_calls) == service_call_counter + 1
assert hmip_device.mock_calls[-1][0] == "turn_off"
await async_manipulate_test_data(hass, hmip_device, "on", False)
ha_entity = hass.states.get(entity_id)
assert ha_entity.state == "off"
await hass.services.async_call(
"light", "turn_on", {"entity_id": entity_id}, blocking=True
)
assert len(hmip_device.mock_calls) == service_call_counter + 3
assert hmip_device.mock_calls[-1][0] == "turn_on"
await async_manipulate_test_data(hass, hmip_device, "on", True)
ha_entity = hass.states.get(entity_id)
assert ha_entity.state == "on"
# HomematicipLightMeasuring
# HomematicipDimmer
async def test_hmip_notification_light(hass, default_mock_hap):
"""Test HomematicipNotificationLight."""
entity_id = "light.treppe_top_notification"
entity_name = "Treppe Top Notification"
device_model = "HmIP-BSL"
ha_entity, hmip_device = get_and_check_entity_basics(
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert ha_entity.state == "off"
service_call_counter = len(hmip_device.mock_calls)
await hass.services.async_call(
"light", "turn_on", {"entity_id": entity_id}, blocking=True
)
assert len(hmip_device.mock_calls) == service_call_counter + 1
assert hmip_device.mock_calls[-1][0] == "set_rgb_dim_level"
await async_manipulate_test_data(hass, hmip_device, "dimLevel", 100, 2)
ha_entity = hass.states.get(entity_id)
assert ha_entity.state == "on"
await hass.services.async_call(
"light", "turn_off", {"entity_id": entity_id}, blocking=True
)
assert len(hmip_device.mock_calls) == service_call_counter + 3
assert hmip_device.mock_calls[-1][0] == "set_rgb_dim_level"
await async_manipulate_test_data(hass, hmip_device, "dimLevel", 0, 2)
ha_entity = hass.states.get(entity_id)
assert ha_entity.state == "off"

View file

@ -2077,6 +2077,144 @@
"type": "SHUTTER_CONTACT",
"updateState": "UP_TO_DATE"
},
"3014F7110000000000000108": {
"availableFirmwareVersion": "1.12.6",
"firmwareVersion": "1.12.6",
"firmwareVersionInteger": 68614,
"functionalChannels": {
"0": {
"coProFaulty": false,
"coProRestartNeeded": false,
"coProUpdateFailure": false,
"configPending": false,
"deviceId": "3014F7110000000000000108",
"deviceOverheated": false,
"deviceOverloaded": false,
"deviceUndervoltage": false,
"dutyCycle": false,
"functionalChannelType": "DEVICE_BASE",
"groupIndex": 0,
"groups": [
"00000000-0000-0000-0000-000000000009"
],
"index": 0,
"label": "",
"lowBat": null,
"routerModuleEnabled": false,
"routerModuleSupported": false,
"rssiDeviceValue": -68,
"rssiPeerValue": -63,
"supportedOptionalFeatures": {
"IFeatureDeviceCoProError": false,
"IFeatureDeviceCoProRestart": false,
"IFeatureDeviceCoProUpdate": false,
"IFeatureDeviceOverheated": true,
"IFeatureDeviceOverloaded": false,
"IFeatureDeviceTemperatureOutOfRange": false,
"IFeatureDeviceUndervoltage": false
},
"temperatureOutOfRange": false,
"unreach": false
},
"1": {
"currentPowerConsumption": 0.0,
"deviceId": "3014F7110000000000000108",
"energyCounter": 6.333200000000001,
"functionalChannelType": "SWITCH_MEASURING_CHANNEL",
"groupIndex": 1,
"groups": [
"00000000-0000-0000-0000-000000000023"
],
"index": 1,
"label": "",
"on": false,
"profileMode": "AUTOMATIC",
"userDesiredProfileMode": "AUTOMATIC"
}
},
"homeId": "00000000-0000-0000-0000-000000000001",
"id": "3014F7110000000000000108",
"label": "Flur oben",
"lastStatusUpdate": 1570365990392,
"liveUpdateState": "LIVE_UPDATE_NOT_SUPPORTED",
"manufacturerCode": 1,
"modelId": 288,
"modelType": "HmIP-BSM",
"oem": "eQ-3",
"permanentlyReachable": true,
"serializedGlobalTradeItemNumber": "3014F7110000000000000108",
"type": "BRAND_SWITCH_MEASURING",
"updateState": "UP_TO_DATE"
},
"3014F7110000000000000109": {
"availableFirmwareVersion": "1.6.2",
"firmwareVersion": "1.6.2",
"firmwareVersionInteger": 67074,
"functionalChannels": {
"0": {
"coProFaulty": false,
"coProRestartNeeded": false,
"coProUpdateFailure": false,
"configPending": false,
"deviceId": "3014F7110000000000000109",
"deviceOverheated": null,
"deviceOverloaded": false,
"deviceUndervoltage": false,
"dutyCycle": false,
"functionalChannelType": "DEVICE_BASE",
"groupIndex": 0,
"groups": [
"00000000-0000-0000-0000-000000000029"
],
"index": 0,
"label": "",
"lowBat": null,
"routerModuleEnabled": false,
"routerModuleSupported": false,
"rssiDeviceValue": -80,
"rssiPeerValue": -73,
"supportedOptionalFeatures": {
"IFeatureDeviceCoProError": false,
"IFeatureDeviceCoProRestart": false,
"IFeatureDeviceCoProUpdate": false,
"IFeatureDeviceOverheated": true,
"IFeatureDeviceOverloaded": false,
"IFeatureDeviceTemperatureOutOfRange": false,
"IFeatureDeviceUndervoltage": false
},
"temperatureOutOfRange": false,
"unreach": false
},
"1": {
"currentPowerConsumption": 0.0,
"deviceId": "3014F7110000000000000109",
"energyCounter": 0.0011,
"functionalChannelType": "SWITCH_MEASURING_CHANNEL",
"groupIndex": 1,
"groups": [
"00000000-0000-0000-0000-000000000030"
],
"index": 1,
"label": "",
"on": false,
"profileMode": "AUTOMATIC",
"userDesiredProfileMode": "AUTOMATIC"
}
},
"homeId": "00000000-0000-0000-0000-000000000001",
"id": "3014F7110000000000000011",
"label": "Ausschalter Terrasse Bewegungsmelder",
"lastStatusUpdate": 1570366291250,
"liveUpdateState": "LIVE_UPDATE_NOT_SUPPORTED",
"manufacturerCode": 1,
"modelId": 289,
"modelType": "HmIP-FSM",
"oem": "eQ-3",
"permanentlyReachable": true,
"serializedGlobalTradeItemNumber": "3014F7110000000000000109",
"type": "FULL_FLUSH_SWITCH_MEASURING",
"updateState": "UP_TO_DATE"
},
"3014F7110000000000000008": {
"availableFirmwareVersion": "0.0.0",
"firmwareVersion": "2.6.2",
@ -2236,6 +2374,57 @@
"type": "PLUGABLE_SWITCH_MEASURING",
"updateState": "UP_TO_DATE"
},
"3014F7110000000000000110": {
"availableFirmwareVersion": "0.0.0",
"firmwareVersion": "2.6.2",
"firmwareVersionInteger": 132610,
"functionalChannels": {
"0": {
"configPending": false,
"deviceId": "3014F7110000000000000110",
"dutyCycle": false,
"functionalChannelType": "DEVICE_BASE",
"groupIndex": 0,
"groups": [
"00000000-0000-0000-0000-000000000017"
],
"index": 0,
"label": "",
"lowBat": null,
"routerModuleEnabled": true,
"routerModuleSupported": true,
"rssiDeviceValue": -47,
"rssiPeerValue": -49,
"unreach": false
},
"1": {
"deviceId": "3014F7110000000000000110",
"functionalChannelType": "SWITCH_CHANNEL",
"groupIndex": 1,
"groups": [
"00000000-0000-0000-0000-000000000018"
],
"index": 1,
"label": "",
"on": true,
"profileMode": "AUTOMATIC",
"userDesiredProfileMode": "AUTOMATIC"
}
},
"homeId": "00000000-0000-0000-0000-000000000001",
"id": "3014F7110000000000000110",
"label": "Schrank",
"lastStatusUpdate": 1524513613922,
"liveUpdateState": "LIVE_UPDATE_NOT_SUPPORTED",
"manufacturerCode": 1,
"modelId": 262,
"modelType": "HMIP-PS",
"oem": "eQ-3",
"permanentlyReachable": true,
"serializedGlobalTradeItemNumber": "3014F7110000000000000110",
"type": "PLUGABLE_SWITCH",
"updateState": "UP_TO_DATE"
},
"3014F7110000000000000011": {
"automaticValveAdaptionNeeded": false,
"availableFirmwareVersion": "2.0.2",