logo gammu

Redémarrer une freebox par SMS avec l’API freebox, Node-RED et une passerelle SMS utilisant gammu (et un raspberry pi)

Ces derniers temps je dois couramment redémarrer ma freebox, car il semble que je sois concerné par ce bug. En effet, en cas de perte momentanée de la synchronisation adsl, le retour à la normale ne se fait correctement que pour le flux TV mais pas pour le flux internet lorsque la freebox est en mode bridge. Pourquoi pas tenter de redémarrer une freebox par SMS.

On peut aisément redémarrer une freebox en débranchant son alimentation par exemple, en revanche c’est plus compliqué lorsqu’on n’est pas à la maison…

Évidemment, il n’est pas possible de redémarrer la freebox à distance si l’accès à internet est coupé pour ce qui est derrière, et on n’a pas forcément envie d’exposer l’API de la freebox sur internet. C’est là où une passerelle SMS peut être décisive. On assumera ici disposer d’une passerelle SMS pouvant envoyer et recevoir des SMS en utilisant gammu.

Node-Red

C’est un workflow réalisé avec l’outil de développement visuel Node-Red qui sera en charge de surveiller l’arrivée d’un nouveau SMS, et de déclencher l’action correspondant à l’ordre reçu.

workflow node-red

Celui-ci surveille le dossier dans lequel gammu dépose un fichier pour chaque SMS reçu. A chaque fois qu’un nouveau fichier est créé, il est analysé:

  • Le numéro de téléphone de l’expéditeur est une composante du nom du fichier : il est extrait et comparé à une liste d’expéditeurs autorisés:
    • Si il n’en fait pas partie, le fichier est détruit.
    • Si l’expéditeur est autorisé, le contenu du fichier est lu.
  • le contenu du fichier est comparé à une liste de commandes connues:
    • si il n’en fait pas partie, le workflow s’arrête là.
    • si la commande contenue dans le SMS est connue, la branche du worflow concernée est déroulée. Dans cet exemple, il n’y a que deux commandes connues:
      • Ca va ? : provoque la réponse « oui » par SMS à l’expéditeur.
      • Reboot freebox : appelle un script qui va redémarrer la freebox par l’intermédiaire de son API.

Voici un export du workflow:

[
    {
        "id": "ca4bf2d6.9fbc",
        "type": "tab",
        "label": "flow SMS",
        "disabled": false,
        "info": "vérifie l'arrivée de nouveaux SMS sur la passerelle\nignore les sms qui ne sont pas envoyés depuis mon numéro de portable\n\n"
    },
    {
        "id": "86ff5b05.235d18",
        "type": "watch",
        "z": "ca4bf2d6.9fbc",
        "name": "verifie nouveaux SMS",
        "files": "/var/spool/gammu/inbox",
        "recursive": "",
        "x": 100,
        "y": 100,
        "wires": [
            [
                "7b3b9a42.386a7c"
            ]
        ]
    },
    {
        "id": "7b3b9a42.386a7c",
        "type": "function",
        "z": "ca4bf2d6.9fbc",
        "name": "récupère expéditeur SMS",
        "func": "var fichiersms = msg.payload;\nvar re = /^.+(0666666666|\\+33666666666).+$/;\nif (fichiersms.match(re) !== null) {\n  msg.expediteur = fichiersms.match(re)[1];\n}\nelse { msg.expediteur = \"expéditeur non approuvé\"; }\nmsg.fichier = fichiersms;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 330,
        "y": 100,
        "wires": [
            [
                "d3435c3c.fac6e8"
            ]
        ]
    },
    {
        "id": "d3435c3c.fac6e8",
        "type": "switch",
        "z": "ca4bf2d6.9fbc",
        "name": "expéditeur approuvé ?",
        "property": "expediteur",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "expéditeur non approuvé",
                "vt": "str"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "true",
        "repair": true,
        "outputs": 2,
        "x": 560,
        "y": 100,
        "wires": [
            [
                "9faaf8e3.7dcb3"
            ],
            [
                "aba086a0.3d4d78"
            ]
        ]
    },
    {
        "id": "aba086a0.3d4d78",
        "type": "file in",
        "z": "ca4bf2d6.9fbc",
        "name": "lit le message",
        "filename": "",
        "format": "utf8",
        "chunk": false,
        "sendError": false,
        "encoding": "none",
        "x": 800,
        "y": 120,
        "wires": [
            [
                "977f5b4a.3686f8"
            ]
        ]
    },
    {
        "id": "9faaf8e3.7dcb3",
        "type": "pythonshell in",
        "z": "ca4bf2d6.9fbc",
        "name": "supprime SMS",
        "pyfile": "/home/pi/scripts/rm.py",
        "virtualenv": "",
        "continuous": false,
        "stdInData": false,
        "x": 820,
        "y": 40,
        "wires": [
            []
        ]
    },
    {
        "id": "977f5b4a.3686f8",
        "type": "switch",
        "z": "ca4bf2d6.9fbc",
        "name": "analyse commande du SMS reçu",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "Ca va ?",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "Reboot freebox",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 2,
        "x": 220,
        "y": 240,
        "wires": [
            [
                "a2ffb584.5f99d8"
            ],
            [
                "26e292da.6c188e"
            ]
        ]
    },
    {
        "id": "b4957659.76414",
        "type": "pythonshell in",
        "z": "ca4bf2d6.9fbc",
        "name": "réponse par SMS",
        "pyfile": "/home/pi/scripts/envoie_sms.py",
        "virtualenv": "",
        "continuous": false,
        "stdInData": false,
        "x": 1230,
        "y": 320,
        "wires": [
            []
        ]
    },
    {
        "id": "a2ffb584.5f99d8",
        "type": "change",
        "z": "ca4bf2d6.9fbc",
        "name": "répond que ça va",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "oui",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 790,
        "y": 240,
        "wires": [
            [
                "b4957659.76414"
            ]
        ]
    },
    {
        "id": "26e292da.6c188e",
        "type": "template",
        "z": "ca4bf2d6.9fbc",
        "name": "prépare reboot freebox",
        "field": "payload",
        "fieldType": "msg",
        "format": "handlebars",
        "syntax": "plain",
        "template": "/home/pi/scripts/reboot-freebox.sh",
        "output": "str",
        "x": 570,
        "y": 400,
        "wires": [
            [
                "1dd3ea8.ca6ea16"
            ]
        ]
    },
    {
        "id": "1dd3ea8.ca6ea16",
        "type": "exec",
        "z": "ca4bf2d6.9fbc",
        "command": "",
        "addpay": true,
        "append": "",
        "useSpawn": "false",
        "timer": "90",
        "oldrc": false,
        "name": "exécute le reboot de la freebox",
        "x": 850,
        "y": 400,
        "wires": [
            [
                "b4957659.76414"
            ],
            [
                "55e51687.cb37e8"
            ],
            []
        ]
    },
    {
        "id": "55e51687.cb37e8",
        "type": "debug",
        "z": "ca4bf2d6.9fbc",
        "name": "débug reboot FB",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 890,
        "y": 460,
        "wires": []
    }
]

