def longPressButton(sensor, buttonevent): logging.info("long press detected") sleep(1) while sensor.state["buttonevent"] == buttonevent: logging.info("still pressed") current_time = datetime.now() sensor.dxState["lastupdated"] = current_time rulesProcessor(sensor, current_time) sleep(0.5) return
def noMotion(sensor): bridgeConfig["sensors"][sensor].protocol_cfg["threaded"] = True logging.info("Monitor the sensor for no motion") while (datetime.now() - bridgeConfig["sensors"][sensor].dxState["presence"]).total_seconds() < 60: sleep(1) bridgeConfig["sensors"][sensor].state["presence"] = False current_time = datetime.now() bridgeConfig["sensors"][sensor].dxState["presence"] = current_time rulesProcessor(bridgeConfig["sensors"][sensor], current_time) bridgeConfig["sensors"][sensor].protocol_cfg["threaded"] = False
def daylightSensor(timezone, sensor): if sensor.config["configured"]: localzone = LocationInfo('localzone', timezone.split("/")[1], timezone, sensor.protocol_cfg["lat"], sensor.protocol_cfg["long"]) s = sun(localzone.observer, date=datetime.utcnow()) deltaSunset = s['sunset'].replace(tzinfo=None) - datetime.utcnow() deltaSunrise = s['sunrise'].replace(tzinfo=None) - datetime.utcnow() deltaSunsetOffset = deltaSunset.total_seconds() + sensor.config["sunsetoffset"] * 60 deltaSunriseOffset = deltaSunrise.total_seconds() + sensor.config["sunriseoffset"] * 60 logging.info("deltaSunsetOffset: " + str(deltaSunsetOffset)) logging.info("deltaSunriseOffset: " + str(deltaSunriseOffset)) current_time = datetime.utcnow() if deltaSunriseOffset < 0 and deltaSunsetOffset > 0: sensor.state["daylight"] = True logging.info("set daylight sensor to true") else: sensor.state["daylight"] = False logging.info("set daylight sensor to false") if deltaSunsetOffset > 0 and deltaSunsetOffset < 3600: logging.info("will start the sleep for sunset") sleep(deltaSunsetOffset) logging.debug("sleep finish at " + current_time.strftime("%Y-%m-%dT%H:%M:%S")) sensor.state = {"daylight":False,"lastupdated": current_time.strftime("%Y-%m-%dT%H:%M:%S")} sensor.dxState["daylight"] = current_time rulesProcessor(["sensors","1"], current_time) elif deltaSunriseOffset > 0 and deltaSunriseOffset < 3600: logging.info("will start the sleep for sunrise") sleep(deltaSunriseOffset) logging.debug("sleep finish at " + current_time.strftime("%Y-%m-%dT%H:%M:%S")) sensor.state = {"daylight":True,"lastupdated": current_time.strftime("%Y-%m-%dT%H:%M:%S")} sensor.dxState["daylight"] = current_time rulesProcessor(["sensors","1"], current_time) # v2 api routines for key, instance in bridgeConfig["behavior_instance"].items(): if "when_extended" in instance.configuration: offset = 0 if instance.configuration["when_extended"]["start_at"]["time_point"]["type"] == "sunrise": if "offset" in instance.configuration["when_extended"]["start_at"]["time_point"]: offset = 60 * instance.configuration["when_extended"]["start_at"]["time_point"]["offset"]["minutes"] if deltaSunriseOffset + offset > 0 and deltaSunriseOffset + offset < 3600: Thread(target=runBackgroundSleep, args=[instance, deltaSunriseOffset + offset]).start() elif instance.configuration["when_extended"]["start_at"]["time_point"]["type"] == "sunset": if "offset" in instance.configuration["when_extended"]["start_at"]["time_point"]: offset = 60 * instance.configuration["when_extended"]["start_at"]["time_point"]["offset"]["minutes"] if deltaSunsetOffset + offset > 0 and deltaSunsetOffset + offset < 3600: Thread(target=runBackgroundSleep, args=[instance, deltaSunsetOffset + offset]).start() else: logging.debug("Daylight Sensor: location is not configured")
def put(self, username, resource, resourceid, param): authorisation = authorize(username, resource, resourceid, param) if "success" not in authorisation: return authorisation putDict = request.get_json(force=True) currentTime = datetime.now() logging.debug(putDict) if resource == "lights" and param == "state": # state is applied to a light bridgeConfig[resource][resourceid].setV1State(putDict) elif param == "action": # state is applied to a light if "scene" in putDict: bridgeConfig[resource][resourceid].setV1Action( state={}, scene=bridgeConfig["scenes"][putDict["scene"]]) else: bridgeConfig[resource][resourceid].setV1Action(state=putDict, scene=None) if "on" in putDict: bridgeConfig["groups"][resourceid].dxState[ "any_on"] = currentTime bridgeConfig["groups"][resourceid].dxState[ "all_on"] = currentTime rulesProcessor(bridgeConfig[resource][resourceid], currentTime) if resource == "sensors" and param == "state": bridgeConfig[resource][resourceid].state.update(putDict) for state in putDict.keys(): bridgeConfig["sensors"][resourceid].dxState[ state] = currentTime bridgeConfig["sensors"][resourceid].state[ "lastupdated"] = datetime.utcnow().strftime( "%Y-%m-%dT%H:%M:%S") bridgeConfig["sensors"][resourceid].dxState[ "lastupdated"] = currentTime rulesProcessor(bridgeConfig[resource][resourceid], currentTime) bridgeConfig[resource][resourceid].update_attr({param: putDict}) responseList = [] responseLocation = "/" + resource + "/" + resourceid + "/" + param + "/" for key, value in putDict.items(): responseList.append({"success": {responseLocation + key: value}}) logging.debug(responseList) return responseList
def get(self): args = request.args if "mac" in args: current_time = datetime.now() mac = args["mac"] if "devicetype" in args: # device registration if is new deviceIsNew = True for device, obj in bridgeConfig["sensors"].items(): if "mac" in obj.protocol_cfg and obj.protocol_cfg["mac"] == mac: deviceIsNew = False break if deviceIsNew: if args["devicetype"] in ["ZLLSwitch", "ZGPSwitch"]: sensor = addHueSwitch("", args["devicetype"]) sensor.protocol_cfg["mac"] = mac elif args["devicetype"] == "ZLLPresence": sensor = addHueMotionSensor("Hue Motion Sensor", "native", {"mac": mac, "threaded": False}) else: for device, obj in bridgeConfig["sensors"].items(): if "mac" in obj.protocol_cfg and obj.protocol_cfg["mac"] == mac: if obj.type == "ZLLLightLevel": dark = True if args["dark"] == "true" else False if obj.state["dark"] != dark: obj.dxState["dark"] = current_time obj.state["dark"] = dark elif obj.type == "ZLLPresence": obj.state["presence"] = True obj.dxState["presence"] = current_time if obj.protocol_cfg["threaded"] == False: Thread(target=noMotion, args=[device]).start() elif obj.type in ["ZLLSwitch", "ZGPSwitch"]: obj.state["buttonevent"] = int(args["button"]) obj.dxState["buttonevent"] = current_time obj.dxState["lastupdated"] = current_time obj.state["lastupdated"] = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S") rulesProcessor(obj, current_time) return {"result": "ok"}
def put(self, username, resource, resourceid): authorisation = authorize(username, resource, resourceid) if "success" not in authorisation: return authorisation putDict = request.get_json(force=True) logging.debug(putDict) currentTime = datetime.now() responseList = [] response_location = "/" + resource + "/" + resourceid + "/" for key, value in putDict.items(): responseList.append({"success": {response_location + key: value}}) if "group" in putDict: putDict["group"] = weakref.ref( bridgeConfig["groups"][putDict["group"]]) if resource == "scenes" and "lights" in putDict: objList = [] for light in putDict["lights"]: objList.append(weakref.ref(bridgeConfig["lights"][light])) putDict["lights"] = objList if "lightstates" in putDict: lightStates = weakref.WeakKeyDictionary() for light, state in putDict["lightstates"].items(): lightStates[bridgeConfig["lights"][light]] = state putDict["lightstates"] = lightStates if resource == "sensors": if "state" in putDict: for state in putDict["state"].keys(): bridgeConfig["sensors"][resourceid].dxState[ state] = currentTime bridgeConfig["sensors"][resourceid].state[ "lastupdated"] = datetime.utcnow().strftime( "%Y-%m-%dT%H:%M:%S") bridgeConfig["sensors"][resourceid].dxState[ "lastupdated"] = currentTime elif resource == "groups": if "lights" in putDict: bridgeConfig["groups"][resourceid].lights = [] #empty the list for light in putDict["lights"]: bridgeConfig["groups"][resourceid].add_light( bridgeConfig["lights"][light]) if "stream" in putDict: if "active" in putDict["stream"]: if putDict["stream"]["active"]: logging.info("start hue entertainment") Thread(target=entertainmentService, args=[ bridgeConfig["groups"][resourceid], bridgeConfig["apiUsers"][username] ]).start() else: logging.info("stop hue entertainent") Popen(["killall", "openssl"]) if "action" in putDict: bridgeConfig["groups"][resourceid].dxState[ "any_on"] = currentTime # lights where removed from group, delete scenes if "lights" in putDict and len(putDict["lights"]) == 0: for scene in list(bridgeConfig["scenes"].keys()): if bridgeConfig["scenes"][scene].type == "GroupScene": if bridgeConfig["scenes"][scene].group( ).id_v1 == resourceid: del bridgeConfig["scenes"][scene] if "locations" in putDict: for light, location in putDict["locations"].items(): bridgeConfig["groups"][resourceid].locations[ bridgeConfig["lights"][light]] = [{ "x": location[0], "y": location[1], "z": location[2] }] bridgeConfig[resource][resourceid].update_attr(putDict) rulesProcessor(bridgeConfig[resource][resourceid], currentTime) logging.debug(responseList) return responseList
def on_message(client, userdata, msg): if bridgeConfig["config"]["mqtt"]["enabled"]: try: current_time = datetime.now() logging.debug("MQTT: got state message on " + msg.topic) data = json.loads(msg.payload) logging.debug(msg.payload) if msg.topic.startswith(discoveryPrefix + "/light/"): on_autodiscovery_light(msg) elif msg.topic == "zigbee2mqtt/bridge/devices": for key in data: if "model_id" in key and ( key["model_id"] in standardSensors or key["model_id"] in motionSensors): # Sensor is supported if getObject(key["friendly_name"] ) == False: ## Add the new sensor logging.info("MQTT: Add new mqtt sensor " + key["friendly_name"]) if key["model_id"] in standardSensors: new_sensor_id = nextFreeId( bridgeConfig, "sensors") sensor_type = list( sensorTypes[key["model_id"]].keys())[0] uniqueid = convertHexToMac( key["ieee_address"]) + "-01-1000" sensorData = { "name": key["friendly_name"], "protocol": "mqtt", "modelid": key["model_id"], "type": sensor_type, "uniqueid": uniqueid, "protocol_cfg": { "friendly_name": key["friendly_name"], "ieeeAddr": key["ieee_address"], "model": key["definition"]["model"] }, "id_v1": new_sensor_id } bridgeConfig["sensors"][ new_sensor_id] = HueObjects.Sensor( sensorData) ### TRADFRI Motion Sensor, Xiaomi motion sensor, etc elif key["model_id"] in motionSensors: logging.info("MQTT: add new motion sensor " + key["model_id"]) addHueMotionSensor( key["friendly_name"], "mqtt", { "modelid": key["model_id"], "lightSensor": "on", "friendly_name": key["friendly_name"] }) else: logging.info("MQTT: unsupported sensor " + key["model_id"]) elif msg.topic == "zigbee2mqtt/bridge/log": light = getObject(data["meta"]["friendly_name"]) if data["type"] == "device_announced": if light.config["startup"]["mode"] == "powerfail": logging.info("set last state for " + light.name) payload = {} payload["state"] = "ON" if light.state["on"] else "OFF" client.publish(light.protocol_cfg['command_topic'], json.dumps(payload)) elif data["type"] == "zigbee_publish_error": logging.info(light.name + " is unreachable") light.state["reachable"] = False else: device_friendlyname = msg.topic.split("/")[1] device = getObject(device_friendlyname) if device != False: if device.getObjectPath()["resource"] == "sensors": if "battery" in data and isinstance( data["battery"], int): device.config["battery"] = data["battery"] if device.config["on"] == False: return convertedPayload = { "lastupdated": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S") } 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.utcnow().strftime("%Y-%m-%dT%H:%M:%S") } lightSensor = findLightSensor(device) if "temperature" in data: tempSensor = findTempSensor(device) tempSensor.state = { "temperature": int(data["temperature"] * 100), "lastupdated": datetime.utcnow().strftime( "%Y-%m-%dT%H:%M:%S") } 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"]: lightPayload["dark"] = False else: lightPayload["dark"] = True lightPayload["lightlevel"] = hue_lightlevel elif lightSensor.protocol_cfg[ "lightSensor"] == "on": lightPayload["dark"] = not bridgeConfig[ "sensors"]["1"].state["daylight"] if lightPayload["dark"]: lightPayload["lightlevel"] = 6000 else: lightPayload["lightlevel"] = 25000 else: # is always dark lightPayload["dark"] = True lightPayload["lightlevel"] = 6000 lightPayload["daylight"] = not lightPayload["dark"] if lightPayload["dark"] != lightSensor.state[ "dark"]: lightSensor.dxState["dark"] = current_time lightSensor.state.update(lightPayload) # send email if alarm is enabled: if data["occupancy"] and bridgeConfig["config"][ "alarm"]["enabled"] and bridgeConfig[ "config"]["alarm"][ "lasttriggered"] + 300 < current_time.timestamp( ): logging.info( "Alarm triggered, sending email...") requests.post( "https://diyhue.org/cdn/mailNotify.php", json={ "to": bridgeConfig["config"]["alarm"] ["email"], "sensor": device.name }, timeout=10) bridgeConfig["config"]["alarm"][ "lasttriggered"] = int( current_time.timestamp()) elif device.modelid in standardSensors: convertedPayload.update(standardSensors[ device.modelid]["dataConversion"][ data[standardSensors[device.modelid] ["dataConversion"]["rootKey"]]]) for key in convertedPayload.keys(): if device.state[key] != convertedPayload[key]: device.dxState[key] = current_time device.state.update(convertedPayload) logging.debug(convertedPayload) if "buttonevent" in convertedPayload and convertedPayload[ "buttonevent"] in [ 1001, 2001, 3001, 4001, 5001 ]: Thread(target=longPressButton, args=[ device, convertedPayload["buttonevent"] ]).start() rulesProcessor(device, current_time) elif device.getObjectPath()["resource"] == "lights": state = {"reachable": True} if "state" in data: if data["state"] == "ON": state["on"] = True else: state["on"] = False if "brightness" in data: state["bri"] = data["brightness"] device.state.update(state) on_state_update(msg) except Exception as e: logging.info("MQTT Exception | " + str(e))
def received_message(self, m): logging.info(m) message = json.loads(str(m)) try: if message["r"] == "sensors": bridgeSensor = getObject("sensors", message["id"]) if "config" in message and bridgeSensor.config["on"]: bridgeSensor.config.update(message["config"]) elif "state" in message and message[ "state"] and bridgeSensor.config["on"]: #convert tradfri motion sensor notification to look like Hue Motion Sensor if bridgeSensor.modelid == "SML001" and "lightSensor" in bridgeSensor.protocol_cfg: #find the light sensor id lightSensor = None for key, sensor in bridgeConfig["sensors"].items(): if sensor.type == "ZLLLightLevel" and sensor.uniqueid == bridgeSensor.uniqueid[: -1] + "0": lightSensor = sensor break if lightSensor.protocol_cfg["lightSensor"] == "no": lightSensor.state["dark"] = True else: lightSensor.state["dark"] = not bridgeConfig[ "sensors"]["1"].state["daylight"] if lightSensor.state["dark"]: lightSensor.state["lightlevel"] = 6000 else: lightSensor.state["lightlevel"] = 25000 lightSensor.state[ "daylight"] = not lightSensor.state["dark"] lightSensor.state["lastupdated"] = datetime.utcnow( ).strftime("%Y-%m-%dT%H:%M:%S") if "dark" in message["state"]: del message["state"]["dark"] if bridgeSensor.modelid == "SML001" and "lightlevel" in message[ "state"]: if message["state"][ lightlevel] > bridgeSensor.config[ "tholddark"]: message["state"]["dark"] = False else: message["state"]["dark"] = True bridgeSensor.state.update(message["state"]) current_time = datetime.now() for key in message["state"].keys(): bridgeSensor.dxState[key] = current_time rulesProcessor(bridgeSensor, current_time) if "buttonevent" in message[ "state"] and bridgeSensor.modelid in [ "TRADFRI remote control", "RWL021", "TRADFRI on/off switch" ]: if message["state"]["buttonevent"] in [ 1001, 2001, 3001, 4001, 5001 ]: Thread(target=longPressButton, args=[ bridgeSensor, message["state"]["buttonevent"] ]).start() if "presence" in message["state"] and message["state"][ "presence"] and bridgeConfig["config"][ "alarm"]["enabled"] and bridgeConfig[ "config"]["alarm"][ "lasttriggered"] + 300 < datetime.now( ).timestamp(): logging.info("Alarm triggered, sending email...") requests.post( "https://diyhue.org/cdn/mailNotify.php", json={ "to": bridgeConfig["config"]["alarm"]["email"], "sensor": bridgeSensor.name }) bridgeConfig["config"]["alarm"][ "lasttriggered"] = int( datetime.now().timestamp()) elif message["r"] == "lights": bridgeLightId = getObject("lights", message["id"]) if "state" in message and "colormode" not in message[ "state"]: bridgeLightId.state.update(message["state"]) except Exception as e: logging.info("unable to process the request" + str(e))