More hue implementation
This commit is contained in:
parent
db5e826aea
commit
c78546ffcf
9 changed files with 1422 additions and 29 deletions
|
@ -5,7 +5,7 @@ import os
|
||||||
from statistics import median
|
from statistics import median
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
import requests as r
|
import requests as r
|
||||||
from ...endpoints.hue import hue
|
from ...endpoints.hue import hue_bridge
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
file_path: str = "bettwaage.csv"
|
file_path: str = "bettwaage.csv"
|
||||||
|
@ -126,9 +126,9 @@ def check_for_change():
|
||||||
# Make room sexy
|
# Make room sexy
|
||||||
if sexy_mode_detection:
|
if sexy_mode_detection:
|
||||||
if number_of_people >= 2 and weight_increased:
|
if number_of_people >= 2 and weight_increased:
|
||||||
hue.in_room_activate_scene("Max Zimmer", "Sexy")
|
hue_bridge.in_room_activate_scene("Max Zimmer", "Sexy")
|
||||||
elif number_of_people == 1 and not weight_increased:
|
elif number_of_people == 1 and not weight_increased:
|
||||||
hue.in_room_activate_scene("Max Zimmer", "Tageslicht")
|
hue_bridge.in_room_activate_scene("Max Zimmer", "Tageslicht")
|
||||||
|
|
||||||
|
|
||||||
def add_line_to_bed_history(line: str) -> None:
|
def add_line_to_bed_history(line: str) -> None:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
from core import Bridge
|
from core import Bridge, Group
|
||||||
from phue import Bridge as phueBridge
|
from phue import Bridge as phueBridge
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
|
@ -9,15 +10,15 @@ class HueBridge(Bridge):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
|
ip_address: str,
|
||||||
id: str,
|
id: str,
|
||||||
ip: str,
|
|
||||||
retry_limit: int = 10,
|
retry_limit: int = 10,
|
||||||
retry_timeout_seconds: int = 5,
|
retry_timeout_seconds: int = 5,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(id=id, type="hue")
|
super().__init__(id=id, type="hue")
|
||||||
self._retry_limit = retry_limit
|
self._retry_limit = retry_limit
|
||||||
self._retry_timeout_seconds = retry_timeout_seconds
|
self._retry_timeout_seconds = retry_timeout_seconds
|
||||||
self._hue: phueBridge = phueBridge(ip)
|
self._hue: phueBridge = phueBridge(ip_address)
|
||||||
|
|
||||||
def disconnect(self) -> None:
|
def disconnect(self) -> None:
|
||||||
self._hue = None
|
self._hue = None
|
||||||
|
@ -47,6 +48,10 @@ class HueBridge(Bridge):
|
||||||
def list_api(self) -> dict:
|
def list_api(self) -> dict:
|
||||||
return self._hue.get_api()
|
return self._hue.get_api()
|
||||||
|
|
||||||
|
def get_all_lights(self) -> Group:
|
||||||
|
light_states = await self.list_api()
|
||||||
|
# TODO
|
||||||
|
|
||||||
def list_scenes(self) -> dict:
|
def list_scenes(self) -> dict:
|
||||||
return self._hue.get_scene()
|
return self._hue.get_scene()
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from core import Entity
|
from core import Entity, Color
|
||||||
from bridges.hue import HueBridge
|
from bridges.hue import HueBridge
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ class HueLight(Entity):
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
bridge: HueBridge,
|
bridge: HueBridge,
|
||||||
|
initial_state: dict,
|
||||||
id: str,
|
id: str,
|
||||||
name: str,
|
name: str,
|
||||||
room: str,
|
room: str,
|
||||||
|
@ -15,8 +16,24 @@ class HueLight(Entity):
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(id=id, name=name, room=room, groups=groups)
|
super().__init__(id=id, name=name, room=room, groups=groups)
|
||||||
self._bridge: HueBridge = bridge
|
self._bridge: HueBridge = bridge
|
||||||
|
self._color: Color = Color()
|
||||||
|
self._on: bool = False
|
||||||
|
self._transition_duration_sec = 0
|
||||||
|
|
||||||
def poll_state(self):
|
self.__parse_state__(initial_state)
|
||||||
|
|
||||||
|
def __parse_state__(self, state: dict):
|
||||||
|
max_int_value = 255
|
||||||
|
self._on = state["state"]["on"]
|
||||||
|
|
||||||
|
h = state["state"]["hue"] / max_int_value
|
||||||
|
s = state["state"]["sat"] / max_int_value
|
||||||
|
v = state["state"]["bri"] / max_int_value
|
||||||
|
|
||||||
|
# TODO: Update color instead of overwriting it, to better keep track of change?
|
||||||
|
self._color = Color(hue=h, saturation=s, brightness=v)
|
||||||
|
|
||||||
|
def update(self):
|
||||||
# TODO
|
# TODO
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
class Color:
|
class Color:
|
||||||
def __init__(self, *, hue: float, saturation: float, brightness: float):
|
def __init__(self, *, hue: float, saturation: float, brightness: float):
|
||||||
self.hue = hue
|
self.hue: float = hue
|
||||||
self.saturation = saturation
|
self.saturation: float = saturation
|
||||||
self.brightness = brightness
|
self.brightness: float = brightness
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from core import Color
|
from .color import Color
|
||||||
|
|
||||||
|
|
||||||
class EntityOpNotSupportedError(Exception):
|
class EntityOpNotSupportedError(Exception):
|
||||||
|
@ -48,9 +48,9 @@ class Entity:
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return f"{self.name} [{self.id}, type {self.device_type}, room {self.room}, in {len(self.groups)} groups]"
|
return f"{self.name} [{self.id}, type {self.device_type}, room {self.room}, in {len(self.groups)} groups]"
|
||||||
|
|
||||||
async def poll_state(self):
|
async def update(self):
|
||||||
"""Implements an entity specific poll operation to get the latest state."""
|
"""Implements an entity specific update operation to get the latest state."""
|
||||||
raise EntityOpNotSupportedError("poll_state")
|
raise EntityOpNotSupportedError("update")
|
||||||
|
|
||||||
async def toggle_state(self):
|
async def toggle_state(self):
|
||||||
"""Turns entity on, if off, and vice versa, if supported."""
|
"""Turns entity on, if off, and vice versa, if supported."""
|
||||||
|
|
|
@ -1,6 +1,43 @@
|
||||||
from core import Entity
|
from .entity import Entity, EntityOpNotSupportedError
|
||||||
|
|
||||||
|
|
||||||
class Group(Entity):
|
class Group(Entity):
|
||||||
def __init__(self, *, id: str, name: str):
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
entities: list[Entity] = ...,
|
||||||
|
id: str = "group",
|
||||||
|
name: str = "Empty Group"
|
||||||
|
):
|
||||||
super().__init__(id=id, name=name, room=None, device_type="group")
|
super().__init__(id=id, name=name, room=None, device_type="group")
|
||||||
|
self._entities: list[Entity] = entities
|
||||||
|
|
||||||
|
# List of method names to dynamically create
|
||||||
|
methods_to_create = [
|
||||||
|
"set_brightness",
|
||||||
|
"set_hue",
|
||||||
|
"set_saturation",
|
||||||
|
"set_color",
|
||||||
|
"set_transition_duration",
|
||||||
|
"turn_on",
|
||||||
|
"turn_off",
|
||||||
|
]
|
||||||
|
|
||||||
|
for method_name in methods_to_create:
|
||||||
|
setattr(self, method_name, self._create_group_method(method_name))
|
||||||
|
|
||||||
|
async def __call_method__(self, method_name: str, *args, **kwargs):
|
||||||
|
for entity in self._entities:
|
||||||
|
try:
|
||||||
|
func = getattr(entity, method_name)
|
||||||
|
await func(*args, **kwargs)
|
||||||
|
except EntityOpNotSupportedError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _create_group_method(self, method_name: str):
|
||||||
|
# Create a method that calls __call_method__ for the given method name
|
||||||
|
async def group_method(*args, **kwargs):
|
||||||
|
await self.__call_method__(method_name, *args, **kwargs)
|
||||||
|
|
||||||
|
return group_method
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from core import Group
|
from .group import Group
|
||||||
|
|
||||||
|
|
||||||
class Room(Group):
|
class Room(Group):
|
||||||
|
|
|
@ -5,22 +5,23 @@ from bridges.hue import HueBridge, HueLight
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from fastapi.responses import HTMLResponse
|
from fastapi.responses import HTMLResponse
|
||||||
|
|
||||||
|
from core import Group
|
||||||
|
|
||||||
router = APIRouter(tags=["hue"])
|
router = APIRouter(tags=["hue"])
|
||||||
hue = HueBridge("192.168.178.85")
|
hue_bridge = HueBridge(ip_address="192.168.178.85", id="hue-bridge")
|
||||||
lights: dict[int, HueLight] = {}
|
hue_lights: Group = Group()
|
||||||
|
|
||||||
poll_delay_sec = 5
|
poll_delay_sec = 5
|
||||||
|
|
||||||
|
|
||||||
async def hue_service():
|
async def hue_service():
|
||||||
global lights
|
global hue_lights
|
||||||
|
|
||||||
|
hue_lights = await hue_bridge.get_all_lights()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
for light in lights:
|
await hue_lights.update()
|
||||||
light.poll_state()
|
|
||||||
|
|
||||||
# TODO: Get all new lights
|
|
||||||
|
|
||||||
await asyncio.sleep(poll_delay_sec)
|
await asyncio.sleep(poll_delay_sec)
|
||||||
except:
|
except:
|
||||||
|
@ -29,7 +30,7 @@ async def hue_service():
|
||||||
|
|
||||||
@router.get("/scenes", tags=["scene"])
|
@router.get("/scenes", tags=["scene"])
|
||||||
async def get_scenes():
|
async def get_scenes():
|
||||||
return hue.list_scenes()
|
return hue_bridge.list_scenes()
|
||||||
|
|
||||||
|
|
||||||
@router.post(
|
@router.post(
|
||||||
|
@ -38,7 +39,7 @@ async def get_scenes():
|
||||||
)
|
)
|
||||||
async def activate_scene(room_name: str, scene_name: str):
|
async def activate_scene(room_name: str, scene_name: str):
|
||||||
try:
|
try:
|
||||||
hue.in_room_activate_scene(room_name, scene_name)
|
hue_bridge.in_room_activate_scene(room_name, scene_name)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return HTMLResponse(status_code=400, content=str(e))
|
return HTMLResponse(status_code=400, content=str(e))
|
||||||
|
|
||||||
|
@ -49,7 +50,7 @@ async def activate_scene(room_name: str, scene_name: str):
|
||||||
)
|
)
|
||||||
async def deactivate_room(room_name: str):
|
async def deactivate_room(room_name: str):
|
||||||
try:
|
try:
|
||||||
hue.in_room_deactivate_lights(room_name)
|
hue_bridge.in_room_deactivate_lights(room_name)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return HTMLResponse(status_code=400, content=str(e))
|
return HTMLResponse(status_code=400, content=str(e))
|
||||||
|
|
||||||
|
@ -60,6 +61,6 @@ async def deactivate_room(room_name: str):
|
||||||
)
|
)
|
||||||
async def activate_room(room_name: str):
|
async def activate_room(room_name: str):
|
||||||
try:
|
try:
|
||||||
hue.in_room_activate_lights(room_name)
|
hue_bridge.in_room_activate_lights(room_name)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return HTMLResponse(status_code=400, content=str(e))
|
return HTMLResponse(status_code=400, content=str(e))
|
||||||
|
|
1333
src/hue_api.json
Normal file
1333
src/hue_api.json
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue