<!-- {%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

### 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>


## 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