async def async_get_localitem(self, request: web.Request): """Handle requests to retrieve info for a single localitem.""" item_id = request.match_info["item_id"] itemtype = request.match_info["itemtype"] items = await self.config.async_get_storage_value(itemtype) result = items.get(item_id, {}) return send_json_response(result)
async def async_delete_localitem(self, request: web.Request): """Handle requests to delete a item from localstorage.""" item_id = request.match_info["item_id"] itemtype = request.match_info["itemtype"] await self.config.async_delete_storage_value(itemtype, item_id) result = [{"success": f"/{itemtype}/{item_id} deleted."}] return send_json_response(result)
async def async_get_light(self, request: web.Request): """Handle requests to retrieve the info for a single light.""" light_id = request.match_info["light_id"] if light_id == "new": return await self.async_get_new_lights(request) entity = await self.config.async_entity_by_light_id(light_id) result = await self.__async_entity_to_hue(entity) return send_json_response(result)
async def async_post_auth(self, request: web.Request, request_data: dict): """Handle requests to create a username for the emulated hue bridge.""" if "devicetype" not in request_data: LOGGER.warning("devicetype not specified") return send_json_response(("Devicetype not specified", 302)) if not self.config.link_mode_enabled: await self.config.async_enable_link_mode_discovery() return send_error_response(request.path, "link button not pressed", 101) userdetails = await self.config.async_create_user( request_data["devicetype"]) response = [{"success": {"username": userdetails["username"]}}] if request_data.get("generateclientkey"): response[0]["success"]["clientkey"] = userdetails["clientkey"] LOGGER.info("Client %s registered", userdetails["name"]) return send_json_response(response)
async def async_get_bridge_config(self, request: web.Request): """Process a request to get (full or partial) config of this emulated bridge.""" username = request.match_info.get("username") valid_user = True if not username or not await self.config.async_get_user(username): valid_user = False result = await self.__async_get_bridge_config(full_details=valid_user) return send_json_response(result)
async def async_create_group(self, request: web.Request, request_data: dict): """Handle requests to create a new group.""" if "class" not in request_data: request_data["class"] = "Other" if "name" not in request_data: request_data["name"] = "" item_id = await self.__async_create_local_item(request_data, "groups") return send_json_response([{"success": {"id": item_id}}])
async def async_put_light_state(self, request: web.Request, request_data: dict): """Handle requests to perform action on a group of lights/room.""" light_id = request.match_info["light_id"] username = request.match_info["username"] entity = await self.config.async_entity_by_light_id(light_id) await self.__async_light_action(entity, request_data) # Create success responses for all received keys response = await self.__async_create_hue_response( request.path, request_data, username) return send_json_response(response)
async def async_get_capabilities(self, request: web.Request): """Return an overview of the capabilities.""" json_response = { "lights": { "available": 50 }, "sensors": { "available": 60, "clip": { "available": 60 }, "zll": { "available": 60 }, "zgp": { "available": 60 }, }, "groups": { "available": 60 }, "scenes": { "available": 100, "lightstates": { "available": 1500 } }, "rules": { "available": 100, "lightstates": { "available": 1500 } }, "schedules": { "available": 100 }, "resourcelinks": { "available": 100 }, "whitelists": { "available": 100 }, "timezones": { "value": self.config.definitions["timezones"] }, "streaming": { "available": 1, "total": 10, "channels": 10 }, } return send_json_response(json_response)
async def async_change_config(self, request: web.Request, request_data: dict): """Process a request to change a config value.""" username = request.match_info["username"] # just log this request and return succes LOGGER.debug("Change config called with params: %s", request_data) for key, value in request_data.items(): await self.config.async_set_storage_value("bridge_config", key, value) response = await self.__async_create_hue_response( request.path, request_data, username) return send_json_response(response)
async def async_update_light(self, request: web.Request, request_data: dict): """Handle requests to update a light.""" light_id = request.match_info["light_id"] username = request.match_info["username"] light_conf = await self.config.async_get_storage_value( "lights", light_id) if not light_conf: return web.Response(status=404) update_dict(light_conf, request_data) response = await self.__async_create_hue_response( request.path, request_data, username) return send_json_response(response)
async def async_update_localitem(self, request: web.Request, request_data: dict): """Handle requests to update an item in localstorage.""" item_id = request.match_info["item_id"] itemtype = request.match_info["itemtype"] username = request.match_info["username"] local_item = await self.config.async_get_storage_value( itemtype, item_id) if not local_item: return web.Response(status=404) update_dict(local_item, request_data) await self.config.async_set_storage_value(itemtype, item_id, local_item) response = await self.__async_create_hue_response( request.path, request_data, username) return send_json_response(response)
async def async_update_group(self, request: web.Request, request_data: dict): """Handle requests to update a group.""" group_id = request.match_info["group_id"] username = request.match_info["username"] group_conf = await self.config.async_get_storage_value( "groups", group_id) if not group_conf: return web.Response(status=404) update_dict(group_conf, request_data) # Hue entertainment support (experimental) if "stream" in group_conf: if group_conf["stream"].get("active"): # Requested streaming start LOGGER.debug( "Start Entertainment mode for group %s - params: %s", group_id, request_data, ) if not self.streaming_api: user_data = await self.config.async_get_user(username) self.streaming_api = EntertainmentAPI( self.hue, group_conf, user_data) group_conf["stream"]["owner"] = username if not group_conf["stream"].get("proxymode"): group_conf["stream"]["proxymode"] = "auto" if not group_conf["stream"].get("proxynode"): group_conf["stream"]["proxynode"] = "/bridge" else: # Request streaming stop LOGGER.info( "Stop Entertainment mode for group %s - params: %s", group_id, request_data, ) group_conf["stream"] = {"active": False} if self.streaming_api: # stop service if needed self.streaming_api.stop() self.streaming_api = None await self.config.async_set_storage_value("groups", group_id, group_conf) response = await self.__async_create_hue_response( request.path, request_data, username) return send_json_response(response)
async def async_group_action(self, request: web.Request, request_data: dict): """Handle requests to perform action on a group of lights/room.""" group_id = request.match_info["group_id"] username = request.match_info["username"] if group_id == "0" and "scene" in request_data: # scene request scene = await self.config.async_get_storage_value( "scenes", request_data["scene"], default={}) for light_id, light_state in scene["lightstates"].items(): entity = await self.config.async_entity_by_light_id(light_id) await self.__async_light_action(entity, light_state) else: # forward request to all group lights async for entity in self.__async_get_group_lights(group_id): await self.__async_light_action(entity, request_data) # Create success responses for all received keys response = await self.__async_create_hue_response( request.path, request_data, username) return send_json_response(response)
async def get_full_state(self, request: web.Request): """Return full state view of emulated hue.""" json_response = { "config": await self.__async_get_bridge_config(True), "schedules": await self.config.async_get_storage_value("schedules", default={}), "rules": await self.config.async_get_storage_value("rules", default={}), "scenes": await self.async_scene_to_full_state(), "resourcelinks": await self.config.async_get_storage_value("resourcelinks", default={}), "lights": await self.__async_get_all_lights(), "groups": await self.__async_get_all_groups(), "sensors": { "1": { "state": { "daylight": None, "lastupdated": "none" }, "config": { "on": True, "configured": False, "sunriseoffset": 30, "sunsetoffset": -30, }, "name": "Daylight", "type": "Daylight", "modelid": "PHDL00", "manufacturername": "Signify Netherlands B.V.", "swversion": "1.0", } }, } return send_json_response(json_response)
async def async_search_new_lights(self, request: web.Request, request_data): """Handle requests to retrieve new added lights to the (virtual) bridge.""" username = request.match_info["username"] self._search_enabled = True LOGGER.info( "Search mode activated. Any deleted/disabled lights will be reactivated." ) def auto_disable(): self._new_lights = {} self.hue.loop.call_later(60, auto_disable) # enable all disabled lights and groups for entity in self.hass.lights: entity_id = entity["entity_id"] light_id = await self.config.async_entity_id_to_light_id(entity_id) light_config = await self.config.async_get_light_config(light_id) if not light_config["enabled"]: light_config["enabled"] = True await self.config.async_set_storage_value( "lights", light_id, light_config) # add to new_lights for the app to show a special badge self._new_lights[light_id] = await self.__async_entity_to_hue( entity, light_config) groups = await self.config.async_get_storage_value("groups", default={}) for group_id, group_conf in groups.items(): if "enabled" in group_conf and not group_conf["enabled"]: group_conf["enabled"] = True await self.config.async_set_storage_value( "groups", group_id, group_conf) response = await self.__async_create_hue_response( request.path, {}, username) return send_json_response(response)
async def async_create_localitem(self, request: web.Request, request_data: dict): """Handle requests to create a new localitem.""" itemtype = request.match_info["itemtype"] item_id = await self.__async_create_local_item(request_data, itemtype) return send_json_response([{"success": {"id": item_id}}])
async def async_get_localitems(self, request: web.Request): """Handle requests to retrieve localitems (e.g. scenes).""" itemtype = request.match_info["itemtype"] result = await self.config.async_get_storage_value(itemtype, default={}) return send_json_response(result)
async def async_get_new_lights(self, request: web.Request): """Handle requests to retrieve new added lights to the (virtual) bridge.""" return send_json_response(self._new_lights)
async def async_get_lights(self, request: web.Request): """Handle requests to retrieve the info all lights.""" return send_json_response(await self.__async_get_all_lights())
async def async_get_new_sensors(self, request: web.Request): """Return all new discovered sensors on the (virtual) bridge.""" # not supported yet but prevent errors return send_json_response({})
async def async_get_groups(self, request: web.Request): """Handle requests to retrieve all rooms/groups.""" groups = await self.__async_get_all_groups() return send_json_response(groups)
async def async_get_timezones(self, request: web.Request): """Return all timezones.""" return send_json_response(self.config.definitions["timezones"])
async def async_get_group(self, request: web.Request): """Handle requests to retrieve info for a single group.""" group_id = request.match_info["group_id"] groups = await self.__async_get_all_groups() result = groups.get(group_id, {}) return send_json_response(result)