You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
9.0 KiB
254 lines
9.0 KiB
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
import json
|
|
from typing import Union
|
|
|
|
from ..HueGroup import HueGroup
|
|
from ..HueLight import HueLight
|
|
from ..HueUtils import make_request
|
|
|
|
|
|
class HueBridge:
|
|
"""This class represents a Hue Bridge
|
|
"""
|
|
|
|
def __init__(self, ipaddress: str, username: str,
|
|
name: str = "", is_reachable: bool = True):
|
|
""" Constructor
|
|
|
|
Args:
|
|
ipaddress (str): The ip address of the bridge
|
|
username (str): The username for this app for this bridge
|
|
name (str, optional): A human readable name for this bridge.
|
|
Is set to ipaddress, if not supplied.
|
|
"""
|
|
self.m_ipaddress: str = ipaddress
|
|
self.m_username: str = username
|
|
self.m_is_reachable = is_reachable
|
|
self.unattached_lights: list[HueLight] = list()
|
|
if name:
|
|
self.m_name: str = name
|
|
else:
|
|
self.m_name = self.m_ipaddress
|
|
if is_reachable:
|
|
self.refresh_bridge()
|
|
else:
|
|
self.m_lights: list[HueLight] = list()
|
|
self.m_new_lights: list[HueLight] = list()
|
|
self.m_groups: list[HueGroup] = list()
|
|
|
|
def refresh_bridge(self):
|
|
self.m_lights: list[HueLight] = self.discover_lights()
|
|
self.discover_new_lights()
|
|
self.m_new_lights: list[HueLight] = self.get_new_lights()
|
|
self.m_groups: list[HueGroup] = self.discover_groups()
|
|
self.unattached_lights: list[HueLight] = list()
|
|
for light in self.get_lights():
|
|
is_in_group: bool = False
|
|
for group in self.get_groups():
|
|
if group.is_light_in_group(light.get_id()):
|
|
is_in_group = True
|
|
if not is_in_group:
|
|
self.unattached_lights.append(light)
|
|
|
|
def __str__(self) -> str:
|
|
"""The string representation of this bridge
|
|
|
|
Returns:
|
|
str: Returns the name
|
|
"""
|
|
return self.m_name
|
|
|
|
def append_new_lights(self) -> bool:
|
|
"""If any new lights were discovered in discover_new_lights(),
|
|
they can be appended to this bridges list of lights with this function
|
|
|
|
Returns:
|
|
bool: True if the request was ok, otherwise False
|
|
"""
|
|
path: str = "{}/lights/new".format(self.m_username)
|
|
response = make_request(self.m_ipaddress, path)
|
|
for key, value in json.loads(response.text).items():
|
|
if key != 'lastscan':
|
|
path: str = "{}/lights/{}".format(self.m_username, key)
|
|
response = make_request(self.m_ipaddress, path)
|
|
self.m_lights.append(HueLight(int(key), response.json(),
|
|
self.get_ipaddress(), self.get_user()))
|
|
return response.ok
|
|
|
|
def create_group(self, lights: list[HueLight], name: str,
|
|
group_type: str = "LightGroup",
|
|
group_class: str = "Other") -> bool:
|
|
"""Create a group from a list of lights
|
|
|
|
Args:
|
|
lights (list[HueLight]): a list of lights to group
|
|
name (str): The name of the new group
|
|
group_type (str, optional): The group type can be “LightGroup”,
|
|
“Room” or either “Luminaire” or
|
|
“LightSource” if a Multisource
|
|
Luminaire is present in the system.
|
|
Defaults to "LightGroup".
|
|
group_class (str, optional): Category of Room Types.
|
|
Defaults to "Other".
|
|
|
|
Returns:
|
|
bool: True if creation was a success, otherwise False
|
|
"""
|
|
path = "{}/groups".format(self.get_user())
|
|
method = "POST"
|
|
data: dict = {'lights': [], 'name': name,
|
|
'type': group_type, 'class': group_class}
|
|
for light in lights:
|
|
data['lights'].append(str(light.get_id()))
|
|
response = make_request(self.get_ipaddress(),
|
|
path, method, json.dumps(data))
|
|
r_json = response.json()
|
|
if 'success' in r_json.keys():
|
|
new_id = r_json['success']['id']
|
|
new_path = "{}/groups/{}".format(self.get_user(), new_id)
|
|
new_group = make_request(self.get_ipaddress(), new_path).json()
|
|
self.m_groups.append(HueGroup(int(new_id), lights, new_group,
|
|
self.get_ipaddress(), self.get_user()))
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def discover_groups(self) -> list[HueGroup]:
|
|
"""Get groups from Hue Api
|
|
|
|
Returns:
|
|
list[HueGroup]: discovered groups
|
|
"""
|
|
path: str = "{}/groups".format(self.m_username)
|
|
response = make_request(self.m_ipaddress, path)
|
|
groups: list[HueGroup] = list()
|
|
for key, value in json.loads(response.text).items():
|
|
lights: list[HueLight] = list()
|
|
for light in value['lights']:
|
|
lights.append(self.get_light_by_id(int(light)))
|
|
groups.append(HueGroup(int(key), lights, value,
|
|
self.get_ipaddress(), self.get_user()))
|
|
return groups
|
|
|
|
def discover_lights(self) -> list[HueLight]:
|
|
"""Get lights from Hue API
|
|
|
|
Returns:
|
|
list[HueLight]: List of discovered lights
|
|
"""
|
|
path: str = "{}/lights".format(self.m_username)
|
|
response = make_request(self.m_ipaddress, path)
|
|
lights: list[HueLight] = list()
|
|
for key, value in json.loads(response.text).items():
|
|
lights.append(HueLight(int(key),
|
|
value, self.get_ipaddress(), self.get_user()))
|
|
return lights
|
|
|
|
def discover_new_lights(self, light_ids: Union[None, list[int]] = None) -> bool:
|
|
"""Makes bridge search for new lights
|
|
|
|
Args:
|
|
light_ids (Union[None, list[int]], optional): Either a list of light ids or None. Defaults to None.
|
|
|
|
Returns:
|
|
bool: True if bridge has started looking for new lights, otherwise False
|
|
"""
|
|
body: str = ""
|
|
if light_ids is not None:
|
|
body_dict = {'deviceid': []}
|
|
for device in light_ids:
|
|
body_dict['deviceid'].append(device)
|
|
body = json.dumps(body_dict)
|
|
path: str = "{}/lights".format(self.m_username)
|
|
method: str = "POST"
|
|
response = make_request(self.m_ipaddress, path, method, body)
|
|
return 'success' in response.json()[0].keys()
|
|
|
|
def get_group_by_id(self, group_id: int) -> HueGroup:
|
|
"""Get a specific group
|
|
|
|
Args:
|
|
group_id (int): The group id of the group to get
|
|
|
|
Returns:
|
|
HueGroup: The group
|
|
"""
|
|
for group in self.m_groups:
|
|
if group.get_id() == group_id:
|
|
return group
|
|
|
|
def get_groups(self) -> list[HueGroup]:
|
|
"""Return all the groups of this bridge
|
|
|
|
Returns:
|
|
list[HueGroup]: A list of all groups owned by this bridge
|
|
"""
|
|
return self.m_groups
|
|
|
|
def get_ipaddress(self) -> str:
|
|
"""Get the ip address of this bridge
|
|
|
|
Returns:
|
|
str: The ip address
|
|
"""
|
|
return self.m_ipaddress
|
|
|
|
def get_light_by_id(self, light_id: int) -> HueLight:
|
|
"""Get a specific light
|
|
|
|
Args:
|
|
light_id (int): The light id of the light to get
|
|
|
|
Returns:
|
|
HueLight: The light
|
|
"""
|
|
for light in self.m_lights:
|
|
if light.get_id() == light_id:
|
|
return light
|
|
|
|
def get_lights(self) -> list[HueLight]:
|
|
"""Get all the lights owned by this bridge
|
|
|
|
Returns:
|
|
list[HueLight]: A flat list of all lights owned by this bridge
|
|
"""
|
|
return self.m_lights
|
|
|
|
def get_new_lights(self) -> list[HueLight]:
|
|
path: str = "{}/lights/new".format(self.m_username)
|
|
response = make_request(self.m_ipaddress, path)
|
|
newlights: list[HueLight] = list()
|
|
for lightid, nameobj in response.json().items():
|
|
if lightid != "lastscan":
|
|
print(lightid)
|
|
if not self.get_light_by_id(int(lightid)):
|
|
lightpath: str = "{}/lights/{}".format(
|
|
self.m_username, int(lightid))
|
|
lightresponse = make_request(self.m_ipaddress, lightpath)
|
|
newlights.append(
|
|
HueLight(int(lightid), lightresponse.json(), self.get_ipaddress(), self.get_user()))
|
|
return newlights
|
|
|
|
def get_user(self) -> str:
|
|
"""A user, or username, is more like a password and is needed to authenticate with the Hue API
|
|
|
|
Returns:
|
|
str: The username
|
|
"""
|
|
return self.m_username
|
|
|
|
def remove_light(self, light: HueLight):
|
|
"""Remove a light from all groups and self
|
|
|
|
Args:
|
|
light (HueLight): The light to remove
|
|
|
|
"""
|
|
for group in self.m_groups:
|
|
group.remove_light(light)
|
|
self.m_lights.remove(light)
|
|
|
|
def is_reachable(self):
|
|
return self.m_is_reachable
|