<!-- {%hackmd @themes/dracula %} --> # Projet IoT - Wifi ###### tags: `06 - Réseaux WIFI` [TOC] ## Objectifs **Éléments à intégrer dans le projet :** - M5Stack (une par personnes) - Capteurs réels - Sockets (UDP ou TCP) - L’utilisation d’une API externe - Packet Tracer - En lien avec la RGPD, une évaluation de risque ou d’impact sur la protection des données personnelles. **À rendre :** une copie de votre code, schéma et présentation dans un fichier ZIP après la présentation du projet. :::info <div class="lead rounded" style="text-align:center; font-style:bold;"> **Lundi 5 juin pendant les heures du cours.** </div> ::: ## Introduction <div class="text-justify"> Le projet a pour objectif de connecter l'appartement d'un utilisateur lui permettant d'éteindre automatiquement ses lumières connectés lorsqu'il sort de son appartement et allumer automatiquement les objets lorsqu'il retourne dedans. Un capteur de mouvement est installé dans le garage permettant d'ouvrire automatiquement la porte lorsque le véhicule est en mouvement et se referme lorsqu'il n'y a plus de mouvement. Lorsque l'utilisateur retourne chez lui, si la température exterieur est supérerieur a 20 degrées, la climatisation s'activera automatiquement afin de tempérer l'appartement. </div> ### Diagramme simple du projet ![](https://hackmd.io/_uploads/Hk2hGtiI2.png) ### Diagramme de sequence simple illustrant la **sortie** de l'utilisateur de son logement ```sequence Utilisateur->M5Stack2: Appuie sur le bouton A Note right of M5Stack2: M5Stack2 interprète le signal M5Stack2->Servo: Fonction open() Note right of Servo: Servo libère les clés Servo->M5Stack2: Signale l'ouverture M5Stack2->Socket: Envoie message UDP "sortir" Note right of Socket: Socket envoie le message à MCU Socket->MCU: Recevoir le message "sortir" Note right of MCU: MCU interprète le signal MCU->ObjetsConnectés: onUDPReceive() Note right of ObjetsConnectés: Les objets se mettent hors tension ``` ### Diagramme de sequence simple illustrant le **retour** de l'utilisateur de son logement ```sequence Utilisateur->M5Stack2: Appuie sur le bouton B Note right of M5Stack2: M5Stack2 interprète le signal M5Stack2->Servo: Fonction close() Note right of Servo: Servo ferme la porte Servo->M5Stack2: Signale la fermeture M5Stack2->Socket: Envoie message UDP "rentrer" Note right of Socket: Socket envoie le message à MCU Socket->MCU: Recevoir le message "rentrer" Note right of MCU: MCU interprète le signal MCU->ObjetsConnectés: Power on() Note right of ObjetsConnectés: Les objets se rallument M5Stack2->API Météo: Requête température extérieure Note right of API Météo: API Météo renvoie la température API Météo->M5Stack2: Recevoir la température Note right of M5Stack2: M5Stack2 interprète la température M5Stack2->Socket: Envoie message UDP "fan" si temp > 20°C Note right of Socket: Socket envoie le message à MCU Socket->MCU: Recevoir le message "fan" Note right of MCU: MCU interprète le signal MCU->Climatisation: Active si message "fan" reçu Note right of Climatisation: La climatisation se met en marche ``` ### Diagramme de sequence simple illustrant le le renvoi d'un signal en fonction des signaux renvoyés par le capteur ```sequence Capteur->>M5Stack1: Mouvement détecté (1) Note right of M5Stack1: M5Stack1 interprète le signal M5Stack1->>Socket: Envoie message UDP "Ouvre" ou "Ferme" Note right of Socket: Socket envoie le message à MCU Socket->>MCU: Recevoir le message "Ouvre" ou "Ferme" Note right of MCU: MCU interprète le signal MCU->>GarageDoor: open() ou close() Note right of GarageDoor: La porte du garage s'ouvre ou se ferme ``` ## Le projet ### M5Stack - 1 :::info :information_source: M5Stack qui est connecté au **capteur de mouvement** permettant d'ouvrir et fermer la porte de garage en cas de mouvement repéré. ::: ```python= import network import time from m5stack import lcd, buttonA, buttonB, buttonC from machine import Pin try: import usocket as socket except: import socket import urequests import json AUTH_OPEN = 0 AUTH_WEP = 1 AUTH_WPA_PSK = 2 AUTH_WPA2_PSK = 3 AUTH_WPA_WPA2_PSK = 4 # SSID = "iPhone de Marc" # PASSWORD = "12345678987654321" # SSID = "pls-16991" # PASSWORD = "mtVD-mA4f-h1UN-wnu5" SSID = "iot1" PASSWORD = "welcome2022" class PIR(): def _init_(self): self.pin = Pin(22,Pin.IN) self.mvt = 0 self.pin.irq(trigger=(Pin.IRQ_RISING | Pin.IRQ_FALLING), handler=self.actionInterruption) def actionInterruption(self,pin): if (pin.value()==1): if (self.mvt==0): self.mvt=1 else: if (self.mvt==1): self.mvt=0 def read(self): return self.mvt def do_connect(ssid,psw): wlan = network.WLAN(network.STA_IF) wlan.active(True) s = wlan.config("mac") mac = ('%02x:%02x:%02x:%02x:%02x:%02x').upper() %(s[0],s[1],s[2],s[3],s[4],s[5]) print("Local MAC:"+mac) #get mac wlan.connect(ssid, psw) if not wlan.isconnected(): print('connecting to network...' + ssid) wlan.connect(ssid, psw) start = time.ticks_ms() # get millisecond counter while not wlan.isconnected(): time.sleep(1) # sleep for 1 second if time.ticks_ms()-start > 20000: print("connect timeout!") break if wlan.isconnected(): print('network config:', wlan.ifconfig()) return wlan def connect(): do_connect(SSID,PASSWORD) def app(): lcd.clear() lcd.setCursor(0, 0) connect() s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.sendto("Capteur de mouvement prêt à être mis en fonction".encode('UTF-8'),("192.168.10.138", 1234)) pir=PIR() while True: print(pir.read()) # check si mouvement if pir.read() == 1: lcd.clear() lcd.setCursor(0, 0) lcd.print("Mouvement !\nLa porte s'ouvre !\n") s.sendto("Ouvre".encode('UTF-8'),("192.168.10.138", 1234)) sleep(2) # si aucun mouvement else: lcd.clear() lcd.setCursor(0, 0) lcd.print("Attention !!!\nLa porte se referme!\n") s.sendto("Ferme".encode('UTF-8'),("192.168.10.138", 1234)) sleep(2) if buttonA.wasPressed(): lcd.clear() lcd.setCursor(0, 0) lcd.print("Button A pressed !\n\n") s.sendto("Ouvre".encode('UTF-8'),("192.168.10.138", 1234)) if buttonB.wasPressed(): lcd.print("Button B pressed !\nExtinction de la lumiere\net arret de la machine a cafe\n") s.sendto("Ferme".encode('UTF-8'),("192.168.10.138", 1234)) if buttonC.wasPressed(): lcd.clear() lcd.setCursor(0, 0) lcd.print('Button C was Pressed !\nFermeture des portes AU REVOIR') s.close() time.sleep(0.2) app() ``` ### M5Stack - 2 :::info :information_source: M5Stack qui est connecté à la **pince** permettant d'ouvrir et fermer la porte en cas de mouvement repéré. Bouton A Bouton B Bouton C ::: ```python= import network from m5stack import lcd, buttonA from machine import Pin, PWM import time from time import sleep import urequests import json try: import usocket as socket except: import socket AUTH_OPEN = 0 AUTH_WEP = 1 AUTH_WPA_PSK = 2 AUTH_WPA2_PSK = 3 AUTH_WPA_WPA2_PSK = 4 SSID = "iot1" PASSWORD = "welcome2022" IP_DEST = "192.168.10.138" PORT_DEST = 1234 button_a = Pin(39, Pin.IN) # Button A button_b = Pin(38, Pin.IN) # Button B button_c = Pin(37, Pin.IN) ### Class Servo qui instanciera le servo de mon projet. Cette classe l'instance de ma pince et les interactions nécessaire seront codé à l'interieur class Servo: def __init__(self, port=21, freq=500): self.freq = freq self.port = port # print('init servo') self.pwm = PWM(21, freq=freq, duty=62-0.666*0) def write_us(self, us): self.pwm.duty(90) sleep_us(10000) self.pwm.duty(0) def write_angle(self, degrees): if degrees >= 35 : # print('35°') degrees=35 if degrees <= -20 : # print('-20°') degrees=-20 self.pwm.duty(62-0.666*degrees) def close(self): self.write_angle(-20) def open(self): self.write_angle(25) def stop(self): self.pwm.deinit() ### Fonction permettant d'attribuer des fonctions au clique d'un bouton def check_buttons(servo, socket, temp): if button_a.value() == 0: # Button A pressed lcd.clear() lcd.setCursor(0, 0) lcd.print("Bye Bye Master") servo.open() socket.sendto("sortir".encode('UTF-8'),(IP_DEST, 1234)) sleep(5) elif button_b.value() == 0: # Button B pressed lcd.clear() lcd.setCursor(0, 0) lcd.print("Salut beau gosse") servo.close() socket.sendto("rentrer".encode('UTF-8'),(IP_DEST, 1234)) sleep(5) if temp > 20: print(temp) socket.sendto("fan".encode('UTF-8'),(IP_DEST, 1234)) sleep(5) elif button_c.value() == 0: # Button C pressed servo.stop() ### Fonction permettant de tester l'initialisation de la pince def test_ini(s): print(s.freq) lcd.print("tentative de mouvement a 55 degree") sleep(3) s.write_angle(55) sleep(3) s.write_angle(0) sleep(3) s.write_angle(-5) sleep(3) s.write_angle(-17) sleep(3) lcd.print('Ouverture') servo.open() sleep(2) lcd.print('Fermeture') servo.close() sleep(2) lcd.print('Ouverture') servo.open() sleep(2) ### Fonction permettant de me connecter au WIFI def do_connect(ssid,psw): wlan = network.WLAN(network.STA_IF) wlan.active(True) s = wlan.config("mac") mac = ('%02x:%02x:%02x:%02x:%02x:%02x').upper() %(s[0],s[1],s[2],s[3],s[4],s[5]) print("Local MAC:"+mac) #get mac wlan.connect(ssid, psw) if not wlan.isconnected(): print('connecting to network...' + ssid) wlan.connect(ssid, psw) start = time.ticks_ms() # get millisecond counter while not wlan.isconnected(): time.sleep(1) # sleep for 1 second if time.ticks_ms()-start > 20000: print("connect timeout!") break if wlan.isconnected(): print('network config:', wlan.ifconfig()) return wlan def connect(): do_connect(SSID,PASSWORD) ### Fonction principal de mon application def main(): lcd.clear() connect() s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) servo = Servo() # test_ini(servo) # Les données de longitude et lattitude sont fournis en dur ici pou récupérer la temperature du jours à Genève r = urequests.get('https://api.open-meteo.com/v1/forecast?latitude=46.230941&longitude=6.073747&forecast_days=2&hourly=temperature_2m') response_json = json.loads(r.content) # heures = response_json['hourly']['time'] temp = response_json['hourly']['temperature_2m'] sleep(2) while True: # 18 est l'heure à laquelle on souhaite connaitre la temperature # Proposition V2 : récupérer l'heure local de la machine pour fournir l'heure exacte check_buttons(servo, s, temp[18]) servo.stop() main() ``` ### MCU :::info :information_source: MCU permettant de communiquer les différents signaux aux objets connectés dans l'appartement en fonction des signaux renvoyés par les M5Stacks. ::: ```python= from realudp import * import requests import json from time import * from gpio import * # IP = "172.20.10.4" IP = "192.168.10.138" PORT = 1234 socket = RealUDPSocket() # VENTILATEUR pinMode(0, OUT) # PORTE DE GARAGE pinMode(1, OUT) # LAMPE pinMode(2, OUT) def onUDPReceive(ip, port, data): print("received from " + ip + ":" + str(port) + ":" + data); if data=="Ouvre": customWrite(1, "1") elif data=="sortir": customWrite(2, "0") customWrite(0, "0") elif data=="rentrer": customWrite(2, "2") elif data=="fan": customWrite(0, "2") elif data=="Ferme": customWrite(1, "0") def main(): socket.onReceive(onUDPReceive) print(socket.begin(PORT)) # count = 0 while True: # count += 1 # socket.send(IP, PORT, "hello " + str(count)) sleep(1) if _name_ == "_main_": main() ``` ## Analyse RGPD <div class="text-justify" style="padding-bottom:20px;"> Dans le cadre de notre projet, une analyse des risques conformément à la RGPD a été réalisé afin de trouver d'isoler les potentiels failles de sécurités et autre risques auquel notre projet est soumis. </div> <div class="text-justify"> </div> ```csvpreview {header="true"} Risques à atténuer,Potentiel,Impact sur le projet,Argument logique,Mesure de mitigation,Potentiel après mitigation,Impact sur le projet après mitigation "1. Non-consentement de l'utilisateur",2,3,"Le RGPD exige le consentement explicite pour la collecte de données, en être en infraction pourrait entraîner des sanctions","Mise en place d'un processus de consentement explicite, Fournir des informations claires et accessibles",1,1 "2. Collecte excessive de données",1,3,"Collecter plus de données que nécessaire expose l'entreprise à un risque accru en cas de violation de données","Principe de minimisation des données, Gestion de bases de données bien conçus, Politiques de conservation des données",1,1 "3. Accès non autorisé aux données du capteur",2,3,"Le piratage de données peut mener à des fuites d'informations sensibles, d'où l'importance de garantir la sécurité des données","Mesures de sécurité robustes, Chiffrement des données, Sécurisation des communications réseau",1,1 "4. Interception des données de l'API météo",1,4,"Les données interceptées peuvent compromettre la sécurité de l'utilisateur, notamment sur sa localisation et/ou la précision des prévisions","Utiliser une connexion sécurisée, Vérifier la fiabilité et la sécurité de l'API",1,2 "5. Fuite des données stockées sur le réseau privé de l'utilisateur",1,3,"La violation de la sécurité du réseau privé pourrait conduire à l'accès non autorisé aux données de l'utilisateur","Mesures de sécurité pour le réseau privé, pare-feu et logiciels antivirus",1,1 "6. Dysfonctionnement du système (capteur, M5Stack, MCU, etc.)",2,4,"Un dysfonctionnement du système peut interrompre le service et nuire à la satisfaction de l'utilisateur","Protocoles de test rigoureux, Maintenance régulière, Système de récupération en cas de défaillance",1,2 ``` </div> ![](https://hackmd.io/_uploads/SyxnHtqL2.png) ![](https://hackmd.io/_uploads/SkinHFqUn.png) ## Conclusion En conclusion, nous sommes satisfaits de la réalisation de notre projet. L'intégration du M5Stack1 et du capteur de mouvement pour automatiser le contrôle de la porte de garage s'est déroulée sans heurts, et le résultat final correspond exactement à ce que nous avions imaginé. L'utilisation des messages UDP pour la communication entre le dispositif et le MCU s'est avérée être une solution fiable et efficace. Cela nous a permis de créer un système réactif qui répond rapidement aux détections de mouvement. Cependant, tout projet offre des opportunités d'amélioration et d'expansion. Un aspect que nous aurions aimé incorporer est un système de journalisation (log) amélioré. L'idée d'intégrer une API Telegram pour gérer et surveiller les logs à distance aurait été un atout intéressant, ajoutant une couche de flexibilité et de contrôle à distance à notre système. C'est une fonctionnalité que nous envisagerons certainement pour les mises à jour futures du projet. En termes de conformité au RGPD, nous sommes conscients que notre projet a encore des points à améliorer. Bien que nous ayons conçu notre système avec la confidentialité et la sécurité des données à l'esprit, des vulnérabilités potentielles subsistent. Cependant, nous sommes convaincus que l'application de notre analyse de risque, associée à une surveillance constante et à des mises à jour régulières du système, permettra de combler ces lacunes. Nous veillerons à maintenir le respect des normes de protection des données tout en assurant la sécurité de notre système. En somme, ce projet a été une expérience enrichissante et éducative. Nous avons appris et surmonté plusieurs défis tout au long du développement. Bien que des améliorations soient encore possibles, nous sommes confiants dans le potentiel et la fiabilité de notre solution actuelle et impatients de continuer à améliorer et à développer notre système à l'avenir. ## Présentation Vous trouverez la présentation faite devant la classe : https://hackmd.io/@OliverGr/Hy1iaVjUn ## Source Les PDF provenants des différents cours nécessitent une connection à Cyberlearn afin de pouvoir les visionner. ### API https://open-meteo.com/ ### Cours de M. Albert Rossier - Gouvernance des Systèmes d'Information #### Menaces et riques - 27 septembre 2022 https://cyberlearn.hes-so.ch/pluginfile.php/4107011/mod_resource/content/0/Menaces%20et%20Risques%202022.pdf #### Analyse des risques - 4 octobre 2022 https://cyberlearn.hes-so.ch/pluginfile.php/4118563/mod_resource/content/0/2.%20Analyse%20des%20risques%202022.pdf ### Cours de Monsieur Bryce - 645-21_RESEAUX_WIFI #### Fiche capteur - Jean-Luc Sarrade - 2022-2023 https://cyberlearn.hes-so.ch/pluginfile.php/4303777/mod_resource/content/0/Fiches%20Capteurs.pdf ### GitHub M5Stack https://github.com/m5stack/M5Cloud