[Tuto] Bash et Téléphone connecté au WI-FI +/- Freebox

Bonjour,

je vous propose un tuto sur la surveillance de la présence d’un téléphone connecté au WI-FI et d’envoyer l’état à Gladys via MQTT.

Je propose 2 versions :

  • Avec nmap (fonctionnel avec toutes les box)
  • Avec l’API Freebox avec ou non nmap dans un second temps.

Le tout sur un Raspberry.


TUTO n°3 : Indiquer la présence d’un utilisateur via le WI-FI de son téléphone.


Côté Gladys :


  1. Création de l’appareil MQTT :

Nom : Téléphone connecté au WIFI
Id externe : mqtt:Salle:PhoneConnected (mqtt:Pièce:Élément)
Pièce : Salle

  1. Ajout d’une fonctionnalité de type Compteur entier :

Nom : État de la connexion
Id externe de la fonctionnalité : mqtt:PhoneConnected:StateConnection (mqtt:Élément:Fonction)
Valeur min : 0 (téléphone non connecté)
Valeur max : 1 (téléphone connecté)
Conserver l’historique des états : Oui
Est-ce un capteur : Oui
Topic MQTT pour publier : Vous pouvez vous mettre de côté le topic qui servira plus loin.

  1. Ajout de l’appareil sur le tableau de bord :

Rien de spécifique ici, il faut procéder comme d’habitude.

Voilà, on en a terminé avec Gladys :slight_smile:


Côté BASH :

  1. Fichier partagé : /opt/mosquitto/MQTTConfig.sh

Je vais utiliser le fichier partagé proposé avec mes autres tuto : [TUTO] Partage d'informations entre BASH et Gladys
Il permet de tester la présence de commandes, d’avoir un partage des variables de connexion à Gladys et d’apporter de la couleur dans les messages.

  1. Script BASH : /opt/mosquitto/PhoneConnected.sh

On va le remplir avec l’un des deux codes ci-dessous, l’un avec nmap, l’autre avec l’API Freebox.
nmap nécessite les droits root.

L’idée est d’exécuter une commande et de rechercher l’IP et l’adresse MAC du téléphone.
Il faut donc connaître les deux et configurer sa box afin que l’Ip du téléphone soit fixe.

Il est possible de ne pas travailler sur l’adresse MAC, pour ça, il faut juste donner l’adresse IP à la variable PhoneMAC.

Seul ce qui se trouve entre ### Variables à personnaliser est à adapter.

  • Code utilisant uniquement nmap :

Nécessite les commandes curl, mosquitto_pub et nmap.

#/bin/bash

############################################################
## Envoi de la présence du téléphone sur le wifi à Gladys ##
############################################################

### Variables à personnaliser
# Nombre de seconde entre les récupération de température
# Une petite valeur n'est pas une très bonne idée...
TimeOut=30

# Adresse du topic de l'appareil
# Disponible dans Gladys > Intégration > MQTT > Appareils > Température Raspberry > Température > Topic MQTT pour publier
Topic="gladys/master/device/mqtt:Salle:PhoneConnected/feature/mqtt:PhoneConnected:StateConnection/state"

# Ip du téléphone
PhoneIP="192.168.0.100"

# Adresse mac du téléphone
PhoneMAC="AA:BB:CC:DD:EE:FF"

# Par défaut, téléphone non connecté
OldState=0
### Variables à personnaliser


# Chargement du fichier commun
source /opt/mosquitto/MQTTConfig.sh

# Vérification de la présence des commandes qui si absentes provoquent l'arrêt du script
# Nécessite la commande curl du paquet curl
# Nécessite la commande mosquitto_pub du paquet mosquitto-clients
# Nécessite la commande nmap du paquet nmap
! CommandCheck "curl:curl" "mosquitto_pub:mosquitto-clients" "nmap:nmap" && exit 1


# Bloque le script si le TimeOut est inférieur à 1
if (( ${TimeOut:-0} < 1 ))
then
    echo -e "[${ROUGE}Erreur${RAZ}] Le TimeOut est inadapté." 1>&2
    exit 1
fi


# Boucle infinie
while true
do
    # Recherche de l'ip du téléphone avec nmap puis de son adresse mac dans le résultat
    # Si on le trouve, c'est un faux négatif
    sudo nmap -sP -n "${PhoneIP}" | grep -q "${PhoneMAC}" && State=1 || State=0

    # Si l'état est différent
    if [[ ${State} != ${OldState} ]]
    then
        # Mise à jour de la variable comparative
        OldState=${State}

        # Affichage de l'information
        echo -e "[${FUCHSIA}$(date +'%x %X')${RAZ}] L'état de la connexion du téléphone a changé, état de la connexion : ${BLEUFONCE}${State}${RAZ}."

        # Envoi de l'information à Gladys avec mosquitto_pub
        # -u User : Utilisateur pour la connexion au brocker MQTT, provient du fichier MQTTConfig.sh
        # -P Pass : Mot de passe pour la connexion au brocker MQTT, provient du fichier MQTTConfig.sh
        # -t Topic : Adresse du Topic de l'appareil créé dans Gladys, définit en début de script
        # -m Temperature : Utilisation de la température
        mosquitto_pub -u "${User}" -P "${Pass}" -t "${Topic}" -m "${State}"

        # Récupération de la valeur retour de la commande mosquitto_pub
        MosquittoReturns=${?}

        # Affichage du code erreur de mosquitto si code retour > 0
        (( ${MosquittoReturns} )) && echo -e "[${ROUGE}Erreur${RAZ}] La commande mosquitto_sub a renvoyé le code ${MosquittoReturns}." 1>&2
    fi

    # Pause du script le temps demandé
    sleep "${TimeOut}"
