From 65118649456c24722aaa35141d0950b2495bd624 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 2 Sep 2024 21:02:42 +0200 Subject: [PATCH] updates and fixes Remove unused import Add .000 to lastupdate Add diyhue info to apiV2 response Update apiV2 response Fix grouped.light error for entertainment https://github.com/diyhue/diyHue/issues/1032 Update openwrt install --- BridgeEmulator/HueEmulator3.py | 2 - BridgeEmulator/HueObjects/BehaviorInstance.py | 1 - BridgeEmulator/HueObjects/Group.py | 37 ++++---- BridgeEmulator/HueObjects/Light.py | 12 ++- BridgeEmulator/HueObjects/Scene.py | 30 ++++--- BridgeEmulator/HueObjects/Sensor.py | 77 +++++++++++++--- BridgeEmulator/configManager/configHandler.py | 3 - .../configManager/runtimeConfigHandler.py | 2 +- BridgeEmulator/flaskUI/core/forms.py | 3 +- BridgeEmulator/flaskUI/espDevices.py | 2 +- BridgeEmulator/flaskUI/restful.py | 7 +- BridgeEmulator/flaskUI/v2restapi.py | 87 ++++++++++++++----- BridgeEmulator/functions/behavior_instance.py | 1 - BridgeEmulator/functions/daylightSensor.py | 1 - BridgeEmulator/functions/network.py | 2 - BridgeEmulator/functions/scripts.py | 1 - BridgeEmulator/install_openwrt.sh | 13 ++- BridgeEmulator/lights/discover.py | 47 ++++------ BridgeEmulator/lights/protocols/elgato.py | 2 +- BridgeEmulator/lights/protocols/flex.py | 8 +- BridgeEmulator/lights/protocols/hue_bl.py | 2 +- BridgeEmulator/lights/protocols/hyperion.py | 1 - BridgeEmulator/lights/protocols/jeedom.py | 1 - BridgeEmulator/lights/protocols/mi_box.py | 2 +- BridgeEmulator/lights/protocols/mqtt.py | 6 -- BridgeEmulator/lights/protocols/tasmota.py | 7 -- BridgeEmulator/lights/protocols/wled.py | 6 +- BridgeEmulator/lights/protocols/yeelight.py | 3 +- BridgeEmulator/sensors/discover.py | 1 - BridgeEmulator/sensors/sensor_types.py | 12 +-- BridgeEmulator/services/deconz.py | 2 +- BridgeEmulator/services/eventStreamer.py | 2 +- BridgeEmulator/services/homeAssistantWS.py | 1 - BridgeEmulator/services/mdns.py | 3 +- BridgeEmulator/services/mqtt.py | 6 +- BridgeEmulator/services/remoteDiscover.py | 1 - BridgeEmulator/services/scheduler.py | 2 +- BridgeEmulator/update_openwrt.sh | 43 +++++++-- 38 files changed, 276 insertions(+), 163 deletions(-) diff --git a/BridgeEmulator/HueEmulator3.py b/BridgeEmulator/HueEmulator3.py index 1c5c7250e..032841439 100755 --- a/BridgeEmulator/HueEmulator3.py +++ b/BridgeEmulator/HueEmulator3.py @@ -1,6 +1,5 @@ #!/usr/bin/env python from flask import Flask -from flask.json import jsonify from flask_cors import CORS from flask_restful import Api from threading import Thread @@ -15,7 +14,6 @@ from flaskUI.Credits import Credits from werkzeug.serving import WSGIRequestHandler from functions.daylightSensor import daylightSensor -from pprint import pprint bridgeConfig = configManager.bridgeConfig.yaml_config logging = logManager.logger.get_logger(__name__) diff --git a/BridgeEmulator/HueObjects/BehaviorInstance.py b/BridgeEmulator/HueObjects/BehaviorInstance.py index df12e680a..11b15c760 100644 --- a/BridgeEmulator/HueObjects/BehaviorInstance.py +++ b/BridgeEmulator/HueObjects/BehaviorInstance.py @@ -35,7 +35,6 @@ def getV2Api(self): result = {"configuration": self.configuration, "dependees": [], "enabled": self.enabled, - "active": self.active, "id": self.id_v2, "last_error": "", "metadata": { diff --git a/BridgeEmulator/HueObjects/Group.py b/BridgeEmulator/HueObjects/Group.py index 67f56461e..ca9cd6eab 100644 --- a/BridgeEmulator/HueObjects/Group.py +++ b/BridgeEmulator/HueObjects/Group.py @@ -129,15 +129,21 @@ def update_attr(self, newdata): def update_state(self): all_on = True any_on = False + bri = 0 + lights_on = 0 if len(self.lights) == 0: all_on = False for light in self.lights: if light(): if light().state["on"]: any_on = True + bri = bri + light().state["bri"] + lights_on = lights_on + 1 else: all_on = False - return {"all_on": all_on, "any_on": any_on} + if any_on: + bri = (((bri/lights_on)/254)*100) + return {"all_on": all_on, "any_on": any_on, "avr_bri": int(bri)} def setV2Action(self, state): v1State = v2StateToV1(state) @@ -197,12 +203,12 @@ def getV1Api(self): result["lightlevel"] = {"state": {"dark": None, "dark_all": None, "daylight": None, "daylight_any": None, "lightlevel": None, "lightlevel_min": None, "lightlevel_max": None, "lastupdated": "none"}} else: - result["class"] = self.icon_class.capitalize() + result["class"] = self.icon_class.capitalize() if len(self.icon_class) > 2 else self.icon_class.upper() result["action"] = self.action return result def getV2Room(self): - result = {"children": [], "grouped_services": [], "services": []} + result = {"children": [], "services": []} for light in self.lights: if light(): result["children"].append({ @@ -211,11 +217,10 @@ def getV2Room(self): "rtype": "device" }) - result["grouped_services"].append({ - "rid": self.id_v2, - "rtype": "grouped_light" - - }) + #result["grouped_services"].append({ + # "rid": self.id_v2, + # "rtype": "grouped_light" + #}) result["id"] = str(uuid.uuid5(uuid.NAMESPACE_URL, self.id_v2 + 'room')) result["id_v1"] = "/groups/" + self.id_v1 result["metadata"] = { @@ -238,7 +243,7 @@ def getV2Room(self): return result def getV2Zone(self): - result = {"children": [], "grouped_services": [], "services": []} + result = {"children": [], "services": []} for light in self.lights: if light(): result["children"].append({ @@ -246,11 +251,10 @@ def getV2Zone(self): "rtype": "light" }) - result["grouped_services"].append({ - "rid": self.id_v2, - "rtype": "grouped_light" - - }) + #result["grouped_services"].append({ + # "rid": self.id_v2, + # "rtype": "grouped_light" + #}) result["id"] = str(uuid.uuid5(uuid.NAMESPACE_URL, self.id_v2 + 'zone')) result["id_v1"] = "/groups/" + self.id_v1 result["metadata"] = { @@ -280,7 +284,7 @@ def getV2GroupedLight(self): ] } result["color"] = {} - result["dimming"] = {} + result["dimming"] = {"brightness": self.update_state()["avr_bri"]} result["dimming_delta"] = {} result["dynamics"] = {} result["id"] = self.id_v2 @@ -291,6 +295,9 @@ def getV2GroupedLight(self): result["owner"] = {"rid": self.owner.username, "rtype": "device"} else: result["owner"] = {"rid": self.id_v2, "rtype": "device"} + result["signaling"] = {"signal_values": [ + "no_signal", + "on_off"]} return result diff --git a/BridgeEmulator/HueObjects/Light.py b/BridgeEmulator/HueObjects/Light.py index 4919c09e4..d177aa0a1 100644 --- a/BridgeEmulator/HueObjects/Light.py +++ b/BridgeEmulator/HueObjects/Light.py @@ -27,6 +27,7 @@ def __init__(self, data): self.streaming = False self.dynamics = deepcopy(lightTypes[self.modelid]["dynamics"]) self.effect = "no_effect" + self.function = data["function"] if "function" in data else "mixed" # entertainment streamMessage = {"creationtime": datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ"), @@ -164,6 +165,8 @@ def setV1State(self, state, advertise=True): self.config[key] = value if key == "name": self.name = value + if key == "function": + self.function = value if "bri" in state: if "min_bri" in self.protocol_cfg and self.protocol_cfg["min_bri"] > state["bri"]: state["bri"] = self.protocol_cfg["min_bri"] @@ -195,6 +198,8 @@ def setV2State(self, state): v1State["archetype"] = state["metadata"]["archetype"] if "name" in state["metadata"]: v1State["name"] = state["metadata"]["name"] + if "function" in state["metadata"]: + v1State["function"] = state["metadata"]["function"] self.setV1State(v1State, advertise=False) self.genStreamEvent(state) @@ -305,7 +310,7 @@ def getV2Api(self): } result["color_temperature"]["mirek_valid"] = True if self.state[ "ct"] != None and self.state["ct"] < 500 and self.state["ct"] > 153 else False - result["color_temperature_delta"] = {} + #result["color_temperature_delta"] = {} if "bri" in self.state: bri_value = self.state["bri"] if bri_value is None or bri_value == "null": @@ -332,7 +337,7 @@ def getV2Api(self): result["identify"] = {} result["id"] = self.id_v2 result["id_v1"] = "/lights/" + self.id_v1 - result["metadata"] = {"name": self.name, "function": "mixed", + result["metadata"] = {"name": self.name, "function": self.function, "archetype": archetype[self.config["archetype"]]} result["mode"] = "normal" if "mode" in self.state and self.state["mode"] == "streaming": @@ -348,6 +353,7 @@ def getV2Api(self): result["signaling"] = {"signal_values": [ "no_signal", "on_off"]} + result["powerup"] = {"preset": "last_on_state"} result["type"] = "light" return result @@ -473,6 +479,6 @@ def dynamicScenePlay(self, palette, index): logging.debug("Dynamic Scene " + self.name + " stopped.") def save(self): - result = {"id_v2": self.id_v2, "name": self.name, "modelid": self.modelid, "uniqueid": self.uniqueid, + result = {"id_v2": self.id_v2, "name": self.name, "modelid": self.modelid, "uniqueid": self.uniqueid, "function": self.function, "state": self.state, "config": self.config, "protocol": self.protocol, "protocol_cfg": self.protocol_cfg} return result diff --git a/BridgeEmulator/HueObjects/Scene.py b/BridgeEmulator/HueObjects/Scene.py index a0d62ace8..f6a9bf836 100644 --- a/BridgeEmulator/HueObjects/Scene.py +++ b/BridgeEmulator/HueObjects/Scene.py @@ -28,6 +28,7 @@ def __init__(self, data): self.speed = data["speed"] if "speed" in data else self.DEFAULT_SPEED self.group = data["group"] if "group" in data else None self.lights = data["lights"] if "lights" in data else [] + self.status = data["status"] if "status" in data else "inactive" if "group" in data: self.storelightstate() self.lights = self.group().lights @@ -54,17 +55,23 @@ def add_light(self, light): def activate(self, data): # activate dynamic scene - if "recall" in data and data["recall"]["action"] == "dynamic_palette": - lightIndex = 0 - for light in self.lights: - if light(): - light().dynamics["speed"] = self.speed - Thread(target=light().dynamicScenePlay, args=[ - self.palette, lightIndex]).start() - lightIndex += 1 - + if "recall" in data: + if data["recall"]["action"] == "dynamic_palette": + self.status = data["recall"]["action"] + lightIndex = 0 + for light in self.lights: + if light(): + light().dynamics["speed"] = self.speed + Thread(target=light().dynamicScenePlay, args=[ + self.palette, lightIndex]).start() + lightIndex += 1 + + if data["recall"]["action"] == "deactivate": + self.status = "inactive" return + queueState = {} + self.status = data["recall"]["action"] for light, state in self.lightstates.items(): logging.debug(state) light.state.update(state) @@ -149,7 +156,7 @@ def getV2Api(self): v2State["dimming"] = { "brightness": round(float(bri_value) / 2.54, 2) } - v2State["dimming_delta"] = {} + #v2State["dimming_delta"] = {} if "xy" in state: v2State["color"] = { @@ -184,6 +191,9 @@ def getV2Api(self): if self.palette: result["palette"] = self.palette result["speed"] = self.speed + result["auto_dynamic"] = False + result["status"] = {"active": self.status} + result["recall"] = {} return result def storelightstate(self): diff --git a/BridgeEmulator/HueObjects/Sensor.py b/BridgeEmulator/HueObjects/Sensor.py index 73937da18..89fee505a 100644 --- a/BridgeEmulator/HueObjects/Sensor.py +++ b/BridgeEmulator/HueObjects/Sensor.py @@ -78,9 +78,9 @@ def getBridgeHome(self): if self.type == "ZLLPresence": rtype = "motion" elif self.type == "ZLLLightLevel": - rtype = "temperature" - elif self.type == "ZLLTemperature": rtype = "light_level" + elif self.type == "ZLLTemperature": + rtype = "temperature" return { "rid": self.id_v2, "rtype": rtype @@ -155,6 +155,7 @@ def getDevice(self): result["type"] = "device" elif self.modelid == "RWL022" or self.modelid == "RWL021" or self.modelid == "RWL020": result = {"id": self.id_v2, "id_v1": "/sensors/" + self.id_v1, "type": "device"} + result["identify"] = {} result["product_data"] = {"model_id": self.modelid, "manufacturer_name": "Signify Netherlands B.V.", "product_name": "Hue dimmer switch", @@ -189,6 +190,7 @@ def getDevice(self): result["type"] = "device" elif self.modelid == "RDM002" and self.type != "ZLLRelativeRotary": result = {"id": self.id_v2, "id_v1": "/sensors/" + self.id_v1, "type": "device"} + result["identify"] = {} result["product_data"] = {"model_id": self.modelid, "manufacturer_name": "Signify Netherlands B.V.", "product_name": "Hue tap dial switch", @@ -223,6 +225,7 @@ def getDevice(self): result["type"] = "device" elif self.modelid == "RDM002" and self.type == "ZLLRelativeRotary": result = {"id": self.id_v2, "id_v1": "/sensors/" + self.id_v1, "type": "device"} + result["identify"] = {} result["product_data"] = {"model_id": self.modelid, "manufacturer_name": "Signify Netherlands B.V.", "product_name": "Hue tap dial switch", @@ -254,21 +257,67 @@ def getDevice(self): 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 - }, + result = { + "enabled": self.config["on"], + "id": str(uuid.uuid5(uuid.NAMESPACE_URL, self.id_v2 + 'motion')), + "id_v1": "/sensors/" + self.id_v1, + "motion": { + "motion_report": { + "changed": self.state["lastupdated"], + "motion": True if self.state["presence"] else False, + } + }, + "sensitivity": { + "status": "set", + "sensitivity": 2, + "sensitivity_max": 2 + }, "owner": { - "rid": str(uuid.uuid5( - uuid.NAMESPACE_URL, self.id_v2 + 'device')), - "rtype": "device" - }, + "rid": str(uuid.uuid5(uuid.NAMESPACE_URL, self.id_v2 + 'device')), + "rtype": "device" + }, "type": "motion"} return result + + def getTemperature(self): + result = None + if self.modelid == "SML001" and self.type == "ZLLTemperature": + result = { + "enabled": self.config["on"], + "id": str(uuid.uuid5(uuid.NAMESPACE_URL, self.id_v2 + 'temperature')), + "id_v1": "/sensors/" + self.id_v1, + "temperature": { + "temperature_report":{ + "changed": self.state["lastupdated"], + "temperature": self.state["temperature"]/100 + } + }, + "owner": { + "rid": str(uuid.uuid5(uuid.NAMESPACE_URL, self.id_v2 + 'device')), + "rtype": "device" + }, + "type": "temperature"} + return result + + def getLightlevel(self): + result = None + if self.modelid == "SML001" and self.type == "ZLLLightLevel": + result = { + "enabled": self.config["on"], + "id": str(uuid.uuid5(uuid.NAMESPACE_URL, self.id_v2 + 'light_level')), + "id_v1": "/sensors/" + self.id_v1, + "light": { + "light_level_report":{ + "changed": self.state["lastupdated"], + "light_level": self.state["lightlevel"] + } + }, + "owner": { + "rid": str(uuid.uuid5(uuid.NAMESPACE_URL, self.id_v2 + 'device')), + "rtype": "device" + }, + "type": "light_level"} + return result def getZigBee(self): result = None diff --git a/BridgeEmulator/configManager/configHandler.py b/BridgeEmulator/configManager/configHandler.py index a74d61784..641f6272c 100644 --- a/BridgeEmulator/configManager/configHandler.py +++ b/BridgeEmulator/configManager/configHandler.py @@ -1,15 +1,12 @@ from configManager import configInit from configManager.argumentHandler import parse_arguments -from datetime import datetime import os import pathlib import subprocess -import json import logManager import yaml import uuid import weakref -from time import sleep from HueObjects import Light, Group, EntertainmentConfiguration, Scene, ApiUser, Rule, ResourceLink, Schedule, Sensor, BehaviorInstance, SmartScene try: from time import tzset diff --git a/BridgeEmulator/configManager/runtimeConfigHandler.py b/BridgeEmulator/configManager/runtimeConfigHandler.py index f48d03f76..ad4b13781 100644 --- a/BridgeEmulator/configManager/runtimeConfigHandler.py +++ b/BridgeEmulator/configManager/runtimeConfigHandler.py @@ -1,4 +1,4 @@ -from dataclasses import dataclass, field +from dataclasses import dataclass from configManager.argumentHandler import parse_arguments diff --git a/BridgeEmulator/flaskUI/core/forms.py b/BridgeEmulator/flaskUI/core/forms.py index 9994a9a91..96b106233 100644 --- a/BridgeEmulator/flaskUI/core/forms.py +++ b/BridgeEmulator/flaskUI/core/forms.py @@ -1,8 +1,7 @@ # Form Based Imports from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField -from wtforms.validators import DataRequired,Email,EqualTo -from wtforms import ValidationError +from wtforms.validators import DataRequired,Email class LoginForm(FlaskForm): email = StringField('Email', validators=[DataRequired(), Email()]) diff --git a/BridgeEmulator/flaskUI/espDevices.py b/BridgeEmulator/flaskUI/espDevices.py index d422e0ec8..c073ad96d 100644 --- a/BridgeEmulator/flaskUI/espDevices.py +++ b/BridgeEmulator/flaskUI/espDevices.py @@ -105,7 +105,7 @@ def get(self): result = {"fail": "unknown device"} obj.dxState["lastupdated"] = current_time obj.state["lastupdated"] = datetime.now(timezone.utc).strftime( - "%Y-%m-%dT%H:%M:%S") + "%Y-%m-%dT%H:%M:%S.000Z") rulesProcessor(obj, current_time) result = {"success": "command applied"} else: diff --git a/BridgeEmulator/flaskUI/restful.py b/BridgeEmulator/flaskUI/restful.py index ac741a1b6..618356030 100644 --- a/BridgeEmulator/flaskUI/restful.py +++ b/BridgeEmulator/flaskUI/restful.py @@ -5,10 +5,8 @@ import uuid import json import os -import requests from subprocess import Popen from threading import Thread -from time import sleep from datetime import datetime, timezone from lights.discover import scanForLights, manualAddLight from functions.core import capabilities, staticConfig, nextFreeId @@ -24,7 +22,6 @@ except ImportError: tzset = None -from pprint import pprint logging = logManager.logger.get_logger(__name__) bridgeConfig = configManager.bridgeConfig.yaml_config @@ -344,7 +341,7 @@ def put(self, username, resource, resourceid): for state in putDict["state"].keys(): bridgeConfig["sensors"][resourceid].dxState[state] = currentTime bridgeConfig["sensors"][resourceid].state["lastupdated"] = datetime.now(timezone.utc - ).strftime("%Y-%m-%dT%H:%M:%S") + ).strftime("%Y-%m-%dT%H:%M:%S.000Z") bridgeConfig["sensors"][resourceid].dxState["lastupdated"] = currentTime elif resource == "groups": if "lights" in putDict: @@ -443,7 +440,7 @@ def put(self, username, resource, resourceid, param): for state in putDict.keys(): bridgeConfig["sensors"][resourceid].dxState[state] = currentTime bridgeConfig["sensors"][resourceid].state["lastupdated"] = datetime.now(timezone.utc - ).strftime("%Y-%m-%dT%H:%M:%S") + ).strftime("%Y-%m-%dT%H:%M:%S.000Z") bridgeConfig["sensors"][resourceid].dxState["lastupdated"] = currentTime rulesProcessor(bridgeConfig[resource][resourceid], currentTime) bridgeConfig[resource][resourceid].update_attr({param: putDict}) diff --git a/BridgeEmulator/flaskUI/v2restapi.py b/BridgeEmulator/flaskUI/v2restapi.py index 08993b648..d77c2d9ac 100644 --- a/BridgeEmulator/flaskUI/v2restapi.py +++ b/BridgeEmulator/flaskUI/v2restapi.py @@ -13,7 +13,6 @@ from functions.core import nextFreeId from datetime import datetime, timezone from functions.scripts import behaviorScripts -from pprint import pprint from lights.discover import scanForLights from functions.daylightSensor import daylightSensor @@ -23,7 +22,7 @@ v2Resources = {"light": {}, "scene": {}, "smart_scene": {}, "grouped_light": {}, "room": {}, "zone": { }, "entertainment": {}, "entertainment_configuration": {}, "zigbee_connectivity": {}, "zigbee_device_discovery": {}, "device": {}, "device_power": {}, -"geofence_client": {}, "motion": {}} +"geofence_client": {}, "motion": {}, "light_level": {}, "temperature": {}, "relative_rotary": {}, "button": {}} def getObject(element, v2uuid): @@ -108,13 +107,18 @@ def v2BridgeZigBee(): def v2BridgeZigBeeDiscovery(): return{"id": str(uuid.uuid5( uuid.NAMESPACE_URL, bridgeConfig["config"]["bridgeid"] + 'zigbee_device_discovery')), - "owner": { - "rid": str(uuid.uuid5(uuid.NAMESPACE_URL, bridgeConfig["config"]["bridgeid"] + 'device')), - "rtype": "device" - }, - "status": bridgeConfig["config"]["zigbee_device_discovery_info"]["status"], - "type": "zigbee_device_discovery", - } + "owner": { + "rid": str(uuid.uuid5(uuid.NAMESPACE_URL, bridgeConfig["config"]["bridgeid"] + 'device')), + "rtype": "device" + }, + "action": { + "action_type_values": [ + "search" + ] + }, + "status": bridgeConfig["config"]["zigbee_device_discovery_info"]["status"], + "type": "zigbee_device_discovery", + } def v2GeofenceClient(): @@ -130,12 +134,13 @@ def v2GeofenceClient(): def v2BridgeHome(): result = {} result["children"] = [] - result["grouped_services"] = [] - if len(bridgeConfig["lights"]) > 0: - result["grouped_services"].append({ - "rid": bridgeConfig["groups"]["0"].id_v2, - "rtype": "grouped_light" - }) + result["children"].append({"rid": str(uuid.uuid5(uuid.NAMESPACE_URL, bridgeConfig["config"]["bridgeid"] + 'device')), "rtype": "device"}) + #result["grouped_services"] = [] + #if len(bridgeConfig["lights"]) > 0: + # result["grouped_services"].append({ + # "rid": bridgeConfig["groups"]["0"].id_v2, + # "rtype": "grouped_light" + # }) result["id"] = str(uuid.uuid5(uuid.NAMESPACE_URL, bridgeConfig["groups"]["0"].id_v2 + 'bridge_home')) result["id_v1"] = "/groups/0" @@ -160,7 +165,6 @@ def v2Bridge(): "bridge_id": bridge_id.lower(), "id": str(uuid.uuid5(uuid.NAMESPACE_URL, bridge_id + 'bridge')), "id_v1": "", - "identify": {}, "owner": {"rid": str(uuid.uuid5(uuid.NAMESPACE_URL, bridge_id + 'device')), "rtype": "device"}, "time_zone": {"time_zone": bridgeConfig["config"]["timezone"]}, "type": "bridge" @@ -184,6 +188,7 @@ def v2BridgeDevice(): result = {"id": str(uuid.uuid5(uuid.NAMESPACE_URL, bridge_id + 'device')), "type": "device"} result["id_v1"] = "" result["metadata"] = {"archetype": "bridge_v2", "name": config["name"]} + result["identify"] = {} result["product_data"] = { "certified": True, "manufacturer_name": "Signify Netherlands B.V.", @@ -200,6 +205,17 @@ def v2BridgeDevice(): ] return result +def v2DiyHueBridge(): + bridge_id = bridgeConfig["config"]["bridgeid"] + return { + "id": str(uuid.uuid5(uuid.NAMESPACE_URL, bridge_id + 'diyhue')), + "id_v1": "", + "owner": {"rid": str(uuid.uuid5(uuid.NAMESPACE_URL, bridge_id + 'device')), "rtype": "device"}, + "type": "diyhue", + "Hue Essentials key": bridgeConfig["config"]["Hue Essentials key"], + "Remote API enabled": bridgeConfig["config"]["Remote API enabled"] + } + class AuthV1(Resource): def get(self): authorisation = authorizeV2(request.headers) @@ -229,6 +245,7 @@ def get(self): data.append(sensor.getDevice()) # bridge data.append(v2Bridge()) + data.append(v2DiyHueBridge()) # zigbee data.append(v2BridgeZigBee()) for key, light in bridgeConfig["lights"].items(): @@ -256,9 +273,6 @@ def get(self): data.append(group.getV2Room()) elif group.type == "Zone": data.append(group.getV2Zone()) - # group - for key, group in bridgeConfig["groups"].items(): - data.append(group.getV2GroupedLight()) # behavior_instance for key, instance in bridgeConfig["behavior_instance"].items(): data.append(instance.getV2Api()) @@ -266,6 +280,9 @@ def get(self): for key, group in bridgeConfig["groups"].items(): if group.type == "Entertainment": data.append(group.getV2Api()) + # group + else: + data.append(group.getV2GroupedLight()) # bridge home data.append(v2BridgeHome()) data.append(v2GeofenceClient()) @@ -276,20 +293,23 @@ def get(self): motion = sensor.getMotion() if motion != None: data.append(motion) - for key, sensor in bridgeConfig["sensors"].items(): buttons = sensor.getButtons() if len(buttons) != 0: for button in buttons: data.append(button) - for key, sensor in bridgeConfig["sensors"].items(): power = sensor.getDevicePower() if power != None: data.append(power) - for key, sensor in bridgeConfig["sensors"].items(): rotarys = sensor.getRotary() if len(rotarys) != 0: for rotary in rotarys: data.append(rotary) + temperature = sensor.getTemperature() + if temperature != None: + data.append(temperature) + lightlevel = sensor.getLightlevel() + if lightlevel != None: + data.append(lightlevel) return {"errors": [], "data": data} @@ -351,12 +371,16 @@ def get(self, resource): response["data"].append(v2BridgeZigBeeDiscovery()) elif resource == "bridge": response["data"].append(v2Bridge()) + elif resource == "diyhue": + response["data"].append(v2DiyHueBridge()) elif resource == "bridge_home": response["data"].append(v2BridgeHome()) elif resource == "homekit": response["data"].append(v2HomeKit()) elif resource == "geolocation": response["data"].append(geoLocation()) + elif resource == "matter": + response["data"].append(matter()) elif resource == "behavior_instance": for key, instance in bridgeConfig["behavior_instance"].items(): response["data"].append(instance.getV2Api()) @@ -387,6 +411,16 @@ def get(self, resource): if len(rotarys) != 0: for rotary in rotarys: response["data"].append(rotary) + elif resource == "temperature": + for key, sensor in bridgeConfig["sensors"].items(): + temperature = sensor.getTemperature() + if temperature != None: + response["data"].append(temperature) + elif resource == "light_level": + for key, sensor in bridgeConfig["sensors"].items(): + lightlevel = sensor.getLightlevel() + if lightlevel != None: + response["data"].append(lightlevel) else: response["errors"].append({"description": "Not Found"}) del response["data"] @@ -553,8 +587,17 @@ def get(self, resource, resourceid): return {"errors": [], "data": [object.getV2Api()]} elif resource == "bridge": return {"errors": [], "data": [v2Bridge()]} + elif resource == "motion": + return {"errors": [], "data": [object.getMotion()]} elif resource == "device_power": return {"errors": [], "data": [object.getDevicePower()]} + elif resource == "button": + return {"errors": [], "data": [object.getButtons()]} + elif resource == "relative_rotary": + return {"errors": [], "data": [object.getRotary()]} + return {"errors": [], "data": [object.getTemperature()]} + elif resource == "light_level": + return {"errors": [], "data": [object.getLightlevel()]} def put(self, resource, resourceid): logging.debug(request.headers) diff --git a/BridgeEmulator/functions/behavior_instance.py b/BridgeEmulator/functions/behavior_instance.py index 4d9c924c0..e5e5a0efc 100755 --- a/BridgeEmulator/functions/behavior_instance.py +++ b/BridgeEmulator/functions/behavior_instance.py @@ -5,7 +5,6 @@ from datetime import datetime from threading import Thread from time import sleep -from pprint import pprint logging = logManager.logger.get_logger(__name__) bridgeConfig = configManager.bridgeConfig.yaml_config diff --git a/BridgeEmulator/functions/daylightSensor.py b/BridgeEmulator/functions/daylightSensor.py index de72c5d25..dcaf2da69 100644 --- a/BridgeEmulator/functions/daylightSensor.py +++ b/BridgeEmulator/functions/daylightSensor.py @@ -1,4 +1,3 @@ -import pytz from astral.sun import sun from astral import LocationInfo from functions.rules import rulesProcessor diff --git a/BridgeEmulator/functions/network.py b/BridgeEmulator/functions/network.py index f700bc6af..03b42e452 100755 --- a/BridgeEmulator/functions/network.py +++ b/BridgeEmulator/functions/network.py @@ -1,6 +1,4 @@ -import logging import socket -import sys def getIpAddress(): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) diff --git a/BridgeEmulator/functions/scripts.py b/BridgeEmulator/functions/scripts.py index 83a58a9c9..9f58a4c65 100644 --- a/BridgeEmulator/functions/scripts.py +++ b/BridgeEmulator/functions/scripts.py @@ -1,6 +1,5 @@ import logManager import configManager -from threading import Thread from time import sleep from random import randrange diff --git a/BridgeEmulator/install_openwrt.sh b/BridgeEmulator/install_openwrt.sh index 1d80c0e2e..f0cf8bb0b 100755 --- a/BridgeEmulator/install_openwrt.sh +++ b/BridgeEmulator/install_openwrt.sh @@ -23,8 +23,17 @@ wait echo -e "\033[32m Copying files to directories.\033[0m" cd /opt/tmp/diyHue/BridgeEmulator -cp HueEmulator3.py updater githubInstall.sh githubUIInstall.sh /opt/hue-emulator/ -cp -r HueObjects configManager flaskUI functions lights logManager sensors services /opt/hue-emulator/ +cp -r flaskUI /opt/hue-emulator/ +cp -r functions /opt/hue-emulator/ +cp -r lights /opt/hue-emulator/ +cp -r sensors /opt/hue-emulator/ +cp -r HueObjects /opt/hue-emulator/ +cp -r services /opt/hue-emulator/ +cp -r configManager /opt/hue-emulator/ +cp -r logManager /opt/hue-emulator/ +cp -r HueEmulator3.py /opt/hue-emulator/ +cp -r githubInstall.sh /opt/hue-emulator/ +cp -r genCert.sh /opt/hue-emulator/ echo -e "\033[32m Copy web interface files.\033[0m" curl -sL https://www.github.com/diyhue/diyHueUI/releases/latest/download/DiyHueUI-release.zip -o diyHueUI.zip diff --git a/BridgeEmulator/lights/discover.py b/BridgeEmulator/lights/discover.py index 3daa1099d..a7ed27817 100644 --- a/BridgeEmulator/lights/discover.py +++ b/BridgeEmulator/lights/discover.py @@ -5,7 +5,7 @@ import uuid from time import sleep from datetime import datetime, timezone -from lights.protocols import tpkasa, wled, mqtt, hyperion, yeelight, hue, deconz, native, native_single, native_multi, tasmota, shelly, esphome, tradfri, elgato +from lights.protocols import tpkasa, wled, mqtt, hyperion, yeelight, hue, deconz, native_multi, tasmota, shelly, esphome, tradfri, elgato from services import homeAssistantWS from HueObjects import Light, StreamEvent from functions.core import nextFreeId @@ -100,23 +100,27 @@ def manualAddLight(ip, protocol, config={}): config["ip"] = ip addNewLight(modelid, name, protocol, config) - -def scanForLights(): # scan for ESP8266 lights and strips - bridgeConfig["temp"]["scanResult"] = {"lastscan": "active"} +def discoveryEvent(): streamMessage = {"creationtime": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), - "data": [{ - "id": str(uuid.uuid5(uuid.NAMESPACE_URL, bridgeConfig["config"]["bridgeid"] + 'zigbee_device_discovery')), - "owner": { - "rid": str(uuid.uuid5(uuid.NAMESPACE_URL, bridgeConfig["config"]["bridgeid"] + 'device')), - "rtype": "device" - }, + "data": [{ + "id": str(uuid.uuid5(uuid.NAMESPACE_URL, bridgeConfig["config"]["bridgeid"] + 'zigbee_device_discovery')), + "owner": { + "rid": str(uuid.uuid5(uuid.NAMESPACE_URL, bridgeConfig["config"]["bridgeid"] + 'device')), + "rtype": "device" + }, "status": bridgeConfig["config"]["zigbee_device_discovery_info"]["status"], "type": "zigbee_device_discovery" }], - "id": str(uuid.uuid4()), - "type": "update" - } + "id": str(uuid.uuid4()), + "type": "update" + } StreamEvent(streamMessage) + + + +def scanForLights(): # scan for ESP8266 lights and strips + bridgeConfig["temp"]["scanResult"] = {"lastscan": "active"} + discoveryEvent() detectedLights = [] if bridgeConfig["config"]["port"]["enabled"]: @@ -167,21 +171,6 @@ def scanForLights(): # scan for ESP8266 lights and strips elgato.discover(detectedLights, elgato_ips) bridgeConfig["temp"]["scanResult"]["lastscan"] = datetime.now().strftime( "%Y-%m-%dT%H:%M:%S") - bridgeConfig["config"]["zigbee_device_discovery_info"]["status"] = "ready" - streamMessage = {"creationtime": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), - "data": [{ - "id": str(uuid.uuid5(uuid.NAMESPACE_URL, bridgeConfig["config"]["bridgeid"] + 'zigbee_device_discovery')), - "owner": { - "rid": str(uuid.uuid5(uuid.NAMESPACE_URL, bridgeConfig["config"]["bridgeid"] + 'device')), - "rtype": "device" - }, - "status": bridgeConfig["config"]["zigbee_device_discovery_info"]["status"], - "type": "zigbee_device_discovery" - }], - "id": str(uuid.uuid4()), - "type": "update" - } - StreamEvent(streamMessage) for light in detectedLights: # check if light is already present lightIsNew = True @@ -232,4 +221,6 @@ def scanForLights(): # scan for ESP8266 lights and strips light["modelid"], light["name"], light["protocol"], light["protocol_cfg"]) bridgeConfig["temp"]["scanResult"][lightId] = { "name": light["name"]} + bridgeConfig["config"]["zigbee_device_discovery_info"]["status"] = "ready" + discoveryEvent() return bridgeConfig["temp"]["scanResult"] diff --git a/BridgeEmulator/lights/protocols/elgato.py b/BridgeEmulator/lights/protocols/elgato.py index d6d20fda9..07fb8bbb6 100644 --- a/BridgeEmulator/lights/protocols/elgato.py +++ b/BridgeEmulator/lights/protocols/elgato.py @@ -3,7 +3,7 @@ import logManager import requests from time import sleep -from zeroconf import IPVersion, ServiceBrowser, ServiceStateChange, Zeroconf, ZeroconfServiceTypes +from zeroconf import IPVersion, ServiceBrowser, ServiceStateChange, Zeroconf logging = logManager.logger.get_logger(__name__) diff --git a/BridgeEmulator/lights/protocols/flex.py b/BridgeEmulator/lights/protocols/flex.py index 2581a0e2d..272cd2ae3 100644 --- a/BridgeEmulator/lights/protocols/flex.py +++ b/BridgeEmulator/lights/protocols/flex.py @@ -1,9 +1,13 @@ import json import logManager import socket +from functions.colors import convert_xy, rgbBrightness logging = logManager.logger.get_logger(__name__) +def pretty_json(data): + return json.dumps(data, sort_keys=True, indent=4, separators=(',', ': ')) + def set_light(light, data): msg = bytearray() if "on" in data: @@ -19,8 +23,8 @@ def set_light(light, data): logging.info(pretty_json(data)) bri = data["bri"] if "bri" in data else light.state["bri"] xy = data["xy"] if "xy" in data else light.state["xy"] - if rgb: - color = rgbBrightness(rgb, bri) + if "rgb" in data: + color = rgbBrightness(data["rgb"], bri) else: color = convert_xy(xy[0], xy[1], bri) msg = bytearray([0x41, color[0], color[1], color[2], 0x00, 0xf0, 0x0f]) diff --git a/BridgeEmulator/lights/protocols/hue_bl.py b/BridgeEmulator/lights/protocols/hue_bl.py index 9fabbb2cd..4e43b1b69 100644 --- a/BridgeEmulator/lights/protocols/hue_bl.py +++ b/BridgeEmulator/lights/protocols/hue_bl.py @@ -1,5 +1,5 @@ import logManager -from functions.colors import convert_rgb_xy, convert_xy, rgbBrightness +from functions.colors import convert_xy logging = logManager.logger.get_logger(__name__) Connections = {} diff --git a/BridgeEmulator/lights/protocols/hyperion.py b/BridgeEmulator/lights/protocols/hyperion.py index 6d47a5a25..ab734e4be 100644 --- a/BridgeEmulator/lights/protocols/hyperion.py +++ b/BridgeEmulator/lights/protocols/hyperion.py @@ -1,6 +1,5 @@ import json import logManager -import random import re import socket from functions.colors import convert_rgb_xy, convert_xy, hsv_to_rgb diff --git a/BridgeEmulator/lights/protocols/jeedom.py b/BridgeEmulator/lights/protocols/jeedom.py index 58159debe..e164614e0 100644 --- a/BridgeEmulator/lights/protocols/jeedom.py +++ b/BridgeEmulator/lights/protocols/jeedom.py @@ -1,4 +1,3 @@ -import json import configManager import requests diff --git a/BridgeEmulator/lights/protocols/mi_box.py b/BridgeEmulator/lights/protocols/mi_box.py index 3fe381f29..7960ede55 100755 --- a/BridgeEmulator/lights/protocols/mi_box.py +++ b/BridgeEmulator/lights/protocols/mi_box.py @@ -1,5 +1,5 @@ import logging, binascii, socket, colorsys, time -from functions.colors import convert_rgb_xy, convert_xy, rgbBrightness +from functions.colors import convert_xy, rgbBrightness #todo: add support for multiple mi boxes? these globals don't look nice commandCounter = 0 diff --git a/BridgeEmulator/lights/protocols/mqtt.py b/BridgeEmulator/lights/protocols/mqtt.py index d4bc47880..09c88ce45 100755 --- a/BridgeEmulator/lights/protocols/mqtt.py +++ b/BridgeEmulator/lights/protocols/mqtt.py @@ -1,11 +1,5 @@ import logManager import json -import random -import requests -from datetime import datetime -from time import strftime -from threading import Thread -import traceback # External import paho.mqtt.publish as publish diff --git a/BridgeEmulator/lights/protocols/tasmota.py b/BridgeEmulator/lights/protocols/tasmota.py index 1e292bf94..64c3c21ef 100755 --- a/BridgeEmulator/lights/protocols/tasmota.py +++ b/BridgeEmulator/lights/protocols/tasmota.py @@ -1,14 +1,7 @@ import json import logManager -import random import requests -import socket -import sys -from time import sleep -from subprocess import check_output -import lights from functions.colors import convert_rgb_xy, convert_xy, rgbBrightness -from functions.network import getIpAddress logging = logManager.logger.get_logger(__name__) diff --git a/BridgeEmulator/lights/protocols/wled.py b/BridgeEmulator/lights/protocols/wled.py index 44b883590..61a06ad36 100644 --- a/BridgeEmulator/lights/protocols/wled.py +++ b/BridgeEmulator/lights/protocols/wled.py @@ -1,14 +1,12 @@ import socket import urllib.request import json -import random import math -import sys import logManager import requests -from functions.colors import convert_rgb_xy, convert_xy, rgbBrightness +from functions.colors import convert_rgb_xy, convert_xy from time import sleep -from zeroconf import IPVersion, ServiceBrowser, ServiceStateChange, Zeroconf, ZeroconfServiceTypes +from zeroconf import IPVersion, ServiceBrowser, ServiceStateChange, Zeroconf logging = logManager.logger.get_logger(__name__) diff --git a/BridgeEmulator/lights/protocols/yeelight.py b/BridgeEmulator/lights/protocols/yeelight.py index e3c4b5a83..e386bdf63 100755 --- a/BridgeEmulator/lights/protocols/yeelight.py +++ b/BridgeEmulator/lights/protocols/yeelight.py @@ -1,7 +1,6 @@ -import json import logManager import yeelight -from functions.colors import convert_rgb_xy, convert_xy, rgbBrightness +from functions.colors import convert_rgb_xy, convert_xy from time import sleep logging = logManager.logger.get_logger(__name__) diff --git a/BridgeEmulator/sensors/discover.py b/BridgeEmulator/sensors/discover.py index dd57c1ba0..c45363b94 100644 --- a/BridgeEmulator/sensors/discover.py +++ b/BridgeEmulator/sensors/discover.py @@ -2,7 +2,6 @@ import configManager from HueObjects import Sensor import random -from sensors.sensor_types import sensorTypes from functions.core import nextFreeId logging = logManager.logger.get_logger(__name__) diff --git a/BridgeEmulator/sensors/sensor_types.py b/BridgeEmulator/sensors/sensor_types.py index 112bf9e53..875cde58f 100644 --- a/BridgeEmulator/sensors/sensor_types.py +++ b/BridgeEmulator/sensors/sensor_types.py @@ -1,13 +1,13 @@ sensorTypes = {} sensorTypes["PHDL00"] = {"Daylight": {"state":{"daylight":None,"lastupdated":"none"}, "config":{"on":True,"configured":False,"sunriseoffset":30,"sunsetoffset":-30}, "static": {"manufacturername":"Signify Netherlands B.V.","swversion":"1.0"}}} -sensorTypes["SML001"] = {"ZLLTemperature" : {"state": {"temperature": None,"lastupdated": "none"},"config": {"on": False,"battery": 100,"reachable": True,"alert": "none","ledindication": False,"usertest": False,"pending": []}, "static": {"swupdate": {"state": "noupdates","lastinstall": "2021-03-16T21:16:40"}, "manufacturername": "Signify Netherlands B.V.","productname": "Hue temperature sensor","swversion": "6.1.1.27575","capabilities": {"certified": True,"primary": False}}}, - "ZLLPresence" : { "state": {"lastupdated": "none","presence": None }, "config": {"on": False,"battery": 100,"reachable": True,"alert": "none","ledindication": False,"usertest": False,"sensitivity": 2,"sensitivitymax": 2,"pending": [] }, "static": {"swupdate": {"state": "noupdates","lastinstall": "2021-03-16T21:16:40"}, "manufacturername": "Signify Netherlands B.V.", "productname": "Hue motion sensor", "swversion": "6.1.1.27575", "capabilities":{"certified":True,"primary":True}}}, - "ZLLLightLevel" : {"state": {"dark": True,"daylight": False,"lightlevel": 6000,"lastupdated": "none"}, "config": {"on": False,"battery": 100,"reachable": True,"alert": "none","tholddark": 9346,"tholdoffset": 7000,"ledindication": False,"usertest": False,"pending": []}, "static": {"swupdate": { "state": "noupdates", "lastinstall": "2021-03-16T21:16:40"}, "manufacturername": "Signify Netherlands B.V.","productname": "Hue ambient light sensor","swversion": "6.1.1.27575","capabilities": { "certified": True, "primary": False}}}} +sensorTypes["SML001"] = {"ZLLTemperature" : {"state": {"temperature": None,"lastupdated": "none"},"config": {"on": False,"battery": 100,"reachable": True,"alert": "none","ledindication": False,"usertest": False,"pending": []}, "static": {"swupdate": {"state": "noupdates","lastinstall": "2021-03-16T21:16:40Z"}, "manufacturername": "Signify Netherlands B.V.","productname": "Hue temperature sensor","swversion": "6.1.1.27575","capabilities": {"certified": True,"primary": False}}}, + "ZLLPresence" : { "state": {"lastupdated": "none","presence": None }, "config": {"on": False,"battery": 100,"reachable": True,"alert": "none","ledindication": False,"usertest": False,"sensitivity": 2,"sensitivitymax": 2,"pending": [] }, "static": {"swupdate": {"state": "noupdates","lastinstall": "2021-03-16T21:16:40Z"}, "manufacturername": "Signify Netherlands B.V.", "productname": "Hue motion sensor", "swversion": "6.1.1.27575", "capabilities":{"certified":True,"primary":True}}}, + "ZLLLightLevel" : {"state": {"dark": True,"daylight": False,"lightlevel": 6000,"lastupdated": "none"}, "config": {"on": False,"battery": 100,"reachable": True,"alert": "none","tholddark": 9346,"tholdoffset": 7000,"ledindication": False,"usertest": False,"pending": []}, "static": {"swupdate": { "state": "noupdates", "lastinstall": "2021-03-16T21:16:40Z"}, "manufacturername": "Signify Netherlands B.V.","productname": "Hue ambient light sensor","swversion": "6.1.1.27575","capabilities": { "certified": True, "primary": False}}}} -sensorTypes["RDM002"] = {"ZLLSwitch": {"state":{"buttonevent":3002,"lastupdated":"2023-05-13T09:34:38"},"config":{"on":True,"battery":100,"reachable":True,"pending":[]},"static":{"swupdate":{"state":"noupdates","lastinstall":"2022-07-01T14:38:51"},"manufacturername":"Signify Netherlands B.V.","productname":"Hue tap dial switch","swversion":"2.59.25","capabilities":{"certified":True,"primary":False,"inputs":[{"repeatintervals":[800],"events":[{"buttonevent":1000,"eventtype":"initial_press"},{"buttonevent":1001,"eventtype":"repeat"},{"buttonevent":1002,"eventtype":"short_release"},{"buttonevent":1003,"eventtype":"long_release"},{"buttonevent":1010,"eventtype":"long_press"}]},{"repeatintervals":[800],"events":[{"buttonevent":2000,"eventtype":"initial_press"},{"buttonevent":2001,"eventtype":"repeat"},{"buttonevent":2002,"eventtype":"short_release"},{"buttonevent":2003,"eventtype":"long_release"},{"buttonevent":2010,"eventtype":"long_press"}]},{"repeatintervals":[800],"events":[{"buttonevent":3000,"eventtype":"initial_press"},{"buttonevent":3001,"eventtype":"repeat"},{"buttonevent":3002,"eventtype":"short_release"},{"buttonevent":3003,"eventtype":"long_release"},{"buttonevent":3010,"eventtype":"long_press"}]},{"repeatintervals":[800],"events":[{"buttonevent":4000,"eventtype":"initial_press"},{"buttonevent":4001,"eventtype":"repeat"},{"buttonevent":4002,"eventtype":"short_release"},{"buttonevent":4003,"eventtype":"long_release"},{"buttonevent":4010,"eventtype":"long_press"}]}]}}}, - "ZLLRelativeRotary":{"state":{"rotaryevent":2,"expectedrotation":90,"expectedeventduration":400,"lastupdated":"2023-05-13T09:34:38"},"config":{"on":True,"battery":100,"reachable":True,"pending":[]},"static":{"swupdate":{"state":"noupdates","lastinstall":"2022-07-01T14:38:51"},"manufacturername":"Signify Netherlands B.V.","productname":"Hue tap dial switch","swversion":"2.59.25","capabilities":{"certified":True,"primary":False,"inputs":[{"repeatintervals":[400],"events":[{"rotaryevent":1,"eventtype":"start"},{"rotaryevent":2,"eventtype":"repeat"}]}]}}}} +sensorTypes["RDM002"] = {"ZLLSwitch": {"state":{"buttonevent":3002,"lastupdated":"2023-05-13T09:34:38Z"},"config":{"on":True,"battery":100,"reachable":True,"pending":[]},"static":{"swupdate":{"state":"noupdates","lastinstall":"2022-07-01T14:38:51Z"},"manufacturername":"Signify Netherlands B.V.","productname":"Hue tap dial switch","swversion":"2.59.25","capabilities":{"certified":True,"primary":False,"inputs":[{"repeatintervals":[800],"events":[{"buttonevent":1000,"eventtype":"initial_press"},{"buttonevent":1001,"eventtype":"repeat"},{"buttonevent":1002,"eventtype":"short_release"},{"buttonevent":1003,"eventtype":"long_release"},{"buttonevent":1010,"eventtype":"long_press"}]},{"repeatintervals":[800],"events":[{"buttonevent":2000,"eventtype":"initial_press"},{"buttonevent":2001,"eventtype":"repeat"},{"buttonevent":2002,"eventtype":"short_release"},{"buttonevent":2003,"eventtype":"long_release"},{"buttonevent":2010,"eventtype":"long_press"}]},{"repeatintervals":[800],"events":[{"buttonevent":3000,"eventtype":"initial_press"},{"buttonevent":3001,"eventtype":"repeat"},{"buttonevent":3002,"eventtype":"short_release"},{"buttonevent":3003,"eventtype":"long_release"},{"buttonevent":3010,"eventtype":"long_press"}]},{"repeatintervals":[800],"events":[{"buttonevent":4000,"eventtype":"initial_press"},{"buttonevent":4001,"eventtype":"repeat"},{"buttonevent":4002,"eventtype":"short_release"},{"buttonevent":4003,"eventtype":"long_release"},{"buttonevent":4010,"eventtype":"long_press"}]}]}}}, + "ZLLRelativeRotary":{"state":{"rotaryevent":2,"expectedrotation":90,"direction":"right","expectedeventduration":400,"lastupdated":"2023-05-13T09:34:38Z"},"config":{"on":True,"battery":100,"reachable":True,"pending":[]},"static":{"swupdate":{"state":"noupdates","lastinstall":"2022-07-01T14:38:51Z"},"manufacturername":"Signify Netherlands B.V.","productname":"Hue tap dial switch","swversion":"2.59.25","capabilities":{"certified":True,"primary":False,"inputs":[{"repeatintervals":[400],"events":[{"rotaryevent":1,"eventtype":"start"},{"rotaryevent":2,"eventtype":"repeat"}]}]}}}} -sensorTypes["RWL021"] = {"ZLLSwitch": {"state":{"buttonevent":4000,"lastupdated":"2022-11-13T09:34:38"}, "config":{"on":True,"battery":None,"reachable":False,"pending":[]}, "static": {"swupdate":{"state":"transferring","lastinstall":"2022-11-13T09:32:55"}, "manufacturername":"Signify Netherlands B.V.","productname":"Hue dimmer switch","diversityid":"6426c751-c093-499e-afb6-9f0c863ec819","swversion":"2.44.0_hBB3C188","capabilities":{"certified":True,"primary":True,"inputs":[{"repeatintervals":[800],"events":[{"buttonevent":1000,"eventtype":"initial_press"},{"buttonevent":1001,"eventtype":"repeat"},{"buttonevent":1002,"eventtype":"short_release"},{"buttonevent":1003,"eventtype":"long_release"},{"buttonevent":1010,"eventtype":"long_press"}]},{"repeatintervals":[800],"events":[{"buttonevent":2000,"eventtype":"initial_press"},{"buttonevent":2001,"eventtype":"repeat"},{"buttonevent":2002,"eventtype":"short_release"},{"buttonevent":2003,"eventtype":"long_release"},{"buttonevent":2010,"eventtype":"long_press"}]},{"repeatintervals":[800],"events":[{"buttonevent":3000,"eventtype":"initial_press"},{"buttonevent":3001,"eventtype":"repeat"},{"buttonevent":3002,"eventtype":"short_release"},{"buttonevent":3003,"eventtype":"long_release"},{"buttonevent":3010,"eventtype":"long_press"}]},{"repeatintervals":[800],"events":[{"buttonevent":4000,"eventtype":"initial_press"},{"buttonevent":4001,"eventtype":"repeat"},{"buttonevent":4002,"eventtype":"short_release"},{"buttonevent":4003,"eventtype":"long_release"},{"buttonevent":4010,"eventtype":"long_press"}]}]}}}} +sensorTypes["RWL021"] = {"ZLLSwitch": {"state":{"buttonevent":4000,"lastupdated":"2022-11-13T09:34:38Z"}, "config":{"on":True,"battery":None,"reachable":False,"pending":[]}, "static": {"swupdate":{"state":"transferring","lastinstall":"2022-11-13T09:32:55Z"}, "manufacturername":"Signify Netherlands B.V.","productname":"Hue dimmer switch","diversityid":"6426c751-c093-499e-afb6-9f0c863ec819","swversion":"2.44.0_hBB3C188","capabilities":{"certified":True,"primary":True,"inputs":[{"repeatintervals":[800],"events":[{"buttonevent":1000,"eventtype":"initial_press"},{"buttonevent":1001,"eventtype":"repeat"},{"buttonevent":1002,"eventtype":"short_release"},{"buttonevent":1003,"eventtype":"long_release"},{"buttonevent":1010,"eventtype":"long_press"}]},{"repeatintervals":[800],"events":[{"buttonevent":2000,"eventtype":"initial_press"},{"buttonevent":2001,"eventtype":"repeat"},{"buttonevent":2002,"eventtype":"short_release"},{"buttonevent":2003,"eventtype":"long_release"},{"buttonevent":2010,"eventtype":"long_press"}]},{"repeatintervals":[800],"events":[{"buttonevent":3000,"eventtype":"initial_press"},{"buttonevent":3001,"eventtype":"repeat"},{"buttonevent":3002,"eventtype":"short_release"},{"buttonevent":3003,"eventtype":"long_release"},{"buttonevent":3010,"eventtype":"long_press"}]},{"repeatintervals":[800],"events":[{"buttonevent":4000,"eventtype":"initial_press"},{"buttonevent":4001,"eventtype":"repeat"},{"buttonevent":4002,"eventtype":"short_release"},{"buttonevent":4003,"eventtype":"long_release"},{"buttonevent":4010,"eventtype":"long_press"}]}]}}}} sensorTypes["ZGPSWITCH"] = {"ZGPSwitch": {"state": {"buttonevent": 0, "lastupdated": "none"}, "config": {"on": True, "battery": 100, "reachable": True}, "static": {"manufacturername": "Signify Netherlands B.V.", "swversion": ""}}} sensorTypes["RWL020"] = sensorTypes["RWL021"] sensorTypes["RWL022"] = sensorTypes["RWL021"] diff --git a/BridgeEmulator/services/deconz.py b/BridgeEmulator/services/deconz.py index 00f8eb8cb..0673c59e1 100644 --- a/BridgeEmulator/services/deconz.py +++ b/BridgeEmulator/services/deconz.py @@ -114,7 +114,7 @@ def received_message(self, m): else: lightSensor.state["lightlevel"] = 25000 lightSensor.state["daylight"] = not lightSensor.state["dark"] - lightSensor.state["lastupdated"] = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S") + lightSensor.state["lastupdated"] = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.000Z") if "dark" in message["state"]: del message["state"]["dark"] diff --git a/BridgeEmulator/services/eventStreamer.py b/BridgeEmulator/services/eventStreamer.py index 9a1931a8d..6a568c3cc 100644 --- a/BridgeEmulator/services/eventStreamer.py +++ b/BridgeEmulator/services/eventStreamer.py @@ -1,5 +1,5 @@ import logManager -from flask import Flask, Response, stream_with_context, Blueprint +from flask import Response, stream_with_context, Blueprint import json from time import sleep, time import HueObjects diff --git a/BridgeEmulator/services/homeAssistantWS.py b/BridgeEmulator/services/homeAssistantWS.py index 796329c7d..3365573c1 100644 --- a/BridgeEmulator/services/homeAssistantWS.py +++ b/BridgeEmulator/services/homeAssistantWS.py @@ -1,7 +1,6 @@ import logManager import json import time -import random import threading from ws4py.client.threadedclient import WebSocketClient diff --git a/BridgeEmulator/services/mdns.py b/BridgeEmulator/services/mdns.py index 9b9067149..813e68b04 100644 --- a/BridgeEmulator/services/mdns.py +++ b/BridgeEmulator/services/mdns.py @@ -1,7 +1,6 @@ import logManager import socket -from time import sleep -from zeroconf import IPVersion, ServiceBrowser, ServiceInfo, Zeroconf +from zeroconf import IPVersion, ServiceInfo, Zeroconf logging = logManager.logger.get_logger(__name__) diff --git a/BridgeEmulator/services/mqtt.py b/BridgeEmulator/services/mqtt.py index 945759081..94cd5a6d6 100644 --- a/BridgeEmulator/services/mqtt.py +++ b/BridgeEmulator/services/mqtt.py @@ -340,17 +340,17 @@ def on_message(client, userdata, msg): device.config["battery"] = data["battery"] if device.config["on"] == False: return - convertedPayload = {"lastupdated": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S")} + convertedPayload = {"lastupdated": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.000Z")} if ("action" in data and data["action"] == "") or ("click" in data and data["click"] == ""): return ### If is a motion sensor update the light level and temperature if device.modelid in motionSensors: convertedPayload["presence"] = data["occupancy"] - lightPayload = {"lastupdated": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S")} + lightPayload = {"lastupdated": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.000Z")} lightSensor = findLightSensor(device) if "temperature" in data: tempSensor = findTempSensor(device) - tempSensor.state = {"temperature": int(data["temperature"] * 100), "lastupdated": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S")} + tempSensor.state = {"temperature": int(data["temperature"] * 100), "lastupdated": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.000Z")} if "illuminance_lux" in data: hue_lightlevel = int(10000 * math.log10(data["illuminance_lux"])) if data["illuminance_lux"] != 0 else 0 if hue_lightlevel > lightSensor.config["tholddark"]: diff --git a/BridgeEmulator/services/remoteDiscover.py b/BridgeEmulator/services/remoteDiscover.py index fed70a742..75833680f 100755 --- a/BridgeEmulator/services/remoteDiscover.py +++ b/BridgeEmulator/services/remoteDiscover.py @@ -1,6 +1,5 @@ import logManager import requests -import json from time import sleep logging = logManager.logger.get_logger(__name__) diff --git a/BridgeEmulator/services/scheduler.py b/BridgeEmulator/services/scheduler.py index e9fd7ac16..0dcdfb16f 100644 --- a/BridgeEmulator/services/scheduler.py +++ b/BridgeEmulator/services/scheduler.py @@ -4,7 +4,7 @@ import random from time import sleep from threading import Thread -from datetime import datetime, timedelta, time, date, timezone +from datetime import datetime, timedelta, time, timezone from functions.request import sendRequest from functions.daylightSensor import daylightSensor from functions.scripts import findGroup, triggerScript diff --git a/BridgeEmulator/update_openwrt.sh b/BridgeEmulator/update_openwrt.sh index 5c8070316..f60186b0f 100644 --- a/BridgeEmulator/update_openwrt.sh +++ b/BridgeEmulator/update_openwrt.sh @@ -2,14 +2,18 @@ echo -e "\033[32m Disable startup service.\033[0m" /etc/init.d/hueemulatorWrt-service disable + echo -e "\033[32m Create directory for backup configuration.\033[0m" mkdir /tmp/diyHue-config + echo -e "\033[32m Copying configuration file.\033[0m" cp /opt/hue-emulator/config.json /tmp/diyHue-config/config.json.bak cp /opt/hue-emulator/cert.pem /tmp/diyHue-config/cert.pem.bak + echo -e "\033[32m Deleting directories.\033[0m" rm -Rf /opt/hue-emulator rm -Rf /etc/init.d/hueemulatorWrt-service + echo -e "\033[32m Updating python3-pip.\033[0m" python3 -m pip install --upgrade pip wait @@ -24,6 +28,7 @@ python3 -m pip install --upgrade ws4py wait python3 -m pip install --upgrade paho-mqtt wait + echo -e "\033[32m Creating directories.\033[0m" mkdir /opt mkdir /opt/tmp @@ -36,11 +41,30 @@ unzip -q -o diyHue.zip wait echo -e "\033[32m Copying unzip files to directories.\033[0m" cd /opt/tmp/diyHue-master/BridgeEmulator -cp HueEmulator3.py updater githubInstall.sh githubUIInstall.sh /opt/hue-emulator/ +cp -r flaskUI /opt/hue-emulator/ +cp -r functions /opt/hue-emulator/ +cp -r lights /opt/hue-emulator/ +cp -r sensors /opt/hue-emulator/ +cp -r HueObjects /opt/hue-emulator/ +cp -r services /opt/hue-emulator/ +cp -r configManager /opt/hue-emulator/ +cp -r logManager /opt/hue-emulator/ +cp -r HueEmulator3.py /opt/hue-emulator/ +cp -r githubInstall.sh /opt/hue-emulator/ +cp -r genCert.sh /opt/hue-emulator/ +cp -r openssl.conf /opt/hue-emulator/ cp /tmp/diyHue-config/config.json.bak /opt/hue-emulator/config.json cp /tmp/diyHue-config/cert.pem.bak /opt/hue-emulator/cert.pem cp default-config.json /opt/hue-emulator/default-config.json -cp -r functions protocols debug web-ui /opt/hue-emulator/ + +echo -e "\033[32m Copy web interface files.\033[0m" +curl -sL https://www.github.com/diyhue/diyHueUI/releases/latest/download/DiyHueUI-release.zip -o diyHueUI.zip +wait +unzip -qo diyHueUI.zip +wait +mv index.html /opt/hue-emulator/flaskUI/templates/ +cp -r static /opt/hue-emulator/flaskUI/ + echo -e "\033[32m Detecting processor architecture.\033[0m" wait arch=`uname -m` @@ -48,24 +72,31 @@ wait echo -e "\033[32m Architecture detected: $arch\033[0m" echo -e "\033[32m Copying binary $arch for Openwrt.\033[0m" cp entertainment-openwrt-$arch /opt/hue-emulator/entertain-srv + echo -e "\033[32m Copying custom network function for openwrt.\033[0m" rm -Rf /opt/hue-emulator/functions/network.py mv /opt/hue-emulator/functions/network_OpenWrt.py /opt/hue-emulator/functions/network.py wait + echo -e "\033[32m Copying startup service.\033[0m" cp /opt/tmp/diyHue-master/BridgeEmulator/hueemulatorWrt-service /etc/init.d/ + echo -e "\033[32m Changing permissions.\033[0m" chmod +x /etc/init.d/hueemulatorWrt-service chmod +x /opt/hue-emulator/HueEmulator3.py -chmod +x /opt/hue-emulator/debug -chmod +x /opt/hue-emulator/protocols -chmod +x /opt/hue-emulator/updater -chmod +x /opt/hue-emulator/web-ui +chmod +x /opt/hue-emulator/HueObjects +chmod +x /opt/hue-emulator/configManager +chmod +x /opt/hue-emulator/flaskUI chmod +x /opt/hue-emulator/functions chmod +x /opt/hue-emulator/config.json chmod +x /opt/hue-emulator/default-config.json chmod +x /opt/hue-emulator/entertain-srv +chmod +x /opt/hue-emulator/lights +chmod +x /opt/hue-emulator/logManager +chmod +x /opt/hue-emulator/sensors +chmod +x /opt/hue-emulator/services chmod +x /opt/hue-emulator/functions/network.py + echo -e "\033[32m Enable startup service.\033[0m" /etc/init.d/hueemulatorWrt-service enable wait