Прикручиваем датчики Zigbee к домотикзу в обход Xiaomi шлюза


Порядок действий:

0. Хорошенько думаем, надо ли оно нам
1. Покупаем "железо"
2. Прошиваем CC2531
3. Устанавливаем софт передающий состояния ZegBee датчиков в MQTT
4. Привязываем устройства
5. Устанавливаем Node-RED
6. Настраиваем взаимодействие MQTT  >>>  Domoticz

Приступим...

0. Хорошенько думаем, надо ли оно нам

Похоже что датчики нельзя привязать одновременно к шлюзу Xiaomi и "юсб-свистку". Либо там, либо там. Это сильно печалит, так-как нет возможности дублирования систем. С другой стороны, эта система может выйти в два раза дешевле шлюза (если брать уже прошитый СС2531)

1. Покупаем "железо"


Что требуется из устройств (помимо Raspberry):

1. юсб-свисток USB dongle CC2531 (БЕЗ ШЛЕЙФА!!! Если будете брать программатор, то и шлейф будет обязательно нужен!)
2. программатор CC Debugger
3. Шлейф-переходник (и там же можно взять и модуль CC2531)

Всё можно приобрести на алиэкспресс. Это не реклама, но я покупал там, и всё пришло целое и работоспособное.




2. Прошиваем CC2531


По инструкции прошиваем юсб-свисток.
С прошивкой проблем быть вообще не должно. Всех делов на минуту. Цитирую:
Нужно установить прошивальщик и скачать прошивку. Процесс прошивки очень быстрый — несколько секунд

3. Устанавливаем софт передающий состояния ZegBee датчиков в MQTT


После прошивки, устанавливаем zigbee2mqtt или xiaomi-zb2mqtt или AqaraHub 

Рекомендую zigbee2mqtt - в ней самые удобные сообщения с которыми наиболее легко работать в Node-Red.

В xiaomi-zb2mqtt - не работает одиночный клик кнопки (возможно что-то еще, но на этом я остановил "знакомство" с этой библиотекой)

AqaraHub - шлет слишком замудрённые сообщения, и как-то странно работает с датчиком движения и датчиком открытия дверей (нужно долго копаться и разбираться), но при этом, здесь самое удобное сопряжение устройств.

4. Привязываем устройства


zigbee2mqtt

Привязка датчика по инструкции:
1. Останавливаем службу и Запускаем сервер
# Остановка zigbee2mqtt
sudo systemctl stop zigbee2mqtt
cd /opt/zigbee2mqtt
npm start
2. Зажимаем кнопку на 5 секунд (скрепкой), датчик мигнет синим, далее в течении минуты (до окончания отсчета) нажимаем на кнопку раз в 2-3 секунды.

В консоли при этом должно быть что-то такое (датчик движения):
spinlock: false []
2018-7-27 17:44:26 INFO New device with address 0x004357865746363 connected!
2018-7-27 17:44:26 INFO MQTT publish, topic: 'zigbee2mqtt/bridge/log', payload: '{"type":"device_connected","message":"0x004357865746363"}'
2018-7-27 17:44:34 INFO MQTT publish, topic: 'zigbee2mqtt/0x004357865746363', payload: '{"occupancy":true}'
2018-7-27 17:44:46 INFO MQTT publish, topic: 'zigbee2mqtt/0x004357865746363', payload: '{"occupancy":true}'
2018-7-27 17:44:51 INFO MQTT publish, topic: 'zigbee2mqtt/0x004357865746363', payload: '{"occupancy":true}'
2018-7-27 17:45:19 INFO Device incoming...
2018-7-27 17:45:19 INFO MQTT publish, topic: 'zigbee2mqtt/bridge/log', payload: '{"type":"pairing","message":"device incoming"}'
2018-7-27 17:45:51 INFO MQTT publish, topic: 'zigbee2mqtt/0x004357865746363', payload: '{"occupancy":false}'

xiaomi-zb2mqtt

Привязка датчика по инструкции:
1. Запускаем сервер
cd xiaomi-zb2mqtt
node index.js
2. Зажимаем кнопку на 5 секунд (скрепкой), датчик мигнет синим, далее в течении минуты (до окончания отсчета) нажимаем на кнопку раз в 2-3 секунды.

Результат: библиотека xiaomi-zb2mqtt - видит датчик движения, при обнаружении движения в консоли выводит:
attreport: 0x0012340001234567 260 1 { cid: 'msOccupancySensing', data: { occupancy: 1 } }
MQTT Reporting to  xiaomiZb/0012340001234567/occupancy  value  1
Кнопка привязалась без проблем, но библиотека не отсылает в MQTT чат сообщение о одиночном клике, зато отсылает двойной, тройной и долгий клик.

AqaraHub

Привязка датчика по инструкции:
1. Запускаем сервер
cd /home/pi/AqaraHub/build
./AqaraHub --port /dev/ttyACM0 --mqtt mqtt://localhost:1883/ --topic AqaraHub
2. Включаем режим сопряжения (в другой консоли отправляем в чат MQTT команду):
mosquitto_pub -h localhost -t AqaraHub/write/permitjoin -m 60
3. Зажимаем кнопку на 5 секунд (скрепкой), датчик мигнет синим, ждем.

5. Устанавливаем Node-RED


Как установить Node-RED я описывал здесь: https://digitallez.blogspot.com/2018/07/node-red.html

6. Настраиваем взаимодействие MQTT  >>>  Domoticz

Пример сценария можно взять тут: 4pda.ru

Мои примеры для всех трех библиотек выкладываю ниже.
Прошу обратить внимание:
а) В ноде switch нужно проставить реальные идентификаторы своих устройств (их видно во время сопряжения, и они имеют приблизительно такой вид: 0x004357865746363)

б) В нодах следующих сразу после switch вам нужно будет правильно указать idx ваших устройств (из домотикза).
в) Также не забываем, при добавлении своих устройств, правильно выставлять тип устройства.



