Example #1
0
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
Example #2
0
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
Example #3
0
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")
Example #4
0
 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
Example #5
0
 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"}
Example #6
0
    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
Example #7
0
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))
Example #8
0
        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))