done

Dans cet exemple, la commande nmap recherche l’ip de mon téléphone (192.168.0.100) et de son adresse MAC (AA:BB:CC:DD:EE:FF) toutes les 30 secondes.
Si l’état change, il est envoyé à Gladys.

  • Version avec la Freebox :

Pour communiquer avec l’API Freebox, il est nécessite d’avoir déclaré une app sur la Freebox.

Tuto vite fait pour ça :
Exécution de la commande curl :

curl -X POST -i "http://mafreebox.freebox.fr/api/v10/login/authorize/" --data '{
   "app_id": "fr.freebox.gladys",
   "app_name": "Présence Telephone",
   "app_version": "0.1",
   "device_name": "pi"
}'

On crée une app nommée Présence Telephone ayant pour id fr.freebox.gladys.
Il faut valider l’action sur l’écran de la Freebox (en tout cas pour ma Freebox Revolution).

Cela renvoie un truc du genre :

{"success":true,"result":{"app_token":"xxxxxxx","track_id":1}}

Il est important de conserver l’app_token ! Il faudra la donner dans les paramètres du script.

Il faut que l’app soit validée, on vérifie avec les commandes curl et jq :

track_id=1 # Numéro indiqué dans le retour de la commande précédente
curl "http://mafreebox.freebox.fr/api/v10/login/authorize/${track_id}" 2>/dev/null | jq -r '.result.status'

Cela doit renvoyer granted.
Si ce n’est pas le cas, il faut attendre un peu avant de relancer la commande.

Le script nécessite les commandes curl, mosquitto_pub, jq et nmap.

#/bin/bash

############################################################
## Envoi de la présence du téléphone sur le wifi à Gladys ##
############################################################

### Variables à personnaliser
# Nombre de seconde entre les récupération de température
# Une petite valeur n'est pas une très bonne idée...
TimeOut=30

# Adresse du topic de l'appareil
# Disponible dans Gladys > Intégration > MQTT > Appareils > Température Raspberry > Température > Topic MQTT pour publier
Topic="gladys/master/device/mqtt:Salle:PhoneConnected/feature/mqtt:PhoneConnected:StateConnection/state"

# Identifiant de l'app FreeBox
AppId="fr.freebox.gladys"

# Token de l'app donné par la FreeBox
FreeBoxAppToken="xxxxxxx"

# API de la FreeBox, j'utilisa le v10
FreeBoxAPi="http://mafreebox.freebox.fr/api/v10"

# Ip du téléphone
PhoneIP="192.168.0.100"

# Adresse mac du téléphone
PhoneMAC="AA:BB:CC:DD:EE:FF"

# Par défaut, téléphone non connecté
OldState=0
### Variables à personnaliser


# Chargement du fichier commun
source /opt/mosquitto/MQTTConfig.sh

# Vérification de la présence des commandes qui si absentes provoquent l'arrêt du script
# Nécessite la commande curl du paquet curl
# Nécessite la commande mosquitto_pub du paquet mosquitto-clients
# Nécessite la commande jq du paquet jq
# Nécessite la commande nmap du paquet nmap
! CommandCheck "curl:curl" "mosquitto_pub:mosquitto-clients" "jq:jq" "nmap:nmap" && exit 1


# Bloque le script si le TimeOut est inférieur à 1
if (( ${TimeOut:-0} < 1 ))
then
    echo -e "[${ROUGE}Erreur${RAZ}] Le TimeOut est inadapté." 1>&2
    exit 1
fi


# Fonction de connexion à la FreeBox
function FreeBoxConnection()
{
    # Récupération du challenge
    Challenge="$(curl "${FreeBoxAPi}/login/" 2>/dev/null | jq -r '.result.challenge')"

    # Hash du du challenge avec le token de l'app
    Password="$(printf "${Challenge}" | openssl sha1 -hmac "${FreeBoxAppToken}")"
    Password="${Password##* }"

    # Demande de token de session
    SessionTokenRequest=$(curl -s -X POST "${FreeBoxAPi}/login/session/" --data "{
\"app_id\": \"${AppId}\",
\"password\": \"${Password}\"
}")

    # Récupération du token de session
    SessionToken=$(jq -r '.result.session_token' <<< "${SessionTokenRequest}")

    # S'il n'y a pas de token de session, on signale le problème
    if [[ "${SessionToken}" == "null" ]]
    then
        echo -e "[${ROUGE}Erreur${RAZ}] Impossible de récupérer le token de session !."
        return 1
    fi

    # Si tout est OK
    return 0
}


