Skip to content

Instantly share code, notes, and snippets.

@emme73
Last active October 13, 2018 16:49
Show Gist options
  • Save emme73/7343f804b475c5b3198fd2221e9ed3b9 to your computer and use it in GitHub Desktop.
Save emme73/7343f804b475c5b3198fd2221e9ed3b9 to your computer and use it in GitHub Desktop.
Domoticz (MQTT) Presence detection with Bluetooth LE tags

This flow will use noBLE node to scan LE devices and activate a switch (or a variable) in Domoticz server using MQTT topic domoticz/in

There is a context array containing the tag devices Mac Addr and configuration. For each tag you can choose:

  • Activate a switch
  • Change a variable value (HOME/AWAY)
  • Put in a variable the RSSI value (rssi/AWAY)

#CONFIGURATION

the configuration context array (included in the InitialConfig node) should be populated with these info:

  • [0] MAC Address
  • [1] Friendly (flow Context display) Name
  • [2] Domoticz MQTT switch IDX
  • [3] Domoticz Switch Update (true or false) On/Off
  • [4] Domoticz MQTT Variable IDX
  • [5] Domoticz Variable Update (true or false) HOME/AWAY
  • [6] Domoticz Variable RSSI Update rssi/AWAY add as many tags as you need just remember that:
  • BLE devices normally stop to be discoverable if paired
  • default BLE interface (hci0) should NOT be used in any other scripts or ssh/terminal usage, it became unstable and unusable until next reboot

HOW IT WORKS

On starting the flow the configuration array is created then another input will toggle between true and fase and activate/deactivate the scan LE node Timer is set to 1min, this works fine, you can change it, but be aware that values less than 40secs gave me some false results during the ON-scan window the LE node will gater all available mac address in the air. if it match with the configuration array then a mqtt telegram is created and sent to domoticz accordingly to the configuration, plut it sets a context variable to TRUE to notify the tag has been found

During the OFF-scan window the context variable are scrolled: if they are setted to FALSE (le not found) it pack an AWAY telegram to the MQTT server

On top of all there is a RBE node to prevent multiple messages with the same content (ie: it is useless to send an AWAY telegram every minute....) the RBE is reseted every day

Tested with NutSpace nutMini and Tile ble devices

