Domotique: Echanger des SMS avec son Arduino

Mon Arduino m'envoie des SMS (et je le lui rends bien ...)
J'ai récemment complété mon installation domotique existante (une commande de chauffage décrite dans ce blog, ainsi qu'un système d'alarme ... pas décrit ...) avec un système de commandes (et de retours de la part de mon installation) par SMS interposés.
Plutôt que d'investir dans un shield officiel (qui tourne autour de 50 euros, ce que je trouve hors de prix), j'ai préféré la réutilisation d'un ancien téléphone portable qui trainait dans un de mes tiroirs: un Sagem MyX4.
Avantage: ce téléphone a encore un port série, et se branchait sur un port DB9 de PC.
En interfaçant mon Arduino sur le câble série d'origine, moyennant le passage par un adaptateur MAX232 acheté sur e-bay, il est très simple de communiquer avec lui.

Certains téléphones GSM sont en effet équipés d'un modem, et acceptent les commandes AT.
Le protocole AT permet, au moyen d'une simple ligne de commande, d'envoyer ou lire un SMS.

Compatibilité AT
Tous les téléphones GSM n'étant pas équipés d'un modem, un petit test préliminaire (depuis un PC) s'impose.
Tout d'abord, il faut relier le téléphone à un port série du PC, puis configurer (si possible, ce qui est normalement le cas des anciens téléphones se branchant sur port série) la vitesse du port série. Le MyX4 permet par exemple de faire des échanges à une vitesse maxi de 38400bd.
Lancer ensuite un hyper terminal sous Windows, en choisissant la configuration suivante:

