THIS IS CURRENTLY A WORK IN PROGRESS
However sharing as others smarter than me can weigh in and add their insights
Project status: Working co-ordinates of iphone via BLE and room-assistant
To-do: 1. 2nd floor (and way to select the right floor based on distance or other sensor)
2. Room division
3. Overlay floorplan strategy
Hi Everyone,
So iāve been trying to solve this FOREVER but never had the time to devote to it (and get the help I needed).
First off, big thanks to @Kermit for help with Node-Red and @mKeRix for room-assistant
My goal eventually is to overlay the positions of the person onto a floorplan (my inspiration was from xandem and their positioning system, which is great - however requires a lot of nodes currently, and doesnāt distinguish between people. Also if you are stationary it wont detect you).
Knowing where the regular house occupants are means I can get much more granular with automations.
The premise is to use 3 Room-assistant nodes on each floor to triangulate the position of a BLE device in my case an Iphone.
So first up the hardware:
3 x Raspberry Pi 3s (you can use Pi zeros, but WiFi and BT iāve found to cause issues, so I hardwired my Pis in to avoid this). Iāve got a couple of ethernet pi zero hats coming to test out too
3 x MicroSDs 8Gb is more than enough
Software Needed:
Room-Assistant beta
Node-Red & HA Palette
Optional - HA NodeRed custom_component
Iphone BLE companion app
Step 1 - Infrastructure stuff
Iām not going to walk people through their HA, Node-Red or Raspi Image set up - there are plenty of guides on that online.
Step 2 - Get BLE device IDs
If using iphone join the beta testflight with this link, approve BT permissions and copy the device ID for all the devices you want to track.
Step 3 - Raspberry Pi
Install Docker, nano, docker-compose and Room-assistant via ssh
sudo apt update
sudo apt upgrade
curl -sSL https://get.docker.com | sh
sudo usermod -a -G docker $USER
sudo apt -y install nano
sudo apt -y install docker-compose
cd ~
mkdir room-assistant
cd room-assistant
mkdir config
nano docker-compose.yml
Use this docker-compose (detailed info on the room-assistant site):
version: '3'
services:
room-assistant:
container_name: room-assistant
image: mkerix/room-assistant:beta
restart: unless-stopped
network_mode: host
volumes:
- /var/run/dbus:/var/run/dbus
- /home/pi/room-assistant/config:/room-assistant/config
[Ctrl+X and then hit Y to save]
nano ~/room-assistant/config/local.yml
Use this in your local.yml
Be sure to change:
instanceName
should be named something different for each one (you can use actual room names if you prefer, just be sure to change them!)
mqttUrl
to the IP of your MQTT server, and the credentials if you use them. if not remove the mqtt Options chunk
whitelist
should include the BLE device IDs from the room-assistant companion app.
NOTE I have specified the network to use the ethernet port to overcome any WiFi issues (I also need to look in to whether I should disable WiFi altogether)
global:
instanceName: ra0
integrations:
- homeAssistant
- bluetoothLowEnergy
cluster:
networkInterface: eth0
homeAssistant:
mqttUrl: 'mqtt://X.X.X.X:1883'
mqttOptions:
username: user
password: pass
bluetoothLowEnergy:
whitelist:
- ble-device-id-1 #name_here
- ble-device-id-2 #name_here
Now start the docker-compose process (assuming you havent logged out yet so the usermod wont have kicked in for docker):
cd ~/room-assistant
sudo docker-compose up
Docker will be pulled down and start up. Be sure to check for any errors before moving on.
To validate the phone is detected and visible use either HA or MQTTfx to subscribe to the following topic:
room-assistant/sensor/ble-{device-id}/#
If when you move the phone, the distance JSON value within attributes
changes you can move on.
If not pause for troubleshooting and re-read the docs.
This part is a little repetitive as you need to build the other 2 raspberry pis, so repeat 1-3 for each one, remembering to change the instanceName
for each local.yml
Step 4 - Node-Red and triangulation
Iām not going to pretend I understand the maths involved but if anyone cares, check out this link.
Essentially you need 3 fixed known locations, and thus the distances of an object from those locations will yield a resulting triangulated position.
Now Iām using the Unraid NodeRed docker, so my settings.js
is in /data/
yours maybe different.
cd /data
cd node_modules
npm install trilateration
sudo apt -y install nano
nano /data/settings.js
Now scroll down until you find:
functionGlobalContext: {
// os:require('os'),
// jfive:require("johnny-five"),
// j5board:require("johnny-five").Board({repl:false})
},
To use the trilateration package globally in NodeRed we need to add it here:
functionGlobalContext: {
trilateration:require('trilateration')
// os:require('os'),
// jfive:require("johnny-five"),
// j5board:require("johnny-five").Board({repl:false})
},
[CTRL+X and hit y]
At this point Iām not sure if required, but I rebooted the NodeRed docker
Now for the flow:
At the end of the flow I use an HA sensor (which requires the HA Node-Red integration to be installed from HACS - instructions) but you can just leave the co-ordinates as a msg
if you want?
[{"id":"1abe71e.6c6f98e","type":"http request","z":"fa164293.781af","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"http://X.X.X.X:6415/entities","tls":"","persist":false,"proxy":"","authType":"","x":413.9745178222656,"y":2304.657470703125,"wires":[["eaeec6bd.a20238"]]},{"id":"b5830319.8d31c","type":"inject","z":"fa164293.781af","name":"","props":[{"p":"payload"}],"repeat":"1","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":210.23840713500977,"y":2303.8727588653564,"wires":[["1abe71e.6c6f98e"]]},{"id":"eaeec6bd.a20238","type":"split","z":"fa164293.781af","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":616.2383193969727,"y":2303.8723487854004,"wires":[["41f11a3d.f7ef04"]]},{"id":"41f11a3d.f7ef04","type":"switch","z":"fa164293.781af","name":"","property":"payload.id","propertyType":"msg","rules":[{"t":"eq","v":"ble-device-id-1","vt":"str"},{"t":"eq","v":"ble-device-id-2","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":770.2383155822754,"y":2301.8723487854004,"wires":[["2c62a50f.cdf57a"],["e429bd13.904"]]},{"id":"2c62a50f.cdf57a","type":"function","z":"fa164293.781af","name":"","func":"var trilateration = global.get('trilateration');\n\ntrilateration.addBeacon(0, trilateration.vector(2, 4));\ntrilateration.addBeacon(1, trilateration.vector(5, 13));\ntrilateration.addBeacon(2, trilateration.vector(11, 2));\n\ntrilateration.setDistance(0, msg.payload.distances.ra0.distance);\ntrilateration.setDistance(1, msg.payload.distances.ra1.distance);\ntrilateration.setDistance(2, msg.payload.distances.ra2.distance);\n\nmsg.payload = trilateration.calculatePosition();\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":947.2381324768066,"y":2255.3531799316406,"wires":[["4764d31f.17f95c","fca290bf.e2bb7"]]},{"id":"e429bd13.904","type":"function","z":"fa164293.781af","name":"","func":"var trilateration = global.get('trilateration');\n\ntrilateration.addBeacon(0, trilateration.vector(2, 4));\ntrilateration.addBeacon(1, trilateration.vector(5, 13));\ntrilateration.addBeacon(2, trilateration.vector(11, 2));\n\ntrilateration.setDistance(0, msg.payload.distances.kitchen.distance);\ntrilateration.setDistance(1, msg.payload.distances.livingroom.distance);\ntrilateration.setDistance(2, msg.payload.distances.serverroom.distance);\n\nmsg.payload = trilateration.calculatePosition();\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":949.2382392883301,"y":2343.8723850250244,"wires":[["a07e06d7.b84318","3770931a.35aa2c"]]},{"id":"4764d31f.17f95c","type":"ha-entity","z":"fa164293.781af","name":"Person1 Y Coordinate","server":"b89bdbfd.f73988","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"person1_y_coordinate"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""}],"state":"payload.y","stateType":"msg","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","x":1207.238437652588,"y":2283.8727588653564,"wires":[[]]},{"id":"fca290bf.e2bb7","type":"ha-entity","z":"fa164293.781af","name":"Person1 X Coordinate","server":"b89bdbfd.f73988","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"person1_x_coordinate"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""}],"state":"payload.x","stateType":"msg","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","x":1209.238437652588,"y":2225.8727588653564,"wires":[[]]},{"id":"3770931a.35aa2c","type":"ha-entity","z":"fa164293.781af","name":"Person2 Y Coordinate","server":"b89bdbfd.f73988","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"person2_y_coordinate"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""}],"state":"payload.y","stateType":"msg","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","x":1190.238437652588,"y":2419.8727588653564,"wires":[[]]},{"id":"a07e06d7.b84318","type":"ha-entity","z":"fa164293.781af","name":"person2 X Coordinate","server":"b89bdbfd.f73988","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"person2_x_coordinate"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""}],"state":"payload.x","stateType":"msg","attributes":[],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","x":1192.238437652588,"y":2361.8727588653564,"wires":[[]]},{"id":"b89bdbfd.f73988","type":"server","name":"Home Assistant","legacy":false,"addon":false,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]
There are a couple of things you will need to change:
- the http request node - you need to add the IP of a Raspberry Pi
- the switch node - add the device ids from above āble-xxxxxx-xxxxxā¦ā
- the function nodes - they both need the
instanceName
trilateration.setDistance(0, msg.payload.distances.ra0.distance);
trilateration.setDistance(1, msg.payload.distances.ra1.distance);
trilateration.setDistance(2, msg.payload.distances.ra2.distance);
replace ra0, ra1, ra2 with the 3 instanceName
strings you used.
Now the inject is set to do so every second, so you may want to turn that to a single inject for testing.
When you hit inject you should see the resulting values.
Now the API is working and successful, in theory we can turn off the HomeAssistant
integration (removing the MQTT load).
If working correctly you now need to calculate the room co-ordinates and the locations of the pi3 devices.
(Update to follow)