Add floor heating device valve positions in Homematic IP Cloud (#122759)

* Update sensor.py for new FALMOT Sensors

First Integration attemp to support ValvePosition as Sensor for HmIP-FALMOT-C12

* Update sensor.py

* Update sensor.py

* Add Valve Position to FALMOT-C12

* modified: devcontainer

* Service für minimum vale postion hinzugefügt.

* update to services

* Service call optimized

* Add valvePosition to HomematicIP Cloud for Falmot-C12 and show only channels that are connected with an motorized actuator

* Fix some tests

* Add icon for service

* Fix tests, add check for ValveState in icon

* Remove minimum valve service

* REmove minimum valve

* Use list comprehension for devices, support other terminal blocks

* Remove unused constant

* Check correct channel

---------

Co-authored-by: thecem <46648579+thecem@users.noreply.github.com>
This commit is contained in:
Barry vd. Heuvel 2024-10-21 17:54:31 +02:00 committed by GitHub
parent 07506faa3a
commit 4009ae7d77
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 279 additions and 48 deletions

View File

@ -8,6 +8,9 @@ from typing import Any
from homematicip.aio.device import (
AsyncBrandSwitchMeasuring,
AsyncEnergySensorsInterface,
AsyncFloorTerminalBlock6,
AsyncFloorTerminalBlock10,
AsyncFloorTerminalBlock12,
AsyncFullFlushSwitchMeasuring,
AsyncHeatingThermostat,
AsyncHeatingThermostatCompact,
@ -28,9 +31,13 @@ from homematicip.aio.device import (
AsyncWeatherSensor,
AsyncWeatherSensorPlus,
AsyncWeatherSensorPro,
AsyncWiredFloorTerminalBlock12,
)
from homematicip.base.enums import FunctionalChannelType, ValveState
from homematicip.base.functionalChannels import FunctionalChannel
from homematicip.base.functionalChannels import (
FloorTerminalBlockMechanicChannel,
FunctionalChannel,
)
from homeassistant.components.sensor import (
SensorDeviceClass,
@ -86,7 +93,7 @@ ILLUMINATION_DEVICE_ATTRIBUTES = {
}
async def async_setup_entry(
async def async_setup_entry( # noqa: C901
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
@ -184,10 +191,74 @@ async def async_setup_entry(
if ch.currentPowerConsumption is not None:
entities.append(HmipEsiLedCurrentPowerConsumption(hap, device))
entities.append(HmipEsiLedEnergyCounterHighTariff(hap, device))
if isinstance(
device,
(
AsyncFloorTerminalBlock6,
AsyncFloorTerminalBlock10,
AsyncFloorTerminalBlock12,
AsyncWiredFloorTerminalBlock12,
),
):
entities.extend(
HomematicipFloorTerminalBlockMechanicChannelValve(
hap, device, channel=channel.index
)
for channel in device.functionalChannels
if isinstance(channel, FloorTerminalBlockMechanicChannel)
and getattr(channel, "valvePosition", None) is not None
)
async_add_entities(entities)
class HomematicipFloorTerminalBlockMechanicChannelValve(
HomematicipGenericEntity, SensorEntity
):
"""Representation of the HomematicIP floor terminal block."""
_attr_native_unit_of_measurement = PERCENTAGE
_attr_state_class = SensorStateClass.MEASUREMENT
def __init__(
self, hap: HomematicipHAP, device, channel, is_multi_channel=True
) -> None:
"""Initialize floor terminal block 12 device."""
super().__init__(
hap,
device,
channel=channel,
is_multi_channel=is_multi_channel,
post="Valve Position",
)
@property
def icon(self) -> str | None:
"""Return the icon."""
if super().icon:
return super().icon
channel = next(
channel
for channel in self._device.functionalChannels
if channel.index == self._channel
)
if channel.valveState != ValveState.ADAPTION_DONE:
return "mdi:alert"
return "mdi:heating-coil"
@property
def native_value(self) -> int | None:
"""Return the state of the floor terminal block mechanical channel valve position."""
channel = next(
channel
for channel in self._device.functionalChannels
if channel.index == self._channel
)
if channel.valveState != ValveState.ADAPTION_DONE:
return None
return round(channel.valvePosition * 100)
class HomematicipAccesspointDutyCycle(HomematicipGenericEntity, SensorEntity):
"""Representation of then HomeMaticIP access point."""

View File

@ -1805,93 +1805,164 @@
"updateState": "UP_TO_DATE"
},
"3014F7110000000000000049": {
"availableFirmwareVersion": "1.0.8",
"availableFirmwareVersion": "1.4.8",
"connectionType": "HMIP_RF",
"firmwareVersion": "1.0.8",
"firmwareVersionInteger": 65544,
"deviceArchetype": "HMIP",
"firmwareVersion": "1.4.8",
"firmwareVersionInteger": 66568,
"functionalChannels": {
"0": {
"busConfigMismatch": null,
"coProFaulty": false,
"coProRestartNeeded": false,
"coProUpdateFailure": false,
"configPending": false,
"configPending": true,
"controlsMountingOrientation": null,
"coolingEmergencyValue": 0.0,
"daliBusState": null,
"defaultLinkedGroup": [],
"deviceCommunicationError": null,
"deviceDriveError": null,
"deviceDriveModeError": null,
"deviceId": "3014F7110000000000000049",
"deviceOperationMode": null,
"deviceOverheated": false,
"deviceOverloaded": false,
"devicePowerFailureDetected": false,
"deviceUndervoltage": false,
"displayContrast": null,
"dutyCycle": false,
"frostProtectionTemperature": 8.0,
"functionalChannelType": "DEVICE_BASE_FLOOR_HEATING",
"groupIndex": 0,
"groups": [],
"heatingEmergencyValue": 0.25,
"groups": ["00000000-0000-0000-0000-000000000005"],
"heatingEmergencyValue": 0.05,
"index": 0,
"label": "",
"lockJammed": null,
"lowBat": null,
"minimumFloorHeatingValvePosition": 0.0,
"pulseWidthModulationAtLowFloorHeatingValvePositionEnabled": true,
"mountingOrientation": null,
"multicastRoutingEnabled": false,
"particulateMatterSensorCommunicationError": null,
"particulateMatterSensorError": null,
"powerShortCircuit": null,
"profilePeriodLimitReached": null,
"pulseWidthModulationAtLowFloorHeatingValvePositionEnabled": false,
"routerModuleEnabled": false,
"routerModuleSupported": false,
"rssiDeviceValue": -55,
"rssiDeviceValue": -83,
"rssiPeerValue": null,
"sensorCommunicationError": null,
"sensorError": null,
"shortCircuitDataLine": null,
"supportedOptionalFeatures": {
"IFeatureBusConfigMismatch": false,
"IFeatureDeviceCoProError": false,
"IFeatureDeviceCoProRestart": false,
"IFeatureDeviceCoProUpdate": false,
"IFeatureDeviceCommunicationError": false,
"IFeatureDeviceDaliBusError": false,
"IFeatureDeviceDriveError": false,
"IFeatureDeviceDriveModeError": false,
"IFeatureDeviceIdentify": false,
"IFeatureDeviceOverheated": false,
"IFeatureDeviceOverloaded": false,
"IFeatureDeviceParticulateMatterSensorCommunicationError": false,
"IFeatureDeviceParticulateMatterSensorError": false,
"IFeatureDevicePowerFailure": false,
"IFeatureDeviceSensorCommunicationError": false,
"IFeatureDeviceSensorError": false,
"IFeatureDeviceTemperatureHumiditySensorCommunicationError": false,
"IFeatureDeviceTemperatureHumiditySensorError": false,
"IFeatureDeviceTemperatureOutOfRange": false,
"IFeatureDeviceUndervoltage": false,
"IFeatureMinimumFloorHeatingValvePosition": true,
"IFeaturePulseWidthModulationAtLowFloorHeatingValvePosition": true
"IFeatureMulticastRouter": false,
"IFeaturePowerShortCircuit": false,
"IFeatureProfilePeriodLimit": false,
"IFeaturePulseWidthModulationAtLowFloorHeatingValvePosition": true,
"IFeatureRssiValue": true,
"IFeatureShortCircuitDataLine": false,
"IOptionalFeatureDefaultLinkedGroup": false,
"IOptionalFeatureDeviceErrorLockJammed": false,
"IOptionalFeatureDeviceOperationMode": false,
"IOptionalFeatureDisplayContrast": false,
"IOptionalFeatureDutyCycle": true,
"IOptionalFeatureLowBat": false,
"IOptionalFeatureMountingOrientation": false
},
"temperatureHumiditySensorCommunicationError": null,
"temperatureHumiditySensorError": null,
"temperatureOutOfRange": false,
"unreach": false,
"valveProtectionDuration": 5,
"valveProtectionSwitchingInterval": 14
},
"1": {
"channelRole": "FLOOR_HEATING_COOLING_CONTROLLER",
"deviceId": "3014F7110000000000000049",
"functionalChannelType": "FLOOR_TERMINAL_BLOCK_MECHANIC_CHANNEL",
"groupIndex": 1,
"groups": [],
"groups": [
"00000000-0000-0000-0000-000000000022",
"00000000-0000-0000-0000-000000000023"
],
"index": 1,
"label": "",
"label": "Heizkreislauf (1) OG Bad r",
"valvePosition": 0.475,
"valveState": "ADAPTION_DONE"
},
"10": {
"channelRole": "FLOOR_HEATING_COOLING_CONTROLLER",
"deviceId": "3014F7110000000000000049",
"functionalChannelType": "FLOOR_TERMINAL_BLOCK_MECHANIC_CHANNEL",
"groupIndex": 10,
"groups": [],
"groups": [
"00000000-0000-0000-0000-000000000030",
"00000000-0000-0000-0000-000000000031"
],
"index": 10,
"label": "",
"valveState": "ADJUSTMENT_TOO_SMALL"
"label": "Heizkreislauf (10) OG AZ rechts",
"valvePosition": 0.385,
"valveState": "ADAPTION_DONE"
},
"11": {
"channelRole": "FLOOR_HEATING_COOLING_CONTROLLER",
"deviceId": "3014F7110000000000000049",
"functionalChannelType": "FLOOR_TERMINAL_BLOCK_MECHANIC_CHANNEL",
"groupIndex": 11,
"groups": [],
"groups": [
"00000000-0000-0000-0000-000000000030",
"00000000-0000-0000-0000-000000000031"
],
"index": 11,
"label": "",
"valveState": "ADJUSTMENT_TOO_SMALL"
"label": "Heizkreislauf (11) OG AZ links",
"valvePosition": 0.385,
"valveState": "ADAPTION_DONE"
},
"12": {
"channelRole": "FLOOR_HEATING_COOLING_CONTROLLER",
"deviceId": "3014F7110000000000000049",
"functionalChannelType": "FLOOR_TERMINAL_BLOCK_MECHANIC_CHANNEL",
"groupIndex": 12,
"groups": [],
"groups": [
"00000000-0000-0000-0000-000000000022",
"00000000-0000-0000-0000-000000000023"
],
"index": 12,
"label": "",
"valveState": "ADJUSTMENT_TOO_SMALL"
"label": "Heizkreislauf (12) OG Bad Heizk\u00f6rper",
"valvePosition": 0.385,
"valveState": "ADAPTION_DONE"
},
"13": {
"deviceId": "3014F7110000000000000049",
"functionalChannelType": "HEAT_DEMAND_CHANNEL",
"groupIndex": 0,
"groups": [],
"groups": [
"00000000-0000-0000-0000-000000000058",
"00000000-0000-0000-0000-000000000059"
],
"index": 13,
"label": ""
},
@ -1899,7 +1970,7 @@
"deviceId": "3014F7110000000000000049",
"functionalChannelType": "DEHUMIDIFIER_DEMAND_CHANNEL",
"groupIndex": 0,
"groups": [],
"groups": ["00000000-0000-0000-0000-000000000060"],
"index": 14,
"label": ""
},
@ -1907,89 +1978,136 @@
"deviceId": "3014F7110000000000000049",
"functionalChannelType": "CHANGE_OVER_CHANNEL",
"groupIndex": 0,
"groups": [],
"groups": [
"00000000-0000-0000-0000-000000000061",
"00000000-0000-0000-0000-000000000062",
"00000000-0000-0000-0000-000000000063",
"00000000-0000-0000-0000-000000000064"
],
"index": 15,
"label": ""
},
"2": {
"channelRole": "FLOOR_HEATING_COOLING_CONTROLLER",
"deviceId": "3014F7110000000000000049",
"functionalChannelType": "FLOOR_TERMINAL_BLOCK_MECHANIC_CHANNEL",
"groupIndex": 2,
"groups": [],
"groups": [
"00000000-0000-0000-0000-000000000022",
"00000000-0000-0000-0000-000000000023"
],
"index": 2,
"label": "",
"label": "Heizkreislauf (2) OG Bad l",
"valvePosition": 0.385,
"valveState": "ADAPTION_DONE"
},
"3": {
"channelRole": "FLOOR_HEATING_COOLING_CONTROLLER",
"deviceId": "3014F7110000000000000049",
"functionalChannelType": "FLOOR_TERMINAL_BLOCK_MECHANIC_CHANNEL",
"groupIndex": 3,
"groups": [],
"groups": [
"00000000-0000-0000-0000-000000000017",
"00000000-0000-0000-0000-000000000018"
],
"index": 3,
"label": "",
"label": "Heizkreislauf (3) OG WZ rechts",
"valvePosition": 0.0,
"valveState": "ADAPTION_DONE"
},
"4": {
"channelRole": "FLOOR_HEATING_COOLING_CONTROLLER",
"deviceId": "3014F7110000000000000049",
"functionalChannelType": "FLOOR_TERMINAL_BLOCK_MECHANIC_CHANNEL",
"groupIndex": 4,
"groups": [],
"groups": [
"00000000-0000-0000-0000-000000000017",
"00000000-0000-0000-0000-000000000018"
],
"index": 4,
"label": "",
"label": "Heizkreislauf (4) OG WZ Mitte rechts",
"valvePosition": 0.0,
"valveState": "ADAPTION_DONE"
},
"5": {
"channelRole": "FLOOR_HEATING_COOLING_CONTROLLER",
"deviceId": "3014F7110000000000000049",
"functionalChannelType": "FLOOR_TERMINAL_BLOCK_MECHANIC_CHANNEL",
"groupIndex": 5,
"groups": [],
"groups": [
"00000000-0000-0000-0000-000000000017",
"00000000-0000-0000-0000-000000000018"
],
"index": 5,
"label": "",
"label": "Heizkreislauf (5) OG WZ Mitte links",
"valvePosition": 0.0,
"valveState": "ADAPTION_DONE"
},
"6": {
"channelRole": "FLOOR_HEATING_COOLING_CONTROLLER",
"deviceId": "3014F7110000000000000049",
"functionalChannelType": "FLOOR_TERMINAL_BLOCK_MECHANIC_CHANNEL",
"groupIndex": 6,
"groups": [],
"groups": [
"00000000-0000-0000-0000-000000000017",
"00000000-0000-0000-0000-000000000018"
],
"index": 6,
"label": "",
"valveState": "ADJUSTMENT_TOO_SMALL"
"label": "Heizkreislauf (6) OG WZ links",
"valvePosition": 0.0,
"valveState": "ADAPTION_DONE"
},
"7": {
"channelRole": "FLOOR_HEATING_COOLING_CONTROLLER",
"deviceId": "3014F7110000000000000049",
"functionalChannelType": "FLOOR_TERMINAL_BLOCK_MECHANIC_CHANNEL",
"groupIndex": 7,
"groups": [],
"groups": [
"00000000-0000-0000-0000-000000000017",
"00000000-0000-0000-0000-000000000018"
],
"index": 7,
"label": "",
"valveState": "ADJUSTMENT_TOO_SMALL"
"label": "Heizkreislauf (7) OG K\u00fcche",
"valvePosition": 0.0,
"valveState": "ADAPTION_DONE"
},
"8": {
"channelRole": "FLOOR_HEATING_COOLING_CONTROLLER",
"deviceId": "3014F7110000000000000049",
"functionalChannelType": "FLOOR_TERMINAL_BLOCK_MECHANIC_CHANNEL",
"groupIndex": 8,
"groups": [],
"groups": [
"00000000-0000-0000-0000-000000000026",
"00000000-0000-0000-0000-000000000027"
],
"index": 8,
"label": "",
"valveState": "ADJUSTMENT_TOO_SMALL"
"label": "Heizkreislauf (8) OG SZ rechts",
"valvePosition": 0.0,
"valveState": "ADAPTION_DONE"
},
"9": {
"channelRole": "FLOOR_HEATING_COOLING_CONTROLLER",
"deviceId": "3014F7110000000000000049",
"functionalChannelType": "FLOOR_TERMINAL_BLOCK_MECHANIC_CHANNEL",
"groupIndex": 9,
"groups": [],
"groups": [
"00000000-0000-0000-0000-000000000026",
"00000000-0000-0000-0000-000000000027"
],
"index": 9,
"label": "",
"valveState": "ADJUSTMENT_TOO_SMALL"
"label": "Heizkreislauf (9) OG SZ links",
"valvePosition": 0.0,
"valveState": "ADAPTION_DONE"
}
},
"homeId": "00000000-0000-0000-0000-000000000001",
"id": "3014F7110000000000000049",
"label": "Fu\u00dfbodenheizungsaktor OG motorisch",
"lastStatusUpdate": 1577486092047,
"label": "Fu\u00dfbodenheizungsaktor",
"lastStatusUpdate": 1704379652281,
"liveUpdateState": "LIVE_UPDATE_NOT_SUPPORTED",
"manuallyUpdateForced": false,
"manufacturerCode": 1,
"measuredAttributes": {},
"modelId": 365,
"modelType": "HmIP-FALMOT-C12",
"oem": "eQ-3",

View File

@ -28,7 +28,7 @@ async def test_hmip_load_all_supported_devices(
test_devices=None, test_groups=None
)
assert len(mock_hap.hmip_device_by_entity_id) == 296
assert len(mock_hap.hmip_device_by_entity_id) == 308
async def test_hmip_remove_device(

View File

@ -12,6 +12,7 @@ from homeassistant.components.homematicip_cloud.entity import (
ATTR_RSSI_DEVICE,
ATTR_RSSI_PEER,
)
from homeassistant.components.homematicip_cloud.hap import HomematicipHAP
from homeassistant.components.homematicip_cloud.sensor import (
ATTR_CURRENT_ILLUMINATION,
ATTR_HIGHEST_ILLUMINATION,
@ -515,6 +516,47 @@ async def test_hmip_passage_detector_delta_counter(
assert ha_state.state == "190"
async def test_hmip_floor_terminal_block_mechanic_channel_1_valve_position(
hass: HomeAssistant, default_mock_hap_factory: HomematicipHAP
) -> None:
"""Test HomematicipFloorTerminalBlockMechanicChannelValve Channel 1 HmIP-FALMOT-C12."""
entity_id = "sensor.heizkreislauf_1_og_bad_r"
entity_name = "Heizkreislauf (1) OG Bad r"
device_model = "HmIP-FALMOT-C12"
mock_hap = await default_mock_hap_factory.async_get_mock_hap(
test_devices=["Fu\u00dfbodenheizungsaktor"]
)
ha_state, hmip_device = get_and_check_entity_basics(
hass, mock_hap, entity_id, entity_name, device_model
)
hmip_device = mock_hap.hmip_device_by_entity_id.get(entity_id)
assert ha_state.state == "48"
assert ha_state.attributes[ATTR_UNIT_OF_MEASUREMENT] == PERCENTAGE
await async_manipulate_test_data(hass, hmip_device, "valvePosition", 0.36)
ha_state = hass.states.get(entity_id)
assert ha_state.state == "36"
await async_manipulate_test_data(hass, hmip_device, "configPending", True)
ha_state = hass.states.get(entity_id)
assert ha_state.attributes["icon"] == "mdi:alert-circle"
await async_manipulate_test_data(hass, hmip_device, "configPending", False)
await async_manipulate_test_data(
hass, hmip_device, "valveState", ValveState.ADAPTION_IN_PROGRESS
)
ha_state = hass.states.get(entity_id)
assert ha_state.attributes["icon"] == "mdi:alert"
await async_manipulate_test_data(
hass, hmip_device, "valveState", ValveState.ADAPTION_DONE
)
ha_state = hass.states.get(entity_id)
assert ha_state.attributes["icon"] == "mdi:heating-coil"
async def test_hmip_esi_iec_current_power_consumption(
hass: HomeAssistant, default_mock_hap_factory: HomeFactory
) -> None: