Multi-Node Bluetooth and Wifi presence detection

Moderator: leecollings

Post Reply
ben53252642
Posts: 543
Joined: Saturday 02 July 2016 5:17
Target OS: Linux
Domoticz version: Beta
Contact:

Multi-Node Bluetooth and Wifi presence detection

Post by ben53252642 »

Hey Folks,

Finally I am releasing my multi-node Bluetooth and WiFi presence detection system, a significantly more advanced version of the original work here: viewtopic.php?t=12570

This system is capable of detecting a single device either via WiFi or Bluetooth using an unlimited number of nodes (eg Raspberry Pi's placed around a house for extended Bluetooth coverage).

The Master Node pings the target via both WiFi and Bluetooth logging the last time that the target device was seen using unix time to a MySQL database. Slave nodes read the database and if it's been more than 8 seconds since the Master Node last saw the target device then they also start searching at maximum speed until a node (Master or Slave) detects the target device.

To save the devices battery the slave nodes sit on Standby not pinging the target unless the master cannot see it.

The system is recommended only for advanced Linux users with mild to moderate PHP knowledge.

Simulated output from the bluegrid engine screen session (I've deliberately enabled / disabled WiFi and Bluetooth my phone to show the different terminal output:

Bens Mobile: Online via WiFi on Master
Bens Mobile: Online via Bluetooth on Master
Device Offline
Bens Mobile: Online via Bluetooth on Kitchen
Bens Mobile: Online via WiFi on Master
Bens Mobile: Online via WiFi on Master

Instructions for Master Node:

1) apt-get install jq screen php5-curl php-mysql php-cli bluez fping

2) mkdir ~/scripts/bluegrid

3) Create the below scripts as per their names with the contents filled out

config.php

Code: Select all

<?php // Configuration
$mysqlserver = "192.168.0.31";
$mysqlusername = "USERNAME";
$mysqlpassword = "PASSWORD";
$mysqldb = "BlueGrid";
$mysqlconn = mysqli_connect("p:".$mysqlserver, $mysqlusername, $mysqlpassword, $mysqldb);
$mysqlconnsetup = mysqli_connect("p:".$mysqlserver, $mysqlusername, $mysqlpassword);
$domoticzserver = "192.168.0.5";
$domoticzusername = "USERNAME";
$domoticzpassword = "PASSWORD";
?>
engine.php

Code: Select all

<?php
// Include system config and other variables
include 'config.php';

// Start work loop
while ( true ){

// Time
$systemutc = shell_exec ("date -u +%s");

// Get data from the MySQL database
$result = mysqli_query($mysqlconn,"SELECT ref,device,node,technology,lastseen FROM devices WHERE ref = '1'");
$row = mysqli_fetch_row($result);

// Check existing state of Domoticz switch
$curl = curl_init();
curl_setopt_array($curl, array(
    CURLOPT_RETURNTRANSFER => 1,
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_SSL_VERIFYHOST => false,
    CURLOPT_URL => "https://$domoticzusername:$domoticzpassword@$domoticzserver/json.htm?type=devices&rid=1137",
));
$resp = curl_exec($curl);
curl_close($curl);
$json = json_decode($resp);
$state = ($json->result[0]->Data);

// Check time since last update
$timedifference = ($systemutc - $row[4]);
// If out of sync with Domoticz switch state, update it
if($timedifference <=5 ) {
echo "$row[1]: Online via $row[3] on $row[2]\n";
if (stripos($state, 'Off') !== false) {
$curl = curl_init();
curl_setopt_array($curl, array(
    CURLOPT_RETURNTRANSFER => 1,
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_SSL_VERIFYHOST => false,
    CURLOPT_URL => "https://$domoticzusername:$domoticzpassword@$domoticzserver/json.htm?type=command&param=switchlight&idx=1137&switchcmd=On",
));
curl_exec($curl);
curl_close($curl);
echo "on";
};
};

// If out of sync with Domoticz switch state, update it
if($timedifference >=20 ) {
echo "Device Offline\n";
if (stripos($state, 'On') !== false) {
$curl = curl_init();
curl_setopt_array($curl, array(
    CURLOPT_RETURNTRANSFER => 1,
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_SSL_VERIFYHOST => false,
    CURLOPT_URL => "https://$domoticzusername:$domoticzpassword@$domoticzserver/json.htm?type=command&param=switchlight&idx=1137&switchcmd=Off",
));
curl_exec($curl);
curl_close($curl);
echo "off";
};
};

// Sleep
usleep(1000000);
}
?>
master.php

