ML model to locate mobile devices around the house based on wifi signal values.
The easiest way I've found to collect wifi signal strength data was using the Home Assistant unifi component. Once set up you will get two values related to the signal strength (rssi, signal) as well as the MAC address of the access point the device is connected to. The component updates every 30 seconds, making it fairly easy to collect data.
The export_to_csv.py script can be used to write collected data to a csv file. The values can be passed to the script as parameters:
python /config/export_to_csv.py -r {{rssi}} -s {{signal}} -a {{ap}} -l {{location}}
The location parameter is the label of the current location/room.
To label the data using Home Assistant, add a new input_select with the different rooms:
input_select:
phone_location:
name: Phone location
options:
- Living Room
- Kitchen
- Bedroom
- Office
- Jere Room
- Bathroom
initial: Living Room
icon: mdi:cellphone
You'll then be able to manually change those values in the UI during data collection.
Automating the data collection is fairly easy using Home assistant and/or Node-red. Step one is to add the export script as a HA shell command like this:
shell_command:
export_csv: 'python /config/export_to_csv.py -r {{rssi}} -s {{signal}} -a {{ap}} -l {{location}}'
If you'd like to include the values directly in this shell command using templates, that can be done as well. For example export_csv: 'python /config/export_to_csv.py -r {{ states.device_tracker.phone.attributes.rssi }} -s {{ states.device_tracker.phone.attributes.rssi }} -a {{ states.device_tracker.phone.attributes.rssi }} -l {{ states.inpout_select.phone_location.state }}'
Using the shell_command, data collection can then be automated. Whenever the device_tracker updates with new wifi signal information, call the shell_command to write those to your CSV file. Here's an example of how this is done using Node-red:
[{"id":"6d2b985d.4e02d8","type":"api-render-template","z":"8d972e1e.28c54","name":"Signal template","server":"90ba4a50.2b5e48","template":"{% set device = states.device_tracker.sevenplus_router %}\n{\"rssi\":{{device.attributes.rssi}},\"signal\":{{device.attributes.signal}},\"ap\":\"{{device.attributes.ap_mac}}\",\"location\":\"{{ states.input_select.phone_location.state }}\"}","x":340,"y":320,"wires":[["729009fd.14d4d8"]]},{"id":"c7ae5708.04f1b8","type":"trigger-state","z":"8d972e1e.28c54","name":"Changed","server":"90ba4a50.2b5e48","entityid":"device_tracker.sevenplus_router","entityidfiltertype":"exact","debugenabled":false,"constraints":[{"id":"26xjecbhtywk","targetType":"entity_id","targetValue":"input_boolean.training_mode","propertyType":"current_state","propertyValue":"new_state.state","comparatorType":"is","comparatorValueDatatype":"str","comparatorValue":"on"}],"constraintsmustmatch":"all","outputs":2,"customoutputs":[],"outputinitially":false,"state_type":"str","x":120,"y":320,"wires":[["6d2b985d.4e02d8"],[]]},{"id":"729009fd.14d4d8","type":"function","z":"8d972e1e.28c54","name":"Template","func":"var dataString = JSON.stringify(msg.payload);\nmsg.payload = \"{\\\"data\\\":\"+dataString+\"}\";\nreturn msg;","outputs":1,"noerr":0,"x":535,"y":318,"wires":[["5737b248.a211fc"]]},{"id":"5737b248.a211fc","type":"api-call-service","z":"8d972e1e.28c54","name":"","server":"90ba4a50.2b5e48","service_domain":"shell_command","service":"export_csv","data":"","mergecontext":"","x":810,"y":340,"wires":[[]]},{"id":"90ba4a50.2b5e48","type":"server","z":"","name":"HomeAssistant","legacy":false}]
Make sure to set the proper device_tracker and input_select names in the template.
To make training easier, I added everything to my Home Assistant Lovelace UI:
- id: 9
title: Training
icon: mdi:library-books
cards:
- id: training # Automatically created id
type: entities
entities:
- input_boolean.training_mode
- input_select.phone_location
Note the input_boolean.training_mode, it's essentially a switch that will start and stop the data collection. It might be useful to add an additional automation to switch off training_mode after 30 minutes or an hour. It happened to me a couple of times that I turned on the training mode and then just walked away, ruining the collected data. Doing data collection 30 minutes at a time can help with that.