# Boucle infinie
while true
do
    # Récupération des connexions
    FreeBoxInfos=$(curl --header "X-Fbx-App-Auth: ${SessionToken}" "${FreeBoxAPi}/wifi/ap/1/stations/" 2>/dev/null)

    # Si la connexion n'est plus active
    if [[ $(jq '.success' <<< "${FreeBoxInfos}") == "false" ]]
    then
        # Boucle infinie essayant de se connecter
        while ! FreeBoxConnection
        do
            sleep "${TimeOut}"
        done

        # Une fois sortie de la boucle, relance la boucle parente
        continue
    fi

    # Recherche du téléphone dans le retour des connexions FreeBox avec son id mac
    # Attention, le State est inversé pour plus de clarté sur Gladys
    # 1 = connecté, 0 = déconnecté
    grep -q "${PhoneMAC}" <<< "${FreeBoxInfos}" && State=1 || State=0

    # 2e vérification en cas de non connexion avec nmap
    # rare cas ou tout semble OK mais le retour n'indique pas le téléphone
    if (( ! ${State} ))
    then
        # Recherche de l'ip du téléphone avec nmap puis de son adresse mac dans le résultat
        # Si on le trouve, c'est un faux négatif
        sudo nmap -sP -n "${PhoneIP}" | grep -q "${PhoneMAC}" && State=1
    fi

    # Si l'état est différent
    if [[ ${State} != ${OldState} ]]
    then
        # Mise à jour de la variable comparative
        OldState=${State}

        # Affichage de l'information
        echo -e "[${FUCHSIA}$(date +'%x %X')${RAZ}] L'état de la connexion du téléphone a changé, état de la connexion : ${BLEUFONCE}${State}${RAZ}."

        # Envoi de l'information à Gladys avec mosquitto_pub
        # -u User : Utilisateur pour la connexion au brocker MQTT, provient du fichier MQTTConfig.sh
        # -P Pass : Mot de passe pour la connexion au brocker MQTT, provient du fichier MQTTConfig.sh
        # -t Topic : Adresse du Topic de l'appareil créé dans Gladys, définit en début de script
        # -m Temperature : Utilisation de la température
        mosquitto_pub -u "${User}" -P "${Pass}" -t "${Topic}" -m "${State}"

        # Récupération de la valeur retour de la commande mosquitto_pub
        MosquittoReturns=${?}

        # Affichage du code erreur de mosquitto si code retour > 0
        (( ${MosquittoReturns} )) && echo -e "[${ROUGE}Erreur${RAZ}] La commande mosquitto_sub a renvoyé le code ${MosquittoReturns}." 1>&2
    fi

    # Pause du script le temps demandé
    sleep "${TimeOut}"
done

L’exemple va demander à la Freebox les connexions actuelles toutes les 30 secondes.
Si le token de session n’est plus valide, un nouveau est demandé.
Si le téléphone est non présent, j’ajoute un scan avec nmap car parfois, la Freebox ne renvoie pas la présence du téléphone alors qu’elle le voit bien.

Si on ne veut pas utiliser nmap en plus de la Freebox :
Il faut modifier :

! CommandCheck "curl:curl" "mosquitto_pub:mosquitto-clients" "jq:jq" "nmap:nmap" && exit 1

en

! CommandCheck "curl:curl" "mosquitto_pub:mosquitto-clients" "jq:jq" && exit 1

et il faut supprimer :

    # 2e vérification en cas de non connexion avec nmap
    # rare cas ou tout semble OK mais le retour n'indique pas le téléphone
    if (( ! ${State} ))
    then
        # Recherche de l'ip du téléphone avec nmap puis de son adresse mac dans le résultat
        # Si on le trouve, c'est un faux négatif
        sudo nmap -sP -n "${PhoneIP}" | grep -q "${PhoneMAC}" && State=1
    fi
  1. Exécution du script :
    Il suffit de faire un simple :
bash /opt/mosquitto/PhoneConnected.sh

Ce qui affichera par exemple :

[24/03/2023 16:18:21] L’état de la connexion du téléphone a changé, état de la connexion : 1.
[24/03/2023 16:18:52] L’état de la connexion du téléphone a changé, état de la connexion : 0.
[24/03/2023 16:19:23] L’état de la connexion du téléphone a changé, état de la connexion : 1.

Et la valeur est bien mise à jour dans Gladys.

En cas de problème, il devrait y avoir des messages d’erreur.

Si tout est fonctionnel, il ne reste plus qu’à exécuter le script au démarrage du Raspberry (crontab ou autre).

N’hésitez pas à faire des retours si vous avez des questions ou des idées d’amélioration.


Autres tuto :

TUTO n°1 : Afficher la température du Raspberry dans Gladys.

TUTO n°2 : Lancer une commande BASH via à une action Gladys.

TUTO n°4 : Gestion de son robot aspirateur sous Valetudo dans Gladys.

7 Likes