---
tags: micropython, IoT, DIY
---
# Micropython sur ModeMCUlike ESP8266
# Installation
http://docs.micropython.org/en/latest/esp8266/tutorial/intro.html#deploying-the-firmware
https://micropython-on-wemos-d1-mini.readthedocs.io/en/latest/basics.html

Installer python3 et pip
sudo apt install python3 python3-pip
## Tester la détection du microcontroleur
:::warning
Flasher micropython sans composant branché au microcontrôleur.
Le controleur pourrait ne pas être reconnu si des composants sont branchés (testé sur DTH11 avec deepsleep connection)
:::
```bash
$ sudo esptool.py flash_id
esptool.py v2.6
Found 1 serial ports
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
MAC: 3c:71:bf:28:d4:bc
Uploading stub...
Running stub...
Stub running...
Manufacturer: 20
Device: 4016
Detected flash size: 4MB
Hard resetting via RTS pin...
```
## Ecriture du firmware micropython
Télécharger la dernière release du firmware pour micropython .bin [Lien](https://micropython.org/download#esp8266)
```bash
$ sudo esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 ~/Téléchargements/esp8266-20190529-v1.11.bin
esptool.py v2.6
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
MAC: 3c:71:bf:28:d4:bc
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Flash params set to 0x0040
Compressed 615388 bytes to 399928...
Wrote 615388 bytes (399928 compressed) at 0x00000000 in 9.0 seconds (effective 547.2 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
```
## Changer les droits sur le port usb
sudo chmod a+rw /dev/ttyUSB0
sudo gpasswd --add mathgon dialout
sudo usermod -a -G dialout mathgon
## Se connecter à la carte
picocom /dev/ttyUSB0 -b115200
print("Hello coco!")
## Se connecter avec Jupyter notebook
Cette méthode offre une plus grande fluidité pour la programmation et le prototypage
Consiste à ajouter le kernel micropython dans Jupyter
```bash
git clone https://github.com/goatchurchprime/jupyter_micropython_kernel.git
pip install -e jupyter_micropython_kernel
python -m jupyter_micropython_kernel.install
jupyter kernelspec list #List les kernels disponibles, verif install
jupyter notebook
```
Créer un nouveau notebook et configurer le kernel via le menu Kernel -> Change kernel -> Micropython USB
La communication avec la board se fait via la commande magique dans un notebook
```python
%serialconnect to --port=/dev/ttyUSB0 --baud=115200
```
# Copier un fichier vers l'ESP
ampy --port /dev/ttyUSB0 put /media/Documents/Owncloud/Documents/Micropython/main.py main.py
## Troubleshoot
:::warning
* Problème de connection lorsque le programme en cours est utilisé très brièvement, pas le temps de copier le nouveau fichier.
* Déconnecter la fermeture du circuit pour deepsleep (entre les PIN DO et RST)
* Retirer la chip de la breadboard
* Recharger le firmware
```
esptool.py --port /dev/ttyUSB0 erase_flash
esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 /media/Documents/Owncloud/Documents/Micropython/esp8266-20190529-v1.11.bin
```
* copier le programme avec la commande précédente
:::
## Commandes
### Réseau
```pyhon
import network
sta_if = network.WLAN(network.STA_IF)
ap_if = network.WLAN(network.AP_IF)
sta_if.active()
ap_if.active()
ap_if.ifconfig()
```
```python
sta_if.active(True)
sta_if.connect('Freebox-RosGon', 'mypassword')
#Désactive le point d'accès si nécessaire
# ap_if.active(False)
```
```python
def do_connect():
""" Fonction permettant de se connecter au wifi """
import network
sta_if = network.WLAN(network.STA_IF)
if not sta_if.isconnected():
print('connecting to network...')
sta_if.active(True)
sta_if.connect('Freebox-RosGon', 'mypassword')
while not sta_if.isconnected():
pass
print('network config:', sta_if.ifconfig())
do_connect()
```
:::warning
Il se peut que la carte tente de se connecter alors que le module WIFI n'est pas démarré, `time.sleep(2)` en début de programme peut résoudre ce problème
:::
### TCP Sockets
```python
def http_get(url):
""" Download une page internet """
_, _, host, path = url.split('/', 3)
addr = socket.getaddrinfo(host, 80)[0][-1]
s = socket.socket()
s.connect(addr)
s.send(bytes('GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' % (path, host), 'utf8'))
while True:
data = s.recv(100)
if data:
print(str(data, 'utf8'), end='')
else:
break
s.close()
```
### Deepsleep
:::warning
Les pins DO et RST soivent être reliée afin de pouvoir redémarer l'ESP.
WARNING: peut empécher de téléverser des fichiers
:::
```python
import machine
# configure RTC.ALARM0 to be able to wake the device
rtc = machine.RTC()
rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP)
# set RTC.ALARM0 to fire after 10 seconds (waking the device)
rtc.alarm(rtc.ALARM0, 10000)
# put the device to sleep
machine.deepsleep()
```
# Lecture de données
### Mesure température/Humidité (DHT22)

```python
from machine import Pin
import dht
my_dht = dht.DHT22(Pin(14, Pin.IN, Pin.PULL_UP))
my_dht.measure()
my_dht.temperature()
my_dht.humidity()
```
```python
def mesure_temperature_and_humidity(DHT22_PIN):
d = dht.DHT22(machine.Pin(DHT22_PIN))
d.measure()
t = d.temperature()
h = d.humidity()
print('temperature = %.2f' % t)
print('humidity = %.2f' % h)
mesure_temperature_and_humidity(14)
```
# Combinaisons de briques
## Mesure de la température/humidité et envoi sur thingspeaks
```python
import network
import machine
import dht
import time
time.sleep(10)
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
sta_if.connect('Freebox-RosGon', 'mypassword')
print('network config:', sta_if.ifconfig())
# Temps entre deux mesures (en secondes)
MESUREMENT_INTERVAL = 120
# configure RTC.ALARM0 to be able to wake the device
# Va procéder à un redémarrage de la carte
rtc = machine.RTC()
rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP)
# set RTC.ALARM0 to fire after MESUREMENT_INTERVAL seconds (waking the device)
rtc.alarm(rtc.ALARM0, MESUREMENT_INTERVAL*1000)
def http_get(url):
import socket
_, _, host, path = url.split('/', 3)
addr = socket.getaddrinfo(host, 80)[0][-1]
s = socket.socket()
s.connect(addr)
s.send(bytes('GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' % (path, host), 'utf8'))
while True:
data = s.recv(100)
if data:
#print(str(data, 'utf8'), end='') # affiche tout le POST
print(time.time(), data)
else:
break
def mesure_temperature_and_humidity():
""" envoi temp et humidite"""
DHT22_PIN = 14
d = dht.DHT22(machine.Pin(DHT22_PIN))
d.measure()
t = d.temperature()
h = d.humidity()
print('%s°C %s ' % (t, h))
base_url = 'https://api.thingspeak.com/update'
API_key = '?api_key=8NA2V52E43RUV00N'
field = '&field1='
data = '&field1=%.2f&field2=%.2f' % (t, h)
url = base_url + API_key + data
http_get(url)
#last_mesurement_time = time.time()
while True:
mesure_temperature_and_humidity()
#mise en pause pendant une duree MESUREMENT_INTERVAL
print("Enter deepsleep")
machine.deepsleep()
current_time = time.time()
if current_time - last_mesurement_time > MESUREMENT_INTERVAL:
mesure_temperature_and_humidity()
last_mesurement_time = current_time
#mise en pause pendant une duree MESUREMENT_INTERVAL
print("Enter deepsleep")
machine.deepsleep()
```
## Mesure de la température/humidité et envoi sur broker MQTT
```python
import network
import machine
import dht
import time
import ubinascii
import webrepl
import ujson
import ujson as json
from time import sleep
from umqtt.simple import MQTTClient
# V0.1: retourne correctement les données de Temp et Hum vers le broker MQTT de HA
# V0.2: intégration du deepsleep entre deux mesures,
# optimisation énergétique, consomme 31mAh en 48h
# V0.3: Generer de manière dynamique le nom du client_id en fonction du nom de la machine
# V0.4:
################-- VARIABLES --################
# Temps entre deux mesures (en secondes)
MESUREMENT_INTERVAL = 1200-5
# Topic de public mqtt
topic = "sensor"
# Data Pin du DHT22
DHT22_PIN = 14
# These defaults are overwritten with the contents of /config.json by load_config()
machine_id = ubinascii.hexlify(machine.unique_id()).decode("utf-8")
CONFIG = {
"broker": "192.168.1.100",
"sensor_pin": 14,
"client_id": "esp8266_" + machine_id ,
"topic": topic + "/" + "esp8266_" + machine_id,
}
client = None
sensor_pin = None
###############################################
time.sleep(10) #Sans ce timing, problème de connexion au WIFI
# Configuration du deepsleep (Attention, les pins D0 et RST doivent être reliées par un cable)
rtc = machine.RTC()
rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP)
rtc.alarm(rtc.ALARM0, MESUREMENT_INTERVAL*1000) #Delai du deepsleep
print("Machine: esp8266_" + ubinascii.hexlify(machine.unique_id()).decode("utf-8"))
while True:
#Connexion au WIFI
sta_if = network.WLAN(network.STA_IF)
while sta_if.isconnected() is False:
print("Connection au wifi...")
sta_if.active(True)
sta_if.connect('Freebox-RosGon', 'mypassword')
time.sleep(3)
print('network config:', sta_if.ifconfig())
#Mesure Temperature et humité
d = dht.DHT22(machine.Pin(DHT22_PIN))
d.measure()
t = d.temperature()
h = d.humidity()
json = ujson.dumps({"Temperature":t,"Humidite":h})
# Connexion au broker MQTT et publication des données
client = MQTTClient(CONFIG['client_id'], CONFIG['broker'])
client.connect()
time.sleep(2)
print("Connected to {}".format(CONFIG['broker']))
client.publish(CONFIG['topic'], json)
time.sleep(2)
print(CONFIG['client_id'], " | ", CONFIG['topic'], " | ", json)
client.disconnect()
time.sleep(2)
print("Enter deepsleeping")
machine.deepsleep()
```
## Une télécommande pour Kodi
* Lecture de touche pressée sur un [keypad 3x4](https://robotdyn.com/button-keypad-3x4-module.html)
* Affichage de la valeur sur un [écran OLED SSD1306](https://fr.aliexpress.com/item/33003239013.html?src=google&src=google&albch=shopping&acnt=494-037-6276&isdl=y&slnk=&plac=&mtctp=&albbt=Google_7_shopping&aff_platform=google&aff_short_key=UneMJZVf&&albagn=888888&albcp=6459793138&albag=77316928277&trgt=743612850714&crea=fr33003239013&netw=u&device=c&gclid=CjwKCAjwo9rtBRAdEiwA_WXcFnu9M2mtBG2xat5fm9GL2GhKY2Kxix7_6ueezfYOBswIR6aB49eYZBoCw6kQAvD_BwE&gclsrc=aw.ds) via I2C
* Envoi d'une requête sur Kodi via API [DOC](https://kodi.wiki/view/JSON-RPC_API)
```python
# V0.1 : lecture des touches et affichage sur l'écran OLED
# V0.2 : Conserver l'affichage de la dernière valeur pressée
# V0.3 :
# V0.4 : API Kodi
# TODO : Paramatérer la config des boutons via un fichier ext
import machine
from machine import RTC, I2C, Pin
import ssd1306
import network
import time
import urequests
# Connection du keypad sur la PIN A0
adc = machine.ADC(0)
# Initialisation de l'écran
oled = ssd1306.SSD1306_I2C(128, 32, I2C(scl=Pin(5), sda=Pin(4)))
oled.fill(0)
oled.text("starting", 0, 5)
oled.text(" soon...", 0, 15)
oled.show()
KODI_URL = 'http://192.168.1.10/jsonrpc'
def keyRead():
# Retourne la valeur correspondant à la touche du Keypad pressée
# Retourne None si aucune touche pressée
adcVal = adc.read()
keyPressed = None
if adcVal > 1010:
keyPressed = 1
if adcVal < 1010 and adcVal > 950:
keyPressed = 2
if adcVal < 950 and adcVal > 880:
keyPressed = 3
if adcVal < 880 and adcVal > 800:
keyPressed = 4
if adcVal < 800 and adcVal > 750:
keyPressed = 5
if adcVal < 750 and adcVal > 700:
keyPressed = 6
if adcVal < 700 and adcVal > 650:
keyPressed = 7
if adcVal < 650 and adcVal > 625:
keyPressed = 8
if adcVal < 625 and adcVal > 575:
keyPressed = 9
if adcVal < 575 and adcVal > 550:
keyPressed = 10
if adcVal < 550 and adcVal > 525:
keyPressed = 11
if adcVal < 525 and adcVal > 400:
keyPressed = 12
return keyPressed
def actionKey_station(val):
# Joue une radion en fonction de la touche sélectionnée
data = {"id":"Select channel","jsonrpc":"2.0","method":"Player.Open","params":{"item":{"channelid":22}}}
if val == 4:
data['params']['item']['channelid'] = 37
station = "Fip nouv"
if val == 5:
data['params']['item']['channelid'] = 21
station = "Nova"
if val == 6:
data['params']['item']['channelid'] = 23
station = "Meuh"
if val == 7:
data['params']['item']['channelid'] = 18
station = "Fip groove"
if val == 8:
data['params']['item']['channelid'] = 26
station = "Francecul"
if val == 9:
data['params']['item']['channelid'] = 20
station = "Jet"
if val == 10:
data['params']['item']['channelid'] = 19
station = "Fip"
if val == 11:
data['params']['item']['channelid'] = 22
station = "France Inter"
if val == 12:
data['params']['item']['channelid'] = 24
station = "Prun"
urequests.post(KODI_URL, json= data)
return station
def actionKey_volume(val):
data = {"jsonrpc":"2.0","method":"Application.SetVolume","id":1,"params":{"volume":"increment"}}
if val == 1:
data = {"jsonrpc":"2.0","method":"Application.SetVolume","id":1,"params":{"volume":"decrement"}}
if val == 2:
data = {"jsonrpc":"2.0","method":"Application.SetVolume","id":1,"params":{"volume":"increment"}}
if val == 3:
return("MuteToggle")
urequests.post(KODI_URL, json= data)
def displayValue(val):
#Affiche sur l'écran OLED la valeur de la touche pressée
oled.fill(0)
oled.text(str(val), 0, 5)
oled.show()
time.sleep(2)
sta_if = network.WLAN(network.STA_IF)
while sta_if.isconnected() is False:
print("Connection au wifi...")
displayValue("Connection au wifi...")
sta_if.active(True)
sta_if.connect('Freebox-RosGon', 'limouchtifaitdesprouts')
time.sleep(3)
print('network config:', sta_if.ifconfig())
displayValue("Wifi connected")
previous_val = None
while True:
val = keyRead()
if val !=None and val != previous_val and val > 3:
print(val)
displayValue(actionKey_station(val))
previous_val = val
"""
if val < 4:
actionKey_volume(val)
"""
```
# Divers
## Webrepl - Connection via navigateur web
Par défaut la fonction est incativée sur le dernier firware.
Activer
import webrepl_setup