From f2e384157371f2221666666d4d65d427ff155d23 Mon Sep 17 00:00:00 2001 From: Marius Date: Mon, 22 Aug 2022 20:32:36 +0300 Subject: [PATCH] add better support for motion sensors in V2 api --- BridgeEmulator/HueObjects/__init__.py | 129 +++++++++++++++++--------- BridgeEmulator/flaskUI/v2restapi.py | 23 ++++- 2 files changed, 108 insertions(+), 44 deletions(-) diff --git a/BridgeEmulator/HueObjects/__init__.py b/BridgeEmulator/HueObjects/__init__.py index f487a47eb..39979c5f6 100644 --- a/BridgeEmulator/HueObjects/__init__.py +++ b/BridgeEmulator/HueObjects/__init__.py @@ -15,6 +15,7 @@ eventstream = [] + def v1StateToV2(v1State): v2State = {} if "on" in v1State: @@ -24,9 +25,11 @@ def v1StateToV2(v1State): if "ct" in v1State: v2State["color_temperature"] = {"mirek": v1State["ct"]} if "xy" in v1State: - v2State["color"] = {"xy": {"x": v1State["xy"][0], "y": v1State["xy"][1]}} + v2State["color"] = { + "xy": {"x": v1State["xy"][0], "y": v1State["xy"][1]}} return v2State + def v2StateToV1(v2State): v1State = {} if "dimming" in v2State: @@ -45,6 +48,7 @@ def v2StateToV1(v2State): v1State["transitiontime"] = v2State["transitiontime"] return v1State + def genV2Uuid(): return str(uuid.uuid4()) @@ -404,8 +408,6 @@ def setV1State(self, state, advertise=True): v2State = v1StateToV2(state) self.genStreamEvent(v2State) - - def setV2State(self, state): v1State = v2StateToV1(state) if "effects" in state: @@ -413,7 +415,7 @@ def setV2State(self, state): self.effect = v1State["effect"] if "dynamics" in state and "speed" in state["dynamics"]: self.dynamics["speed"] = state["dynamics"]["speed"] - self.setV1State(v1State,advertise=False) + self.setV1State(v1State, advertise=False) self.genStreamEvent(state) def genStreamEvent(self, v2State): @@ -424,7 +426,8 @@ def genStreamEvent(self, v2State): } streamMessage["id_v1"] = "/lights/" + self.id_v1 streamMessage["data"][0].update(v2State) - streamMessage["data"][0].update({"owner": {"rid": self.getDevice()["id"],"rtype": "device"}}) + streamMessage["data"][0].update( + {"owner": {"rid": self.getDevice()["id"], "rtype": "device"}}) eventstream.append(streamMessage) def getDevice(self): @@ -859,16 +862,21 @@ def getV2Api(self): ] } if light().modelid in ["LCX001", "LCX002", "LCX003"]: - channel["position"] = {"x": gradienStripPositions[x]["x"], "y": gradienStripPositions[x]["y"], "z": gradienStripPositions[x]["z"]} + channel["position"] = {"x": gradienStripPositions[x]["x"], + "y": gradienStripPositions[x]["y"], "z": gradienStripPositions[x]["z"]} elif light().modelid in ["915005987201", "LCX004"]: if x == 0: - channel["position"] = {"x": self.locations[light()][0]["x"], "y": self.locations[light()][0]["y"], "z": self.locations[light()][0]["z"]} + channel["position"] = {"x": self.locations[light( + )][0]["x"], "y": self.locations[light()][0]["y"], "z": self.locations[light()][0]["z"]} elif x == 2: - channel["position"] = {"x": self.locations[light()][1]["x"], "y": self.locations[light()][1]["y"], "z": self.locations[light()][1]["z"]} + channel["position"] = {"x": self.locations[light( + )][1]["x"], "y": self.locations[light()][1]["y"], "z": self.locations[light()][1]["z"]} else: - channel["position"] = {"x": (self.locations[light()][0]["x"] + self.locations[light()][1]["x"]) / 2, "y": (self.locations[light()][0]["y"] + self.locations[light()][1]["y"]) / 2, "z": (self.locations[light()][0]["z"] + self.locations[light()][1]["z"]) / 2} + channel["position"] = {"x": (self.locations[light()][0]["x"] + self.locations[light()][1]["x"]) / 2, "y": (self.locations[light( + )][0]["y"] + self.locations[light()][1]["y"]) / 2, "z": (self.locations[light()][0]["z"] + self.locations[light()][1]["z"]) / 2} else: - channel["position"] = {"x": self.locations[light()][0]["x"], "y": self.locations[light()][0]["y"], "z": self.locations[light()][0]["z"]} + channel["position"] = {"x": self.locations[light( + )][0]["x"], "y": self.locations[light()][0]["y"], "z": self.locations[light()][0]["z"]} result["channels"].append(channel) channel_id += 1 @@ -880,8 +888,6 @@ def setV2Action(self, state): setGroupAction(self, v1State) self.genStreamEvent(state) - - def setV1Action(self, state, scene=None): setGroupAction(self, state, scene) v2State = v1StateToV2(state) @@ -1023,13 +1029,13 @@ def update_attr(self, newdata): streamMessage = {"creationtime": datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ"), "data": [self.getV2Room() if self.type == "Room" else self.getV2Zone()], - "owner":{ - "rid":self.getV2Room()["id"] if self.type == "Room" else self.getV2Zone()["id"], - "rtype": "room" if self.type == "Room" else "zone" - }, - "id": str(uuid.uuid4()), - "type": "update" - } + "owner": { + "rid": self.getV2Room()["id"] if self.type == "Room" else self.getV2Zone()["id"], + "rtype": "room" if self.type == "Room" else "zone" + }, + "id": str(uuid.uuid4()), + "type": "update" + } eventstream.append(streamMessage) def update_state(self): @@ -1067,11 +1073,11 @@ def genStreamEvent(self, v2State): eventstream.append(streamMessage) streamMessage = {"creationtime": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"), "data": [{"id": self.id_v2, "type": "grouped_light", - "owner":{ - "rid":self.getV2Room()["id"] if self.type == "Room" else self.getV2Zone()["id"], - "rtype": "room" if self.type == "Room" else "zone" - } - }], + "owner": { + "rid": self.getV2Room()["id"] if self.type == "Room" else self.getV2Zone()["id"], + "rtype": "room" if self.type == "Room" else "zone" + } + }], "id": str(uuid.uuid4()), "type": "update" } @@ -1715,8 +1721,8 @@ def getDevice(self): "rtype": "motion" }, { - "rid": str(uuid.uuid5(uuid.NAMESPACE_URL, self.id_v2 + 'battery')), - "rtype": "battery" + "rid": str(uuid.uuid5(uuid.NAMESPACE_URL, self.id_v2 + 'device_power')), + "rtype": "device_power" }, { "rid": str(uuid.uuid5(uuid.NAMESPACE_URL, self.id_v2 + 'zigbee_connectivity')), @@ -1733,6 +1739,25 @@ def getDevice(self): ] return result + def getMotion(self): + result = None + if self.modelid == "SML001" and self.type == "ZLLPresence": + result = {"enabled": self.config["on"], + "id": str(uuid.uuid5( + uuid.NAMESPACE_URL, self.id_v2 + 'motion')), + "id_v1": "/sensors/" + self.id_v1, + "motion": { + "motion": True if self.state["presence"] else False, + "motion_valid": True + }, + "owner": { + "rid": str(uuid.uuid5( + uuid.NAMESPACE_URL, self.id_v2 + 'device')), + "rtype": "device" + }, + "type": "motion"} + return result + def getZigBee(self): result = None if self.modelid == "SML001" and self.type == "ZLLPresence": @@ -1745,15 +1770,35 @@ def getZigBee(self): result["type"] = "zigbee_connectivity" return result + def getDevicePower(self): + result = False + if "battery" in self.config: + result = { + "id": str(uuid.uuid5( + uuid.NAMESPACE_URL, self.id_v2 + 'device_power')), + "id_v1": "/sensors/" + self.id_v1, + "owner": { + "rid": str(uuid.uuid5( + uuid.NAMESPACE_URL, self.id_v2 + 'device')), + "rtype": "device" + }, + "power_state": { + "battery_level": self.config["battery"], + "battery_state": "normal" + }, + "type": "device_power" + } + return result + def update_attr(self, newdata): if self.id_v1 == "1" and "config" in newdata: # manage daylight sensor if "long" in newdata["config"] and "lat" in newdata["config"]: - self.config["configured"] = True - self.protocol_cfg = {"long": float( + self.config["configured"]=True + self.protocol_cfg={"long": float( newdata["config"]["long"][:-1]), "lat": float(newdata["config"]["lat"][:-1])} return for key, value in newdata.items(): - updateAttribute = getattr(self, key) + updateAttribute=getattr(self, key) if isinstance(updateAttribute, dict): updateAttribute.update(value) setattr(self, key, updateAttribute) @@ -1761,17 +1806,17 @@ def update_attr(self, newdata): setattr(self, key, value) def save(self): - result = {} - result["name"] = self.name - result["id_v1"] = self.id_v1 - result["id_v2"] = self.id_v2 - result["state"] = self.state - result["config"] = self.config - result["type"] = self.type - result["modelid"] = self.modelid - result["manufacturername"] = self.manufacturername - result["uniqueid"] = self.uniqueid - result["swversion"] = self.swversion - result["protocol"] = self.protocol - result["protocol_cfg"] = self.protocol_cfg + result={} + result["name"]=self.name + result["id_v1"]=self.id_v1 + result["id_v2"]=self.id_v2 + result["state"]=self.state + result["config"]=self.config + result["type"]=self.type + result["modelid"]=self.modelid + result["manufacturername"]=self.manufacturername + result["uniqueid"]=self.uniqueid + result["swversion"]=self.swversion + result["protocol"]=self.protocol + result["protocol_cfg"]=self.protocol_cfg return result diff --git a/BridgeEmulator/flaskUI/v2restapi.py b/BridgeEmulator/flaskUI/v2restapi.py index 696eaf652..155516c1e 100644 --- a/BridgeEmulator/flaskUI/v2restapi.py +++ b/BridgeEmulator/flaskUI/v2restapi.py @@ -20,7 +20,7 @@ bridgeConfig = configManager.bridgeConfig.yaml_config v2Resources = {"light": {}, "scene": {}, "grouped_light": {}, "room": {}, "zone": { -}, "entertainment": {}, "entertainment_configuration": {}, "zigbee_connectivity": {}, "device": {}} +}, "entertainment": {}, "entertainment_configuration": {}, "zigbee_connectivity": {}, "device": {}, "device_power": {}} def getObject(element, v2uuid): @@ -252,6 +252,15 @@ def get(self): data.append(v2GeofenceClient()) for script in behaviorScripts(): data.append(script) + for key, sensor in bridgeConfig["sensors"].items(): + motion = sensor.getMotion() + if motion != None: + data.append(motion) + #for key, sensor in bridgeConfig["sensors"].items(): + # power = sensor.getDevicePower() + # if power != None: + # data.append(power) + return {"errors": [], "data": data} @@ -322,7 +331,15 @@ def get(self, resource): for script in behaviorScripts(): response["data"].append(script) elif resource == "motion": - response["data"] = [] + for key, sensor in bridgeConfig["sensors"].items(): + motion = sensor.getMotion() + if motion != None: + response["data"].append(motion) + elif resource == "device_power": + for key, sensor in bridgeConfig["sensors"].items(): + power = sensor.getDevicePower() + if power != None: + response["data"].append(power) else: response["errors"].append({"description": "Not Found"}) del response["data"] @@ -456,6 +473,8 @@ def get(self, resource, resourceid): return {"errors": [], "data": [object.getV2Api()]} elif resource == "bridge": return {"errors": [], "data": [v2Bridge()]} + elif resource == "device_power": + return {"errors": [], "data": [object.getDevicePower()]} def put(self, resource, resourceid): logging.debug(request.headers)