Hello,
I propose a tutorial on monitoring the presence of a phone connected to Wi-Fi and sending the status to Gladys via MQTT.
I propose two versions:
- With nmap (functional with all boxes)
- With the Freebox API with or without nmap as a second step.
All on a Raspberry Pi.
TUTORIAL #3: Indicate the presence of a user via the Wi-Fi of their phone.
Gladys Side:
- Creating the MQTT device:
Name: Phone connected to Wi-Fi
External ID: mqtt:Room:PhoneConnected (mqtt:Room:Element)
Room: Room
- Adding a feature of the integer counter type:
Name: Connection status
External feature ID: mqtt:PhoneConnected:StateConnection (mqtt:Element:Feature)
Min value: 0 (phone not connected)
Max value: 1 (phone connected)
Keep state history: Yes
Is this a sensor: Yes
MQTT topic to publish: You can set aside the topic that will be used later.
- Adding the device to the dashboard:
Nothing specific here, you need to proceed as usual.
That’s it, we’re done with Gladys ![]()
BASH Side:
- Shared file: /opt/mosquitto/MQTTConfig.sh
I will use the shared file proposed with my other tutorials: [TUTO] Partage d'informations entre BASH et Gladys
It allows you to test the presence of commands, share connection variables to Gladys, and add color to messages.
- BASH script: /opt/mosquitto/PhoneConnected.sh
We will fill it with one of the two codes below, one with nmap, the other with the Freebox API.
nmap requires root privileges.
The idea is to execute a command and search for the IP and MAC address of the phone.
You must therefore know both and configure your box so that the phone’s IP is fixed.
It is possible not to work on the MAC address, for this, you just need to give the IP address to the PhoneMAC variable.
Only what is between ### Variables to customize needs to be adapted.
- Code using only nmap:
Requires the curl, mosquitto_pub, and nmap commands.
#/bin/bash
############################################################
## Sending the presence of the phone on the wifi to Gladys ##
############################################################
### Variables to customize
# Number of seconds between temperature retrievals
# A small value is not a very good idea...
TimeOut=30
# Topic address of the device
# Available in Gladys > Integration > MQTT > Devices > Raspberry Temperature > Temperature > MQTT Topic to publish
Topic="gladys/master/device/mqtt:Room:PhoneConnected/feature/mqtt:PhoneConnected:StateConnection/state"
# Phone IP
PhoneIP="192.168.0.100"
# MAC address of the phone
PhoneMAC="AA:BB:CC:DD:EE:FF"
# By default, phone not connected
OldState=0
### Variables to customize
# Loading the common file
source /opt/mosquitto/MQTTConfig.sh
# Checking the presence of commands that, if absent, cause the script to stop
# Requires the curl command from the curl package
# Requires the mosquitto_pub command from the mosquitto-clients package
# Requires the nmap command from the nmap package
! CommandCheck "curl:curl" "mosquitto_pub:mosquitto-clients" "nmap:nmap" && exit 1
# Blocks the script if the TimeOut is less than 1
if (( ${TimeOut:-0} < 1 ))
then
echo -e "[${ROUGE}Error${RAZ}] The TimeOut is inappropriate." 1>&2
exit 1
fi
# Infinite loop
while true
do
# Search for the phone's IP with nmap then its MAC address in the result
# If found, it's a false negative
sudo nmap -sP -n "${PhoneIP}" | grep -q "${PhoneMAC}" && State=1 || State=0
# If the state is different
if [[ ${State} != ${OldState} ]]
then
# Updating the comparative variable
OldState=${State}
# Displaying the information
echo -e "[${FUCHSIA}$(date +'%x %X')${RAZ}] The connection status of the phone has changed, connection status: ${BLEUFONCE}${State}${RAZ}."
# Sending the information to Gladys with mosquitto_pub
# -u User: User for connecting to the MQTT broker, comes from the MQTTConfig.sh file
# -P Pass: Password for connecting to the MQTT broker, comes from the MQTTConfig.sh file
# -t Topic: Address of the Topic of the device created in Gladys, defined at the beginning of the script
# -m Temperature: Using the temperature
mosquitto_pub -u "${User}" -P "${Pass}" -t "${Topic}" -m "${State}"
# Retrieving the return value of the mosquitto_pub command
MosquittoReturns=${?}
# Displaying the mosquitto error code if return code > 0
(( ${MosquittoReturns} )) && echo -e "[${ROUGE}Error${RAZ}] The mosquitto_sub command returned code ${MosquittoReturns}." 1>&2
fi
# Pausing the script for the requested time
sleep "${TimeOut}"
done
In this example, the nmap command searches for the IP of my phone (192.168.0.100) and its MAC address (AA:BB:CC:DD:EE:FF) every 30 seconds.
If the state changes, it is sent to Gladys.
- Freebox version:
To communicate with the Freebox API, you need to have declared an app on the Freebox.
Quick tutorial for that:
Executing the curl command:
curl -X POST -i "http://mafreebox.freebox.fr/api/v10/login/authorize/" --data '{
"app_id": "fr.freebox.gladys",
"app_name": "Phone Presence",
"app_version": "0.1",
"device_name": "pi"
}'
We create an app named Phone Presence with the id fr.freebox.gladys.
You need to validate the action on the Freebox screen (at least for my Freebox Revolution).
This returns something like:
{"success":true,"result":{"app_token":"xxxxxxx","track_id":1}}
It is important to keep the app_token! You will need to provide it in the script parameters.
The app must be validated, we check with the curl and jq commands:
track_id=1 # Number indicated in the return of the previous command
curl "http://mafreebox.freebox.fr/api/v10/login/authorize/${track_id}" 2>/dev/null | jq -r '.result.status'
It should return granted.
If not, you need to wait a bit before running the command again.
The script requires the curl, mosquitto_pub, jq, and nmap commands.
#/bin/bash
############################################################
## Sending the phone's presence on Wi-Fi to Gladys ##
############################################################
### Variables to customize
# Number of seconds between temperature retrievals
# A small value is not a good idea...
TimeOut=30
# Address of the device topic
# Available in Gladys > Integration > MQTT > Devices > Raspberry Temperature > Temperature > MQTT Topic to publish
Topic="gladys/master/device/mqtt:Salle:PhoneConnected/feature/mqtt:PhoneConnected:StateConnection/state"
# FreeBox app ID
AppId="fr.freebox.gladys"
# App token provided by the FreeBox
FreeBoxAppToken="xxxxxxx"
# FreeBox API, I used v10
FreeBoxAPi="http://mafreebox.freebox.fr/api/v10"
# Phone IP
PhoneIP="192.168.0.100"
# Phone MAC address
PhoneMAC="AA:BB:CC:DD:EE:FF"
# By default, phone not connected
OldState=0
### Variables to customize
# Loading the common file
source /opt/mosquitto/MQTTConfig.sh
# Checking for the presence of commands that, if absent, cause the script to stop
# Requires the curl command from the curl package
# Requires the mosquitto_pub command from the mosquitto-clients package
# Requires the jq command from the jq package
# Requires the nmap command from the nmap package
! CommandCheck "curl:curl" "mosquitto_pub:mosquitto-clients" "jq:jq" "nmap:nmap" && exit 1
# Blocks the script if the TimeOut is less than 1
if (( ${TimeOut:-0} < 1 ))
then
echo -e "[${ROUGE}Error${RAZ}] The TimeOut is inappropriate." 1>&2
exit 1
fi
# Function to connect to the FreeBox
function FreeBoxConnection()
{
# Retrieving the challenge
Challenge="$(curl "${FreeBoxAPi}/login/" 2>/dev/null | jq -r '.result.challenge')"
# Hashing the challenge with the app token
Password="$(printf "${Challenge}" | openssl sha1 -hmac "${FreeBoxAppToken}")"
Password="${Password##* }"
# Requesting a session token
SessionTokenRequest=$(curl -s -X POST "${FreeBoxAPi}/login/session/" --data "{
\"app_id\": \"${AppId}\",
\"password\": \"${Password}\"
}")
# Retrieving the session token
SessionToken=$(jq -r '.result.session_token' <<< "${SessionTokenRequest}")
# If there is no session token, report the problem
if [[ "${SessionToken}" == "null" ]]
then
echo -e "[${ROUGE}Error${RAZ}] Unable to retrieve the session token!"
return 1
fi
# If everything is OK
return 0
}
# Infinite loop
while true
do
# Retrieving connections
FreeBoxInfos=$(curl --header "X-Fbx-App-Auth: ${SessionToken}" "${FreeBoxAPi}/wifi/ap/1/stations/" 2>/dev/null)
# If the connection is no longer active
if [[ $(jq '.success' <<< "${FreeBoxInfos}") == "false" ]]
then
# Infinite loop trying to connect
while ! FreeBoxConnection
do
sleep "${TimeOut}"
done
# Once out of the loop, restart the parent loop
continue
fi
# Searching for the phone in the FreeBox connection return with its MAC ID
# Note: The State is inverted for better clarity in Gladys
# 1 = connected, 0 = disconnected
grep -q "${PhoneMAC}" <<< "${FreeBoxInfos}" && State=1 || State=0
# 2nd check in case of non-connection with nmap
# Rare case where everything seems OK but the return does not indicate the phone
if (( ! ${State} ))
then
# Searching for the phone's IP with nmap and then its MAC address in the result
# If found, it's a false negative
sudo nmap -sP -n "${PhoneIP}" | grep -q "${PhoneMAC}" && State=1
fi
# If the state is different
if [[ ${State} != ${OldState} ]]
then
# Updating the comparative variable
OldState=${State}
# Displaying the information
echo -e "[${FUCHSIA}$(date +'%x %X')${RAZ}] The phone connection status has changed, connection status: ${BLEUFONCE}${State}${RAZ}."
# Sending the information to Gladys with mosquitto_pub
# -u User: User for connecting to the MQTT broker, comes from the MQTTConfig.sh file
# -P Pass: Password for connecting to the MQTT broker, comes from the MQTTConfig.sh file
# -t Topic: Address of the device topic created in Gladys, defined at the beginning of the script
# -m Temperature: Using the temperature
mosquitto_pub -u "${User}" -P "${Pass}" -t "${Topic}" -m "${State}"
# Retrieving the return value of the mosquitto_pub command
MosquittoReturns=${?}
# Displaying the mosquitto error code if return code > 0
(( ${MosquittoReturns} )) && echo -e "[${ROUGE}Error${RAZ}] The mosquitto_sub command returned code ${MosquittoReturns}." 1>&2
fi
# Pausing the script for the requested time
sleep "${TimeOut}"
done
The example will ask the Freebox for current connections every 30 seconds.
If the session token is no longer valid, a new one is requested.
If the phone is not present, I add a scan with nmap because sometimes the Freebox does not return the presence of the phone even though it sees it well.
If you don’t want to use nmap in addition to the Freebox:
You need to modify:
! CommandCheck "curl:curl" "mosquitto_pub:mosquitto-clients" "jq:jq" "nmap:nmap" && exit 1
to
! CommandCheck "curl:curl" "mosquitto_pub:mosquitto-clients" "jq:jq" && exit 1
and you need to delete:
# 2nd check in case of non-connection with nmap
# Rare case where everything seems OK but the return does not indicate the phone
if (( ! ${State} ))
then
# Searching for the phone's IP with nmap and then its MAC address in the result
# If found, it's a false negative
sudo nmap -sP -n "${PhoneIP}" | grep -q "${PhoneMAC}" && State=1
fi
- Running the script:
Just do a simple:
bash /opt/mosquitto/PhoneConnected.sh
This will display, for example:
[24/03/2023 16:18:21] The phone connection status has changed, connection status: 1.
[24/03/2023 16:18:52] The phone connection status has changed, connection status: 0.
[24/03/2023 16:19:23] The phone connection status has changed, connection status: 1.
…
And the value is correctly updated in Gladys.
In case of problems, there should be error messages.
If everything is functional, all that’s left is to run the script at Raspberry startup (crontab or other).
Feel free to provide feedback if you have questions or ideas for improvement.
Other tutorials:
TUTORIAL #1: Displaying the Raspberry’s temperature in Gladys.
TUTORIAL #2: Running a BASH command via a Gladys action.
TUTORIAL #4: Managing your robot vacuum under Valetudo in Gladys.