From 1892acb3f6f7a7b23636c6c4f4bd2722310a3257 Mon Sep 17 00:00:00 2001 From: Mevel <4347330+Mevel@users.noreply.github.com> Date: Fri, 1 Jul 2022 09:34:28 +0200 Subject: [PATCH 1/4] add experimental Senic remote support add experimental support for Senic friends of hue Switch --- BridgeEmulator/sensors/sensor_types.py | 1 + BridgeEmulator/services/mqtt.py | 141 ++++++++++++++++--------- 2 files changed, 90 insertions(+), 52 deletions(-) diff --git a/BridgeEmulator/sensors/sensor_types.py b/BridgeEmulator/sensors/sensor_types.py index a8e0dc25a..9c448dd97 100644 --- a/BridgeEmulator/sensors/sensor_types.py +++ b/BridgeEmulator/sensors/sensor_types.py @@ -11,3 +11,4 @@ sensorTypes["TRADFRI remote control"] = {"ZHASwitch": {"state": {"buttonevent": 1002, "lastupdated": "none"}, "config": {"alert": "none", "battery": 90, "on": True, "reachable": True}, "static": {"swversion": "1.2.214", "manufacturername": "IKEA of Sweden"}}} sensorTypes["TRADFRI on/off switch"] = {"ZHASwitch": {"state": {"buttonevent": 1002, "lastupdated": "none"}, "config": {"alert": "none", "battery": 90, "on": True, "reachable": True}, "static": {"swversion": "2.2.008", "manufacturername": "IKEA of Sweden"}}} sensorTypes["TRADFRI wireless dimmer"] = {"ZHASwitch": {"state": {"buttonevent": 1002, "lastupdated": "none"}, "config": {"alert": "none", "battery": 90, "on": True, "reachable": True}, "static": {"swversion": "1.2.248", "manufacturername": "IKEA of Sweden"}}} +sensorTypes["Pushbutton transmitter module"] = {"ZGPSwitch": {"state": {"buttonevent": 0, "lastupdated": "none"}, "config": {"on": True, "battery": 100, "reachable": True}, "static": {"manufacturername": "Signify Netherlands B.V.", "swversion": ""}}} \ No newline at end of file diff --git a/BridgeEmulator/services/mqtt.py b/BridgeEmulator/services/mqtt.py index e07be6ab6..6e02119ce 100644 --- a/BridgeEmulator/services/mqtt.py +++ b/BridgeEmulator/services/mqtt.py @@ -26,19 +26,24 @@ discoveredDevices = {} -motionSensors = ["TRADFRI motion sensor", "lumi.sensor_motion.aq2", "lumi.sensor_motion", "SML001"] +motionSensors = ["TRADFRI motion sensor", + "lumi.sensor_motion.aq2", "lumi.sensor_motion", "SML001"] standardSensors = { - "TRADFRI remote control": { - "dataConversion": {"rootKey": "action", "toggle": {"buttonevent": 1002}, "arrow_right_click": {"buttonevent": 5002}, "arrow_right_hold": {"buttonevent": 5001}, "arrow_left_click": {"buttonevent": 4002}, "arrow_left_hold": {"buttonevent": 4001}, "brightness_up_click": {"buttonevent": 2002}, "brightness_up_hold": {"buttonevent": 2001}, "brightness_down_click": {"buttonevent": 3002}, "brightness_down_hold": {"buttonevent": 3001}, "brightness_up_release": {"buttonevent": 2003}, "brightness_down_release": {"buttonevent": 3003}, "arrow_left_release": {"buttonevent": 4003}, "arrow_right_release": {"buttonevent": 5003}}}, - "TRADFRI on/off switch": { - "dataConversion": {"rootKey": "click", "on": {"buttonevent": 1002}, "off": {"buttonevent": 2002}, "brightness_up": {"buttonevent": 1001}, "brightness_down": {"buttonevent": 2001}, "brightness_stop": {"buttonevent": 3001}}}, - "TRADFRI wireless dimmer": { - "dataConversion": {"rootKey": "action", "rotate_right_quick": {"buttonevent": 1002}, "rotate_right": {"buttonevent": 2002}, "rotate_left": {"buttonevent": 3002}, "rotate_left_quick": {"buttonevent": 4002}, "rotate_stop": {}, "": {}}}, - "RWL021": { - "dataConversion": {"rootKey": "action", "on_press": {"buttonevent": 1002}, "on-press": {"buttonevent": 1002}, "on_hold": {"buttonevent": 1001}, "on-hold": {"buttonevent": 1001}, "on_hold_release": {"buttonevent": 1003}, "on-hold-release": {"buttonevent": 1003},"up_press": {"buttonevent": 2000}, "up_hold": {"buttonevent": 2001}, "up-hold": {"buttonevent": 2001}, "up_hold_release": {"buttonevent": 2002}, "up-hold-release": {"buttonevent": 2002}, "down_press": {"buttonevent": 3000}, "down-press": {"buttonevent": 3000}, "down_hold": {"buttonevent": 3001}, "down-hold": {"buttonevent": 3001}, "down_hold_release": {"buttonevent": 3002}, "down-hold-release": {"buttonevent": 3002},"off_press": {"buttonevent": 4000} ,"off-press": {"buttonevent": 4000} }}, - "WXKG01LM": {"dataConversion": {"rootKey": "action", "single": {"buttonevent": 1001}, "double": {"buttonevent": 1002}, "triple": {"buttonevent": 1003}, "quadruple": {"buttonevent": 1004}, "hold": {"buttonevent": 2001}, "release": {"buttonevent": 2002}, "release": {"many": 2003}}}, - "Remote Control N2": {"dataConversion": {"rootKey": "action", "on": {"buttonevent": 1001}, "off": {"buttonevent": 2001}, "brightness_move_up": {"buttonevent": 1002}, "brightness_stop": {"buttonevent": 1003}, "brightness_move_down": {"buttonevent": 2002}, "arrow_left_click": {"buttonevent": 3002}, "arrow_right_click": {"many": 4002}}} - } + "TRADFRI remote control": { + "dataConversion": {"rootKey": "action", "toggle": {"buttonevent": 1002}, "arrow_right_click": {"buttonevent": 5002}, "arrow_right_hold": {"buttonevent": 5001}, "arrow_left_click": {"buttonevent": 4002}, "arrow_left_hold": {"buttonevent": 4001}, "brightness_up_click": {"buttonevent": 2002}, "brightness_up_hold": {"buttonevent": 2001}, "brightness_down_click": {"buttonevent": 3002}, "brightness_down_hold": {"buttonevent": 3001}, "brightness_up_release": {"buttonevent": 2003}, "brightness_down_release": {"buttonevent": 3003}, "arrow_left_release": {"buttonevent": 4003}, "arrow_right_release": {"buttonevent": 5003}}}, + "TRADFRI on/off switch": { + "dataConversion": {"rootKey": "click", "on": {"buttonevent": 1002}, "off": {"buttonevent": 2002}, "brightness_up": {"buttonevent": 1001}, "brightness_down": {"buttonevent": 2001}, "brightness_stop": {"buttonevent": 3001}}}, + "TRADFRI wireless dimmer": { + "dataConversion": {"rootKey": "action", "rotate_right_quick": {"buttonevent": 1002}, "rotate_right": {"buttonevent": 2002}, "rotate_left": {"buttonevent": 3002}, "rotate_left_quick": {"buttonevent": 4002}, "rotate_stop": {}, "": {}}}, + "RWL021": { + "dataConversion": {"rootKey": "action", "on_press": {"buttonevent": 1002}, "on-press": {"buttonevent": 1002}, "on_hold": {"buttonevent": 1001}, "on-hold": {"buttonevent": 1001}, "on_hold_release": {"buttonevent": 1003}, "on-hold-release": {"buttonevent": 1003}, "up_press": {"buttonevent": 2000}, "up_hold": {"buttonevent": 2001}, "up-hold": {"buttonevent": 2001}, "up_hold_release": {"buttonevent": 2002}, "up-hold-release": {"buttonevent": 2002}, "down_press": {"buttonevent": 3000}, "down-press": {"buttonevent": 3000}, "down_hold": {"buttonevent": 3001}, "down-hold": {"buttonevent": 3001}, "down_hold_release": {"buttonevent": 3002}, "down-hold-release": {"buttonevent": 3002}, "off_press": {"buttonevent": 4000}, "off-press": {"buttonevent": 4000}}}, + "WXKG01LM": {"dataConversion": {"rootKey": "action", "single": {"buttonevent": 1001}, "double": {"buttonevent": 1002}, "triple": {"buttonevent": 1003}, "quadruple": {"buttonevent": 1004}, "hold": {"buttonevent": 2001}, "release": {"buttonevent": 2002}, "release": {"many": 2003}}}, + "Remote Control N2": {"dataConversion": {"rootKey": "action", "on": {"buttonevent": 1001}, "off": {"buttonevent": 2001}, "brightness_move_up": {"buttonevent": 1002}, "brightness_stop": {"buttonevent": 1003}, "brightness_move_down": {"buttonevent": 2002}, "arrow_left_click": {"buttonevent": 3002}, "arrow_right_click": {"many": 4002}}}, + "Pushbutton transmitter module":{ + "dataConversion": {"rootKey": "action", "press_1": {"buttonevent": 1002}, "press_3": {"buttonevent": 2002}, "press_2": {"buttonevent": 1001}, "press_4": {"buttonevent": 2001}, "release_2": {"buttonevent": 3001}, "release_4": {"buttonevent": 3001}}}, + +} + # WXKG01LM MiJia wireless switch https://www.zigbee2mqtt.io/devices/WXKG01LM.html @@ -53,7 +58,7 @@ def longPressButton(sensor, buttonevent): sleep(1) while sensor.state["buttonevent"] == buttonevent: logging.info("still pressed") - current_time = datetime.now() + current_time = datetime.now() sensor.dxState["lastupdated"] = current_time rulesProcessor(sensor, current_time) sleep(0.5) @@ -82,11 +87,13 @@ def getObject(friendly_name): return False # Will get called zero or more times depending on how many lights are available for autodiscovery + + def on_autodiscovery_light(msg): data = json.loads(msg.payload) logging.info("Auto discovery message on: " + msg.topic) #logging.debug(json.dumps(data, indent=4)) - discoveredDevices[data['unique_id']] = data; + discoveredDevices[data['unique_id']] = data for key, data in discoveredDevices.items(): device_new = True for light, obj in bridgeConfig["lights"].items(): @@ -109,7 +116,7 @@ def on_autodiscovery_light(msg): modelid = None if light_color and light_ct: modelid = "LCT015" - elif light_color: # Every light as LCT001? Or also support other lights + elif light_color: # Every light as LCT001? Or also support other lights modelid = "LCT001" elif light_ct: modelid = "LTW001" @@ -117,16 +124,15 @@ def on_autodiscovery_light(msg): modelid = "LWB010" else: modelid = "LOM001" - protocol_cfg = { "uid": data["unique_id"], - "ip":"mqtt", - "state_topic": data["state_topic"], - "command_topic": data["command_topic"], - "mqtt_server": bridgeConfig["config"]["mqtt"]} + protocol_cfg = {"uid": data["unique_id"], + "ip": "mqtt", + "state_topic": data["state_topic"], + "command_topic": data["command_topic"], + "mqtt_server": bridgeConfig["config"]["mqtt"]} addNewLight(modelid, lightName, "mqtt", protocol_cfg) - def on_state_update(msg): logging.debug("MQTT: got state message on " + msg.topic) data = json.loads(msg.payload) @@ -134,10 +140,12 @@ def on_state_update(msg): logging.debug(json.dumps(data, indent=4)) # on_message handler (linked to client below) + + def on_message(client, userdata, msg): if bridgeConfig["config"]["mqtt"]["enabled"]: try: - current_time = datetime.now() + current_time = datetime.now() logging.debug("MQTT: got state message on " + msg.topic) data = json.loads(msg.payload) logging.debug(msg.payload) @@ -145,21 +153,31 @@ def on_message(client, userdata, msg): 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"]) + # Sensor is supported + if "model_id" in key and (key["model_id"] in standardSensors or key["model_id"] in motionSensors): + 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 + 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"]}) + 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"]) + 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": @@ -167,7 +185,8 @@ def on_message(client, userdata, msg): 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)) + 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 @@ -180,19 +199,23 @@ def on_message(client, userdata, msg): device.config["battery"] = data["battery"] if device.config["on"] == False: return - convertedPayload = {"lastupdated": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S")} + 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 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")} + 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")} + 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 + 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: @@ -200,11 +223,11 @@ def on_message(client, userdata, msg): lightPayload["lightlevel"] = hue_lightlevel elif lightSensor.protocol_cfg["lightSensor"] == "on": lightPayload["dark"] = not bridgeConfig["sensors"]["1"].state["daylight"] - if lightPayload["dark"]: + if lightPayload["dark"]: lightPayload["lightlevel"] = 6000 else: lightPayload["lightlevel"] = 25000 - else: # is always dark + else: # is always dark lightPayload["dark"] = True lightPayload["lightlevel"] = 6000 lightPayload["daylight"] = not lightPayload["dark"] @@ -213,18 +236,23 @@ def on_message(client, userdata, msg): 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()) + 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"]]]) + 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() + 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} @@ -241,36 +269,43 @@ def on_message(client, userdata, msg): except Exception as e: logging.info("MQTT Exception | " + str(e)) + def findLightSensor(sensor): lightSensorUID = sensor.uniqueid[:-1] + "0" for key, obj in bridgeConfig["sensors"].items(): if obj.uniqueid == lightSensorUID: return obj + def findTempSensor(sensor): lightSensorUID = sensor.uniqueid[:-1] + "2" for key, obj in bridgeConfig["sensors"].items(): if obj.uniqueid == lightSensorUID: return obj + def convertHexToMac(hexValue): - s = '{0:016x}'.format(int(hexValue,16)) + s = '{0:016x}'.format(int(hexValue, 16)) s = ':'.join(s[i:i + 2] for i in range(0, 16, 2)) return s # on_connect handler (linked to client below) + + def on_connect(client, userdata, flags, rc): logging.debug("Connected with result code "+str(rc)) # Subscribing in on_connect() means that if we lose the connection and # reconnect then subscriptions will be renewed. # Start autodetection on lights - autodiscoveryTopic = discoveryPrefix + "/light/+/light/config" # + in topic is wildcard + autodiscoveryTopic = discoveryPrefix + \ + "/light/+/light/config" # + in topic is wildcard client.subscribe(autodiscoveryTopic) client.subscribe("zigbee2mqtt/+") client.subscribe("zigbee2mqtt/bridge/devices") client.subscribe("zigbee2mqtt/bridge/log") + def mqttServer(): logging.info("Strting MQTT service...") @@ -278,7 +313,8 @@ def mqttServer(): # Set user/password on client if supplied if bridgeConfig["config"]["mqtt"]["mqttUser"] != "" and bridgeConfig["config"]["mqtt"]["mqttPassword"] != "": - client.username_pw_set(bridgeConfig["config"]["mqtt"]["mqttUser"],bridgeConfig["config"]["mqtt"]["mqttPassword"]) + client.username_pw_set( + bridgeConfig["config"]["mqtt"]["mqttUser"], bridgeConfig["config"]["mqtt"]["mqttPassword"]) if bridgeConfig["config"]["mqtt"]['discoveryPrefix'] is not None: discoveryPrefix = bridgeConfig["config"]["mqtt"]['discoveryPrefix'] @@ -286,7 +322,8 @@ def mqttServer(): client.on_connect = on_connect client.on_message = on_message # Connect to the server - client.connect(bridgeConfig["config"]["mqtt"]["mqttServer"], bridgeConfig["config"]["mqtt"]["mqttPort"]) + client.connect(bridgeConfig["config"]["mqtt"]["mqttServer"], + bridgeConfig["config"]["mqtt"]["mqttPort"]) # start the loop to keep receiving data client.loop_forever() From d8da4d243da214e051feb25401468fce42823723 Mon Sep 17 00:00:00 2001 From: Mevel <4347330+Mevel@users.noreply.github.com> Date: Fri, 1 Jul 2022 16:11:02 +0200 Subject: [PATCH 2/4] initial longpress support initial longpress support for GreenPower devices --- BridgeEmulator/sensors/sensor_types.py | 2 +- BridgeEmulator/services/mqtt.py | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/BridgeEmulator/sensors/sensor_types.py b/BridgeEmulator/sensors/sensor_types.py index 9c448dd97..fe6018067 100644 --- a/BridgeEmulator/sensors/sensor_types.py +++ b/BridgeEmulator/sensors/sensor_types.py @@ -11,4 +11,4 @@ sensorTypes["TRADFRI remote control"] = {"ZHASwitch": {"state": {"buttonevent": 1002, "lastupdated": "none"}, "config": {"alert": "none", "battery": 90, "on": True, "reachable": True}, "static": {"swversion": "1.2.214", "manufacturername": "IKEA of Sweden"}}} sensorTypes["TRADFRI on/off switch"] = {"ZHASwitch": {"state": {"buttonevent": 1002, "lastupdated": "none"}, "config": {"alert": "none", "battery": 90, "on": True, "reachable": True}, "static": {"swversion": "2.2.008", "manufacturername": "IKEA of Sweden"}}} sensorTypes["TRADFRI wireless dimmer"] = {"ZHASwitch": {"state": {"buttonevent": 1002, "lastupdated": "none"}, "config": {"alert": "none", "battery": 90, "on": True, "reachable": True}, "static": {"swversion": "1.2.248", "manufacturername": "IKEA of Sweden"}}} -sensorTypes["Pushbutton transmitter module"] = {"ZGPSwitch": {"state": {"buttonevent": 0, "lastupdated": "none"}, "config": {"on": True, "battery": 100, "reachable": True}, "static": {"manufacturername": "Signify Netherlands B.V.", "swversion": ""}}} \ No newline at end of file +sensorTypes["GreenPower_2"] = {"ZGPSwitch": {"state": {"buttonevent": 0, "lastupdated": "none"}, "config": {"on": True, "battery": 100, "reachable": True}, "static": {"manufacturername": "Signify Netherlands B.V.", "swversion": ""}}} \ No newline at end of file diff --git a/BridgeEmulator/services/mqtt.py b/BridgeEmulator/services/mqtt.py index 6e02119ce..70bf23990 100644 --- a/BridgeEmulator/services/mqtt.py +++ b/BridgeEmulator/services/mqtt.py @@ -39,8 +39,8 @@ "dataConversion": {"rootKey": "action", "on_press": {"buttonevent": 1002}, "on-press": {"buttonevent": 1002}, "on_hold": {"buttonevent": 1001}, "on-hold": {"buttonevent": 1001}, "on_hold_release": {"buttonevent": 1003}, "on-hold-release": {"buttonevent": 1003}, "up_press": {"buttonevent": 2000}, "up_hold": {"buttonevent": 2001}, "up-hold": {"buttonevent": 2001}, "up_hold_release": {"buttonevent": 2002}, "up-hold-release": {"buttonevent": 2002}, "down_press": {"buttonevent": 3000}, "down-press": {"buttonevent": 3000}, "down_hold": {"buttonevent": 3001}, "down-hold": {"buttonevent": 3001}, "down_hold_release": {"buttonevent": 3002}, "down-hold-release": {"buttonevent": 3002}, "off_press": {"buttonevent": 4000}, "off-press": {"buttonevent": 4000}}}, "WXKG01LM": {"dataConversion": {"rootKey": "action", "single": {"buttonevent": 1001}, "double": {"buttonevent": 1002}, "triple": {"buttonevent": 1003}, "quadruple": {"buttonevent": 1004}, "hold": {"buttonevent": 2001}, "release": {"buttonevent": 2002}, "release": {"many": 2003}}}, "Remote Control N2": {"dataConversion": {"rootKey": "action", "on": {"buttonevent": 1001}, "off": {"buttonevent": 2001}, "brightness_move_up": {"buttonevent": 1002}, "brightness_stop": {"buttonevent": 1003}, "brightness_move_down": {"buttonevent": 2002}, "arrow_left_click": {"buttonevent": 3002}, "arrow_right_click": {"many": 4002}}}, - "Pushbutton transmitter module":{ - "dataConversion": {"rootKey": "action", "press_1": {"buttonevent": 1002}, "press_3": {"buttonevent": 2002}, "press_2": {"buttonevent": 1001}, "press_4": {"buttonevent": 2001}, "release_2": {"buttonevent": 3001}, "release_4": {"buttonevent": 3001}}}, + "GreenPower_2":{ + "dataConversion": {"rootKey": "action", "press_1": {"buttonevent": 1002}, "longpress_1": {"buttonevent": 1001}, "press_2": {"buttonevent": 2002}, "longpress_2": {"buttonevent": 2001}, "press_3": {"buttonevent": 3002}, "longpress_3": {"buttonevent": 3001}, "press_4": {"buttonevent": 4002}, "longpress_4": {"buttonevent": 4001}, "release_1": {"buttonevent": 1003}, "release_2": {"buttonevent": 2003}, "release_3": {"buttonevent": 3003}, "release_4": {"buttonevent": 4003}}}, } @@ -64,6 +64,21 @@ def longPressButton(sensor, buttonevent): sleep(0.5) return +def longPressGreenPower(sensor): + print("running.....") + logging.info("detecting long press") + sleep(1) + initialButton = sensor.state["buttonevent"] + while sensor.state["buttonevent"] not in [1003, 2003, 3003, 4003]: # not released yet + logging.info("still pressed") + current_time = datetime.now() + sensor.dxState["lastupdated"] = current_time + sensor.state["buttonevent"] = initialButton - 1 + rulesProcessor(sensor, current_time) + sleep(0.5) + return + + def getObject(friendly_name): if friendly_name in devices_ids: @@ -253,6 +268,10 @@ def on_message(client, userdata, msg): if "buttonevent" in convertedPayload and convertedPayload["buttonevent"] in [1001, 2001, 3001, 4001, 5001]: Thread(target=longPressButton, args=[ device, convertedPayload["buttonevent"]]).start() + if (device.modelid in standardSensors and device.modelid == "GreenPower_2" and convertedPayload["buttonevent"] in [1002, 2002, 3002, 4002]): # initial button click + Thread(target=longPressGreenPower, args=[ + device, convertedPayload["buttonevent"]]).start() + return rulesProcessor(device, current_time) elif device.getObjectPath()["resource"] == "lights": state = {"reachable": True} From 6d315a2a9120ebe3a50a833898bf8dfb22f7d235 Mon Sep 17 00:00:00 2001 From: Mevel <4347330+Mevel@users.noreply.github.com> Date: Fri, 8 Jul 2022 13:18:20 +0200 Subject: [PATCH 3/4] start implement senic friends of hue emulation --- BridgeEmulator/sensors/sensor_types.py | 86 +++++++++++++++++++++++++- BridgeEmulator/services/mqtt.py | 45 +++++++++++--- 2 files changed, 123 insertions(+), 8 deletions(-) diff --git a/BridgeEmulator/sensors/sensor_types.py b/BridgeEmulator/sensors/sensor_types.py index fe6018067..d1056d7dc 100644 --- a/BridgeEmulator/sensors/sensor_types.py +++ b/BridgeEmulator/sensors/sensor_types.py @@ -11,4 +11,88 @@ sensorTypes["TRADFRI remote control"] = {"ZHASwitch": {"state": {"buttonevent": 1002, "lastupdated": "none"}, "config": {"alert": "none", "battery": 90, "on": True, "reachable": True}, "static": {"swversion": "1.2.214", "manufacturername": "IKEA of Sweden"}}} sensorTypes["TRADFRI on/off switch"] = {"ZHASwitch": {"state": {"buttonevent": 1002, "lastupdated": "none"}, "config": {"alert": "none", "battery": 90, "on": True, "reachable": True}, "static": {"swversion": "2.2.008", "manufacturername": "IKEA of Sweden"}}} sensorTypes["TRADFRI wireless dimmer"] = {"ZHASwitch": {"state": {"buttonevent": 1002, "lastupdated": "none"}, "config": {"alert": "none", "battery": 90, "on": True, "reachable": True}, "static": {"swversion": "1.2.248", "manufacturername": "IKEA of Sweden"}}} -sensorTypes["GreenPower_2"] = {"ZGPSwitch": {"state": {"buttonevent": 0, "lastupdated": "none"}, "config": {"on": True, "battery": 100, "reachable": True}, "static": {"manufacturername": "Signify Netherlands B.V.", "swversion": ""}}} \ No newline at end of file +sensorTypes["GreenPower_2"] = {"ZHASwitch": {"state": {"buttonevent": 0, "lastupdated": "none"}, "config": {"on": True, "battery": 100, "reachable": True}, "static": {"manufacturername": "Signify Netherlands B.V.", "swversion": ""}}} +#sensorTypes["GreenPower_2"] = {"FOHSwitch": {"state": {"buttonevent": 0, "lastupdated": "none"}, "config": {"on": True, "battery": 100, "reachable": True}, "static": {"manufacturername": "Signify Netherlands B.V.", "swversion": ""}}} + + + + +# { +# "state": { +# "buttonevent": 21, +# "lastupdated": "2022-06-27T13:55:33" +# }, +# "swupdate": { +# "state": "notupdatable", +# "lastinstall": null +# }, +# "config": { +# "on": true +# }, +# "name": "Friends of Hue Switch 1", +# "type": "ZGPSwitch", +# "modelid": "FOHSWITCH", +# "manufacturername": "PhilipsFoH", +# "productname": "Friends of Hue Switch", +# "diversityid": "ded6468f-6b26-4a75-9582-f2b52d36a5a3", +# "uniqueid": "00:00:00:00:01:70:10:9f-f2", +# "capabilities": { +# "certified": true, +# "primary": true, +# "inputs": [ +# { +# "repeatintervals": [], +# "events": [ +# { +# "buttonevent": 16, #Top Left +# "eventtype": "initial_press" +# }, +# { +# "buttonevent": 20, +# "eventtype": "short_release" +# } +# ] +# }, +# { +# "repeatintervals": [], +# "events": [ +# { +# "buttonevent": 17, #Bottom Left +# "eventtype": "initial_press" +# }, +# { +# "buttonevent": 21, +# "eventtype": "short_release" +# } +# ] +# }, +# { +# "repeatintervals": [], +# "events": [ +# { +# "buttonevent": 19, #Top Right +# "eventtype": "initial_press" +# }, +# { +# "buttonevent": 23, +# "eventtype": "short_release" +# } +# ] +# }, +# { +# "repeatintervals": [], +# "events": [ +# { +# "buttonevent": 18, #Bottom Right +# "eventtype": "initial_press" +# }, +# { +# "buttonevent": 22, +# "eventtype": "short_release" +# } +# ] +# } +# ] +# } +# } + diff --git a/BridgeEmulator/services/mqtt.py b/BridgeEmulator/services/mqtt.py index 70bf23990..82b80c0c6 100644 --- a/BridgeEmulator/services/mqtt.py +++ b/BridgeEmulator/services/mqtt.py @@ -1,3 +1,4 @@ +from sqlalchemy import false, true import logManager import configManager import json @@ -41,6 +42,8 @@ "Remote Control N2": {"dataConversion": {"rootKey": "action", "on": {"buttonevent": 1001}, "off": {"buttonevent": 2001}, "brightness_move_up": {"buttonevent": 1002}, "brightness_stop": {"buttonevent": 1003}, "brightness_move_down": {"buttonevent": 2002}, "arrow_left_click": {"buttonevent": 3002}, "arrow_right_click": {"many": 4002}}}, "GreenPower_2":{ "dataConversion": {"rootKey": "action", "press_1": {"buttonevent": 1002}, "longpress_1": {"buttonevent": 1001}, "press_2": {"buttonevent": 2002}, "longpress_2": {"buttonevent": 2001}, "press_3": {"buttonevent": 3002}, "longpress_3": {"buttonevent": 3001}, "press_4": {"buttonevent": 4002}, "longpress_4": {"buttonevent": 4001}, "release_1": {"buttonevent": 1003}, "release_2": {"buttonevent": 2003}, "release_3": {"buttonevent": 3003}, "release_4": {"buttonevent": 4003}}}, + # "GreenPower_2":{ + # "dataConversion": {"rootKey": "action", "press_1": {"buttonevent": 16}, "release_1": {"buttonevent": 20}, "press_2": {"buttonevent": 19}, "release_2": {"buttonevent": 23}, "press_3": {"buttonevent": 17}, "release_3": {"buttonevent": 21},"press_4": {"buttonevent": 17}, "release_4": {"buttonevent": 21}}}, } @@ -64,19 +67,47 @@ def longPressButton(sensor, buttonevent): sleep(0.5) return -def longPressGreenPower(sensor): - print("running.....") +def longPressGreenPower(sensor, buttonevent): + count = 0 # iterate to stay below (count * sleep(seconds) < 7 Seconds) to prevent pairing mode via longpress + maxCount = 10 + logging.debug("running.....") logging.info("detecting long press") - sleep(1) - initialButton = sensor.state["buttonevent"] - while sensor.state["buttonevent"] not in [1003, 2003, 3003, 4003]: # not released yet + sleep(1) + global longpressDetected + longpressDetected = False + while sensor.state["buttonevent"] not in [1003, 2003, 3003, 4003] and count <= maxCount: # current state not released and button not pressed for longer than 7 sec. + mState = sensor.state["buttonevent"] logging.info("still pressed") + longpressDetected = True current_time = datetime.now() sensor.dxState["lastupdated"] = current_time - sensor.state["buttonevent"] = initialButton - 1 + sensor.state["buttonevent"] = buttonevent - 1 rulesProcessor(sensor, current_time) + + if mState in [1003, 2003, 3003, 4003]: + return + count += 1 sleep(0.5) - return + + + if(not longpressDetected): + current_time = datetime.now() + sensor.dxState["lastupdated"] = current_time + sensor.state["buttonevent"] = buttonevent + rulesProcessor(sensor, current_time) + current_time = datetime.now() + sensor.dxState["lastupdated"] = current_time + sensor.state["buttonevent"] = buttonevent + 1 #send release codes + rulesProcessor(sensor, current_time) + + + if(count == maxCount): # Set state to released + current_time = datetime.now() + sensor.dxState["lastupdated"] = current_time + sensor.state["buttonevent"] = buttonevent + 2 + rulesProcessor(sensor, current_time) + + return From b7ed1727cc2e08647fbe58d53256a3a97b2eb105 Mon Sep 17 00:00:00 2001 From: Jessica Simian Date: Tue, 17 Oct 2023 16:10:47 +0100 Subject: [PATCH 4/4] Adds support for LCX006 --- BridgeEmulator/HueObjects/__init__.py | 15 ++++++++------- BridgeEmulator/lights/light_types.py | 9 +++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/BridgeEmulator/HueObjects/__init__.py b/BridgeEmulator/HueObjects/__init__.py index 7fc10c684..a382e5801 100644 --- a/BridgeEmulator/HueObjects/__init__.py +++ b/BridgeEmulator/HueObjects/__init__.py @@ -479,7 +479,8 @@ def getBridgeHome(self): def getV2Api(self): result = {} result["alert"] = {"action_values": ["breathe"]} - if self.modelid in ["LCX002", "915005987201", "LCX004"]: + # gradient lights + if self.modelid in ["LCX002", "915005987201", "LCX004", "LCX006"]: result["effects"] = { "effect_values": [ "no_effect", @@ -497,7 +498,7 @@ def getV2Api(self): "points_capable": self.protocol_cfg["points_capable"]} # color lights only - if self.modelid in ["LST002", "LCT001", "LCT015", "LCX002", "915005987201", "LCX004"]: + if self.modelid in ["LST002", "LCT001", "LCT015", "LCX002", "915005987201", "LCX004", "LCX006"]: colorgamut = lightTypes[self.modelid]["v1_static"]["capabilities"]["control"]["colorgamut"] result["color"] = { "gamut": { @@ -587,7 +588,7 @@ def getV2Entertainment(self): "length": 2, "start": 18 }] - elif self.modelid in ["915005987201", "LCX004"]: + elif self.modelid in ["915005987201", "LCX004", "LCX006"]: result["segments"]["max_segments"] = 10 result["segments"]["segments"] = [ { @@ -622,11 +623,11 @@ def dynamicScenePlay(self, palette, index): while self.dynamics["status"] == "dynamic_palette": transition = int(30 / self.dynamics["speed"]) logging.debug("using transistiontime " + str(transition)) - if self.modelid in ["LCT001", "LCT015", "LST002", "LCX002", "915005987201", "LCX004"]: + if self.modelid in ["LCT001", "LCT015", "LST002", "LCX002", "915005987201", "LCX004", "LCX006"]: if index == len(palette["color"]): index = 0 points = [] - if self.modelid in ["LCX002", "915005987201", "LCX004"]: + if self.modelid in ["LCX002", "915005987201", "LCX004", "LCX006"]: gradientIndex = index # for gradient lights for x in range(self.protocol_cfg["points_capable"]): @@ -843,7 +844,7 @@ def getV2Api(self): gradientStrip = False if light().modelid in ["LCX001", "LCX002", "LCX003"]: loops = len(gradienStripPositions) - elif light().modelid in ["915005987201", "LCX004"]: + elif light().modelid in ["915005987201", "LCX004", "LCX006"]: loops = 3 for x in range(loops): channel = { @@ -860,7 +861,7 @@ def getV2Api(self): } if light().modelid in ["LCX001", "LCX002", "LCX003"]: channel["position"] = {"x": gradienStripPositions[x]["x"], "y": gradienStripPositions[x]["y"], "z": gradienStripPositions[x]["z"]} - elif light().modelid in ["915005987201", "LCX004"]: + elif light().modelid in ["915005987201", "LCX004", "LCX006"]: if x == 0: channel["position"] = {"x": self.locations[light()][0]["x"], "y": self.locations[light()][0]["y"], "z": self.locations[light()][0]["z"]} elif x == 2: diff --git a/BridgeEmulator/lights/light_types.py b/BridgeEmulator/lights/light_types.py index 6e0de4888..c0ed6d450 100644 --- a/BridgeEmulator/lights/light_types.py +++ b/BridgeEmulator/lights/light_types.py @@ -73,6 +73,15 @@ lightTypes["LCX004"]["config"] = {"archetype": "huelightstrip", "function": "mixed", "direction": "omnidirectional","startup": {"mode": "safety","configured": False}} lightTypes["LCX004"]["dynamics"] = {"speed": 0, "speed_valid": False, "status": "none", "status_values": ["none", "dynamic_palette"]} +# Hue Play Gradient Lightstrip for PC +lightTypes["LCX006"] = {"v1_static": {"type": "Extended color light", "manufacturername": "Signify Netherlands B.V.", "productname": "Hue gradient lightstrip","swversion": "1.94.2","swconfigid": "DC0A18AF","productid": "4422-9482-0441_HG01_PSU03"}} +lightTypes["LCX006"]["v1_static"]["swupdate"] = {"state": "noupdates","lastinstall": "2022-01-13T22:54:51"} +lightTypes["LCX006"]["v1_static"]["capabilities"] = {"certified": True,"control": {"mindimlevel": 100,"maxlumen": 1600,"colorgamuttype": "C","colorgamut": [[0.6915,0.3083],[0.1700,0.7000],[0.1532,0.0475]],"ct": {"min": 153,"max": 500}},"streaming": {"renderer": True,"proxy": True}} +lightTypes["LCX006"]["device"] = {"certified": True,"hardware_platform_type": "100b-118","manufacturer_name": "Signify Netherlands B.V.","model_id": "LCX004","product_archetype": "hue_lightstrip","product_name": "Hue gradient lightstrip","software_version": "1.94.2"} +lightTypes["LCX006"]["state"] = {"on": False, "bri": 254,"hue": 8417,"sat": 140,"effect": "none","xy": [0.0,0.0],"ct": 366,"alert": "select","colormode": "ct","mode": "homeautomation","reachable": True, "gradient": {"points": []}} +lightTypes["LCX006"]["config"] = {"archetype": "huelightstrip", "function": "mixed", "direction": "omnidirectional","startup": {"mode": "safety","configured": False}} +lightTypes["LCX006"]["dynamics"] = {"speed": 0, "speed_valid": False, "status": "none", "status_values": ["none", "dynamic_palette"]} + ## Hue Plug lightTypes["LOM001"] = {"v1_static": {"type": "On/Off plug-in unit","manufacturername": "Signify Netherlands B.V.","productname": "Hue Smart plug","swversion": "1.90.1","swconfigid": "A641B5AB","productid": "SmartPlug_OnOff_v01-00_01"}} lightTypes["LOM001"]["v1_static"]["swupdate"] = {"state": "noupdates","lastinstall": "2020-12-09T19:13:52"}