Je vous ai présenté il y a quelque temps le boîtier Pironman de SunFounder. C’est un superbe boîtier type PC avec des faces latérales transparentes qui laissent voir des LEDs colorées. Avec la carte NadHAT MK2 4G de Garatronic je me suis dit qu’on pouvait trouver une application regroupant les deux objets, pour piloter les LEDs par SMS.
Au sommaire :
Piloter les LEDs de Pironman par SMS avec la carte NadHAT MK2 4G de Garatronic
A quoi ça sert ?
A quoi ça sert de piloter les LEDs d’un boîtier de Raspberry Pi par SMS ?
A rien !
Et comme beaucoup de projets makers, quand ça ne sert à rien c’est indispensable …
Non, allez, je vous explique : Vous avez une maison au bout d’un chemin où Internet n’arrive pas (une zone blanche, c’est pour ça qu’il y a de la neige). Avec un Raspberry Pi et la carte 4G NadHAT MK2 de Garatronic vous pouvez connecter le Raspberry Pi à la 4G et naviguer sur Internet, mais aussi piloter une installation domotique par SMS.
Par exemple vous mettrez la chaudière en fonctionnement avant votre arrivée, vous ouvrirez les volets… En retour vous recevrez un accusé de réception et des valeurs de votre choix (température, humidité, détecteur de flamme de la chaudière…).
La carte NadHAT MK2 et le Raspberry Pi
La carte NadHAT MK2 dispose d’un connecteur qui permet de la raccorder au GPIO et d’utiliser le port série disponible sur le Raspberry Pi.
Pour montrer en exposition ce n’est pas la meilleure solution pour moi car avec le boîtier Pironman la carte serait impossible à monter à cause du Ventirad. De plus le port série est plus lent que l’USB et en 4G ça fait goulet d’étranglement.
J’ai donc choisi de coller la carte NadHAT MK2 4G au dessus du boîtier Pironman avec un double face.
Les commandes AT ou Hayes
Pour un « vieux » informaticien comme moi, les commandes du modem Hayes, ou commandes AT c’est tout un volet de mon travail à une époque lointaine (au millénaire dernier) parce que tous les modems parlaient ce langage. Si vous démarrez avec ces commandes qui commencent par… AT , je vous laisse les découvrir. Il y a des commandes « universelles » et certaines qui sont propres à certains constructeurs, parce qu’elles n’existent que chez CE constructeur ou qu’elles sont « un peu » aménagées pour répondre à ses besoins.
Le Programme Python
Comme je dis toujours, je suis un maker, pas un développeur. L’objectif de mes programmes, c’est de faire fonctionner le projet. Après si vous y regardez de près vous trouverez des trucs pas jolis, des choses qu’on ne fait pas… Moi, si ça fonctionne ça me va. Le programme est disponible sur GitHub, brut de fonderie et il ne tient qu’à vous de l’améliorer et de le redistribuer (j’ajouterai le lien avec plaisir !)
Il y a du debuggage de maker, oui, des print() ! pour voir par où passe le programme et m’aider à trouver mes conneries erreurs… Libre à vous de les enlever également. Mais pour ceux qui sont passés sur le stand à Vitré et ont changé les couleurs du Piroman par SMS, le programme a bien fonctionné 😉
A noter des sleep() qui laissent le temps à la carte de réagir. vous les supprimerez si ça vous chante, mais ça risque de moins bien marcher…
# -*- coding : utf8 -*-
# NadHat_MK2.py
# https://www.python-exemplarisch.ch/index_en.php?inhalt_links=navigation_en.inc.php&inhalt_mitte=raspi/en/gsm.inc.php
# NadHAT MK2 sur boitier Pironman
# Attent un prénom puis une couleur
# Affiche la couleur dans le Pironman
import serial
import io
import time
import os
import subprocess
import sys
import shlex
from gpiozero import CPUTemperature
liste_couleurs = ['rouge', 'vert', 'bleu', 'jaune', 'mauve', 'blanc']
liste_hexa = ['FF000', '00FF00', '0000FF', 'FFFF00', 'FF00FF', 'FFFFFF']
tel_carte = "+336xxxxxx13"
SERIAL_PORT = "/dev/ttyUSB2"
signal = serial.Serial(
port=SERIAL_PORT,
baudrate=9600,
bytesize=8,
parity='N',
timeout=1,
stopbits=1,
rtscts=False,
dsrdtr=False
)
signal_text = io.TextIOWrapper(signal, newline='\r\n')
# Configurer la carte pour les SMS
# Passer en mode ECHO OFF
print("\r\nMode ECHO OFF")
signal.write(str.encode('ATE0\r'))
rep = signal.read(signal.inWaiting())
print(rep)
# Stocker les SMS en mémoire flash
print("\r\nStocker les SMS dans la mémoire flash")
signal.write(str.encode('AT+CPMS="ME", "ME", "ME"\r'))
rep = signal.read(signal.inWaiting())
print(rep)
signal.write('AT+CSCS="IRA"\r'.encode()) # mode IRA
time.sleep(1)
rep = signal.read(signal.inWaiting())
print(rep)
signal.write("AT+CMGF=1\r\n".encode()) # set to text mode
time.sleep(1)
rep = signal.read(signal.inWaiting())
print(rep)
signal.write('AT+CMGD=1,4\r\n'.encode()) # delete all SMS
time.sleep(1)
rep = signal.read(signal.inWaiting())
print(rep)
# =======================================================================
# On envoie un SMS sur la carte elle même pour récupérer l'heure GSM
# et mettre le Raspberry Pi à l'heure s'il n'est pas connecté à un réseau
# Envoyer SMS au N° de la carte
print ('AT+CMGS="'+ tel_carte + '"')
signal.write(('AT+CMGS="' + tel_carte +'"\r\n').encode())
time.sleep(3)
rep = signal.read(signal.inWaiting())
print("Apres CGMS : \r\n",rep.decode())
time.sleep(3)
sms = "SMS\r\n"
signal.write(sms.encode())
time.sleep(1)
rep = signal.read(signal.inWaiting())
print("SMS Carte envoyé : \r\n",rep.decode())
signal.write(chr(26).encode())
time.sleep(1)
rep = signal.read(signal.inWaiting())
print("Fin SMS et OK : \r\n",rep.decode())
time.sleep(1)
# On lit le SMS
signal.write("AT+CMGR=1\r".encode())
time.sleep(1)
reply = signal.read(signal.inWaiting())
print ("SMS sur la carte reçu : \n\r", reply)
time.sleep(2)
# Extraire les données du message
data = reply.decode()
# Séparer en fonction de CR LF
decoupe=(data.split("\r\n"))
#print ("Decoupe : ", decoupe)
message = decoupe[2]
print("Message : ", message)
print("Message Type : ",type(message))
#Telephone de l'appelant
tel = data[23:35]
#print(type(tel))
print ("Téléphone : ", tel)
# Date fournie par le réseau
date = data[41:58]
print("Date : ", date)
#Créer chaine date_heure
an= data[41:43]
print(type(an))
mois=data[44:46]
jour=data[47:49]
heure=data[50:52]
minute=data[53:55]
seconde=data[56:58]
# Traitement de la date et de l'heure
date_sms = jour + " " + mois + " 20" + an
heure_sms = heure + ":" + minute + ":" + seconde
print("Date du SMS : ", date_sms)
print("Heure du SMS : ", heure_sms)
# Effacer tous les SMS
signal.write('AT+CMGD=1,4\r\n'.encode()) # delete all SMS
time.sleep(1)
rep = signal.read(signal.inWaiting())
print("Efface les SMS : \r\n",rep.decode())
# Mettre l'OS à l'heure
# Créer la chaine date Heure
date_heure = "'20"+an+"-"+mois+"-"+jour+" "+heure+":"+minute+":"+seconde+"'"
# Créer la chaine date Heure
#date_heure = "'2023-01-17 11:00:00'"
chaine = "sudo date -s " + date_heure
print ("Chaine : ", chaine)
# Arrêter la mise à l'heure NTP
print("Arret NTP")
subprocess.run(["sudo", "timedatectl", "set-ntp", "0"])
time.sleep(1)
print("Mofifier heure système ")
#subprocess.call(shlex.split("sudo date -s '2023-01-17 19:00:00'"))
subprocess.call(shlex.split(chaine))
print ("Heure modifiée ")
time.sleep(1)
# On se met en attente du SMS qui va déclencher le programme
reply = signal.read(signal.inWaiting()) # Clean bu
print ("\r\n=============== EN ATTENTE DE SMS... ==============================")
while True:
reply = signal.read(signal.inWaiting())
#print(reply, len(reply))
# Est-ce qu'on a reçu un SMS ?
if len(reply) != 0:
signal.write("AT+CMGR=1\r".encode())
time.sleep(1)
reply = signal.read(signal.inWaiting())
print ("SMS reçu : \n\r", reply)
time.sleep(2)
# Extraire les données du message
data = reply.decode()
# Séparer en fonction de CR LF
decoupe=(data.split("\r\n"))
#print ("Decoupe : ", decoupe)
message = decoupe[2]
print("Message : ", message)
print("Message Type : ",type(message))
#Telephone de l'appelant
tel = data[23:35]
#print(type(tel))
print ("Téléphone : ", tel)
# Date fournie par le réseau
date = data[41:58]
print("Date : ", date)
#Créer chaine date_heure
an= data[41:43]
print(type(an))
mois=data[44:46]
jour=data[47:49]
heure=data[50:52]
minute=data[53:55]
seconde=data[56:58]
# Now create new time string in the form MMDDhhmmYYYY for the date program
date_sms = jour + " " + mois + " 20" + an
heure_sms = heure + ":" + minute + ":" + seconde
print("Date du SMS : ", date_sms)
print("Heure du SMS : ", heure_sms)
# Effacer tous les SMS
signal.write('AT+CMGD=1,4\r\n'.encode()) # delete all SMS
time.sleep(1)
rep = signal.read(signal.inWaiting())
print("Efface les SMS : \r\n",rep.decode())
# Enlever les espaces avant/après message
message = message.strip()
#print(type(message))
# Envoyer la réponse au N° appelant
print ('AT+CMGS="'+ tel + '"')
signal.write(('AT+CMGS="' + tel +'"\r\n').encode())
time.sleep(3)
rep = signal.read(signal.inWaiting())
print("Apres CGMS : \r\n",rep.decode())
time.sleep(3)
choix_couleur = "\r\nChoisis ta couleur : \r\n Rouge, vert, bleu, jaune, mauve, blanc et envoie la par SMS"
retour = "Bonjour " + message + choix_couleur +"\r\n"
print ("Retour : ", retour)
signal.write(retour.encode())
time.sleep(1)
rep = signal.read(signal.inWaiting())
print("Texte retour envoyé : \r\n",rep.decode())
signal.write(chr(26).encode())
time.sleep(1)
rep = signal.read(signal.inWaiting())
print("Fin SMS et OK : \r\n",rep.decode())
time.sleep(1)
# Attendre la réponse +CMGR
# Effacer tous les SMS
signal.write('AT+CMGD=1,4\r\n'.encode()) # delete all SMS
time.sleep(1)
# Attendre la réponse du participant
#print(reply, len(reply))
# Est-ce qu'on a reçu un SMS ?
reply = signal.read(signal.inWaiting())
print(type(reply))
print("Reply avant le while : ",reply)
while bytes("+CMGR", 'utf_8') not in reply :
signal.write("AT+CMGR=1\r".encode())
time.sleep(1)
reply = signal.read(signal.inWaiting())
data = reply.decode()
decoupe=(data.split("\r\n"))
time.sleep(1)
print ("Decoupe : ", decoupe, "\r\nLongueur de Découpe : ", len(decoupe))
for morceau in decoupe :
print("Decoupe : ", morceau)
# Si la ligne 2 contient CMTI lire ligne 4
# Sinon lire ligne 2
"""if len(decoupe) == 8 :
couleur = decoupe[4]
if len(decoupe) == 6 :
couleur = decoupe[2]
if len(decoupe) == 7 :
couleur = decoupe[3]"""
if "CMTI" in decoupe[1] :
couleur = decoupe[4]
else :
couleur = decoupe[2]
print("Couleur reçue : \r\n",couleur)
# Vérifier si la couleur est présente
rep_couleur = couleur.strip() # Supprimer les espaces avant/après
rep_couleur = rep_couleur.lower() # mettre la réponse en minuscules
# Effacer tous les SMS
signal.write('AT+CMGD=1,4\r\n'.encode()) # delete all SMS
time.sleep(1)
if rep_couleur in liste_couleurs :
# Lire la température CPU
cpu = CPUTemperature()
print("Température : ", cpu.temperature)
# La couleur existe dans la liste
print("La couleur existe : ", rep_couleur)
# Répondre que la couleur est OK
# Préparer la date
date_sms = jour + "/" + mois + "/" + "20" + an
heure_sms = heure + ":" + minute
date = date_sms + heure_sms
degre = "C"
chaine = date_sms + "\r\n" + heure_sms + "\r\n" + "OK, je passe en couleur " + rep_couleur + "\r\n" + "La température du CPU est : " + "\r\n" + str(int(cpu.temperature)) + degre
# Envoyer la réponse au N° appelant
print ('AT+CMGS="'+ tel + '"')
signal.write(('AT+CMGS="' + tel +'"\r\n').encode())
time.sleep(3)
rep = signal.read(signal.inWaiting())
print("Apres CGMS : \r\n",rep.decode())
time.sleep(3)
signal.write(chaine.encode())
time.sleep(1)
rep = signal.read(signal.inWaiting())
print("Texte confirmation envoyé : \r\n",rep.decode())
signal.write(chr(26).encode())
time.sleep(1)
rep = signal.read(signal.inWaiting())
print("Fin confirmation : \r\n",rep.decode())
time.sleep(1)
# Récupérer l'indice de la couleur dans la liste
position = liste_couleurs.index(rep_couleur)
print("Position de la couleur : ", position)
# Récupérer le code hexa correspondant
hexa = liste_hexa[position]
print("Code hexa : ", hexa)
# Modifier la couleur des LED
subprocess.run(["pironman", "-rc", hexa])
# Vider le buffer
rep = signal.read(signal.inWaiting())
time.sleep(3)
rep = signal.read(signal.inWaiting())
print("Contenu à la fin des op : ", rep)
# Recommencer
print ("\r\n======================= ENVOYEZ VOTRE PRENOM ==============================\n\r" )
else:
# La couleur n'existe pas
# On envoie un SMS pour dire que ce n'est pas bon !
print ('AT+CMGS="'+ tel + '"')
signal.write(('AT+CMGS="' + tel +'"\r\n').encode())
time.sleep(1)
rep = signal.read(signal.inWaiting())
print("Apres CGMS : \r\n",rep.decode())
erreur_couleur = "\r\nCette couleur n'existe pas dans la liste !"
retour = "Désolé " + message + ", il faut recommencer à zéro en envoyant ton prénom !" +"\r\n"
print ("Retour erreur : ", retour)
signal.write(retour.encode())
time.sleep(1)
rep = signal.read(signal.inWaiting())
print("Texte erreur envoyé : \r\n",rep.decode())
signal.write(chr(26).encode())
time.sleep(1)
rep = signal.read(signal.inWaiting())
print("Fin SMS et OK : \r\n",rep.decode())
time.sleep(1)
Comme le Raspberry Pi n’est pas connecté à Internet, ni au WiFi (je vous rappelle qu’on est en zone blanche Internet), il faut quand même le mettre à l’heure.
Je n’ai pas trouvé comment récupérer l’heure du réseau (apparemment la commande AT ne fonctionne pas alors qu’avec la NadHAT v1 en 2G ça fonctionnait). J’ai contourné le problème en enlevant la mise à l’heure via NTP et en envoyant un premier SMS à la carte. Comme le SMS est horodaté… Cette information me sert à mettre l’horloge sur RasPi à l’heure (et à la date). Ce n’est parfois pas immédiat mais ça fonctionne. Il faut désactiver le NTP (et le remettre lorsque vous connectez le Raspberry Pi à un réseau local en filaire ou en WiFi)
timedatectl set-ntp true
(ou false)
Voilà je vous livre ça tel quel, c’est un exemple d’utilisation de la carte Garatronic « en vrai » et vous pourrez l’utiliser pour développer vos propres applications. Ceux qui sont passés sur le stand à Vitré ont pu tester ce programme…







Ping : Piloter les LEDs de Pironman par SMS avec la carte NadHAT MK2 4G de Garatronic
Ping : Boîtier Pironman 5 de SunFounder pour Raspberry Pi 5 avec M.2 NVMe PCIe - Framboise 314, le Raspberry Pi à la sauce française....