Continued implementing hue bridge and first entities

This commit is contained in:
Maximilian Giller 2024-11-09 04:22:22 +01:00
parent b9d8c5312c
commit b3106e8bae
13 changed files with 187 additions and 10 deletions

View file

@ -27,7 +27,8 @@ class HueBridge(Bridge):
for _ in range(self._retry_limit):
try:
self._hue.connect()
break
logging.info(f"Connected to Hue Bridge [{self.id}].")
return
except Exception as e:
logging.exception(
f"Failed to connect to Hue bridge [ip {self._hue.ip}]. Retrying in [{self._retry_timeout_seconds}] seconds.",
@ -35,7 +36,9 @@ class HueBridge(Bridge):
)
sleep(self._retry_timeout_seconds)
logging.info(f"Connected to Hue Bridge [{self.id}].")
logging.error(
f"Unable to connect to Hue bridge [{self.id}]. Retry count exceeded [{self._retry_limit}]."
)
@property
def is_connected(self) -> bool | None:
@ -54,6 +57,18 @@ class HueBridge(Bridge):
return scene
return None
def set_light(self, lights, command):
return self._hue.set_light(lights, command)
def get_light(self, id, command=None):
return self._hue.get_light(id, command)
def set_group(self, groups, command):
return self._hue.set_group(groups, command)
def get_group(self, id, command=None):
return self._hue.get_group(id, command)
def in_room_activate_scene(self, room_name: str, scene_name: str):
"""Activate a scene in a room.

View file

@ -0,0 +1,13 @@
from mash.core.entities.light import Light
from mash.core.utilities.glow import Glow
class HueLight(Light):
def __init__(
self, *, id: str, name: str, room: str, groups: list[str] = ...
) -> None:
super().__init__(id=id, name=name, room=room, groups=groups)
def __on_change__(self, current_on: bool, current_glow: Glow):
pass
# TODO: Requires reference to bridge

View file

@ -1,5 +1,3 @@
from .entities import *
from .bridge import Bridge, BridgeException
from .entity import Entity
from .group import Group
from .home import Home
from .feature import Feature

View file

@ -0,0 +1,6 @@
from .entity import Entity
from .group import Group
from .home import Home
from .contact_sensor import ContactSensor
from .light import Light
from .device_type import DeviceTypes

View file

@ -0,0 +1,21 @@
from mash.core.entities.device_type import DeviceType
from mash.core.entities.entity import Entity
class ContactSensor(Entity):
def __init__(
self, *, id: str, name: str, room: str, groups: list[str] = ...
) -> None:
super().__init__(
id=id,
name=name,
room=room,
device_type=DeviceType.CONTACT_SENSOR,
groups=groups,
)
self._has_contact: bool = False
def is_closed(self) -> bool:
return self._has_contact
# TODO: Update state

View file

@ -0,0 +1,6 @@
from enum import Enum
class DeviceType(Enum):
LIGHT = "light"
CONTACT_SENSOR = "contact_sensor"

View file

@ -1,6 +1,15 @@
from mash.core.entities.device_type import DeviceType
class Entity:
def __init__(
self, *, id: str, name: str, room: str, device_type: str, groups: list[str] = []
self,
*,
id: str,
name: str,
room: str,
device_type: DeviceType,
groups: list[str] = [],
) -> None:
self._id = id
self._name = name
@ -21,7 +30,7 @@ class Entity:
return self._room
@property
def device_type(self) -> str:
def device_type(self) -> DeviceType:
return self._device_type
@property

View file

@ -1,4 +1,4 @@
from mash.core.entity import Entity
from mash.core.entities.entity import Entity
from fnmatch import fnmatch

View file

@ -1,5 +1,5 @@
from mash.core.entity import Entity
from mash.core.group import Group
from mash.core.entities.entity import Entity
from mash.core.entities.group import Group
class Home(Group):

View file

@ -0,0 +1,66 @@
from mash.core.entities.device_type import DeviceType
from mash.core.entities.entity import Entity
from mash.core.utilities.glow import Glow
from mash.core.utilities.validation import clip_int
class Light(Entity):
def __init__(
self, *, id: str, name: str, room: str, groups: list[str] = ...
) -> None:
super().__init__(
id=id, name=name, room=room, device_type=DeviceType.LIGHT, groups=groups
)
self._glow: Glow = Glow()
self._on: bool = False
def __on_change__(self, current_on: bool, current_glow: Glow):
pass
def __check_for_change__(self, obj, prop, new_value):
old_value = getattr(obj, prop)
if old_value == new_value:
return
setattr(obj, prop, new_value)
self.__on_change__(current_on=self.on, current_glow=self._glow)
@property
def on(self) -> bool:
"""True, if light is emitting glow. False, if light is off."""
return self._on
@on.setter
def on(self, value: bool):
"""True, if light is emitting glow. False, if light is off."""
self.__check_for_change__(self, "_on", value)
@property
def brightness(self) -> int:
"""Brightness in the range [0, 254]."""
return self._glow.brightness
@brightness.setter
def brightness(self, value: int):
"""Brightness in the range [0, 254]. Value will be clipped."""
self.__check_for_change__(self._glow, "brightness", clip_int(value, 0, 254))
@property
def saturation(self) -> int:
"""Saturation in the range [0, 254]."""
return self._glow.saturation
@saturation.setter
def saturation(self, value: int):
"""Saturation in the range [0, 254]. Value will be clipped."""
self.__check_for_change__(self._glow, "saturation", clip_int(value, 0, 254))
@property
def hue(self) -> int:
"""Hue in the range [0, 65535]."""
return self._glow.hue
@hue.setter
def hue(self, value: int):
"""Hue in the range [0, 65535]. Value will be clipped."""
self.__check_for_change__(self._glow, "hue", clip_int(value, 0, 65535))

View file

@ -0,0 +1,2 @@
from .glow import Glow
from .validation import clip_int

View file

@ -0,0 +1,39 @@
class Glow:
"""Concept of colored light-rays."""
def __init__(
self, *, brightness: int = 0, saturation: int = 0, hue: int = 0
) -> None:
self._brightness: int = brightness
self._saturation: int = saturation
self._hue: int = hue
@property
def brightness(self) -> int:
"""Brightness in the range [0, 254]."""
return self._brightness
@brightness.setter
def brightness(self, value: int):
"""Brightness in the range [0, 254]."""
self._brightness = value
@property
def saturation(self) -> int:
"""Saturation in the range [0, 254]."""
return self._saturation
@saturation.setter
def saturation(self, value: int):
"""Saturation in the range [0, 254]."""
self._saturation = value
@property
def hue(self) -> int:
"""Hue in the range [0, 65535]."""
return self._hue
@hue.setter
def hue(self, value: int):
"""Hue in the range [0, 65535]."""
self._hue = value

View file

@ -0,0 +1,2 @@
def clip_int(value, min_val: int, max_val: int) -> int:
return min([max([int(value), min_val]), max_val])