
Monitoring the status of our Xiaomi Mi Vacuum robot vacuum cleaner in Grafana
If we have the wonderful and all-powerful Xiaomi robot vacuum cleaner and you want to visualize its data in a Grafana dashboard, This is your post! In it we will see how to connect to the vacuum cleaner, how we can ask you questions and obtain all kinds of interesting data, and then store it in a MySQL database that we will attack with Grafana to visualize and process these metrics.
We start, The most important thing, We're going to use a great bookcase that we have in GitHub to control the vacuum cleaner or to obtain information on its status or consumables.
We start as always with the requirements, the first and most important thing will be to have Python 3.5, installed and as default, if you are doing it from a Raspbian you may have to follow these steps to install and select it:
[SourceCode]sudo update-alternatives –install /usr/bin/python python /usr/bin/python2.7 1
sudo update-alternatives –install /usr/bin/python python /usr/bin/python3.5 2
sudo update-alternatives –Config Python
Python –version
python -m pip uninstall pip
pip install construct==2.9.31[/SourceCode]
We install virtualenv, and we use this directory as a virtual environment., We finally installed Mirobo and some requirements that we will also need:
[SourceCode]sudo pip install virtualenv
Mkdir mirobo
virtualenv -p /usr/bin/python3 mirobo
Cooldown Miro
source bin/activate
sudo apt-get install libffi-dev libssl-dev -y
PIP Install Python-MIIO[/SourceCode]
Move! We will now be able to run 'Mirobo Discover’ to search for our vacuum cleaner on the net, If we're lucky (I said no) We'll see the token we need, otherwise we will have to figure out how to obtain it, in my case, by having the Xiaomi Home app installed on my Android mobile phone, with a File Explorer on mobile, we'll go to the path '/SmartHome/logs/Plug_Devicemanager/’ and search in plain text files formatted AAAA-MM-DD.txt our token, View the most recent file that you will see easily.
And finally we will be able to use the application without any problems to, for example, see its status, Consumables, The History… we could even control it and send it to be cleaned….
[SourceCode]export MIROBO_IP=DIRECCION_IP_DE_LA_ASPIRADORA
export MIROBO_TOKEN=TOKEN_DE_AUTH_DE_LA_ASPIRADORA
Miro
State: Charging
Battery: 100 %
Fanspeed: 60 %
Cleaning since: 0:33:27
Cleaned area: 35.48 m²
Mirobo consumables
Main brush: 22:26:19 (left 11 Days, 13:33:41)
Side brush: 22:26:19 (left 7 Days, 9:33:41)
Filter: 22:26:19 (left 5 Days, 7:33:41)
Dirty sensor: 22:26:19 (left 7:33:41)
Mirobo Cleaning-History
Total clean count: 301
Cleaned for: 10 Days, 18:31:57 (Area: 13288.1575 m²)
Clean #0: 2019-06-27 17:42:06-2019-06-27 18:15:33 (Complete: True, error: No error)
Area cleaned: 35.48 m²
Duration: (0:33:27)
Clean #1: 2019-06-21 21:16:55-2019-06-21 21:59:12 (Complete: True, error: No error)
…[/SourceCode]
If you want to export this to a MySQL database I leave you the script txurro I made, Just in case you care. This script 'chekea_aspiradora_consumibles.sh’ Runs using cron every 5 minutes, and stores in a database table the data that will interest us and then process them with Grafana, how is the status of the Xiaomi vacuum cleaner, Battery Status, Cleanings, route… :
[SourceCode]#! /bin/bash
cd /home/pi/mirobo
source bin/activate
export MIROBO_IP=DIRECCION_IP_DE_LA_ASPIRADORA
export MIROBO_TOKEN=TOKEN_DE_AUTH_DE_LA_ASPIRADORA
Miro > mirobo_general.txt
state='cat mirobo_general.txt |grep state | aw '{print $2}’`
state='$estado’
battery='cat mirobo_general.txt |grep battery | aw '{print $2}’`
speed='cat mirobo_general.txt |grep Fanspeed | aw '{print $2}’`
Mirobo Cleaning-History > mirobo_historial.txt
cleaning='cat mirobo_historial.txt |grep 'Total clean count’ | aw '{print $4}’`
route='cat mirobo_historial.txt |grep 'Cleaned for’ | aw '{print $7}’`
dias='cat mirobo_historial.txt |grep 'Cleaned for’ | aw '{print $3}’`
Days='echo $((days*24*60*60))`
hours='cat mirobo_historial.txt |grep 'Cleaned for’ | aw '{print substr($5,1,2)}’`
hours='echo $((hours*60*60))`
minutes='cat mirobo_historial.txt |grep 'Cleaned for’ | aw '{print substr($5,4,2)}’`
minutes='echo $((minutes*60))`
seconds='cat mirobo_historial.txt |grep 'Cleaned for’ | aw '{print substr($5,7,2)}’`
total_tiempo=$((days+hours+minutes+seconds))
hora_desde='cat mirobo_historial.txt |grep 'clean #0’ | aw '{print substr($4,1,8)}’`
hora_hasta='cat mirobo_historial.txt |grep 'clean #0’ | aw '{print substr($5,1,8)}’`
hora_desde='date -d $hora_from_+%s'
hora_hasta='date -d $hora_up to +%s'
tiempo_limpieza='echo $(( hora_hasta-hora_desde ))`
metros_limpieza='cat mirobo_historial.txt |grep 'Area cleaned’ | aw '{print $3; exit}’`
ultima_limpieza='cat mirobo_historial.txt |grep 'clean #0’ | aw '{print $3, Substr($4,1,8)}’`
ultima_limpieza='$ultima_cleanup’
Mirobo -D consumables &> mirobo_consumibles.txt
##### FILTER
line='cat mirobo_consumibles.txt |Grep filter_work_time'
filtro_ini='cat mirobo_consumibles.txt |Grep filter_work_time | grep -b -o filter_work_time'
filtro_ini='echo $filtro_ini | cut -d ':’ -F1'
filter='echo ${Line:$filtro_ini+19:15}| tr -dc ‘0-9’`
filtro_restante=$((540000-$filter))
### SIDE BRUSH
line='cat mirobo_consumibles.txt |grep side_brush_work_time'
escobilla_lat_ini='cat mirobo_consumibles.txt |Grep side_brush_work_time | grep -b -o side_brush_work_time'
escobilla_lat_ini='echo $escobilla_lat_ini | cut -d ':’ -F1'
escobilla_lat='echo ${Line:$escobilla_lat_ini+23:15}| tr -dc ‘0-9’`
escobilla_lat_restante=$((720000-$escobilla_lat))
### SENSOR
line='cat mirobo_consumibles.txt |Grep sensor_dirty_time'
sensor_ini='cat mirobo_consumibles.txt |Grep sensor_dirty_time | grep -b -o sensor_dirty_time'
sensor_ini='echo $sensor_ini | cut -d ':’ -F1'
sensor='echo ${Line:$sensor_ini+19:15}| tr -dc ‘0-9’`
sensor_restante=$((108000-$sensor))
### MAIN BRUSH
line='cat mirobo_consumibles.txt |Grep main_brush_work_time'
escobilla_pri_ini='cat mirobo_consumibles.txt |Grep main_brush_work_time | grep -b -o main_brush_work_time'
escobilla_pri_ini='echo $escobilla_pri_ini | cut -d ':’ -F1'
escobilla_pri='echo ${Line:$escobilla_pri_ini+23:15}| tr -dc ‘0-9’`
escobilla_pri_restante=$((1080000-$escobilla_pri))
echo "INSERT INTO vacuum cleaner (state,Battery,velocity,Cleanings,route,total_tiempo,tiempo_limpieza,metros_limpieza,ultima_limpieza,filter,filtro_restante,escobilla_lat,escobilla_lat_restante,sensor,sensor_restante,escobilla_pri,escobilla_pri_restante) VALUES ($state,$Battery,$velocity,$Cleanings,$route,$total_tiempo,$tiempo_limpieza,$metros_limpieza,$ultima_limpieza,$filter,$filtro_restante,$escobilla_lat,$escobilla_lat_restante,$sensor,$sensor_restante,$escobilla_pri,$escobilla_pri_restante);" | mysql -uUSERNAME -pPASSWORD -h IP_SERVIDOR_MYSQL BASE_DE_DATOS;[/SourceCode]
Here's an example of the code you can use in MySQL to create this table called 'vacuum cleaner'’ with 18 fields where we will store everything that the previous script spits out. We will then be able to store all this interesting information and later exploit it with Grafana!
[SourceCode]CREATE TABLE 'vacuum cleaner' (
'status' CHAR(20) NULL DEFAULT NULL,
'battery' FLOAT NULL DEFAULT NULL,
'speed' FLOAT NULL DEFAULT NULL,
'cleanups' FLOAT NULL DEFAULT NULL,
'path' FLOAT NULL DEFAULT NULL,
'total_tiempo' FLOAT NULL DEFAULT NULL,
'tiempo_limpieza' FLOAT NULL DEFAULT NULL,
'metros_limpieza' FLOAT NULL DEFAULT NULL,
'ultima_limpieza' DATETIME NULL DEFAULT NULL,
'filter' FLOAT NULL DEFAULT NULL,
'filtro_restante' FLOAT NULL DEFAULT NULL,
'escobilla_lat' FLOAT NULL DEFAULT NULL,
'escobilla_lat_restante' FLOAT NULL DEFAULT NULL,
'sensor' FLOAT NULL DEFAULT NULL,
'sensor_restante' FLOAT NULL DEFAULT NULL,
'escobilla_pri' FLOAT NULL DEFAULT NULL,
'escobilla_pri_restante' FLOAT NULL DEFAULT NULL,
'date' TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
COLLATE='utf8mb4_general_ci’
ENGINE=InnoDB;[/SourceCode]
And nothing, as usual, already with data in the DB, we can create a DataSource against that MySQL database in Grafana and start by creating our Dashboard to which we will add some panels, I leave you with these examples and the queries I used to obtain this data:
- Main brush:
[SourceCode]SELECT escobilla_pri_restante FROM vacuum cleaner ORDER BY date OFF LIMIT 1[/SourceCode]
- Side brush:
[SourceCode]SELECT escobilla_lat_restante FROM vacuum cleaner ORDER BY date OFF LIMIT 1[/SourceCode]
- Filter:
[SourceCode]SELECT filtro_restante FROM vacuum cleaner ORDER BY date OFF LIMIT 1[/SourceCode]
- Clean Sensors:
[SourceCode]SELECT sensor_restante FROM vacuum cleaner ORDER BY date OFF LIMIT 1[/SourceCode]
- Last Cleaning:
[SourceCode]SELECT timestamp(DATE_FORMAT(ultima_limpieza, '%Y/%m/%d %H:%i:%s’)) as time_sec FROM vacuum cleaner ORDER BY date DESC LIMIT 1[/SourceCode]
- Cleaning (Depending on the time selected, it will tell you how long you were vacuuming), I multiply it x 5 since in my chron I execute it every 5 minutes:
[SourceCode]SELECT (COUNT(*) * 5) FROM vacuum cleaner WHERE status='Cleaning'’ and $__timeFilter(date)[/SourceCode]
- Total cleanups:
[SourceCode]SELECT cleanings FROM vacuum cleaner ORDER BY date OFF LIMIT 1[/SourceCode]
- Total distance traveled:
[SourceCode]SELECT ROUTE FROM vacuum cleaner ORDER BY date DESC LIMIT 1[/SourceCode]
- Total Cleaning:
[SourceCode]SELECT total_tiempo FROM vacuum cleaner ORDER BY date OFF LIMIT 1[/SourceCode]
- And the graph shows 2 stuff, (i) the square meters cleaned and (Ii) the time spent, through these 2 Different selects:
[SourceCode]SELECT UNIX_TIMESTAMP(ultima_limpieza) So time_sec, metros_limpieza as value, "Meters" as metric FROM vacuum cleaner WHERE $__timeFilter(ultima_limpieza) ORDER BY ultima_limpieza, time_sec ASC[/SourceCode]
[SourceCode]SELECT UNIX_TIMESTAMP(ultima_limpieza) So time_sec, tiempo_limpieza as value, "Time" as metric FROM vacuum cleaner WHERE $__timeFilter(ultima_limpieza) ORDER BY ultima_limpieza, time_sec ASC[/SourceCode]
Well, I hope you find it interesting, Another more controlled and squeezed clunker! As we see, with Grafana and the combination of multiple products we can make our home smarter, where we have control panels, The usual, I hope you found it interesting!