Мой сценарий для zigbee2mqtt в Node-RED (он более универсален примера с 4pda):
 [{"id":"5ca46b4e.bd1454","type":"tab","label":"zigbee2mqtt","disabled":false,"info":""},{"id":"5f8a6919.56bec8","type":"mqtt in","z":"5ca46b4e.bd1454","name":"zigbee2mqtt","topic":"zigbee2mqtt/#","qos":"2","broker":"10ea5265.66934e","x":70,"y":20,"wires":[["5459e3c9.02bc6c","b90a775d.ed1ee8"]]},{"id":"e1f6a436.2f8268","type":"inject","z":"5ca46b4e.bd1454","name":"MotionHall_OFF","topic":"","payload":"{ \"idx\" : 18, \"nvalue\" : 0}","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":600,"y":60,"wires":[["f0d3109b.52f4a"]]},{"id":"f0d3109b.52f4a","type":"mqtt out","z":"5ca46b4e.bd1454","name":"domoticz/in","topic":"domoticz/in","qos":"2","retain":"","broker":"10ea5265.66934e","x":770,"y":200,"wires":[]},{"id":"815d9097.0182d","type":"inject","z":"5ca46b4e.bd1454","name":"MotionHall_ON","topic":"","payload":"{ \"idx\" : 18, \"nvalue\" : 1}","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":600,"y":20,"wires":[["f0d3109b.52f4a"]]},{"id":"c8501461.be6658","type":"function","z":"5ca46b4e.bd1454","name":"GetStatus","func":"if (msg.topic == \"zigbee2mqtt/bridge/state\" && msg.payload == \"offline\") {\n    msg.idx = null;\n    node.status({text: \"zigbee2mqtt state OFFLINE\"});\n    return msg;\n}\n\n// -----------------------------------------------------------------------------\n\nif(msg.DeviceType == \"Button\") {\n    \n    node.status({text: \"Button msg.payload: \" + msg.payload.click});\n    \n    if (msg.payload.click == \"single\") {\n        node.status({text: \"Кнопка: одиночный клик; idx=\" + msg.idx});\n        return {payload:{command: \"switchlight\", idx: msg.idx, switchcmd: \"Set Level\", level:10}};\n    }\n    else if (msg.payload.click == \"double\") {\n        node.status({text: \"Кнопка: двойной клик; idx=\" + msg.idx});\n        return {payload:{command: \"switchlight\", idx: msg.idx, switchcmd: \"Set Level\", level:20}};\n    }\n    else if (msg.payload.click == \"long\") {\n        node.status({text: \"Кнопка: длинный клик; idx=\" + msg.idx});\n        return {payload:{command: \"switchlight\", idx: msg.idx, switchcmd: \"Set Level\", level:30}};\n    }\n    else if (msg.payload.click == \"long_release\") {\n        node.status({text: \"Кнопка: отпущен длинный клик; idx=\" + msg.idx});\n        return {payload:{command: \"switchlight\", idx: msg.idx, switchcmd: \"Set Level\", level:40}};\n    }\n}\n\n// -----------------------------------------------------------------------------\n\nif(msg.DeviceType == \"Motion\") {\n    \n    isNewValue = false;\n    \n    if (typeof context.occupancy === 'undefined') {\n        context.occupancy = [];\n        context.occupancy[msg.idx] = -1;\n    }\n    \n    if (typeof msg.payload.occupancy !== 'undefined') {\n        if(msg.payload.occupancy) {\n            if (context.occupancy[msg.idx] != 1) {\n                context.occupancy[msg.idx] = 1;\n                isNewValue = true;\n            }\n        }\n        else if(!msg.payload.occupancy) {\n            if (context.occupancy[msg.idx] !== 0) {\n                context.occupancy[msg.idx] = 0;\n                isNewValue = true;\n            }\n        }\n    }\n        \n    if (isNewValue) {\n        node.status({text: \"Наличие движения: \" + context.occupancy[msg.idx] + \"; idx=\" + msg.idx});\n        return {payload:{ idx: msg.idx , nvalue:context.occupancy[msg.idx]}};\n    }\n}\n\n// -----------------------------------------------------------------------------\n\nif(msg.DeviceType == \"Door\") {\n    \n    if(msg.payload.contact) {\n        node.status({text: \"Дверь: открыта; idx=\" + msg.idx});\n        return {payload:{ idx: msg.idx , nvalue:0}};\n    }\n    else {\n        node.status({text: \"Дверь: закрыта; idx=\" + msg.idx});\n        return {payload:{ idx: msg.idx , nvalue:1}};\n    }\n}\n\n// -----------------------------------------------------------------------------\n\nif(msg.DeviceType == \"Temp\") {\n    \n    //isNewValue = false;\n    \n    if (typeof context.temperature === 'undefined') {\n        context.temperature = [];\n        context.temperature[msg.idx] = 0;\n    }\n    \n    if (typeof context.humidity === 'undefined') {\n        context.humidity = [];\n        context.humidity[msg.idx] = 0;\n    }\n    \n    if (typeof msg.payload.temperature !== 'undefined') {\n        context.temperature[msg.idx] = msg.payload.temperature;\n        isNewValue = true;\n    }\n    if (typeof msg.payload.humidity !== 'undefined') {\n        context.humidity[msg.idx] = msg.payload.humidity;\n        isNewValue = true;\n    }\n    \n    if (isNewValue && context.temperature[msg.idx] !== 0 && context.humidity[msg.idx] !== 0) \n    {\n        node.status({text: \"температура: \" + context.temperature[msg.idx] + \"°С, влажность: \" +  context.humidity[msg.idx] + \"%; idx=\" + msg.idx});\n        return {payload:{ idx: msg.idx , nvalue:0, svalue:context.temperature[msg.idx] +\";\"+ context.humidity[msg.idx] +\";1\"}};\n    }\n}\n\n// -----------------------------------------------------------------------------\n\nmsg.idx = null;\nnode.status(\"Сообщение не обработано\");\nreturn msg;","outputs":1,"noerr":0,"x":440,"y":240,"wires":[["25b8f04f.f0d5e"]]},{"id":"25b8f04f.f0d5e","type":"switch","z":"5ca46b4e.bd1454","name":"IsIdxFound","property":"payload.idx","propertyType":"msg","rules":[{"t":"nnull"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":610,"y":240,"wires":[["f0d3109b.52f4a"],["9e349af0.0d1478"]]},{"id":"a4bc054f.0ca0c8","type":"switch","z":"5ca46b4e.bd1454","name":"","property":"topic","propertyType":"msg","rules":[{"t":"cont","v":"0x00158d0001","vt":"str"},{"t":"cont","v":"0x00158d0002","vt":"str"},{"t":"cont","v":"0x00158d0003","vt":"str"},{"t":"cont","v":"0x00158d0004","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":5,"x":90,"y":220,"wires":[["e654f585.8e0568"],["e91b72fc.e516b"],["aa65f4c2.e26d58"],["d761fd7b.fd2c2"],["3a71a203.b4692e"]]},{"id":"e654f585.8e0568","type":"change","z":"5ca46b4e.bd1454","name":"MotionHall","rules":[{"t":"set","p":"idx","pt":"msg","to":"18","tot":"num"},{"t":"set","p":"DeviceType","pt":"msg","to":"Motion","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":250,"y":120,"wires":[["c8501461.be6658"]]},{"id":"e91b72fc.e516b","type":"change","z":"5ca46b4e.bd1454","name":"TempHall","rules":[{"t":"set","p":"idx","pt":"msg","to":"21","tot":"num"},{"t":"set","p":"DeviceType","pt":"msg","to":"Temp","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":240,"y":160,"wires":[["c8501461.be6658"]]},{"id":"aa65f4c2.e26d58","type":"change","z":"5ca46b4e.bd1454","name":"ButtonHall","rules":[{"t":"set","p":"idx","pt":"msg","to":"13","tot":"num"},{"t":"set","p":"DeviceType","pt":"msg","to":"Button","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":250,"y":200,"wires":[["c8501461.be6658"]]},{"id":"d4c961cf.ed93b","type":"json","z":"5ca46b4e.bd1454","name":"","property":"payload","action":"","pretty":false,"x":370,"y":60,"wires":[["a4bc054f.0ca0c8"]]},{"id":"b90a775d.ed1ee8","type":"debug","z":"5ca46b4e.bd1454","name":"Input","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":230,"y":20,"wires":[]},{"id":"5459e3c9.02bc6c","type":"switch","z":"5ca46b4e.bd1454","name":"IsJson","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"{","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":230,"y":60,"wires":[["d4c961cf.ed93b"]]},{"id":"d761fd7b.fd2c2","type":"change","z":"5ca46b4e.bd1454","name":"Door","rules":[{"t":"set","p":"idx","pt":"msg","to":"10","tot":"num"},{"t":"set","p":"DeviceType","pt":"msg","to":"Door","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":230,"y":240,"wires":[["c8501461.be6658"]]},{"id":"8aa01d85.957c6","type":"inject","z":"5ca46b4e.bd1454","name":"","topic":"zigbee2mqtt/0x00158d0006","payload":"{\"battery\":\"100.00\",\"voltage\":3025,\"temperature\":24.22,\"humidity\":42.96}","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":80,"wires":[["5459e3c9.02bc6c"]]},{"id":"3a71a203.b4692e","type":"debug","z":"5ca46b4e.bd1454","name":"ID not found","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":250,"y":320,"wires":[]},{"id":"9e349af0.0d1478","type":"debug","z":"5ca46b4e.bd1454","name":"GetStatus error","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":780,"y":280,"wires":[]},{"id":"10ea5265.66934e","type":"mqtt-broker","z":"","name":"MQTT-localhost","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]


Для xiaomi-zb2mqtt я сценарий не стал дописывать (бросил эту затею), в связи с тем, что библиотека не очень хорошо работает:

 [{"id":"b0a56543.2ed988","type":"tab","label":"xiaomiZb","disabled":false,"info":""},{"id":"c9af0ae3.ec1f08","type":"mqtt in","z":"b0a56543.2ed988","name":"xiaomiZb","topic":"xiaomiZb/#","qos":"2","broker":"10ea5265.66934e","x":96.0173568725586,"y":37.010414123535156,"wires":[["4c979f06.98101"]]},{"id":"4c979f06.98101","type":"switch","z":"b0a56543.2ed988","name":"","property":"topic","propertyType":"msg","rules":[{"t":"cont","v":"00158d0001","vt":"str"},{"t":"cont","v":"00158d0002","vt":"str"},{"t":"cont","v":"00158d0003","vt":"str"},{"t":"cont","v":"00158d0004","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":138.01734924316406,"y":105.01040935516357,"wires":[["8196597f.b2d548"],["46959b62.5d4374"],["24d7d147.85eabe"],["129c1869.bfa7d8"]]},{"id":"24d7d147.85eabe","type":"change","z":"b0a56543.2ed988","name":"ButtonHall","rules":[{"t":"set","p":"idx","pt":"msg","to":"13","tot":"num"},{"t":"set","p":"DeviceType","pt":"msg","to":"Button","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":297.0173454284668,"y":115.0103874206543,"wires":[["87773d65.e12fa"]]},{"id":"87773d65.e12fa","type":"function","z":"b0a56543.2ed988","name":"GetStatus","func":"if(msg.DeviceType == \"Button\" && msg.payload == \"true\") {\n    if(msg.topic.indexOf(\"/click\") > 0)\n        context.level = 10;\n    else if(msg.topic.indexOf(\"/double_click\") > 0)\n        context.level = 20;\n    else if(msg.topic.indexOf(\"/long_click\") > 0)\n        context.level = 30;\n    \n        \n    node.status({text: \"Button level: \" + context.level});\n    \n        \n    if (context.level !== null && context.level !== undefined)\n        return {payload:{command: \"switchlight\", idx: msg.idx, switchcmd: \"Set Level\", level:context.level}};\n}\n\nif(msg.DeviceType == \"Motion\") {\n    \n    if(msg.topic.indexOf(\"/occupancy\") > 0) {\n        if(msg.payload == \"true\") {\n            node.status({text: \"Двежение: обнаружено; idx=\" + msg.idx});\n            return {payload:{ idx: msg.idx , nvalue:1}};\n        }\n        else if(msg.payload == \"false\") {\n            node.status({text: \"Двежение: нет; idx=\" + msg.idx});\n            return {payload:{ idx: msg.idx , nvalue:0}};\n        }\n        else if(msg.payload == \"0\") {\n            return {};\n        }\n    }\n    \n    node.status({text: \"Двежение: показания не распознаны\"});\n}\n\nif(msg.DeviceType == \"Door\") {\n    if(msg.topic.indexOf(\"/contact\") > 0) {\n        if(msg.payload == \"true\") {\n            node.status({text: \"Дверь: открыта; idx=\" + msg.idx});\n            return {payload:{ idx: msg.idx , nvalue:1}};\n        }\n        else if(msg.payload == \"false\") {\n            node.status({text: \"Дверь: закрыта; idx=\" + msg.idx});\n            return {payload:{ idx: msg.idx , nvalue:0}};\n        }\n        \n        context.contact = msg.payload;\n    }\n    \n    node.status({text: \"Дверь: показания не распознаны\"});\n}\n\n\n\n\nif(msg.DeviceType == \"Temp\") {\n    if(msg.topic.indexOf(\"/temperature\") > 0) {\n        context.temperature = msg.payload;\n        node.status({text: \"температура: \" + context.temperature + \"°С\"});\n        return {payload:{ idx: msg.idx , nvalue:0, svalue:context.temperature+\";0;1\"}};\n    }\n    if(msg.topic.indexOf(\"/humidity\") > 0) {\n        context.humidity = msg.payload;\n        node.status({text: \"влажность: \" +  context.humidity + \"%\"});\n        return {payload:{ idx: msg.idx , nvalue:0, svalue:\"0;\"+context.humidity+\";1\"}};\n    }\n    \n    node.status({text: \"Показания датчика температуры не распознаны\"});\n    return  {payload:{ idx: msg.idx , nvalue:0, svalue:\"0;0;1\"}};\n}\n\nreturn \"\";","outputs":1,"noerr":0,"x":481.0173454284668,"y":104.01042556762695,"wires":[["1791e115.4046df"]]},{"id":"823afb42.825058","type":"mqtt out","z":"b0a56543.2ed988","name":"domoticz/in","topic":"domoticz/in","qos":"2","retain":"","broker":"10ea5265.66934e","x":793.0173721313477,"y":104.01047039031982,"wires":[]},{"id":"46959b62.5d4374","type":"change","z":"b0a56543.2ed988","name":"TempHall","rules":[{"t":"set","p":"idx","pt":"msg","to":"21","tot":"num"},{"t":"set","p":"DeviceType","pt":"msg","to":"Temp","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":286.01738357543945,"y":81.01039505004883,"wires":[["87773d65.e12fa"]]},{"id":"8196597f.b2d548","type":"change","z":"b0a56543.2ed988","name":"MotionHall","rules":[{"t":"set","p":"idx","pt":"msg","to":"18","tot":"num"},{"t":"set","p":"DeviceType","pt":"msg","to":"Motion","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":296.0368843078613,"y":48.0143011212931,"wires":[["87773d65.e12fa"]]},{"id":"129c1869.bfa7d8","type":"change","z":"b0a56543.2ed988","name":"Door","rules":[{"t":"set","p":"idx","pt":"msg","to":"10","tot":"num"},{"t":"set","p":"DeviceType","pt":"msg","to":"Door","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":276.03689193725586,"y":148.01432418823242,"wires":[["87773d65.e12fa"]]},{"id":"1791e115.4046df","type":"switch","z":"b0a56543.2ed988","name":"IsIdxFound","property":"payload.idx","propertyType":"msg","rules":[{"t":"nnull"}],"checkall":"true","repair":false,"outputs":1,"x":632.0368804931641,"y":104.01432418823242,"wires":[["823afb42.825058"]]},{"id":"10ea5265.66934e","type":"mqtt-broker","z":"","name":"MQTT-localhost","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]

Для AqaraHub я пробовал что-то таки нарисовать на Node-Red, но библиотека сыра, и я пока решил перейти к использованию zigbee2mqtt.
Скрипт Node-Red:
 [{"id":"a400da21.868228","type":"tab","label":"AqaraHub","disabled":false,"info":""},{"id":"3e4a6721.c4c5d8","type":"debug","z":"a400da21.868228","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":803.0002021789551,"y":173.00002574920654,"wires":[]},{"id":"1a5ffb55.1b5f55","type":"mqtt in","z":"a400da21.868228","name":"AqaraHub","topic":"AqaraHub/#","qos":"2","broker":"10ea5265.66934e","x":65,"y":20,"wires":[["f02c1dee.04cd7"]]},{"id":"f02c1dee.04cd7","type":"switch","z":"a400da21.868228","name":"IsJson","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"{","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":195.01952362060547,"y":20,"wires":[["523a4af9.95cb64"],[]]},{"id":"523a4af9.95cb64","type":"json","z":"a400da21.868228","name":"","property":"payload","action":"","pretty":false,"x":316.0195426940918,"y":20,"wires":[["7d160de6.210924"]]},{"id":"7d160de6.210924","type":"switch","z":"a400da21.868228","name":"","property":"topic","propertyType":"msg","rules":[{"t":"cont","v":"00158D0001","vt":"str"},{"t":"cont","v":"00158D0002","vt":"str"},{"t":"cont","v":"00158D0003","vt":"str"},{"t":"cont","v":"00158D0004","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":94.01958465576172,"y":146.0038719177246,"wires":[["30eb482.7c8fdb8"],["3c59c549.98da0a"],["eac3b71.cb6e648"],["394b9172.9ca37e"]]},{"id":"3c59c549.98da0a","type":"change","z":"a400da21.868228","name":"TempHall","rules":[{"t":"set","p":"idx","pt":"msg","to":"21","tot":"num"},{"t":"set","p":"DeviceType","pt":"msg","to":"Temp","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":267.0195960998535,"y":133.0038547515869,"wires":[["95289e9f.d21f5"]]},{"id":"30eb482.7c8fdb8","type":"change","z":"a400da21.868228","name":"MotionHall","rules":[{"t":"set","p":"idx","pt":"msg","to":"18","tot":"num"},{"t":"set","p":"DeviceType","pt":"msg","to":"Motion","tot":"str"},{"t":"set","p":"reset123","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":276.0195732116699,"y":98.00385665893555,"wires":[["95289e9f.d21f5","9cbdba42.2398c8"]]},{"id":"eac3b71.cb6e648","type":"change","z":"a400da21.868228","name":"ButtonHall","rules":[{"t":"set","p":"idx","pt":"msg","to":"13","tot":"num"},{"t":"set","p":"DeviceType","pt":"msg","to":"Button","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":277.0195732116699,"y":167.00385665893555,"wires":[["95289e9f.d21f5"]]},{"id":"394b9172.9ca37e","type":"change","z":"a400da21.868228","name":"Door","rules":[{"t":"set","p":"idx","pt":"msg","to":"10","tot":"num"},{"t":"set","p":"DeviceType","pt":"msg","to":"Door","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":257.0195732116699,"y":202.00385665893555,"wires":[["95289e9f.d21f5"]]},{"id":"de27ab9f.cf1058","type":"mqtt out","z":"a400da21.868228","name":"domoticz/in","topic":"domoticz/in","qos":"2","retain":"","broker":"10ea5265.66934e","x":801.0195541381836,"y":222.00389766693115,"wires":[]},{"id":"95289e9f.d21f5","type":"function","z":"a400da21.868228","name":"GetStatus","func":"if(msg.DeviceType == \"Button\") {\n    \n/*\n    0\tOff\t\t\n    10\tClick\n    20\tDouble Click\n    30\tLong Click\n    40\tLong Click Release\n*/\n    if(msg.topic.indexOf(\"/1/in/OnOff/Report Attributes/OnOff\") > 0) {\n        //node.status({text: \"Button: single click\"});\n        // single\n        if (msg.payload.type == \"bool\" && !msg.payload.value) {\n            // msg.payload.value === false - кнопка нажата\n            // msg.payload.value === true - кнопка отпущена\n            // тут можно добавить проверку времени нажатия для релизации длинного клика\n            node.status({text: \"Button: single click\"});\n            return {payload:{command: \"switchlight\", idx: msg.idx, switchcmd: \"Set Level\", level: 10}};\n        }\n        \n    }\n    \n    if(msg.topic.indexOf(\"/1/in/OnOff/Report Attributes/0x8000\") > 0){\n        // double\n        if (msg.payload.type == \"uint8\" && (msg.payload.value == 2 || msg.payload.value == 3 || msg.payload.value == 128)) {\n            node.status({text: \"Button: double click\"});\n            return {payload:{command: \"switchlight\", idx: msg.idx, switchcmd: \"Set Level\", level: 20}};\n        }\n        \n    }\n    \n}\n\nif(msg.DeviceType == \"Motion\") {\n    \n    if(msg.topic.indexOf(\"/1/in/Occupancy Sensing/Report Attributes/Occupancy\") > 0) {\n        if(msg.payload.type == \"map8\" && msg.payload.value[0]) {\n            node.status({text: \"Двежение: обнаружено; idx=\" + msg.idx});\n            return {payload:{ idx: msg.idx , nvalue:1}};\n        }\n        /*else if(msg.payload == \"false\") {\n            node.status({text: \"Двежение: нет; idx=\" + msg.idx});\n            return {payload:{ idx: msg.idx , nvalue:0}};\n        }\n        else if(msg.payload == \"0\") {\n            return {};\n        }\n        */\n    }\n    //if (msg.payload.IsTrigger) {\n    //    return msg;\n    //}\n    //node.status({text: \"Двежение: показания не распознаны\"});\n}\n\nif(msg.DeviceType == \"Door\") {\n    /*\n    if(msg.topic.indexOf(\"/contact\") > 0) {\n        if(msg.payload == \"true\") {\n            node.status({text: \"Дверь: открыта; idx=\" + msg.idx});\n            return {payload:{ idx: msg.idx , nvalue:1}};\n        }\n        else if(msg.payload == \"false\") {\n            node.status({text: \"Дверь: закрыта; idx=\" + msg.idx});\n            return {payload:{ idx: msg.idx , nvalue:0}};\n        }\n        \n        context.contact = msg.payload;\n    }\n    */\n    if(msg.topic.indexOf(\"/1/in/OnOff/Report Attributes/OnOff\") > 0) {\n        if (msg.payload.type == \"bool\" && msg.payload.value) {\n            node.status({text: \"Door: open\"});\n            return {payload:{ idx: msg.idx , nvalue:1}};\n        }\n        if (msg.payload.type == \"bool\" && !msg.payload.value) {\n            node.status({text: \"Door: closed\"});\n            return {payload:{ idx: msg.idx , nvalue:0}};\n        }\n    }\n    \n    /*\n    if(msg.topic.indexOf(\"/linkquality\") > 0){\n        // open?\n        if (!msg.IsJson) {\n            node.status({text: \"Door: open\"});\n            return {payload:{ idx: msg.idx , nvalue:1}};\n        }\n    }\n    */\n    /*\n    if(msg.topic.endsWith(\"/1/in/OnOff/Report Attributes\") > 0){\n        // open\n        if (msg.payload.type == \"uint8\" && (msg.payload.value == 2 || msg.payload.value == 3 || msg.payload.value == 128)) {\n            node.status({text: \"Door: open\"});\n            return {payload:{command: \"switchlight\", idx: msg.idx, switchcmd: \"Set Level\", level: 20}};\n        }\n    }\n    */\n    \n    //node.status({text: \"Дверь: показания не распознаны\"});\n}\n\n\n\n\nif(msg.DeviceType == \"Temp\") {\n    isNewValue = false;\n    \n    \n    if (typeof context.temperature === 'undefined')\n    {\n        context.temperature = [];\n        context.temperature[msg.idx] = 0;\n    }\n    \n    if (typeof context.humidity === 'undefined')\n    {\n        context.humidity = [];\n        context.humidity[msg.idx] = 0;\n    }\n    \n    \n    if(msg.topic.indexOf(\"/in/Temperature Measurement/Report Attributes/MeasuredValue\") > 0) {\n        context.temperature[msg.idx] = msg.payload.value / 100;\n        //node.status({text: \"температура: \" + context.temperature[msg.idx] + \"°С\"});\n        //return {payload:{ idx: msg.idx , nvalue:0, svalue:context.temperature+\";0;1\"}};\n        isNewValue = true;\n    }\n    if(msg.topic.indexOf(\"/in/Relative Humidity Measurement/Report Attributes/MeasuredValue\") > 0) {\n        context.humidity[msg.idx] = msg.payload.value / 100;\n        //node.status({text: \"влажность: \" +  context.humidity[msg.idx] + \"%\"});\n        //return {payload:{ idx: msg.idx , nvalue:0, svalue:\"0;\"+context.humidity+\";1\"}};\n        isNewValue = true;\n    }\n    \n    if (isNewValue)\n    {\n        node.status({text: \"температура: \" + context.temperature[msg.idx] + \"°С; влажность: \" +  context.humidity[msg.idx] + \"%\"});\n        return {payload:{ idx: msg.idx , nvalue:0, svalue:context.temperature[msg.idx] + \";\" + context.humidity[msg.idx] + \";1\"}};\n    }\n    //node.status({text: \"Показания датчика температуры не распознаны\"});\n    //return  {payload:{ idx: msg.idx , nvalue:0, svalue:\"0;0;1\"}};\n}\n\nreturn \"\";","outputs":1,"noerr":0,"x":513.0195159912109,"y":225.0038890838623,"wires":[["de27ab9f.cf1058","3e4a6721.c4c5d8"]]},{"id":"9cbdba42.2398c8","type":"trigger","z":"a400da21.868228","op1":"","op2":"{\"idx\":18,\"nvalue\":0}","op1type":"pay","op2type":"str","duration":"3","extend":false,"units":"s","reset":"","bytopic":"all","name":"MotionHall_OFF_3sec","x":537.6354484558105,"y":97.4305419921875,"wires":[["de27ab9f.cf1058","3e4a6721.c4c5d8"]]},{"id":"10ea5265.66934e","type":"mqtt-broker","z":"","name":"MQTT-localhost","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]




Комментарии

Популярные сообщения