Code: Select all

<?php
// Target device
$targetbluetoothmac = "xx:xx:xx:xx:xx:xx";
$targetwifiip = "192.168.0.80";
$targetname = "Bens Mobile";
$targetref = "1";
$nodename = "Master";

// Include system config and other variables
include 'config.php';
// Create tables in the database if needed
$createmysqldatabase = ("CREATE TABLE devices (
ref BIGINT(19) UNSIGNED PRIMARY KEY NOT NULL,
device CHAR(255),
node CHAR(255),
technology CHAR(255),
lastseen BIGINT(19)
)ENGINE = MEMORY;");
mysqli_query($mysqlconn, $createmysqldatabase);
//Disable PHP error reporting
error_reporting(0);

// Start work loop
while ( true ){

// Query WiFi Target
$wifi = shell_exec ("fping -c1 -b 32 -t1000 $targetwifiip 2>/dev/null 1>/dev/null && echo On || echo Off");
if (stripos($wifi, 'On') !== false) {
echo "$targetname: Online via Wifi\n";
$technology = "WiFi";
$sleep = "1000000";
};

// Query Bluetooth Target - if target was not reachable via WiFi
if (stripos($wifi, 'Off') !== false) {
$l2ping = shell_exec ("l2ping -c1 -s32 -t1 $targetbluetoothmac 2>/dev/null 1>/dev/null && echo On || echo Off");
if (stripos($l2ping, 'On') !== false) {
echo "$targetname: Online via Bluetooth\n";
$technology = "Bluetooth";
$sleep = "2500000";
};
};

// Display in terminal if device was not reachable
if ((stripos($wifi, 'Off') !== false) && (stripos($l2ping, 'Off') !== false)) { echo "$targetname: Offline\n"; };

// Send result to MySQL database
if ((stripos($wifi, 'On') !== false) OR (stripos($l2ping, 'On') !== false)) {
$systemutc = shell_exec ("date -u +%s");
$mysqldatainsert = "REPLACE INTO devices(ref, device, node, technology, lastseen)VALUES('$targetref','$targetname','$nodename','$technology','$systemutc')";
mysqli_query($mysqlconn, $mysqldatainsert);
};

// Sleep
usleep("$sleep");
}
?>
setup.php

Code: Select all

<?php
// Include system config and other variables
include 'config.php';
// Check if MySQL server is running at server IP
if (mysqli_ping($mysqlconnsetup)){
echo "";}
else {
  echo "Unable to connect to MySQL server at $mysqlserver is it running?";}
// Create MySQL Database if nessesary
if ($mysqlconnsetup->connect_error) {
    die("Connection failed: " . $mysqlconn->connect_error);}
$mysqlcreatedb = "CREATE DATABASE IF NOT EXISTS $mysqldb";
if ($mysqlconnsetup->query($mysqlcreatedb) === TRUE) {
    echo "MySQL database setup was successful!";
} else {
    echo "MySQL setup error..." . $mysqlconnsetup->error;}
?>
startup.sh

Code: Select all

#!/bin/bash

# Path to BlueGrid folder
cd /root/scripts/bluegrid

# BlueGrid Master
/usr/bin/screen -S bluegridmaster -d -m nice -17 ionice -c2 -n6 php -f master.php

# BlueGrid Engine
/usr/bin/screen -S bluegridengine -d -m nice -17 ionice -c2 -n6 php -f engine.php
4) setup.php is run once to create a new MySQL database: php -f setup.php

5) Run startup.sh to start the master.php and engine.php processes and remember to set the Domoticz device IDX number in the engine.php curl commands. If everything is filled out correctly and you can see your database created in phpmyadmin you should be able to type screen -x and see the screen sessions running and enter them to see the inside operations.

Instructions for Slave Node:

1) apt-get install jq screen php5-curl php-mysql php-cli bluez

2) mkdir ~/scripts/bluegrid

3) Create the below scripts as per their names with the contents filled out

config.php

Code: Select all

