Files
ad-prod/apps/drivers/moes_pad.py
2025-12-12 08:20:24 -06:00

105 lines
4.1 KiB
Python

from enum import Enum
from typing import Any
from appdaemon.adapi import ADAPI
from appdaemon.adbase import ADBase
class MoesButtons(int, Enum):
TOP_LEFT = 1
TOP_RIGHT = 2
BOTTOM_LEFT = 3
BOTTOM_RIGHT = 4
class MoesActions(str, Enum):
SINGLE_PRESS = 'single'
DOUBLE_PRESS = 'double'
LONG_PRESS = 'hold'
class MoesBridge(ADBase):
"""Class for an app that listens for state changes generated by 4 button Moes Pads and makes the events more
sensible with enums."""
adapi: ADAPI
def initialize(self):
self.adapi = self.get_ad_api()
self.log = self.adapi.log
self.event_handle = self.adapi.listen_state(self.handle_state_change)
def handle_state_change(self, entity: str, attribute: str, old: Any, new: Any, **kwargs: Any) -> None:
if new == '' or not new[0].isdigit():
return
domain, ent = entity.split('.', 1)
if domain == 'sensor' and ent.startswith('moes'):
button, action = new.split('_')
button = MoesButtons(int(button))
button_str = button.name.lower().replace('_', ' ')
action = MoesActions(action)
self.log(f'Moes Pad action detected: {action.value} on button {button_str}')
self.adapi.fire_event(
'moes_pad',
device=entity,
button=button,
action=action,
)
class MoesPad(ADBase):
"""Specfic implementation of a Moes Pad."""
def initialize(self):
self.adapi = self.get_ad_api()
self.log = self.adapi.log
self.event_handle = self.adapi.listen_event(self.handle_moes_event, 'moes_pad')
self.bedroom_offs = ('bedroom_stick', 'bedroom_john', 'bedroom_sydney')
self.main_offs = ('bar', 'server_lamp', 'living_room_stick')
# self.set_many(self.main_offs, state='on')
def handle_moes_event(self, event_name: str, data: dict[str, Any], **kwargs: Any) -> None:
button = MoesButtons(data.get('button'))
action = MoesActions(data.get('action'))
self.log(f'Received Moes Pad event: {action} on button {button}')
match action:
case MoesActions.SINGLE_PRESS:
self.handle_single_press(button)
case MoesActions.DOUBLE_PRESS:
self.handle_double_press(button)
def handle_single_press(self, button: MoesButtons) -> None:
match button:
case MoesButtons.TOP_LEFT:
self.adapi.call_service('light/toggle', entity_id='light.bedroom_sydney')
case MoesButtons.TOP_RIGHT:
self.adapi.call_service('light/toggle', entity_id='light.bedroom_john')
case MoesButtons.BOTTOM_LEFT:
self.adapi.call_service('light/toggle', entity_id='light.bedroom_stick')
case MoesButtons.BOTTOM_RIGHT:
any_on = any(self.adapi.get_state(f'light.{e}') == 'on' for e in self.bedroom_offs)
scene = {'entities': {f'light.{e}': {'state': 'off' if any_on else 'on'}} for e in self.bedroom_offs}
self.adapi.call_service('scene/apply', **scene)
def handle_double_press(self, button: MoesButtons) -> None:
match button:
case MoesButtons.BOTTOM_RIGHT:
all_lights = [*self.bedroom_offs, *self.main_offs]
any_on = self.check_many(all_lights, state='on')
new_state = 'off' if any_on else 'on'
self.log(f'New state from double press: {new_state}')
self.set_many(self.bedroom_offs, state=new_state)
self.set_many(self.main_offs, state=new_state)
def set_many(self, lights: set[str], state: str = 'off'):
entity_ids = [f'light.{e}' if not e.startswith('light') else e for e in lights]
scene = {'entities': {eid: {'state': state} for eid in entity_ids}}
return self.adapi.call_service('scene/apply', **scene)
def check_many(self, lights: set[str], state: str = 'off') -> bool:
entity_ids = [f'light.{e}' if not e.startswith('light') else e for e in lights]
return any(self.adapi.get_state(eid) == state for eid in entity_ids)