def ddxRecheck(rule, device, current_time, ddx_delay, ddx_sensor): for x in range(ddx_delay): if current_time != dxState[ddx_sensor[1]][ddx_sensor[2]][ddx_sensor[3]][ddx_sensor[4]]: logging.info("ddx rule " + rule + " canceled after " + str(x) + " seconds") return # rule not valid anymore because sensor state changed while waiting for ddx delay sleep(1) current_time = datetime.now() rule_state = checkRuleConditions(rule, device, current_time, True) if rule_state[0]: #if all conditions are meet again logging.info("delayed rule " + rule + " is triggered") bridge_config["rules"][rule]["lasttriggered"] = current_time.strftime("%Y-%m-%dT%H:%M:%S") bridge_config["rules"][rule]["timestriggered"] += 1 for action in bridge_config["rules"][rule]["actions"]: sendRequest("/api/" + bridge_config["rules"][rule]["owner"] + action["address"], action["method"], json.dumps(action["body"]))
def rulesProcessor(device, current_time): bridge_config["config"]["localtime"] = current_time.strftime("%Y-%m-%dT%H:%M:%S") #required for operator dx to address /config/localtime actionsToExecute = [] for rule in bridge_config["rules"].keys(): if bridge_config["rules"][rule]["status"] == "enabled": rule_result = checkRuleConditions(rule, device, current_time) if rule_result[0]: if rule_result[1] == 0: #is not ddx rule logging.info("rule " + rule + " is triggered") bridge_config["rules"][rule]["lasttriggered"] = current_time.strftime("%Y-%m-%dT%H:%M:%S") bridge_config["rules"][rule]["timestriggered"] += 1 for action in bridge_config["rules"][rule]["actions"]: actionsToExecute.append(action) else: #if ddx rule logging.info("ddx rule " + rule + " will be re validated after " + str(rule_result[1]) + " seconds") Thread(target=ddxRecheck, args=[rule, device, current_time, rule_result[1], rule_result[2]]).start() for action in actionsToExecute: sendRequest("/api/" + list(bridge_config["config"]["whitelist"])[0] + action["address"], action["method"], json.dumps(action["body"]))
def sendLightRequest(light, data, lights, addresses): payload = {} if light in addresses: protocol_name = addresses[light]["protocol"] for protocol in protocols: if "protocols." + protocol_name == protocol.__name__: try: light_state = protocol.set_light(addresses[light], lights[light], data) except Exception as e: lights[light]["state"]["reachable"] = False logging.warning(lights[light]["name"] + " light not reachable: %s", e) return if addresses[light]["protocol"] == "native": #ESP8266 light or strip url = "http://" + addresses[light]["ip"] + "/set?light=" + str(addresses[light]["light_nr"]) method = 'GET' for key, value in data.items(): if key == "xy": url += "&x=" + str(value[0]) + "&y=" + str(value[1]) else: url += "&" + key + "=" + str(value) elif addresses[light]["protocol"] in ["hue","deconz"]: #Original Hue light or Deconz light url = "http://" + addresses[light]["ip"] + "/api/" + addresses[light]["username"] + "/lights/" + addresses[light]["light_id"] + "/state" method = 'PUT' payload.update(data) elif addresses[light]["protocol"] == "domoticz": #Domoticz protocol url = "http://" + addresses[light]["ip"] + "/json.htm?type=command&idx=" + addresses[light]["light_id"] method = 'GET' if "on" in data and not "bri" in data and not "ct" in data and not "xy" in data: for key, value in data.items(): url += "¶m=switchlight" if key == "on": if value: url += "&switchcmd=On" else: url += "&switchcmd=Off" else: url += "¶m=setcolbrightnessvalue" color_data = {} old_light_state = lights[light]["state"] colormode = old_light_state["colormode"] ct = old_light_state["ct"] bri = old_light_state["bri"] xy = old_light_state["xy"] if "bri" in data: bri = data["bri"] if "ct" in data: ct = data["ct"] if "xy" in data: xy = data["xy"] bri = int(bri) color_data["m"] = 1 #0: invalid, 1: white, 2: color temp, 3: rgb, 4: custom if colormode == "ct": color_data["m"] = 2 ct01 = (ct - 153) / (500 - 153) #map color temperature from 153-500 to 0-1 ct255 = ct01 * 255 #map color temperature from 0-1 to 0-255 color_data["t"] = ct255 elif colormode == "xy": color_data["m"] = 3 (color_data["r"], color_data["g"], color_data["b"]) = convert_xy(xy[0], xy[1], 255) url += "&color="+json.dumps(color_data) url += "&brightness=" + str(round(float(bri)/255*100)) urlObj = {} urlObj["url"] = url elif addresses[light]["protocol"] == "jeedom": #Jeedom protocol url = "http://" + addresses[light]["ip"] + "/core/api/jeeApi.php?apikey=" + addresses[light]["light_api"] + "&type=cmd&id=" method = 'GET' for key, value in data.items(): if key == "on": if value: url += addresses[light]["light_on"] else: url += addresses[light]["light_off"] elif key == "bri": url += addresses[light]["light_slider"] + "&slider=" + str(round(float(value)/255*100)) # jeedom range from 0 to 100 (for zwave devices) instead of 0-255 of bridge elif addresses[light]["protocol"] == "milight": #MiLight bulb url = "http://" + addresses[light]["ip"] + "/gateways/" + addresses[light]["device_id"] + "/" + addresses[light]["mode"] + "/" + str(addresses[light]["group"]) method = 'PUT' for key, value in data.items(): if key == "on": payload["status"] = value elif key == "bri": payload["brightness"] = value elif key == "ct": payload["color_temp"] = int(value / 1.6 + 153) elif key == "hue": payload["hue"] = value / 180 elif key == "sat": payload["saturation"] = value * 100 / 255 elif key == "xy": payload["color"] = {} (payload["color"]["r"], payload["color"]["g"], payload["color"]["b"]) = convert_xy(value[0], value[1], lights[light]["state"]["bri"]) logging.info(json.dumps(payload)) elif addresses[light]["protocol"] == "ikea_tradfri": #IKEA Tradfri bulb url = "coaps://" + addresses[light]["ip"] + ":5684/15001/" + str(addresses[light]["device_id"]) for key, value in data.items(): if key == "on": payload["5850"] = int(value) elif key == "transitiontime": payload["5712"] = value elif key == "bri": payload["5851"] = value elif key == "ct": if value < 270: payload["5706"] = "f5faf6" elif value < 385: payload["5706"] = "f1e0b5" else: payload["5706"] = "efd275" elif key == "xy": payload["5709"] = int(value[0] * 65535) payload["5710"] = int(value[1] * 65535) if "hue" in data or "sat" in data: if("hue" in data): hue = data["hue"] else: hue = lights[light]["state"]["hue"] if("sat" in data): sat = data["sat"] else: sat = lights[light]["state"]["sat"] if("bri" in data): bri = data["bri"] else: bri = lights[light]["state"]["bri"] rgbValue = hsv_to_rgb(hue, sat, bri) xyValue = convert_rgb_xy(rgbValue[0], rgbValue[1], rgbValue[2]) payload["5709"] = int(xyValue[0] * 65535) payload["5710"] = int(xyValue[1] * 65535) if "5850" in payload and payload["5850"] == 0: payload.clear() #setting brightnes will turn on the ligh even if there was a request to power off payload["5850"] = 0 elif "5850" in payload and "5851" in payload: #when setting brightness don't send also power on command del payload["5850"] elif addresses[light]["protocol"] == "flex": msg = bytearray() if "on" in data: if data["on"]: msg = bytearray([0x71, 0x23, 0x8a, 0x0f]) else: msg = bytearray([0x71, 0x24, 0x8a, 0x0f]) checksum = sum(msg) & 0xFF msg.append(checksum) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP sock.sendto(msg, (addresses[light]["ip"], 48899)) if ("bri" in data and lights[light]["state"]["colormode"] == "xy") or "xy" in data: logging.info(pretty_json(data)) bri = data["bri"] if "bri" in data else lights[light]["state"]["bri"] xy = data["xy"] if "xy" in data else lights[light]["state"]["xy"] rgb = convert_xy(xy[0], xy[1], bri) msg = bytearray([0x41, rgb[0], rgb[1], rgb[2], 0x00, 0xf0, 0x0f]) checksum = sum(msg) & 0xFF msg.append(checksum) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP sock.sendto(msg, (addresses[light]["ip"], 48899)) elif ("bri" in data and lights[light]["state"]["colormode"] == "ct") or "ct" in data: bri = data["bri"] if "bri" in data else lights[light]["state"]["bri"] msg = bytearray([0x41, 0x00, 0x00, 0x00, bri, 0x0f, 0x0f]) checksum = sum(msg) & 0xFF msg.append(checksum) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP sock.sendto(msg, (addresses[light]["ip"], 48899)) try: if addresses[light]["protocol"] == "ikea_tradfri": if "5712" not in payload: payload["5712"] = 4 #If no transition add one, might also add check to prevent large transitiontimes check_output("./coap-client-linux -m put -u \"" + addresses[light]["identity"] + "\" -k \"" + addresses[light]["preshared_key"] + "\" -e '{ \"3311\": [" + json.dumps(payload) + "] }' \"" + url + "\"", shell=True) elif addresses[light]["protocol"] in ["hue", "deconz"]: color = {} if "xy" in payload: color["xy"] = payload["xy"] del(payload["xy"]) elif "ct" in payload: color["ct"] = payload["ct"] del(payload["ct"]) elif "hue" in payload: color["hue"] = payload["hue"] del(payload["hue"]) elif "sat" in payload: color["sat"] = payload["sat"] del(payload["sat"]) if len(payload) != 0: sendRequest(url, method, json.dumps(payload)) if addresses[light]["protocol"] == "deconz": sleep(0.7) if len(color) != 0: sendRequest(url, method, json.dumps(color)) else: sendRequest(url, method, json.dumps(payload)) except: lights[light]["state"]["reachable"] = False logging.info("request error") else: lights[light]["state"]["reachable"] = True logging.info("LightRequest: " + url)
def syncWithLights(lights, addresses, users, groups, off_if_unreachable): #update Hue Bridge lights states while True: logging.info("sync with lights") for light in addresses: try: protocol_name = addresses[light]["protocol"] for protocol in protocols: if "protocols." + protocol_name == protocol.__name__: try: light_state = protocol.get_light_state(addresses[light], lights[light]) lights[light]["state"].update(light_state) lights[light]["state"]["reachable"] = True except Exception as e: lights[light]["state"]["reachable"] = False lights[light]["state"]["on"] = False logging.warning(lights[light]["name"] + " is unreachable: %s", e) if addresses[light]["protocol"] == "native": light_data = json.loads(sendRequest("http://" + addresses[light]["ip"] + "/get?light=" + str(addresses[light]["light_nr"]), "GET", "{}")) lights[light]["state"].update(light_data) lights[light]["state"]["reachable"] = True elif addresses[light]["protocol"] == "hue": light_data = json.loads(sendRequest("http://" + addresses[light]["ip"] + "/api/" + addresses[light]["username"] + "/lights/" + addresses[light]["light_id"], "GET", "{}")) lights[light]["state"].update(light_data["state"]) elif addresses[light]["protocol"] == "ikea_tradfri": light_data = json.loads(check_output("./coap-client-linux -m get -u \"" + addresses[light]["identity"] + "\" -k \"" + addresses[light]["preshared_key"] + "\" \"coaps://" + addresses[light]["ip"] + ":5684/15001/" + str(addresses[light]["device_id"]) +"\"", shell=True).decode('utf-8').rstrip('\n').split("\n")[-1]) lights[light]["state"]["on"] = bool(light_data["3311"][0]["5850"]) lights[light]["state"]["bri"] = light_data["3311"][0]["5851"] if "5706" in light_data["3311"][0]: if light_data["3311"][0]["5706"] == "f5faf6": lights[light]["state"]["ct"] = 170 elif light_data["3311"][0]["5706"] == "f1e0b5": lights[light]["state"]["ct"] = 320 elif light_data["3311"][0]["5706"] == "efd275": lights[light]["state"]["ct"] = 470 else: lights[light]["state"]["ct"] = 470 lights[light]["state"]["reachable"] = True elif addresses[light]["protocol"] == "milight": light_data = json.loads(sendRequest("http://" + addresses[light]["ip"] + "/gateways/" + addresses[light]["device_id"] + "/" + addresses[light]["mode"] + "/" + str(addresses[light]["group"]), "GET", "{}")) if light_data["state"] == "ON": lights[light]["state"]["on"] = True else: lights[light]["state"]["on"] = False if "brightness" in light_data: lights[light]["state"]["bri"] = light_data["brightness"] if "color_temp" in light_data: lights[light]["state"]["colormode"] = "ct" lights[light]["state"]["ct"] = int(light_data["color_temp"] * 1.6) elif "bulb_mode" in light_data and light_data["bulb_mode"] == "color": lights[light]["state"]["colormode"] = "hs" lights[light]["state"]["hue"] = light_data["hue"] * 180 if (not "saturation" in light_data) and addresses[light]["mode"] == "rgbw": lights[light]["state"]["sat"] = 255 else: lights[light]["state"]["sat"] = int(light_data["saturation"] * 2.54) lights[light]["state"]["reachable"] = True elif addresses[light]["protocol"] == "domoticz": #domoticz protocol light_data = json.loads(sendRequest("http://" + addresses[light]["ip"] + "/json.htm?type=devices&rid=" + addresses[light]["light_id"], "GET", "{}")) if light_data["result"][0]["Status"] == "Off": lights[light]["state"]["on"] = False else: lights[light]["state"]["on"] = True lights[light]["state"]["bri"] = str(round(float(light_data["result"][0]["Level"])/100*255)) lights[light]["state"]["reachable"] = True elif addresses[light]["protocol"] == "jeedom": #jeedom protocol light_data = json.loads(sendRequest("http://" + addresses[light]["ip"] + "/core/api/jeeApi.php?apikey=" + addresses[light]["light_api"] + "&type=cmd&id=" + addresses[light]["light_id"], "GET", "{}")) if light_data == 0: lights[light]["state"]["on"] = False else: lights[light]["state"]["on"] = True lights[light]["state"]["bri"] = str(round(float(light_data)/100*255)) lights[light]["state"]["reachable"] = True if off_if_unreachable: if lights[light]["state"]["reachable"] == False: lights[light]["state"]["on"] = False updateGroupStats(light, lights, groups) except Exception as e: lights[light]["state"]["reachable"] = False lights[light]["state"]["on"] = False logging.warning(lights[light]["name"] + " is unreachable: %s", e) sleep(10) #wait at last 10 seconds before next sync i = 0 while i < 300: #sync with lights every 300 seconds or instant if one user is connected for user in users.keys(): if users[user]["last use date"] == datetime.now().strftime("%Y-%m-%dT%H:%M:%S"): i = 300 break i += 1 sleep(1)
def scheduleProcessor(): while True: for schedule in bridge_config["schedules"].keys(): try: delay = 0 if bridge_config["schedules"][schedule]["status"] == "enabled": if bridge_config["schedules"][schedule]["localtime"][ -9:-8] == "A": delay = random.randrange( 0, int(bridge_config["schedules"][schedule] ["localtime"][-8:-6]) * 3600 + int(bridge_config["schedules"][schedule] ["localtime"][-5:-3]) * 60 + int(bridge_config["schedules"][schedule] ["localtime"][-2:])) schedule_time = bridge_config["schedules"][schedule][ "localtime"][:-9] else: schedule_time = bridge_config["schedules"][schedule][ "localtime"] if schedule_time.startswith("W"): pieces = schedule_time.split('/T') if int(pieces[0][1:]) & ( 1 << 6 - datetime.today().weekday()): if pieces[1] <= datetime.now().strftime( "%H:%M:%S"): logging.info("execute schedule: " + schedule + " withe delay " + str(delay)) sendRequest( bridge_config["schedules"][schedule] ["command"]["address"], bridge_config["schedules"][schedule] ["command"]["method"], json.dumps(bridge_config["schedules"] [schedule]["command"]["body"]), 1, delay) elif schedule_time.startswith("PT"): timer = schedule_time[2:] (h, m, s) = timer.split(':') d = timedelta(hours=int(h), minutes=int(m), seconds=int(s)) if bridge_config["schedules"][schedule][ "starttime"] <= ( datetime.utcnow() - d).replace(microsecond=0).isoformat(): logging.info("execute timer: " + schedule + " withe delay " + str(delay)) sendRequest( bridge_config["schedules"][schedule]["command"] ["address"], bridge_config["schedules"] [schedule]["command"]["method"], json.dumps(bridge_config["schedules"][schedule] ["command"]["body"]), 1, delay) bridge_config["schedules"][schedule][ "status"] = "disabled" elif schedule_time.startswith("R/PT"): timer = schedule_time[4:] (h, m, s) = timer.split(':') d = timedelta(hours=int(h), minutes=int(m), seconds=int(s)) if bridge_config["schedules"][schedule][ "starttime"] <= ( datetime.utcnow() - d).replace(microsecond=0).isoformat(): logging.info("execute timer: " + schedule + " withe delay " + str(delay)) bridge_config["schedules"][schedule][ "starttime"] = datetime.utcnow().replace( microsecond=0).isoformat() sendRequest( bridge_config["schedules"][schedule]["command"] ["address"], bridge_config["schedules"] [schedule]["command"]["method"], json.dumps(bridge_config["schedules"][schedule] ["command"]["body"]), 1, delay) else: if schedule_time <= datetime.now().strftime( "%Y-%m-%dT%H:%M:%S"): logging.info("execute schedule: " + schedule + " withe delay " + str(delay)) sendRequest( bridge_config["schedules"][schedule]["command"] ["address"], bridge_config["schedules"] [schedule]["command"]["method"], json.dumps(bridge_config["schedules"][schedule] ["command"]["body"]), 1, delay) if bridge_config["schedules"][schedule][ "autodelete"]: del bridge_config["schedules"][schedule] except Exception as e: logging.info("Exception while processing the schedule " + schedule + " | " + str(e)) if (datetime.now().strftime("%M:%S") == "00:10" ): #auto save configuration every hour configManager.bridgeConfig.save_config() Thread(target=daylightSensor).start() if (datetime.now().strftime("%H") == "23" and datetime.now().strftime("%A") == "Sunday"): #backup config every Sunday at 23:00:10 configManager.bridgeConfig.save_config(True) sleep(1)
def scanDeconz(): deconz_ip = configManager.runtimeConfig.arg["DECONZ"] if not bridge_config["deconz"]["enabled"]: if "username" not in bridge_config["deconz"]: try: registration = json.loads( sendRequest( "http://" + deconz_ip + ":" + str(bridge_config["deconz"]["port"]) + "/api", "POST", "{\"username\": \"283145a4e198cc6535\", \"devicetype\":\"Hue Emulator\"}" )) except: logging.info("registration fail, is the link button pressed?") return if "success" in registration[0]: bridge_config["deconz"]["username"] = registration[0][ "success"]["username"] bridge_config["deconz"]["enabled"] = True if "username" in bridge_config["deconz"]: deconz_config = json.loads( sendRequest( "http://" + deconz_ip + ":" + str(bridge_config["deconz"]["port"]) + "/api/" + bridge_config["deconz"]["username"] + "/config", "GET", "{}")) bridge_config["deconz"]["websocketport"] = deconz_config[ "websocketport"] #lights deconz_lights = json.loads( sendRequest( "http://" + deconz_ip + ":" + str(bridge_config["deconz"]["port"]) + "/api/" + bridge_config["deconz"]["username"] + "/lights", "GET", "{}")) for light in deconz_lights: if light not in bridge_config["deconz"][ "lights"] and "modelid" in deconz_lights[light]: new_light_id = nextFreeId(bridge_config, "lights") logging.info("register new light " + new_light_id) bridge_config["lights"][new_light_id] = deconz_lights[light] bridge_config["lights_address"][new_light_id] = { "username": bridge_config["deconz"]["username"], "light_id": light, "ip": deconz_ip + ":" + str(bridge_config["deconz"]["port"]), "protocol": "deconz" } bridge_config["deconz"]["lights"][light] = { "bridgeid": new_light_id, "modelid": deconz_lights[light]["modelid"], "type": deconz_lights[light]["type"] } #sensors deconz_sensors = json.loads( sendRequest( "http://" + deconz_ip + ":" + str(bridge_config["deconz"]["port"]) + "/api/" + bridge_config["deconz"]["username"] + "/sensors", "GET", "{}")) for sensor in deconz_sensors: if sensor not in bridge_config["deconz"][ "sensors"] and "modelid" in deconz_sensors[sensor]: new_sensor_id = nextFreeId(bridge_config, "sensors") if deconz_sensors[sensor]["modelid"] in [ "TRADFRI remote control", "TRADFRI wireless dimmer" ]: logging.info("register new " + deconz_sensors[sensor]["modelid"]) bridge_config["sensors"][new_sensor_id] = { "config": deconz_sensors[sensor]["config"], "manufacturername": deconz_sensors[sensor]["manufacturername"], "modelid": deconz_sensors[sensor]["modelid"], "name": deconz_sensors[sensor]["name"], "state": deconz_sensors[sensor]["state"], "type": deconz_sensors[sensor]["type"], "uniqueid": deconz_sensors[sensor]["uniqueid"] } if "swversion" in deconz_sensors[sensor]: bridge_config["sensors"][new_sensor_id][ "swversion"] = deconz_sensors[sensor]["swversion"] bridge_config["deconz"]["sensors"][sensor] = { "bridgeid": new_sensor_id, "modelid": deconz_sensors[sensor]["modelid"], "type": deconz_sensors[sensor]["type"] } elif deconz_sensors[sensor][ "modelid"] == "TRADFRI motion sensor": logging.info( "register TRADFRI motion sensor as Philips Motion Sensor" ) newMotionSensorId = addHueMotionSensor( "", deconz_sensors[sensor]["name"]) bridge_config["deconz"]["sensors"][sensor] = { "bridgeid": newMotionSensorId, "triggered": False, "modelid": deconz_sensors[sensor]["modelid"], "type": deconz_sensors[sensor]["type"], "lightsensor": "internal" } elif deconz_sensors[sensor]["modelid"] == "lumi.vibration.aq1": logging.info( "register Xiaomi Vibration sensor as Philips Motion Sensor" ) newMotionSensorId = addHueMotionSensor( "", deconz_sensors[sensor]["name"]) bridge_config["deconz"]["sensors"][sensor] = { "bridgeid": newMotionSensorId, "triggered": False, "modelid": deconz_sensors[sensor]["modelid"], "type": deconz_sensors[sensor]["type"], "lightsensor": "astral" } elif deconz_sensors[sensor][ "modelid"] == "lumi.sensor_motion.aq2": if deconz_sensors[sensor]["type"] == "ZHALightLevel": logging.info("register new Xiaomi light sensor") bridge_config["sensors"][new_sensor_id] = { "name": "Hue ambient light sensor 1", "uniqueid": "00:17:88:01:02:" + deconz_sensors[sensor]["uniqueid"][12:], "type": "ZLLLightLevel", "swversion": "6.1.0.18912", "state": { "dark": True, "daylight": False, "lightlevel": 6000, "lastupdated": "none" }, "manufacturername": "Philips", "config": { "on": False, "battery": 100, "reachable": True, "alert": "none", "tholddark": 21597, "tholdoffset": 7000, "ledindication": False, "usertest": False, "pending": [] }, "modelid": "SML001" } bridge_config["sensors"][nextFreeId( bridge_config, "sensors")] = { "name": "Hue temperature sensor 1", "uniqueid": "00:17:88:01:02:" + deconz_sensors[sensor]["uniqueid"][12:-1] + "2", "type": "ZLLTemperature", "swversion": "6.1.0.18912", "state": { "temperature": None, "lastupdated": "none" }, "manufacturername": "Philips", "config": { "on": False, "battery": 100, "reachable": True, "alert": "none", "ledindication": False, "usertest": False, "pending": [] }, "modelid": "SML001" } bridge_config["deconz"]["sensors"][sensor] = { "bridgeid": new_sensor_id, "modelid": deconz_sensors[sensor]["modelid"], "type": deconz_sensors[sensor]["type"] } elif deconz_sensors[sensor]["type"] == "ZHAPresence": logging.info("register new Xiaomi motion sensor") bridge_config["sensors"][new_sensor_id] = { "name": deconz_sensors[sensor]["name"], "uniqueid": "00:17:88:01:02:" + deconz_sensors[sensor]["uniqueid"][12:], "type": "ZLLPresence", "swversion": "6.1.0.18912", "state": { "lastupdated": "none", "presence": None }, "manufacturername": "Philips", "config": { "on": False, "battery": 100, "reachable": True, "alert": "lselect", "ledindication": False, "usertest": False, "sensitivity": 2, "sensitivitymax": 2, "pending": [] }, "modelid": "SML001" } bridge_config["deconz"]["sensors"][sensor] = { "bridgeid": new_sensor_id, "modelid": deconz_sensors[sensor]["modelid"], "type": deconz_sensors[sensor]["type"] } elif deconz_sensors[sensor]["modelid"] == "lumi.sensor_motion": logging.info( "register Xiaomi Motion sensor w/o light sensor") newMotionSensorId = addHueMotionSensor( "", deconz_sensors[sensor]["name"]) bridge_config["deconz"]["sensors"][sensor] = { "bridgeid": newMotionSensorId, "triggered": False, "modelid": deconz_sensors[sensor]["modelid"], "type": deconz_sensors[sensor]["type"] } else: bridge_config["sensors"][new_sensor_id] = deconz_sensors[ sensor] bridge_config["deconz"]["sensors"][sensor] = { "bridgeid": new_sensor_id, "modelid": deconz_sensors[sensor]["modelid"], "type": deconz_sensors[sensor]["type"] } else: #temporary patch for config compatibility with new release bridge_config["deconz"]["sensors"][sensor][ "modelid"] = deconz_sensors[sensor]["modelid"] bridge_config["deconz"]["sensors"][sensor][ "type"] = deconz_sensors[sensor]["type"] generateDxState() if "websocketport" in bridge_config["deconz"]: logging.info("Starting deconz websocket") Thread(target=websocketClient).start()
def runScheduler(): while True: for schedule, obj in bridgeConfig["schedules"].items(): try: delay = 0 if obj.status == "enabled": if obj.localtime[-9:-8] == "A": delay = random.randrange( 0, int(obj.localtime[-8:-6]) * 3600 + int(obj.localtime[-5:-3]) * 60 + int(obj.localtime[-2:])) schedule_time = obj.localtime[:-9] else: schedule_time = obj.localtime if schedule_time.startswith("W"): pices = schedule_time.split('/T') if int(pices[0][1:]) & ( 1 << 6 - datetime.today().weekday()): if pices[1] == datetime.now().strftime("%H:%M:%S"): logging.info("execute schedule: " + schedule + " withe delay " + str(delay)) sendRequest(obj.command["address"], obj.command["method"], json.dumps(obj.command["body"]), 1, delay) elif schedule_time.startswith("PT"): timmer = schedule_time[2:] (h, m, s) = timmer.split(':') d = timedelta(hours=int(h), minutes=int(m), seconds=int(s)) if obj.starttime == (datetime.utcnow() - d).replace( microsecond=0).isoformat(): logging.info("execute timmer: " + schedule + " withe delay " + str(delay)) sendRequest(obj.command["address"], obj.command["method"], json.dumps(obj.command["body"]), 1, delay) obj.status = "disabled" elif schedule_time.startswith("R/PT"): timmer = schedule_time[4:] (h, m, s) = timmer.split(':') d = timedelta(hours=int(h), minutes=int(m), seconds=int(s)) if obj.starttime == (datetime.utcnow() - d).replace( microsecond=0).isoformat(): logging.info("execute timmer: " + schedule + " withe delay " + str(delay)) obj.starttime = datetime.utcnow().replace( microsecond=0).isoformat() sendRequest(obj.command["address"], obj.command["method"], json.dumps(obj.command["body"]), 1, delay) else: if schedule_time == datetime.now().strftime( "%Y-%m-%dT%H:%M:%S"): logging.info("execute schedule: " + schedule + " withe delay " + str(delay)) sendRequest(obj.command["address"], obj.command["method"], json.dumps(obj.command["body"]), 1, delay) if obj.autodelete: del obj except Exception as e: logging.info("Exception while processing the schedule " + schedule + " | " + str(e)) for instance, obj in bridgeConfig["behavior_instance"].items(): try: delay = 0 if obj.enabled: if "when" in obj.configuration: if "recurrence_days" in obj.configuration["when"]: if datetime.now().strftime( "%A").lower() not in obj.configuration[ "when"]["recurrence_days"]: continue if "time_point" in obj.configuration[ "when"] and obj.configuration["when"][ "time_point"]["type"] == "time": triggerTime = obj.configuration["when"][ "time_point"]["time"] time_object = datetime( year=1, month=1, day=1, hour=triggerTime["hour"], minute=triggerTime["minute"], second=triggerTime["second"] if "second" in triggerTime else 0) if "fade_in_duration" in obj.configuration: fade_duration = obj.configuration[ "fade_in_duration"] delta = timedelta( hours=fade_duration["hours"] if "hours" in fade_duration else 0, minutes=fade_duration["minutes"] if "minutes" in fade_duration else 0, seconds=fade_duration["seconds"] if "seconds" in fade_duration else 0) time_object = time_object - delta if datetime.now( ).second == time_object.second and datetime.now( ).minute == time_object.minute and datetime.now( ).hour == time_object.hour: logging.info("execute timmer: " + obj.name) Thread(target=triggerScript, args=[obj]).start() elif "when_extended" in obj.configuration: if "recurrence_days" in obj.configuration[ "when_extended"]: if datetime.now().strftime( "%A").lower() not in obj.configuration[ "when_extended"]["recurrence_days"]: continue if "start_at" in obj.configuration[ "when_extended"] and "time_point" in obj.configuration[ "when_extended"][ "start_at"] and obj.configuration[ "when_extended"]["start_at"][ "time_point"][ "type"] == "time": triggerTime = obj.configuration[ "when_extended"]["start_at"]["time_point"][ "time"] time_object = time( hour=triggerTime["hour"], minute=triggerTime["minute"], second=triggerTime["second"] if "second" in triggerTime else 0) if datetime.now( ).second == time_object.second and datetime.now( ).minute == time_object.minute and datetime.now( ).hour == time_object.hour: logging.info("execute timmer: " + obj.name) Thread(target=triggerScript, args=[obj]).start() except Exception as e: logging.info("Exception while processing the schedule " + obj.name + " | " + str(e)) if (datetime.now().strftime("%M:%S") == "00:10" ): #auto save configuration every hour configManager.bridgeConfig.save_config() Thread(target=daylightSensor, args=[ bridgeConfig["config"]["timezone"], bridgeConfig["sensors"]["1"] ]).start() if (datetime.now().strftime("%H") == "23" and datetime.now().strftime("%A") == "Sunday"): #backup config every Sunday at 23:00:10 configManager.bridgeConfig.save_config(backup=True) sleep(1)