peribeir / homeassistant-rademacher

This custom integration provides access to Rademacher Devices connected to a HomePilot (or Start2Smart) bridge.
GNU General Public License v3.0
55 stars 8 forks source link

Motion Sensor 9484 and Actor Automatic Mode integration #96

Open Kraetzik opened 7 months ago

Kraetzik commented 7 months ago

Hi there, I am trying to integrate a switch which makes it possible to change the automatic mode of actors (auto_mode_cfg from device) from the motion sensor. This is necessary due to the fact that Motion sensors are only triggered if the actor is set to automatic mode. I deactivate them during the day. To use them as an alarm system I need to set the auto_mode by automation.

this is the button I want to trigger on HomePilot: Screenshot 2023-11-20 183946

I tried to use the code from a switch as a template and change it as necessary.

I tried some things with the code but I did not make it to run. Maybe someone else has a helping hand.

changes in the code are marked with >

"""Platform for Rademacher Bridge"""
import asyncio
import logging

from homeassistant.helpers.entity import EntityCategory

from homeassistant.const import CONF_EXCLUDE
from homeassistant.components.switch import SwitchDeviceClass, SwitchEntity
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

from homepilot.manager import HomePilotManager
from homepilot.device import HomePilotDevice
from homepilot.hub import HomePilotHub
from homepilot.switch import HomePilotSwitch
from homepilot.cover import HomePilotCover

from .const import DOMAIN
from .entity import HomePilotEntity

_LOGGER = logging.getLogger(__name__)

async def async_setup_entry(hass, config_entry, async_add_entities):
    """Setup of entities for switch platform"""
    entry = hass.data[DOMAIN][config_entry.entry_id]
    manager: HomePilotManager = entry[0]
    coordinator: DataUpdateCoordinator = entry[1]
    exclude_devices: list[str] = entry[3][CONF_EXCLUDE]
    new_entities = []
    for did in manager.devices:
        if did not in exclude_devices:
            device: HomePilotDevice = manager.devices[did]
            if isinstance(device, HomePilotHub):
                _LOGGER.info("Found Led Switch for Device ID: %s", device.did)
                new_entities.append(HomePilotLedSwitchEntity(coordinator, device))
                new_entities.append(HomePilotAutoUpdaeSwitchEntity(coordinator, device))
            if isinstance(device, HomePilotSwitch):
>                if device.has_auto_mode_cfg:
>                   _LOGGER.info("Found Auto_Mode Config switch for Device ID: %s", device.did)
>                    new_entities.append(HomePilotAutoModeSwitchEntity(coordinator, device))
                _LOGGER.info("Found Switch for Device ID: %s", device.did)
                new_entities.append(HomePilotSwitchEntity(coordinator, device))

            if isinstance(device, HomePilotCover):
                cover: HomePilotCover = device
                if cover.has_ventilation_position_config:
                    _LOGGER.info("Found Ventilation Position Config Switch for Device ID: %s", device.did)
                    new_entities.append(HomePilotVentilationSwitchEntity(coordinator, device))

    # If we have any new devices, add them
    if new_entities:
        async_add_entities(new_entities)

class HomePilotSwitchEntity(HomePilotEntity, SwitchEntity):
    """This class represents all Switches supported"""

    def __init__(
        self, coordinator: DataUpdateCoordinator, device: HomePilotDevice
    ) -> None:
        super().__init__(
            coordinator,
            device,
            unique_id=device.uid,
            name=device.name,
            device_class=SwitchDeviceClass.SWITCH.value,
        )

    @property
    def is_on(self):
        return self.coordinator.data[self.did].is_on

    async def async_turn_on(self, **kwargs):
        """Turn the entity on."""
        device: HomePilotSwitch = self.coordinator.data[self.did]
        await device.async_turn_on()
        await asyncio.sleep(5)
        await self.coordinator.async_request_refresh()

    async def async_turn_off(self, **kwargs):
        """Turn the entity off."""
        device: HomePilotSwitch = self.coordinator.data[self.did]
        await device.async_turn_off()
        await asyncio.sleep(5)
        await self.coordinator.async_request_refresh()

    async def async_toggle(self, **kwargs):
        """Toggle the entity."""
        if self.is_on:
            await self.async_turn_off()
        else:
            await self.async_turn_on()

class HomePilotLedSwitchEntity(HomePilotEntity, SwitchEntity):
    """This class represents the Led Switch which controls the LEDs on the hub"""

    def __init__(
        self, coordinator: DataUpdateCoordinator, device: HomePilotDevice
    ) -> None:
        super().__init__(
            coordinator,
            device,
            unique_id=f"{device.uid}_led_status",
            name=f"{device.name} LED Status",
            device_class=SwitchDeviceClass.SWITCH.value,
            entity_category=EntityCategory.CONFIG,
        )

    @property
    def is_on(self):
        device: HomePilotHub = self.coordinator.data[self.did]
        return device.led_status

    async def async_turn_on(self, **kwargs):
        """Turn the entity on."""
        device: HomePilotHub = self.coordinator.data[self.did]
        await device.async_turn_led_on()
        await asyncio.sleep(5)
        await self.coordinator.async_request_refresh()

    async def async_turn_off(self, **kwargs):
        """Turn the entity off."""
        device: HomePilotHub = self.coordinator.data[self.did]
        await device.async_turn_led_off()
        await asyncio.sleep(5)
        await self.coordinator.async_request_refresh()

    async def async_toggle(self, **kwargs):
        """Toggle the entity."""
        if self.is_on:
            await self.async_turn_off()
        else:
            await self.async_turn_on()