<?php // Configuration
$mysqlserver = "192.168.0.31";
$mysqlusername = "USERNAME";
$mysqlpassword = "PASSWORD";
$mysqldb = "BlueGrid";
$mysqlconn = mysqli_connect("p:".$mysqlserver, $mysqlusername, $mysqlpassword, $mysqldb);
$mysqlconnsetup = mysqli_connect("p:".$mysqlserver, $mysqlusername, $mysqlpassword);
?>
slave.php

Code: Select all

<?php
// Target device
$targetbluetoothmac = "xx:xx:xx:xx:xx:xx";
$targetname = "Bens Mobile";
$targetref = "1";
$nodename = "Kitchen";

// Include system config and other variables
include 'config.php';
//Disable PHP error reporting
error_reporting(0);

// Start work loop
while ( true ){

// Time
$systemutc = shell_exec ("date -u +%s");

// Get data from the MySQL database
$result = mysqli_query($mysqlconn,"SELECT ref,device,node,technology,lastseen FROM devices WHERE ref = '1'");
$row = mysqli_fetch_row($result);

// Check time since last update
$timedifference = ($systemutc - $row[4]);

// Query Bluetooth Target
if($timedifference >=8 ) {
$l2ping = shell_exec ("l2ping -c1 -s32 -t1 $targetbluetoothmac 2>/dev/null 1>/dev/null && echo On || echo Off");
if (stripos($l2ping, 'On') !== false) {
echo "$targetname: Online via Bluetooth\n";
$technology = "Bluetooth";
$sleep = "2500000";
};

if ((stripos($l2ping, 'On') !== false)) {
$systemutc = shell_exec ("date -u +%s");
$mysqldatainsert = "REPLACE INTO devices(ref, device, node, technology, lastseen)VALUES('$targetref','$targetname','$nodename','$technology','$systemutc')";
mysqli_query($mysqlconn, $mysqldatainsert);
};
};

if($timedifference <=5 ) {
echo "Standing by...\n";
};

// Sleep
usleep(2500000);
}
?>
4) For the slave startup I'm just using a script in: nano /etc/init.d/bluegrid

Code: Select all

#!/bin/sh
### BEGIN INIT INFO
# Provides: bluegrid  
# Required-Start: $network
# Required-Stop: $network
# Default-Start: 2 3 5
# Default-Stop:
# Description:    
### END INIT INFO

case "$1" in
'start')
        sudo /usr/bin/screen -S bluegridslave -d -m sudo php -f /home/pi/scripts/bluegrid/slave.php
        ;;
'stop')
        ;;
*)
        echo "Usage: $0 { start | stop }"
        ;;
esac
exit 0
Notes:
1) You need to understand and edit as needed the above script to work in your own environment.
2) The PHP curl command is set to allow unsigned SSL certificates which depending on your environment may be a security risk.
3) Raspberry Pi Zero W's make really good slave nodes (they are very small with low power consumption and have built in Bluetooth). :D
Unless otherwise stated, all my code is released under GPL 3 license: https://www.gnu.org/licenses/gpl-3.0.en.html
User avatar
Marci
Posts: 531
Joined: Friday 22 January 2016 18:00
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.8153
Location: Wakefield, West Yorkshire UK
Contact:

Re: Multi-Node Bluetooth and Wifi presence detection

Post by Marci »

For a typical install on Raspberry Pi...

Code: Select all

apt-get install jq screen php5-curl php-mysql php-cli bluez fping
...results in...

Code: Select all

pi@rasprf ~ $ sudo apt-get install jq screen php5-curl php-mysql php-cli bluez fping
Reading package lists... Done
Building dependency tree       
Reading state information... Done
E: Unable to locate package php-mysql
E: Unable to locate package php-cli
The following works fine however.

Code: Select all

sudo apt-get install jq screen php5-curl php5-mysql php5-cli bluez fping
For step 2)

Code: Select all

mkdir ~/scripts/bluegrid
Only works if ~/scripts already exists, otherwise it results in:

Code: Select all

pi@rasprf ~ $ mkdir ~/scripts/bluegrid
mkdir: cannot create directory ‘/home/pi/scripts/bluegrid’: No such file or directory.
This should be...

Code: Select all

mkdir -p ~/scripts/bluegrid
Extended Domoticz homebridge-plugin for latest Homebridge - adds temp/humidity/pressure sensors, power consumption sensors, DarkSkies virtual weather station support, YouLess Meter support, general % usage support & switch/lamp status checking!
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest