--- 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 ![](https://i.imgur.com/6nU2RfP.png) 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) ![](https://micropython-on-wemos-d1-mini.readthedocs.io/en/latest/_images/dht11.png) ```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