class HomePilotAutoUpdaeSwitchEntity(HomePilotEntity, SwitchEntity):
    """This class represents the Led Switch which controls the LEDs on the hub"""

    def __init__(
        self, coordinator: DataUpdateCoordinator, device: HomePilotDevice
    ) -> None:
        super().__init__(
            coordinator,
            device,
            unique_id=f"{device.uid}_auto_update",
            name=f"{device.name} Auto Update",
            device_class=SwitchDeviceClass.SWITCH.value,
            entity_category=EntityCategory.CONFIG,
        )

    @property
    def is_on(self):
        device: HomePilotHub = self.coordinator.data[self.did]
        return device.auto_update

    async def async_turn_on(self, **kwargs):
        """Turn the entity on."""
        device: HomePilotHub = self.coordinator.data[self.did]
        await device.async_set_auto_update_on()
        await asyncio.sleep(5)
        await self.coordinator.async_request_refresh()

    async def async_turn_off(self, **kwargs):
        """Turn the entity off."""
        device: HomePilotHub = self.coordinator.data[self.did]
        await device.async_set_auto_update_off()
        await asyncio.sleep(5)
        await self.coordinator.async_request_refresh()

    async def async_toggle(self, **kwargs):
        """Toggle the entity."""
        if self.is_on:
            await self.async_turn_off()
        else:
            await self.async_turn_on()

class HomePilotVentilationSwitchEntity(HomePilotEntity, SwitchEntity):
    """This class represents the Switch which controls Ventilation Position Mode"""

    def __init__(
        self, coordinator: DataUpdateCoordinator, device: HomePilotDevice
    ) -> None:
        super().__init__(
            coordinator,
            device,
            unique_id=f"{device.uid}_ventilation_position_mode",
            name=f"{device.name} Ventilation Position Mode",
            device_class=SwitchDeviceClass.SWITCH.value,
            entity_category=EntityCategory.CONFIG,
        )

    @property
    def is_on(self):
        device: HomePilotCover = self.coordinator.data[self.did]
        return device.ventilation_position_mode

    async def async_turn_on(self, **kwargs):
        """Turn the entity on."""
        device: HomePilotCover = self.coordinator.data[self.did]
        await device.async_set_ventilation_position_mode(True)
        await asyncio.sleep(5)
        await self.coordinator.async_request_refresh()

    async def async_turn_off(self, **kwargs):
        """Turn the entity off."""
        device: HomePilotCover = self.coordinator.data[self.did]
        await device.async_set_ventilation_position_mode(False)
        await asyncio.sleep(5)
        await self.coordinator.async_request_refresh()

    async def async_toggle(self, **kwargs):
        """Toggle the entity."""
        if self.is_on:
            await self.async_turn_off()
        else:
            await self.async_turn_on()

>class HomePilotAutoModeSwitchEntity(HomePilotEntity, SwitchEntity):
>   """This class represents the Switch which controls Auto Mode"""
>
>    def __init__(
>        self, coordinator: DataUpdateCoordinator, device: HomePilotDevice
>    ) -> None:
>        super().__init__(
>            coordinator,
>            device,
>            unique_id=f"{device.uid}_auto_mode",
>            name=f"{device.name} Auto Mode",
>            device_class=SwitchDeviceClass.SWITCH.value,
>            entity_category=EntityCategory.CONFIG,
>        )
>
>    @property
>    def is_on(self):
>        return self.coordinator.data[self.did].is_on
>
>    async def async_turn_on(self, **kwargs):
>        """Turn the entity on."""
>        device: HomePilotSwitch = self.coordinator.data[self.did]
>        await device.async_auto_mode_cfg(True)
>        await asyncio.sleep(5)
>        await self.coordinator.async_request_refresh()
>
>    async def async_turn_off(self, **kwargs):
>        """Turn the entity off."""
>        device: HomePilotSwitch = self.coordinator.data[self.did]
>        await device.async_auto_mode_cfg(False)
>        await asyncio.sleep(5)
>        await self.coordinator.async_request_refresh()
>
>    async def async_toggle(self, **kwargs):
>        """Toggle the entity."""
>        if self.is_on:
>            await self.async_turn_off()
>        else:
>            await self.async_turn_on()

here is the code from the device