Dans le terminal, saisir ensuite (attention, il va falloir suivre, c'est complexe !):
AT puis appuyer sur Entrée

Si le téléphone est compatible, il va répondre:
OK

Vous pouvez prendre une pause bien méritée ...

Format des SMS
Saisir ensuite AT+CMGF?
Si le téléphone répond 1, c'est gagné, vous pourrez envoyer des SMS au format texte. Attention cependant, le format texte implique des envois avec du texte simple sans caractères accentués.
Si le téléphone répond 0:
Saisir AT+CMGF=1 pour tenter de forcer le mode texte.
Si le téléphone répond ERROR, votre tel n'acceptera d'envoyer / recevoir des SMS qu'au format PDU. Allez donc faire un petit tour sur cette page ...

Envoyer un SMS
Tapez AT+CMGS="num_tel_cible" puis Entrée
Un prompt > s'affiche
Tapez le contenu du SMS, puis CTRL-Z pour envoyer
Le téléphone va vous répondre quelque chose du genre: +CMGS:01

Après quelques secondes, votre destinataire va recevoir votre SMS

Recevoir un SMS
Il va falloir déterminer où sont stockés vos SMS reçus. C'est normalement configurable dans le téléphone, mais une commande AT va vous permettre de vous aider. Les SMS peuvent être soit stockés dans la mémoire du téléphone (ME), soit sur la sim (SM).
Si vous lisez à un endroit où il n'y a pas de SMS, le téléphone ne vous répondra rien lors de vos demandes de lecture.
Choisissez tout d'abord la zone de stockage. Par exemple, pour lire la mémoire du téléphone, tapez:
AT+CPMS="ME"

Pour lire les SMS, tapez ensuite AT+CGML="ALL"
Si un/des SMS se trouvent dans la zone choisie, vous aurez droit à une réponse du genre:
+CGML:900,"REC UNREAD",+336xxxxxxxx",,12/02/13,19/99/99+02"
CONTENU DU SMS

Effacer les SMS
Pour supprimer un SMS, il suffit (normalement) de saisir:
AT+CGMD=Indice_du_SMS
Il se trouve que cette commande ne fonctionne pas sur mon tel. Par contre la commande suivante fonctionne sans problème:
AT+CGMD=1,4
J'ai trouvé cette astuce je ne sais plus trop où. En gros elle doit supprimer tous les SMS reçus, ou au moins les 4 premiers. Toujours est-il que cette commande fonctionne.

Via Arduino
L'envoi ou la réception depuis l'Arduino est somme toute très simple: il suffit de fixer la vitesse du port série à la même vitesse que celui du téléphone, puis de communiquer via Serial.print ou Serial.read.
Pour ma part les commandes implémentées sont assez simples: Th20 pour fixer le chauffage à 20°, ou ThOff pour l'éteindre. Même chose pour l'alarme: AlaOn ou AlaOff.

Mon installation domotique me répond à toute mes commandes pour m'indique si elle a bien pris en compte. De même, je suis prévenu si l'alarme se déclenche ...

Sans trop investir, il est donc possible de s'ouvrir pas mal de possibilités. Et merci à Free, qui permet de faire tout ça pour 2€ par mois !



Une solution alternative, 2 euros moins cher !

Moyennant quelques restrictions, vous n'aurez besoin ni d'abonnement Free, ni même de modem !

Il y a quand même 4 (plus ou moins grosses) limites:
- seul votre Arduino pourra vous sms-er
- il faudra éviter les surconsommation sous peines de blocages (temporaires), mais cette limitation est contournable si vous avez les data actives sur votre téléphone (pour recevoir les notifications de l'agenda Google)
- seul le titulaire de l'agenda Google sera prévenu
- il faut que votre Arduino puisse communiquer avec un PC (via la liaison série par exemple)


Il suffit pour cela de détourner un peu l'utilisation de base de Google Calendar.

A chaque fois que vous créez une tâche dans l'agenda Google, il est possible de paramétrer cette tâche afin d'être prévenu par SMS, alerte ou e-mail.
Il suffit donc de faire un petit script pour qu'il crée une tâche avec demande de SMS et/ou de notification, et vous recevrez ce SMS et cette notif après quelques secondes. Après essais d'une 20aine de tâches (sur une courte période, il s'avère que les SMS ne passent plus (Google doit faire un blocage) mais ça revient très vite, et ça ne coupe même jamais si on n'abuse pas.
Dans tous les cas, les notifications, elles passent toujours (mais il faut garder les data actives sur le téléphone récepteur)

Côté Arduino
En partant du principe que votre Installation Arduino détecte l'évènement à notifier par SMS, et que le PC fait le traitement de création de tâche, autant dire que la notification Arduino->PC est plutôt simple: un simple Serial.Println d'une chaine de caractères quelconque fera l'affaire.

Côté PC
Google fournit une API permettant de créer des évènements (ou de les lire, comme dans mon installation de commande de chauffage) avec Calendar.
Pour ma part j'ai choisi de m'interfacer avec Calendar via des scripts Python.

Voici donc le script permettant de créer ces évènements:


try:
    from xml.etree import ElementTree
except ImportError:
    from elementtree import ElementTree
import gdata.calendar.service
import gdata.service
import atom.service
import gdata.calendar
import atom
import base64
import time

def send_sms(message_text):
    cal_client = gdata.calendar.service.CalendarService()
    cal_client.email = "identifiant GMAIL"
    cal_client.password = "mot de passe GMAIL"
    cal_client.source = 'calendar-sms-misuse-1.0'
    cal_client.ProgrammaticLogin()

    event = gdata.calendar.CalendarEventEntry()
    event.title = atom.Title(text=message_text)
    event.content = atom.Content(text="")

    
    # Les notifs par SMS ne fonctionnent pas si elles ne sont pas programmées pour être déclenchées
    #  au moins 5mn avant le début de la tâche
    # On crée donc une tache commencant dans 6mn, d'une durée de 1mn
    start_time = time.strftime('%Y-%m-%dT%H:%M:%S.000Z', time.gmtime(time.time()+(6*60)))
    end_time = time.strftime('%Y-%m-%dT%H:%M:%S.000Z', time.gmtime(time.time() + 7*60))
    when = gdata.calendar.When(start_time=start_time, end_time=end_time)
    # On crée une alerte à 5mn:

    # Dans le cas où on veut être alerté par tous les moyens possibles
        reminder = gdata.calendar.Reminder(minutes=5, extension_attributes={"method":"all"})
    # Dans le cas où une notif suffit
        reminder = gdata.calendar.Reminder(minutes=5, extension_attributes={"method":"alert"})
    # et dans le cas d'un SMS
        reminder = gdata.calendar.Reminder(minutes=5, extension_attributes={"method":"alert"})
        
    when.reminder.append(reminder)
    event.when.append(when)

    cal_client.InsertEvent(event, '/calendar/feeds/default/private/full')



send_sms("contenu du SMS")
En espérant que ces 2 méthodes vous soient utiles !