Reorg and test attributes for HomematicIP Cloud (#28234)

* Reorg and test attribute for HomematicIP Cloud

* Add dutyCycle check to security_group

* Edit test to improve coverage

* Add missing flow test

* apply suggestion

Co-Authored-By: Martin Hjelmare <marhje52@kth.se>

* fix assert condition
This commit is contained in:
SukramJ 2019-10-28 01:03:26 +01:00 committed by Martin Hjelmare
parent 6ac7796fb7
commit 75f94b9147
7 changed files with 169 additions and 19 deletions

View File

@ -39,7 +39,6 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.typing import HomeAssistantType
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice
from .device import ATTR_GROUP_MEMBER_UNREACHABLE
from .hap import HomematicipHAP
_LOGGER = logging.getLogger(__name__)
@ -48,7 +47,6 @@ ATTR_ACCELERATION_SENSOR_MODE = "acceleration_sensor_mode"
ATTR_ACCELERATION_SENSOR_NEUTRAL_POSITION = "acceleration_sensor_neutral_position"
ATTR_ACCELERATION_SENSOR_SENSITIVITY = "acceleration_sensor_sensitivity"
ATTR_ACCELERATION_SENSOR_TRIGGER_ANGLE = "acceleration_sensor_trigger_angle"
ATTR_LOW_BATTERY = "low_battery"
ATTR_MOISTURE_DETECTED = "moisture_detected"
ATTR_MOTION_DETECTED = "motion_detected"
ATTR_POWER_MAINS_FAILURE = "power_mains_failure"
@ -59,12 +57,10 @@ ATTR_WATER_LEVEL_DETECTED = "water_level_detected"
ATTR_WINDOW_STATE = "window_state"
GROUP_ATTRIBUTES = {
"lowBat": ATTR_LOW_BATTERY,
"moistureDetected": ATTR_MOISTURE_DETECTED,
"motionDetected": ATTR_MOTION_DETECTED,
"powerMainsFailure": ATTR_POWER_MAINS_FAILURE,
"presenceDetected": ATTR_PRESENCE_DETECTED,
"unreach": ATTR_GROUP_MEMBER_UNREACHABLE,
"waterlevelDetected": ATTR_WATER_LEVEL_DETECTED,
}
@ -408,17 +404,22 @@ class HomematicipSecuritySensorGroup(
def is_on(self) -> bool:
"""Return true if safety issue detected."""
parent_is_on = super().is_on
if parent_is_on:
return True
if (
parent_is_on
or self._device.powerMainsFailure
self._device.powerMainsFailure
or self._device.moistureDetected
or self._device.waterlevelDetected
or self._device.lowBat
or self._device.dutyCycle
):
return True
if (
self._device.smokeDetectorAlarmType is not None
and self._device.smokeDetectorAlarmType != SmokeDetectorAlarmType.IDLE_OFF
):
return True
return False

View File

@ -15,6 +15,9 @@ from .hap import HomematicipHAP
_LOGGER = logging.getLogger(__name__)
ATTR_MODEL_TYPE = "model_type"
ATTR_LOW_BATTERY = "low_battery"
ATTR_CONFIG_PENDING = "config_pending"
ATTR_DUTY_CYCLE_REACHED = "duty_cycle_reached"
ATTR_ID = "id"
ATTR_IS_GROUP = "is_group"
# RSSI HAP -> Device
@ -26,27 +29,40 @@ ATTR_GROUP_MEMBER_UNREACHABLE = "group_member_unreachable"
ATTR_DEVICE_OVERHEATED = "device_overheated"
ATTR_DEVICE_OVERLOADED = "device_overloaded"
ATTR_DEVICE_UNTERVOLTAGE = "device_undervoltage"
ATTR_EVENT_DELAY = "event_delay"
DEVICE_ATTRIBUTE_ICONS = {
"lowBat": "mdi:battery-outline",
"sabotage": "mdi:alert",
"sabotage": "mdi:shield-alert",
"dutyCycle": "mdi:alert",
"deviceOverheated": "mdi:alert",
"deviceOverloaded": "mdi:alert",
"deviceUndervoltage": "mdi:alert",
"configPending": "mdi:alert-circle",
}
DEVICE_ATTRIBUTES = {
"modelType": ATTR_MODEL_TYPE,
"sabotage": ATTR_SABOTAGE,
"dutyCycle": ATTR_DUTY_CYCLE_REACHED,
"rssiDeviceValue": ATTR_RSSI_DEVICE,
"rssiPeerValue": ATTR_RSSI_PEER,
"deviceOverheated": ATTR_DEVICE_OVERHEATED,
"deviceOverloaded": ATTR_DEVICE_OVERLOADED,
"deviceUndervoltage": ATTR_DEVICE_UNTERVOLTAGE,
"configPending": ATTR_CONFIG_PENDING,
"eventDelay": ATTR_EVENT_DELAY,
"id": ATTR_ID,
}
GROUP_ATTRIBUTES = {"modelType": ATTR_MODEL_TYPE}
GROUP_ATTRIBUTES = {
"modelType": ATTR_MODEL_TYPE,
"lowBat": ATTR_LOW_BATTERY,
"sabotage": ATTR_SABOTAGE,
"dutyCycle": ATTR_DUTY_CYCLE_REACHED,
"configPending": ATTR_CONFIG_PENDING,
"unreach": ATTR_GROUP_MEMBER_UNREACHABLE,
}
class HomematicipGenericDevice(Entity):

View File

@ -39,12 +39,21 @@ from .hap import HomematicipHAP
_LOGGER = logging.getLogger(__name__)
ATTR_CURRENT_ILLUMINATION = "current_illumination"
ATTR_LOWEST_ILLUMINATION = "lowest_illumination"
ATTR_HIGHEST_ILLUMINATION = "highest_illumination"
ATTR_LEFT_COUNTER = "left_counter"
ATTR_RIGHT_COUNTER = "right_counter"
ATTR_TEMPERATURE_OFFSET = "temperature_offset"
ATTR_WIND_DIRECTION = "wind_direction"
ATTR_WIND_DIRECTION_VARIATION = "wind_direction_variation_in_degree"
ILLUMINATION_DEVICE_ATTRIBUTES = {
"currentIllumination": ATTR_CURRENT_ILLUMINATION,
"lowestIllumination": ATTR_LOWEST_ILLUMINATION,
"highestIllumination": ATTR_HIGHEST_ILLUMINATION,
}
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the HomematicIP Cloud sensors devices."""
@ -273,6 +282,18 @@ class HomematicipIlluminanceSensor(HomematicipGenericDevice):
"""Return the unit this state is expressed in."""
return "lx"
@property
def device_state_attributes(self):
"""Return the state attributes of the wind speed sensor."""
state_attr = super().device_state_attributes
for attr, attr_key in ILLUMINATION_DEVICE_ATTRIBUTES.items():
attr_value = getattr(self._device, attr, None)
if attr_value:
state_attr[attr_key] = attr_value
return state_attr
class HomematicipPowerSensor(HomematicipGenericDevice):
"""Representation of a HomematicIP power measuring device."""

View File

@ -8,8 +8,19 @@ from homeassistant.components.homematicip_cloud.binary_sensor import (
ATTR_ACCELERATION_SENSOR_NEUTRAL_POSITION,
ATTR_ACCELERATION_SENSOR_SENSITIVITY,
ATTR_ACCELERATION_SENSOR_TRIGGER_ANGLE,
ATTR_LOW_BATTERY,
ATTR_MOISTURE_DETECTED,
ATTR_MOTION_DETECTED,
ATTR_POWER_MAINS_FAILURE,
ATTR_PRESENCE_DETECTED,
ATTR_WATER_LEVEL_DETECTED,
ATTR_WINDOW_STATE,
)
from homeassistant.components.homematicip_cloud.device import (
ATTR_EVENT_DELAY,
ATTR_GROUP_MEMBER_UNREACHABLE,
ATTR_LOW_BATTERY,
ATTR_RSSI_DEVICE,
ATTR_SABOTAGE,
)
from homeassistant.const import STATE_OFF, STATE_ON
from homeassistant.setup import async_setup_component
@ -105,6 +116,13 @@ async def test_hmip_shutter_contact(hass, default_mock_hap):
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_OFF
# test common attributes
assert ha_state.attributes[ATTR_RSSI_DEVICE] == -54
assert not ha_state.attributes.get(ATTR_SABOTAGE)
await async_manipulate_test_data(hass, hmip_device, "sabotage", True)
ha_state = hass.states.get(entity_id)
assert ha_state.attributes[ATTR_SABOTAGE]
async def test_hmip_motion_detector(hass, default_mock_hap):
"""Test HomematicipMotionDetector."""
@ -137,6 +155,11 @@ async def test_hmip_presence_detector(hass, default_mock_hap):
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
assert not ha_state.attributes.get(ATTR_EVENT_DELAY)
await async_manipulate_test_data(hass, hmip_device, "eventDelay", True)
ha_state = hass.states.get(entity_id)
assert ha_state.attributes[ATTR_EVENT_DELAY]
async def test_hmip_smoke_detector(hass, default_mock_hap):
"""Test HomematicipSmokeDetector."""
@ -267,10 +290,25 @@ async def test_hmip_security_zone_sensor_group(hass, default_mock_hap):
)
assert ha_state.state == STATE_OFF
assert not ha_state.attributes.get(ATTR_MOTION_DETECTED)
assert not ha_state.attributes.get(ATTR_PRESENCE_DETECTED)
assert not ha_state.attributes.get(ATTR_GROUP_MEMBER_UNREACHABLE)
assert not ha_state.attributes.get(ATTR_SABOTAGE)
assert not ha_state.attributes.get(ATTR_WINDOW_STATE)
await async_manipulate_test_data(hass, hmip_device, "motionDetected", True)
await async_manipulate_test_data(hass, hmip_device, "presenceDetected", True)
await async_manipulate_test_data(hass, hmip_device, "unreach", True)
await async_manipulate_test_data(hass, hmip_device, "sabotage", True)
await async_manipulate_test_data(hass, hmip_device, "windowState", WindowState.OPEN)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
assert ha_state.attributes[ATTR_MOTION_DETECTED] is True
assert ha_state.attributes[ATTR_MOTION_DETECTED]
assert ha_state.attributes[ATTR_PRESENCE_DETECTED]
assert ha_state.attributes[ATTR_GROUP_MEMBER_UNREACHABLE]
assert ha_state.attributes[ATTR_SABOTAGE]
assert ha_state.attributes[ATTR_WINDOW_STATE] == WindowState.OPEN
async def test_hmip_security_sensor_group(hass, default_mock_hap):
@ -283,14 +321,6 @@ async def test_hmip_security_sensor_group(hass, default_mock_hap):
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,
@ -299,7 +329,45 @@ async def test_hmip_security_sensor_group(hass, default_mock_hap):
)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
assert (
ha_state.attributes["smoke_detector_alarm"]
== SmokeDetectorAlarmType.PRIMARY_ALARM
)
await async_manipulate_test_data(
hass, hmip_device, "smokeDetectorAlarmType", SmokeDetectorAlarmType.IDLE_OFF
)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_OFF
assert not ha_state.attributes.get(ATTR_LOW_BATTERY)
assert not ha_state.attributes.get(ATTR_MOTION_DETECTED)
assert not ha_state.attributes.get(ATTR_PRESENCE_DETECTED)
assert not ha_state.attributes.get(ATTR_POWER_MAINS_FAILURE)
assert not ha_state.attributes.get(ATTR_MOISTURE_DETECTED)
assert not ha_state.attributes.get(ATTR_WATER_LEVEL_DETECTED)
assert not ha_state.attributes.get(ATTR_GROUP_MEMBER_UNREACHABLE)
assert not ha_state.attributes.get(ATTR_SABOTAGE)
assert not ha_state.attributes.get(ATTR_WINDOW_STATE)
await async_manipulate_test_data(hass, hmip_device, "lowBat", True)
await async_manipulate_test_data(hass, hmip_device, "motionDetected", True)
await async_manipulate_test_data(hass, hmip_device, "presenceDetected", True)
await async_manipulate_test_data(hass, hmip_device, "powerMainsFailure", True)
await async_manipulate_test_data(hass, hmip_device, "moistureDetected", True)
await async_manipulate_test_data(hass, hmip_device, "waterlevelDetected", True)
await async_manipulate_test_data(hass, hmip_device, "unreach", True)
await async_manipulate_test_data(hass, hmip_device, "sabotage", True)
await async_manipulate_test_data(hass, hmip_device, "windowState", WindowState.OPEN)
ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_ON
assert ha_state.attributes[ATTR_LOW_BATTERY]
assert ha_state.attributes[ATTR_MOTION_DETECTED]
assert ha_state.attributes[ATTR_PRESENCE_DETECTED]
assert ha_state.attributes[ATTR_POWER_MAINS_FAILURE]
assert ha_state.attributes[ATTR_MOISTURE_DETECTED]
assert ha_state.attributes[ATTR_WATER_LEVEL_DETECTED]
assert ha_state.attributes[ATTR_GROUP_MEMBER_UNREACHABLE]
assert ha_state.attributes[ATTR_SABOTAGE]
assert ha_state.attributes[ATTR_WINDOW_STATE] == WindowState.OPEN

View File

@ -98,6 +98,15 @@ async def test_init_flow_show_form(hass):
assert result["type"] == "form"
async def test_init_flow_user_show_form(hass):
"""Test config flow shows up with a form."""
flow = config_flow.HomematicipCloudFlowHandler()
flow.hass = hass
result = await flow.async_step_user(user_input=None)
assert result["type"] == "form"
async def test_init_already_configured(hass):
"""Test accesspoint is already configured."""
MockConfigEntry(

View File

@ -2,8 +2,20 @@
from homematicip.base.enums import ValveState
from homeassistant.components.homematicip_cloud import DOMAIN as HMIPC_DOMAIN
from homeassistant.components.homematicip_cloud.device import (
ATTR_CONFIG_PENDING,
ATTR_DEVICE_OVERHEATED,
ATTR_DEVICE_OVERLOADED,
ATTR_DEVICE_UNTERVOLTAGE,
ATTR_DUTY_CYCLE_REACHED,
ATTR_RSSI_DEVICE,
ATTR_RSSI_PEER,
)
from homeassistant.components.homematicip_cloud.sensor import (
ATTR_CURRENT_ILLUMINATION,
ATTR_HIGHEST_ILLUMINATION,
ATTR_LEFT_COUNTER,
ATTR_LOWEST_ILLUMINATION,
ATTR_RIGHT_COUNTER,
ATTR_TEMPERATURE_OFFSET,
ATTR_WIND_DIRECTION,
@ -92,6 +104,9 @@ async def test_hmip_humidity_sensor(hass, default_mock_hap):
await async_manipulate_test_data(hass, hmip_device, "humidity", 45)
ha_state = hass.states.get(entity_id)
assert ha_state.state == "45"
# test common attributes
assert ha_state.attributes[ATTR_RSSI_DEVICE] == -76
assert ha_state.attributes[ATTR_RSSI_PEER] == -77
async def test_hmip_temperature_sensor1(hass, default_mock_hap):
@ -153,6 +168,23 @@ async def test_hmip_power_sensor(hass, default_mock_hap):
await async_manipulate_test_data(hass, hmip_device, "currentPowerConsumption", 23.5)
ha_state = hass.states.get(entity_id)
assert ha_state.state == "23.5"
# test common attributes
assert not ha_state.attributes.get(ATTR_DEVICE_OVERHEATED)
assert not ha_state.attributes.get(ATTR_DEVICE_OVERLOADED)
assert not ha_state.attributes.get(ATTR_DEVICE_UNTERVOLTAGE)
assert not ha_state.attributes.get(ATTR_DUTY_CYCLE_REACHED)
assert not ha_state.attributes.get(ATTR_CONFIG_PENDING)
await async_manipulate_test_data(hass, hmip_device, "deviceOverheated", True)
await async_manipulate_test_data(hass, hmip_device, "deviceOverloaded", True)
await async_manipulate_test_data(hass, hmip_device, "deviceUndervoltage", True)
await async_manipulate_test_data(hass, hmip_device, "dutyCycle", True)
await async_manipulate_test_data(hass, hmip_device, "configPending", True)
ha_state = hass.states.get(entity_id)
assert ha_state.attributes[ATTR_DEVICE_OVERHEATED]
assert ha_state.attributes[ATTR_DEVICE_OVERLOADED]
assert ha_state.attributes[ATTR_DEVICE_UNTERVOLTAGE]
assert ha_state.attributes[ATTR_DUTY_CYCLE_REACHED]
assert ha_state.attributes[ATTR_CONFIG_PENDING]
async def test_hmip_illuminance_sensor1(hass, default_mock_hap):
@ -187,6 +219,9 @@ async def test_hmip_illuminance_sensor2(hass, default_mock_hap):
await async_manipulate_test_data(hass, hmip_device, "averageIllumination", 231)
ha_state = hass.states.get(entity_id)
assert ha_state.state == "231"
assert ha_state.attributes[ATTR_CURRENT_ILLUMINATION] == 785.2
assert ha_state.attributes[ATTR_HIGHEST_ILLUMINATION] == 837.1
assert ha_state.attributes[ATTR_LOWEST_ILLUMINATION] == 785.2
async def test_hmip_windspeed_sensor(hass, default_mock_hap):

View File

@ -136,7 +136,7 @@ async def test_hmip_group_switch(hass, default_mock_hap):
assert not ha_state.attributes.get(ATTR_GROUP_MEMBER_UNREACHABLE)
await async_manipulate_test_data(hass, hmip_device, "unreach", True)
ha_state = hass.states.get(entity_id)
assert ha_state.attributes[ATTR_GROUP_MEMBER_UNREACHABLE] is True
assert ha_state.attributes[ATTR_GROUP_MEMBER_UNREACHABLE]
async def test_hmip_multi_switch(hass, default_mock_hap):