On remarque que le workflow appelle 3 scripts. Les deux premiers, en python, auraient parfaitement pu être évités et les commandes qu’ils fournissent exécutées en bash (une commande gammu pour envoyer un SMS, une commande pour supprimer un fichier…) mais c’était l’occasion de tester le node de type pythonshell. Le 3e script, « reboot-freebox.sh » fait appel à l’API de la freebox.

Utilisation de l’API freebox avec bash

On utilise la librairie bash « freeboxos_bash_api.sh » (merci à son auteur) que le script qui redémarre la freebox sourcera. Elle servira également à autoriser le script auprès de la freebox.

Autoriser le script dans la freebox

En suivant la documentation fournie:

$ source ./freeboxos_bash_api.sh
$ authorize_application  'reboot_FB.app'  'Reboot de la FB'  '1.0'  'SMS gateway'

Please grant/deny access to the application on the Freebox LCD...
Authorization granted

MY_APP_ID="reboot_FB.app"
MY_APP_TOKEN="zlsfwaiciP0uetipVal+GNlf1L+26CyqFAKEQYjOx3JScAGkGAaFMBtPSwZ21X+V"

Il est nécessaire de réaliser une action physique sur la freebox, pour répondre « oui » à la question qui demande si l’on veut bien autoriser l’application à interagir avec elle. De plus, dans l’interface web de gestion de la freebox, à la rubrique gestion des accès -> applications, il faudra éditer notre autorisation fraîchement déclarée pour ajouter le droit de modifier les paramètres de la freebox. C’est en effet nécessaire pour que l’application ait le droit de la redémarrer.

Le retour de la commande fournit en plus de l’identifiant de l’application autorisée un token qu’il faudra renseigner à chaque interaction avec la freebox.

Ajuster les droits du script sur l’api freebox

Pour pouvoir utiliser la fonction reboot_freebox de l’api, le script devra avoir le droit de modifier les paramètres de la freebox. Ça se fait depuis l’interface web d’administration de Freebox OS, dans les paramètres de la freebox, rubrique gestion des accès, onglet applications :

Le script de redémarrage de la freebox

#!/bin/bash

source /home/pi/scripts/freeboxos_bash_api.sh

MY_APP_ID="reboot_FB.app"
MY_APP_TOKEN="zlsfwaiciP0uetipVal+GNlf1L+26CyqFAKEQYjOx3JScAGkGAaFMBtPSwZ21X+V"

login_freebox $MY_APP_ID $MY_APP_TOKEN
reboot_freebox

echo "freebox en cours de reboot..."                                

Il n’y a pas grand chose à faire ici car c’est la librairie qui a fait tout le boulot, le script s’identifie à la freebox avec l’ID et le token reçus précédemment. Il appelle ensuite la fonction « reboot_freebox » de la librairie bash. Le echo final est surtout là pour être récupéré par le workflow Node-Red afin d’être envoyé à l’opérateur pour confirmer que la commande a bien été reçue.

o/

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *