All long labels have been removed as the bridge list interface and discovery interface was reworked. Discovery of new lights happens automatically and bridges are refereshed when changes happen.
240 lines
8.7 KiB
Python
240 lines
8.7 KiB
Python
#!/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
|