[
{
"id": "8fca45c5.75bcc8",
"type": "tab",
"label": "Flow 1",
"disabled": false,
"info": ""
},
{
"id": "f2fc0bb0.1a66b8",
"type": "inject",
"z": "8fca45c5.75bcc8",
"name": "inject Impulse",
"topic": "",
"payload": "",
"payloadType": "str",
"repeat": "60",
"crontab": "",
"once": true,
"onceDelay": "5",
"x": 145,
"y": 145,
"wires": [
[
"98676583.d01628"
]
]
},
{
"id": "98676583.d01628",
"type": "function",
"z": "8fca45c5.75bcc8",
"name": "scanToggle",
"func": "var msg = {};\nmsg.payload = {};\n\nflow.set('scanStatus', !flow.get('scanStatus'));\nmsg.payload.scan = flow.get('scanStatus');\n\nreturn msg;\n",
"outputs": 1,
"noerr": 0,
"x": 335,
"y": 145,
"wires": [
[
"8defa7dc.fb3558",
"8c16719b.3442f"
]
]
},
{
"id": "7bd5c8aa.fb7ea8",
"type": "rbe",
"z": "8fca45c5.75bcc8",
"name": "",
"func": "rbe",
"gap": "",
"start": "",
"inout": "out",
"property": "payload",
"x": 870,
"y": 174,
"wires": [
[
"f53544b6.934ba8",
"d96aeb02.ce5188"
]
]
},
{
"id": "3097ff9f.b2127",
"type": "inject",
"z": "8fca45c5.75bcc8",
"name": "",
"topic": "inject Config",
"payload": "true",
"payloadType": "bool",
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"x": 155,
"y": 105,
"wires": [
[
"f6b48a8f.753b88"
]
]
},
{
"id": "8c16719b.3442f",
"type": "delay",
"z": "8fca45c5.75bcc8",
"name": "",
"pauseType": "delay",
"timeout": "500",
"timeoutUnits": "milliseconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"x": 505,
"y": 175,
"wires": [
[
"acccc36a.2f11a"
]
]
},
{
"id": "8defa7dc.fb3558",
"type": "scan ble",
"z": "8fca45c5.75bcc8",
"uuids": "",
"duplicates": false,
"name": "",
"x": 505,
"y": 125,
"wires": [
[
"e2ea0105.e6f2b"
]
]
},
{
"id": "acccc36a.2f11a",
"type": "function",
"z": "8fca45c5.75bcc8",
"name": "setAwayMqtt",
"func": "/*\n deviceConfig Array must be follow this layout:\n [0] MAC Address\n [1] Friendly (flow Context display) Name\n [2] Domoticz MQTT switch IDX\n [3] Domoticz Switch Update (true or false) On/Off\n [4] Domoticz MQTT Variable IDX\n [5] Domoticz Variable Update (true or false) HOME/AWAY\n [6] Domoticz Variable RSSI Update rssi/AWAY\n*/\n\nvar tagArray = flow.get(\"deviceConfig\");\n\n// ==== Setting up mqtt standard telegrams\nvar varMqtt = {};\nvarMqtt.payload = {};\nvarMqtt.payload.command = \"setuservariable\";\n//varMqtt.payload.idx = 000;\nvarMqtt.payload.value = \"AWAY\";\n\nvar devMqtt = {};\ndevMqtt.payload = {};\ndevMqtt.payload.command = \"switchlight\";\ndevMqtt.payload.switchcmd = \"Off\";\n//devMqtt.payload.idx = 000;\n\n// setting up outgoing message (this will contain multimple messages)\nvar outMsg = [];\n\nif (flow.get('scanStatus')===false) {\n tagArray.forEach(macLookup); \n}\n\nreturn [outMsg];\n\nfunction macLookup(ble) {\n if (flow.get(ble[1])===false) { // Mac Address Found - Updating\n\n if (ble[3]===true) { // Update the switch\n devMqtt.topic = ble[1];\n devMqtt.payload.idx = ble[2];\n outMsg.push(JSON.parse(JSON.stringify(devMqtt)));\n }\n \n if (ble[5]===true) { // Update the Variable\n varMqtt.topic = ble[1];\n varMqtt.payload.idx = ble[4];\n outMsg.push(JSON.parse(JSON.stringify(varMqtt)));\n }\n } else {\n flow.set(ble[1], false);\n }\n}\n",
"outputs": 1,
"noerr": 0,
"x": 665,
"y": 175,
"wires": [
[
"7bd5c8aa.fb7ea8"
]
]
},
{
"id": "63dfb40a.0c58fc",
"type": "function",
"z": "8fca45c5.75bcc8",
"name": "reset RBE",
"func": "var msg = {};\nmsg.reset = null;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 665,
"y": 215,
"wires": [
[
"7bd5c8aa.fb7ea8"
]
]
},
{
"id": "975737c8.e0c308",
"type": "inject",
"z": "8fca45c5.75bcc8",
"name": "reset Rbe",
"topic": "",
"payload": "{\"reset\":true}",
"payloadType": "json",
"repeat": "",
"crontab": "00 00 * * *",
"once": false,
"onceDelay": 0.1,
"x": 135,
"y": 215,
"wires": [
[
"63dfb40a.0c58fc"
]
]
},
{
"id": "f6b48a8f.753b88",
"type": "function",
"z": "8fca45c5.75bcc8",
"name": "initial Config",
"func": "/*\n deviceConfig Array must be follow this layout:\n [0] MAC Address\n [1] Friendly (flow Context display) Name\n [2] Domoticz MQTT switch IDX\n [3] Domoticz Switch Update (true or false) On/Off\n [4] Domoticz MQTT Variable IDX\n [5] Domoticz Variable Update (true or false) HOME/AWAY\n [6] Domoticz Variable RSSI Update rssi/AWAY\n \n NOTE\n RSSI is updated if [5] and [6] are true to idx [4]\n You can update both a switch and a variable\n \n HOW IT WORKS\n Scan BLE will pass a msg for each device found\n The mac addresses are compared to the array, if match domoticz will be updated \n via mqtt accordingly to the configuration (switch on/off, rssi etc etc)\n then a flag in the flow is updated for switcing off capability\n*/\n\nvar deviceConfig = [\n [\"mac address as shown in the scan\", \"device name\", 0, false, 0, true, true]\n ];\n \nflow.set('deviceConfig', deviceConfig);\ndeviceConfig.forEach(setupContext);\n\nflow.set('scanStatus',false);\n\nreturn msg;\n\nfunction setupContext(ble) {\n flow.set(ble[1], false);\n}\n",
"outputs": 1,
"noerr": 0,
"x": 335,
"y": 105,
"wires": [
[]
]
},
{
"id": "e2ea0105.e6f2b",
"type": "function",
"z": "8fca45c5.75bcc8",
"name": "setHomeMqtt",
"func": "/*\n deviceConfig Array must be follow this layout:\n [0] MAC Address\n [1] Friendly (flow Context display) Name\n [2] Domoticz MQTT switch IDX\n [3] Domoticz Switch Update (true or false) On/Off\n [4] Domoticz MQTT Variable IDX\n [5] Domoticz Variable Update (true or false) HOME/AWAY\n [6] Domoticz Variable RSSI Update rssi/AWAY\n*/\n\nvar tagArray = flow.get('deviceConfig');\n\n// ==== Setting up mqtt standard telegrams\nvar varMqtt = {};\nvarMqtt.payload = {};\nvarMqtt.payload.command = \"setuservariable\";\n//varMqtt.payload.idx = 000;\n//varMqtt.payload.value = msg.rssi;\n\nvar devMqtt = {};\ndevMqtt.payload = {};\ndevMqtt.payload.command = \"switchlight\";\ndevMqtt.payload.switchcmd = \"On\";\n//devMqtt.payload.idx = 000;\n\n// setting up outgoing message (this will contain multimple messages)\nvar outMsg = [];\n\n// Initializing the script\nvar currentMac = msg.peripheralUuid;\nvar currentRssi = msg.rssi;\n\ntagArray.forEach(macLookup);\nreturn [outMsg];\n\nfunction macLookup(ble) {\n if (currentMac == ble[0]) { // Mac Address Found - Updating\n flow.set(ble[1], true); // Set the nut flag to true\n \n if (ble[3] === true) { // Update the switch\n devMqtt.payload.idx = ble[2];\n devMqtt.topic = ble[1];\n outMsg.push(JSON.parse(JSON.stringify(devMqtt)));\n }\n \n if (ble[5]===true) { // Update the Variable\n varMqtt.payload.idx = ble[4];\n varMqtt.topic = ble[1];\n if (ble[6]===true) {\n varMqtt.payload.value = currentRssi;\n } else {\n varMqtt.payload.value = 'HOME';\n }\n outMsg.push(JSON.parse(JSON.stringify(varMqtt)));\n }\n }\n}\n",
"outputs": 1,
"noerr": 0,
"x": 671,
"y": 125,
"wires": [
[
"7bd5c8aa.fb7ea8"
]
]
},
{
"id": "6fe2bb01.d82ca4",
"type": "catch",
"z": "8fca45c5.75bcc8",
"name": "",
"scope": null,
"x": 839,
"y": 222,
"wires": [
[
"f53544b6.934ba8"
]
]
},
{
"id": "f53544b6.934ba8",
"type": "debug",
"z": "8fca45c5.75bcc8",
"name": "",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"x": 1007,
"y": 221,
"wires": []
},
{
"id": "d96aeb02.ce5188",
"type": "mqtt out",
"z": "8fca45c5.75bcc8",
"name": "",
"topic": "domoticz/in",
"qos": "",
"retain": "",
"broker": "5643db66.dd9264",
"x": 1036,
"y": 173,
"wires": []
},
{
"id": "5643db66.dd9264",
"type": "mqtt-broker",
"z": "",
"name": "",
"broker": "127.0.0.1",
"port": "1883",
"clientid": "",
"usetls": false,
"compatmode": true,
"keepalive": "60",
"cleansession": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"closeTopic": "",
"closePayload": "",
"willTopic": "",
"willQos": "0",
"willPayload": ""
}
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment