Description de l'implémentation de la surveillance interne¶
Ce script implique la connexion à un broker MQTT et l'envoi de données à partir d'un capteur DHT22 à l'aide d'un microcontrôleur. Il utilise la bibliothèque umqttsimple
pour la communication MQTT et une bibliothèque de journalisation personnalisée pour enregistrer les événements.
Connexion MQTT¶
La bibliothèque umqttsimple
est une bibliothèque officielle MicroPython permettant de communiquer avec un broker MQTT (Message Queuing Telemetry Transport). Voici le lien vers cette bibliothèque : umqttsimple.
Logging¶
La bibliothèque de journalisation que j'ai créée en Python sert à créer et à écrire des logs dans un fichier, fournissant des informations sur ce que fait le microcontrôleur en temps réel. Mon log est constitué de trois parties :
- Niveau de gravité : Il y a quatre possibilités :
- [Info] : Pour les informations générales envoyées au serveur.
- [Data] : Pour les données envoyées au serveur.
- [Warning] : Pour les avertissements indiquant que certaines exécutions n'ont pas fonctionné.
- [Error] : Pour toutes les erreurs d'exécution.
- Date et heure : Une chaîne de caractères composée de la date avec l'heure, les minutes et les secondes, récupérée grâce à la fonction
time.localtime()
. - Message : Une chaîne de caractères qui informe de ce qu'il s'est produit.
Voici un exemple d'une information retournée par un module de surveillance interne :
[Info] 2024-04-04 14:21:55 : Network config: ('192.168.1.191', '255.255.255.0', '192.168.1.1', '192.168.1.1')
Pour plus de détails voici le lien de la documentation de la bibliothèque.
Fonctionnement asynchrone¶
Le code utilise la bibliothèque uasyncio
pour gérer les opérations de manière asynchrone, ce qui permet au microcontrôleur de traiter plusieurs tâches sans bloquer l'exécution. Voici comment cela fonctionne dans ce projet :
Tâche MQTT¶
La tâche mqtt_task
vérifie périodiquement les nouveaux messages MQTT. Elle est définie comme suit :
Cette tâche utilise une boucle infinie pour appeler client.check_msg()
, qui vérifie les nouveaux messages MQTT. La fonction await asyncio.sleep(0.1)
permets de faire une pause de 0,1 seconde avant de vérifier à nouveau les messages, permettant ainsi à d'autres tâches de s'exécuter.
Boucle principale¶
La boucle principale main_loop
lit les données du capteur DHT22 et les envoie au broker MQTT. Elle est définie comme suit :
async def main_loop():
while True:
try:
sensor.measure()
time.sleep(5)
voltage = adc.read_u16() * 3.3 / (65535 * 3)
battery_level = voltage / 3.3 * 100
data = {
"id_mac": mac_address,
"temperature": sensor.temperature(),
"humidity": sensor.humidity(),
"voltage": battery_level
}
client.publish(topic_pub_data, json.dumps(data))
logging.info(f"Data: {data}")
gc.collect()
await asyncio.sleep(600)
except Exception as e:
logging.error(f"Error reading data from DHT22: {e}")
Cette boucle lit les données du capteur DHT22, calcule le niveau de batterie, et publie ces données au broker MQTT avec comme identifiant ça mac adresse. La fonction await asyncio.sleep(600)
permets de faire une pause de 10 minutes après chaque cycle, permettant aux autres tâches de s'exécuter.
Gestion des commandes¶
La fonction callback
gère les messages MQTT reçus et effectue des actions en conséquence. Elle est définie comme suit :
def callback(topic, msg):
global task_main_loop
message = msg.decode("utf-8")
if message == "is_alive":
logging.receive("Is alive")
client.publish(topic_pub_response, msg='Alive')
elif message == "status":
logging.receive("status")
client.publish(topic_pub_response, msg=ssid + ' & ' + key)
elif message == "clean_log":
logging.receive("Clean log")
logging.clean()
client.publish(topic_pub_response, 'Log file has been cleaned')
elif message == "show_log":
logging.receive("Show last 10 log")
last_10_log = logging.get_10_last_lines()
client.publish(topic_pub_response, json.dumps(last_10_log))
elif message == "start":
logging.receive("Start measurement")
asyncio.create_task(start_sensor())
client.publish(topic_pub_response, 'Main loop started')
elif message == "stop":
logging.receive("Stop measurement")
asyncio.create_task(stop_sensor())
client.publish(topic_pub_response, 'Main loop stopped')
elif message == "restart":
logging.receive("Restart measurement")
asyncio.create_task(restart_sensor())
client.publish(topic_pub_response, 'Main loop restarted')
En fonction du message reçu, la fonction callback
effectue diverses actions telles que répondre à des commandes de statut, nettoyer les logs, ou démarrer/arrêter/reprendre la boucle principale.
Fonction principale¶
La fonction principale main
gère la connexion Wi-Fi, la synchronisation de l'heure et la connexion au broker MQTT, et lance les tâches asynchrones. Elle est définie comme suit :
async def main():
connect_wifi(ssid, key)
sync_rtc_with_ntp()
connect_mqtt()
await asyncio.gather(
mqtt_task(),
start_sensor()
)
La fonction asyncio.gather
permet d'exécuter plusieurs tâches asynchrones en parallèle : mqtt_task
et start_sensor
. Cela permet au microcontrôleur de vérifier les messages MQTT tout en lisant les données du capteur simultanément.
Exécution de la boucle principale¶
Enfin, la boucle principale est lancée avec asyncio.run(main())
:
Cela démarre l'exécution de la fonction main
, initiant ainsi la connexion Wi-Fi, la synchronisation de l'heure, la connexion MQTT, et les tâches asynchrones définies.