{"error_description":"OK","error_code":0,"payload":{"device":{"capabilities":
[{"name":"STAIRWAY_MODE_CFG","value":"true","read_only":false,"timestamp":169973831
8},{"name":"POS_UP_CMD","read_only":false,"timestamp":-1},
{"name":"VERSION_CFG","value":"1.5-1","read_only":false,"timestamp":1699738321},
{"name":"INC_CMD","read_only":false,"timestamp":-1},
{"name":"PROD_CODE_DEVICE_LOC","value":"32501772_A","read_only":false,"timestamp":-1},
{"name":"REACHABILITY_EVT","value":"true","read_only":true,"timestamp":1699738321},
{"name":"TURN_OFF_CMD","read_only":false,"timestamp":-1},
{"name":"RESET_WO_PAIR_CMD","read_only":false,"timestamp":-1},
{"name":"CONTACT_OPEN_CMD","read_only":false,"timestamp":-1},
{"name":"NAME_DEVICE_LOC","value":"AmBel Flur OG","read_only":false,"timestamp":-1},
{"name":"PROT_ID_DEVICE_LOC","value":"651185_A_1","read_only":false,"timestamp":-1},
{"name":"INTF_ID_DEVICE_LOC","value":"3","read_only":false,"timestamp":-1},
{"name":"GOTO_DAWN_POS_CMD","read_only":false,"timestamp":-1},
{"name":"ICONSET_LOC","value":"iconset21","read_only":false,"timestamp":-1},
{"name":"STAIRWAY_DUR_CFG","value":"60.0","min_value":"0.0","max_value":"3276.5","step_size":"0.1","read_only":false,"timestamp":1699738318},{"name":"DEVICE_TYPE_LOC","value":"1","read_only":false,"timestamp":-1},
{"name":"TURN_ON_CMD","read_only":false,"timestamp":-1},
{"name":"ICONSET_INV_LOC","value":"false","read_only":false,"timestamp":-1},
{"name":"RMT_STOP_PAIR_CMD","read_only":false,"timestamp":-1},
{"name":"VOICE_CONTROLLED_LOC","value":"","read_only":false,"timestamp":-1},
{"name":"DUSK_AUTO_CFG","value":"true","read_only":false,"timestamp":1699738318},
{"name":"REQ_STATUS_CMD","read_only":false,"timestamp":-1},
{"name":"AUTO_MODE_CFG","value":"true","read_only":false,"timestamp":1699738318},
{"name":"DAWN_AUTO_CFG","value":"true","read_only":false,"timestamp":1699738318},
{"name":"RESET_FULL_CMD","read_only":false,"timestamp":-1},
{"name":"PUSH_CMD","read_only":false,"timestamp":-1},
{"name":"PAIRING_CONFIRMED_LOC","value":"true","read_only":false,"timestamp":-1},
{"name":"ID_DEVICE_LOC","value":"1010066","read_only":false,"timestamp":-1},
{"name":"PROTOCOL_ID_CFG","value":"651185","read_only":false,"timestamp":-1},
{"name":"CURR_SWITCH_POS_CFG","value":"false","read_only":false,"timestamp":1699738318},
{"name":"CONTACT_CLOSE_CMD","read_only":false,"timestamp":-1},
{"name":"RMT_START_PAIR_CMD","read_only":false,"timestamp":-1},
{"name":"SUN_PROG_ACTIVE_EVT","value":"false","read_only":true,"timestamp":1699738318},
{"name":"GOTO_DUSK_POS_CMD","read_only":false,"timestamp":-1},
{"name":"SUN_START_CMD","read_only":false,"timestamp":-1},
{"name":"SUN_STOP_CMD","read_only":false,"timestamp":-1},
{"name":"DISCONNECT_SENSOR_2_ACTUATOR_CFG","value":"false","read_only":false,"timestamp":1699738321},
{"name":"SUN_AUTO_CFG","value":"true","read_only":false,"timestamp":1699738318},
{"name":"STOP_CMD","value":"false","read_only":false,"timestamp":-1},
{"name":"VIS_DEVICE_LOC","value":"true","read_only":false,"timestamp":-1},
{"name":"RMT_START_UNPAIR_CMD","read_only":false,"timestamp":-1},
{"name":"INVERSE_MODE_CFG","value":"true","read_only":false,"timestamp":1699738318},
{"name":"POS_DOWN_CMD","read_only":false,"timestamp":-1},
{"name":"DESCR_DEVICE_LOC","value":"Schaltaktor Bewegungsmelder Flur OG","read_only":false,"timestamp":-1},
{"name":"TIME_AUTO_CFG","value":"true","read_only":false,"timestamp":1699738318},
{"name":"PING_CMD","read_only":false,"timestamp":-1},
{"name":"DEC_CMD","read_only":false,"timestamp":-1}],"scenes":[],"automation":[]}}}

If anything else is needed to solve the problem please request. Thanks y'all in advance!

I found that the climates do use the automatic mode switch.

async def async_set_hvac_mode(self, hvac_mode: str) -> None:
        device: HomePilotThermostat = self.coordinator.data[self.did]
        if device.has_auto_mode:
            await device.async_set_auto_mode(hvac_mode == HVAC_MODE_AUTO)
            await asyncio.sleep(5)
            await self.coordinator.async_request_refresh()

I am unable to get the code working for the Motion Sensor switches. any ideas? I have already spend many hours trying to understand why it isn't working and I am really frustrated right now... The code provided by peribeir looks well structured and understandable! Is there anybody who can give a statement on why it is not as easy as I thought it would be?