Geschichten um einen kleinen Weihnachtsbaum - AZ-Delivery
Le storie di solito iniziano con "C'era una volta". Le seguenti storie si svolgono oggi ed adesso. Oggi svilupperemo alcuni progetti intorno ad un albero di Natale speciale.
Stiamo parlando di un alberello alto circa 11,5 cm con 36 (37) luci colorate. Lampeggiano tutti i colori in modo divertente. Ma lo fanno più o meno sempre allo stesso modo. Questo mi ha dato l'idea di portare un po' di ordine nel caos aggiungendo qualche altro componente. Il risultato è un sistema di controllo con un ESP32 e vari sensori, che mettono l'illuminazione dei LED al servizio di vari compiti di misurazione, o semplicemente provocano stupore. Nei capitoli seguenti, presenterò alcune delle possibilità una per una. Tutte le applicazioni sono programmate in MicroPython. Il mio collega Andreas Wolter ha anche portato i programmi in C++ per l'IDE di Arduino. Benvenuti 

Storie di un piccolo albero di Natale

Figura 1: le storie dell'albero

Figura 1: Le storie dell'alberello

Il contenuto:

  1. La lista delle parti
  2. Il software
  3. Costruiamo l'alberello e lo cabliamo
  4. Illuminazione mirata
  5. Il display OLED per le informazioni in chiaro
  6. Illuminazione a gradini
  7. L'alberello incantato
  8. Chi sta facendo tutto questo rumore?
  9. Sulle tracce del furto dell'albero
  10. Godetevi il vostro soggiorno con ESP32 e DHT22/DHT11
  11. La lotteria di Natale un po' diversa
  12. L'app dell'albero di Natale


1. la lista delle componenti

1

Kit albero di Natale a LED DIY

1

Sensore modulo SMD LED KY-009 RGB o

KY-016 FZ0455 Modulo LED RGB a 3 colori

1

Display 1,3 pollici OLED I2C 128x64 compatibile con Arduino e Raspberry Pi

1

DHT22 AM2302 Sensore di temperatura ed umidità

1

KY-021 Switch Mini Sensore Magnetico Reed

1

KeyCard RFID 13.56 MHz Key MF S50 (13.56 MHz) - 10x scheda RFID

1

Kit RFID RC522 con lettore, chip e carta per Raspberry PI e Co. (13.56 MHz)

1

Breadboard Kit - 3x65pcs. Cavo M2M ; 3 x Mini Breadboard 400 Pin Compatibile con Arduino e Raspberry Pi

1

KY-038 Modulo di Rilevamento del Suono

1

Scheda di sviluppo WIFI Modulo Nodemcu ESP32 WLAN con CP2102

1

GY-521 MPU-6050 Giroscopio a 3 assi - Accelerometro alternativa GY-61 ADXL335 Sensore di accelerazione

Contatto virtuale KY-020 o KY-002 (*)

1

Cavo Jumper 3 x 40 pezzi ciascuno 20 cm M2M/ F2M / F2F

3

Resistenza 1.0KΩ.

(*) L'uso dei contatti a vibrazione o del modulo GY-51 richiede una programmazione diversa.

2. Il software.

Per il flashing e la programmazione dell'ESP32:

Thonso. o

μPyCraft.

pacetender. per testare l'ESP32/ESP8266 come server UDP

Browser: Opera o Chrome

Firmware usato:

Firmware micropython.

Si prega di scegliere una versione stabile

I programmi Micropython per il progetto:

Con testo di licenza

Driver del dispositivo:

GY521RC..py.

mfrc522.py.

sh1106.py.

Oled.py.

File di progetto MicroPython:

allarme.py.

noisy.py.

rfid.py.

Roomclimate.py.

miglioramento.py.

incantato.py.

WebControl.py.

File del progetto Arduino IDE:

Avviso:
La versione dell'IDE Arduino usata qui è la 1.8.16.
La versione dell'ESP32 Arduino Core è 2.0.2


Per usare l'ESP32 Core, devi inserire questo link come URL aggiuntivo dell'amministratore della scheda nelle preferenze:

https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json

Cercare poi ESP32 tramite il menu Strumenti -> Scheda -> Amministratore scheda e installalo.

Le librerie utilizzate, come LittleFS, sono state integrate nel nucleo solo in una fase tardiva. Pertanto, è importante aggiornarlo se necessario.

I2c_scanner.ino.

Oledtest.ino.


Allarme.ino

noisy.ino.

opzionale noisy_ticker_h.ino. (con ticker.h Bibliothek)

rfid.ino.

Roomclimate.ino.

miglioramento.ino

incantato.ino.

WebControl.ino.


MicroPython - Linguaggio - Moduli e programmi

Potete trovare istruzioni dettagliate per installare Thonny qui. C'è anche una descrizione di come masterizzare il MicropythonFirmware sul chip ESP.

MicroPython è un linguaggio interprete. La differenza principale rispetto all'IDE di Arduino, dove si flashano sempre e solo programmi interi, è che è necessario flashare il firmware MicroPython solo una volta all'inizio sull'ESP32 prima che il controller capisca le istruzioni MicroPython. Potete usare Thonny, µPyCraft o esptool.py per farlo. Per Thonny, ho descritto il processo qui.

Non appena il firmware è flashato, potete comunicate senza alcuna difficoltà con il vostro controller, testare singoli comandi e vedere immediatamente la risposta senza dover prima compilare e trasferire un intero programma. Questo è esattamente ciò che mi dà fastidio dell'IDE di Arduino. Si risparmia semplicemente un'enorme quantità di tempo se si possono controllare semplici test della sintassi e dell'hardware fino a provare e perfezionare funzioni e intere parti del programma tramite la linea di comando in anticipo, prima di farne un programma. A questo scopo, mi piace anche creare piccoli programmi di prova di tanto in tanto. Come una specie di macro, riassumono i comandi ricorrenti. A volte intere applicazioni sono sviluppate da tali frammenti di programma.

Autostart

Se il programma deve partire autonomamente all'accensione del controller, copiate il testo del programma in un nuovo file vuoto. Salvate questo file sotto boot.py nell'area di lavoro e caricatelo sul chip ESP. La prossima volta che il controller viene resettato o acceso, il programma partirà automaticamente.

Programmi di test

Manualmente, i programmi vengono avviati dalla finestra corrente dell'editor nell'IDE Thonny tramite il tasto F5. Questo è più veloce che cliccare sul pulsante di avvio o usare il menu Esegui. Solo i moduli utilizzati nel programma devono trovarsi nel flash dell'ESP32.

Arduino IDE di nuovo in mezzo?

Se volete usare di nuovo il controller più tardi insieme all'IDE di Arduino, è necessario flashare il programma nel solito modo. Tuttavia, l'ESP32/ESP8266 avrà poi dimenticato di aver mai parlato MicroPython. Al contrario, qualsiasi chip Espressif che contiene un programma compilato dall'IDE di Arduino o il firmware AT o LUA o ... può facilmente ricevere il firmware MicroPython. Il processo è sempre quello descritto qui.

3. Assembliamo gli alberi e lo cabliamo

C'è un video per il montaggio dell'alberello.

Naturalmente, dopo aver assemblato l'albero, puoi sederti e ammirare il tuo lavoro. È ancora più divertente se modifichiamo il processo di assemblaggio in alcuni punti. In tre punti del video dobbiamo procedere diversamente per il nostro progetto. Le resistenze da 4.7kΩ menzionate sono resistenze da 10kΩ nella confezione delle parti. E queste tre resistenze per scheda A e B sono saldate solo nei punti della scheda come mostrato nelle illustrazioni Fig.2 e Fig.3, l'altra estremità di queste resistenze rimane libera per il momento. Più tardi saldiamo dei cavi sottili (per esempio ribbon piatto) a queste estremità libere per il collegamento all'ESP32. Questo vale per entrambe le schede, A e B. I condensatori elettrolitici sono lasciati completamente fuori.

Figura 2: parte A

Figura 2: Parte A

Figura 3: parte B

Figura 2: Parte B

Il resto del montaggio può essere fatto esattamente come mostrato nel video. Quando anche la piastra di base è attaccata, saldiamo i cavetti alle estremità libere delle resistenze da 10kΩ. La lunghezza dovrebbe essere tra i 25 e i 30 cm. Per rendere il tutto collegabile, saldiamo un pezzo di pin strip all'altra estremità del cavo.

Figura 4: la connessione dell'albero

Figura 4: The Tree-Connection

L'assegnazione delle connessioni sull'albero ai GPIO dell'ESP32 può essere vista nella tabella 1. L'indice si riferisce all'elenco degli oggetti pin. Questa lista con il nome di strato è usata per indirizzare gli strati di LED tramite dei cicli, come vedremo. Le connessioni sono distribuite in modo tale che un indice pari è sempre seguito dal livello LED sulla scheda B con lo stesso livello. Naturalmente, qualsiasi riorganizzazione è possibile in qualsiasi momento.

Alberi

A1

B1

A2

B2

A3

B3

GPIO

32

26

33

27

25

12

Indice

0

1

2

3

4

5

Tabella 1: Connessioni tra l'alberello e ESP32

Figura 5: cablaggio di base

Figura 5: Cablaggio di base

Figura 6: resistori di base sulla parte B - Dettaglio, le estremità libere sono sopra

Figura 6: resistenze di base sulla parte B - dettaglio, le estremità libere sono in alto

Figura 7: cablato della parte A

Figura 7: cablato alla parte A

4. illuminazione mirata

Il cablaggio è terminato? Allora accendiamo i LED sull'alberello. Alimentiamo l'alberello sia tramite le batterie che tramite il cavo in dotazione da una porta USB. Dopo l'accensione, rimane buio. Naturalmente, poiché le connessioni di base dei transistor sono esposte, non può fluire alcuna corrente di base e poiché non fluisce alcuna corrente di collettore, i LED rimangono scuri.

Figura 8: uno dei 6 livelli di transistor

Figura 8: Uno dei 6 stadi a transistor

Questo cambia quando i GPIO sono programmati come uscite e il livello del potenziale GND viene portato a 3,3V. Otteniamo questo assegnando un 1 come valore. Nel terminale di Thonny inseriamo le seguenti linee.

>>> from machine import Pin
>>> a1=Pin(32,Pin.OUT,value=0)
>>> a1.value(1)

Se il cablaggio è corretto, i LED del livello A1 inizieranno ora ad accendersi per indicare

>>> a1.value(0)

A differenza della versione precedente del kit dell'alberello, la nuova versione è dotata di LED tremolanti. Prima erano semplici LED colorati. Questo ha un certo svantaggio perché non è più possibile oscurare i "LED lampeggianti". Tuttavia, è divertente sperimentare con loro. Attraverso i sei transistor, siamo ora in grado di avviare o spegnere tutti i 6 livelli esattamente secondo i nostri desideri. Questo ci permette anche di influenzare la luminosità generale.

La disposizione delle luci è mostrata in fig. 9. Si applica sia alla parte A che alla parte B.

Figura 9: La distribuzione dei LED è il grado

Figura 9: Distribuzione dei LED a turno

La disposizione dei LED, il cablaggio all'ESP32 e le connessioni all'ESP32 sono presi come dati per tutti gli esperimenti successivi. Non appaiono quindi esplicitamente nelle descrizioni e negli schemi dei sottocircuiti. 5.


5. Il display OLED

Il display OLED può fornirci informazioni di testo semplice, ma può anche visualizzare la grafica in bianco e nero. La programmazione è facile se usiamo i moduli software MicroPython associati. Il driver hardware SH1106 è direttamente responsabile del display da 1,3'' e può essere usato solo per questo. Il modulo framebuf integrato nel core di MicroPython fornisce semplici comandi di grafica e testo e il modulo oled.py ci dà comodi comandi per l'output di testo.

Il display è controllato solo attraverso le due linee del bus I2C. Creiamo un oggetto I2C e lo passiamo al costruttore della classe OLED. L'indirizzo del dispositivo hardware del display è fisso e ancorato come una costante in OLED. Tuttavia, controlliamo prima ciò che è disponibile sul bus. Poi sopprimiamo lo schermo ed emettiamo alcune righe.

Il grafico di Fig. 10 e il programma seguente dimostrano la gestione. Inseriamo il programma nell'editor di Thonny, lo salviamo e poi lo avviamo con il tasto funzione F5.

Figura 10: l'OLED su ESP32

Figura 10: L'OLED sull'ESP32

OLEDTEST.PY

 # OLED-Display-Demo
 #
 from machine import PinI2C
 from time import sleep
 from oled import OLED
 
 # Initialisieren der Schnittstelle **********************
 i2c=I2C(-1,scl=Pin(22),sda=Pin(21))
 print(i2c.scan())
 d=OLED(i2c)
 
 d.clearAll()
 d.writeAt("Der",0,0,False)
 d.writeAt("kleine",0,1,False)
 d.writeAt("Weihnachts-",0,2,False)
 d.writeAt("baum",0,3)
 sleep(4)
 d.clearFT(0,2,15,2,False)
 d.writeAt("Christ-",0,2)

Uscita:

[60]
this is the constructor of OLED class
Size:128x64

L'indirizzo del dispositivo del display è 60 decimale o 0x3C esadecimale. Il costruttore della classe OLED sa anche che il display ha 128 x 64 pixel. Dopo l'uscita delle quattro linee, 4 secondi dopo "Christmas-" è sostituito da "Chist-". Prima di questo, ovviamente, dobbiamo cancellare questa linea. Sentitevi liberi di provare i singoli comandi individualmente tramite REPL, la console terminale di Thonny.

Per Arduino IDE:

Per il display viene utilizzata la libreria U2G8, che potete installare tramite l'amministrazione della libreria.

Scaricare oledtest.ino

6. Luminescenza a gradini

Figura 11: Livello1

Figura 11: Livello1

Figura 12: Livello2

Figura 12: Livello2

Dato che possiamo controllare separatamente i singoli livelli dei LED sull'alberello, approfittiamone per andare su e giù dal livello più basso - OFF - alla luminosità massima. Non abbiamo bisogno di cambiare nulla nel circuito. Il display ci informa sul livello attualmente attivo.

steigerung.py

 # steigerung.py
 #
 import sys
 from machine import PinI2C
 from oled import OLED
 from time import sleep,ticks_msticks_ussleep_ms
 
 # Initialisieren der Schnittstellen **********************
 i2c=I2C(-1,scl=Pin(22),sda=Pin(21))
 d=OLED(i2c)
 
 # LED-Schichten einrichten *******************************
 #schichtPin = [32,33,25,27,26,12] # sortiert
 schichtPin = [32,26,33,27,25,12]   # verteilt
 schicht=[0]*6
 for i in range(6): # Ausgaenge erzeugen und auf 0
     schicht[i]=Pin(schichtPin[i],Pin.OUT)
     schicht[i].value(0)
 
 # Funktionen defnieren ***********************************
 def  switch(n,val):  # Ebene n ein-/ausschalten
     schicht[n].value(val)
 
 def stop():  # alle LED-Ebenen aus
     d.writeAt("GOOD BYE",4,3)
     for i in range(6):
         switch(i,0)
 
 def alle():  # alle LED-Ebenen ein
     for i in range(6):
         sleep_ms(300)
         switch(i,1)
     
 # Hauptprogramm ******************************************
 d.clearAll()
 d.rect(4,16,123,40,1)  # Rechteck in Pixelwerten
 for j in range(3):
     for i in range(6):
         d.writeAt("Ebene: {} ein".format(i),2,3)
         switch(i,1)
         sleep_ms(3000)
     for i in range(5,-1,-1):
         d.writeAt("Ebene: {} aus".format(i),2,3)
         switch(i,0)
         sleep_ms(3000)
 d.clearFT(2,3,14,3,False)
 stop()

Definiamo l'ordine dei livelli nella lista layerPin. Gli oggetti pin sono creati nel seguente ciclo for secondo questo schema. Le funzioni switch(), stop() e all() ci aiutano a rendere più chiaro il programma. Li useremo in diverse occasioni nei capitoli seguenti.

Nel programma principale puliamo lo schermo e disegniamo una cornice. 4 e 16 sono le coordinate dei pixel dell'angolo superiore sinistro, 123 e 40 sono la larghezza e l'altezza in pixel e 1 è il colore bianco, non ci sono più colori. Il ciclo for esterno conta il totale dei passaggi. Il primo ciclo for interno conta i in intervalli di 3 secondi e attiva i livelli. Il secondo ciclo conta a ritroso e cancella di nuovo i LED.

L'ultima uscita viene rimossa e la funzione stop() cancella in modo affidabile tutti i LED e saluta con un amichevole "GOOD BYE".

Possiamo specificare noi stessi il comportamento dei LED attraverso la lunghezza dell'intervallo e il numero di passaggi.

Per Arduino IDE

Scaricare steigerung.ino

7. L'albero incantato

Chiunque può passare e desiderare di accendere il nostro alberello. Ma niente da fare, è possibile solo con le nostre mani magiche. Naturalmente, non diciamo che abbiamo una piccola barra di magnete al neodimio nascosta in ogni mano. A cosa ci serve? Per "magia". Perché nel frattempo abbiamo ricostruito il nostro circuito. Un contatto reed a terra è ora collegato al pin 13 del GPIO. Il tubo di vetro contiene un contatto di commutazione che si chiude quando si avvicina un magnete.

Figura 13: i babbani non hanno magnete, l'albero rimane scuro

Figura 13: i babbani non hanno un magnete, l'albero rimane scuro

Figura 14: nel marker giallo: contatto e magnete

Figura 14: Nella marcatura gialla: contatto e magnete

Attenzione:

Il vetro è molto fragile e i fili sono molto rigidi. Non piegateli, altrimenti il vetro andrà in frantumi e potrete seppellire il componente.

Figura 15: Reed Contact aiuta la magia

Figura 15: Il contatto Reed aiuta a evocare

Un'altra cosa che non dobbiamo dimenticare è che l'OLED e l'alberello rimangono collegati come descritto sopra.

verzaubert.py

 from os import uname
 import sys
 from machine import  PinI2C
 from oled import OLED
 from time import sleep_ms
 
 # Initialisieren der Schnittstellen **********************
 i2c=I2C(-1,scl=Pin(22),sda=Pin(21))
 d=OLED(i2c)
 
 taste=Pin(0,Pin.IN,Pin.PULL_UP)
 reed=Pin(13,Pin.IN,Pin.PULL_UP)
 
 # LED-Schichten einrichten *******************************
 schichtPin = [32,33,25,26,27,12]
 schicht=[0]*6
 for i in range(6):
     schicht[i]=Pin(schichtPin[i],Pin.OUT)
     schicht[i].value(0)
 
 # Funktionen defnieren ***********************************
 def  switch(n,val):
     schicht[n].value(val)
 
 def stop():
     d.writeAt("   MUGGLE     ",1,3)
     for i in range(6):
         switch(i,0)
 
 def alle():
     d.writeAt(" DUMBLEDOR   ",1,3)
     for i in range(6):
         sleep_ms(300)
         switch(i,1)
     
 # Hauptprogramm ******************************************
 d.clearAll()
 d.writeAt("Kannst du ...",0,0)
 d.writeAt("ZAUBERN???",0,1)
 while 1:
     if reed()==0:
         alle()
     else:
         stop()

Il contatto reed deve essere posizionato in modo tale che possiamo avvicinarci ad esso con il nostro magnete quando mettiamo il nostro alberello o Breadboard sul palmo della mano. Un sottile guanto nero ci aiuta a mantenere il magnete invisibile. Probabilmente tutti quelli che ti circondano sono babbani. 

Il programma è molto semplice. Sappiamo già tutto fino al programma principale. Il ciclo while gira all'infinito fino a quando l'alimentazione non viene spenta. Se il contatto nelle vicinanze del magnete è chiuso, GPIO13 è al potenziale GND e tutte le luci si accendono. Altrimenti, la resistenza incorporata nel modulo tira GPIO13 a Vcc=3.3V e le luci si spengono.

Per far funzionare meglio la magia, l'alberello con la breadboard dovrebbe essere alimentato dalla batteria. La connessione positiva della batteria deve essere collegata al pin Vin / 5V dell'ESP32. Inoltre, il programma deve essere caricato sull'ESP32 come boot.py in modo che il controller si avvii autonomamente dopo l'accensione. Come fare questo è descritto in dettaglio nel Capitolo 2 - Autostart.

Per l'IDE di Arduino.

Scarica incantato.ino

8 Avvento e Natale, il tempo della "staad".

Tradotto in tedesco, "staad" significa qualcosa come "calmo", "contemplativo". La vita quotidiana ci insegna, tuttavia, che le cose possono anche scaldarsi nel periodo che precede il Natale. Quando le cose diventano troppo turbolente, l'alberello ci ricorda di abbassare il volume di qualche decibel. Come fa a farlo? Bene, c'è un modulo sonoro che capta il suono e fornisce il segnale digitalizzato all'ESP32.

Figura 16: Volume OK

Figura 16: Volume OK

Figura 17: troppo rumoroso

Figura 17: Troppo forte

Figura 18: Sound Machine su ESP32

Figura 18: Macchina del suono sull'ESP32

noisy.py.

  # noisy.py
 import esp32
 from os import uname
 from machine import TimerPinI2C
 from oled import OLED
 from time import timesleep,
 
 
 i2c=I2C(-1,scl=Pin(22),sda=Pin(21))
 d=OLED(i2c)
 
 # IRQ-Steuerung durch Soundmodul
 ST=Timer(1)
 sound=Pin(17,Pin.IN)
 #
 # LED-Schichten einrichten *******************************
 schichtPin = [32,33,25,27,26,12]
 L=len(schichtPin)
 schicht=[0]*L
 for i in range(L):
     schicht[i]=Pin(schichtPin[i],Pin.OUT)
     schicht[i].value(0)
 
 # Funktionen defnieren ***********************************
 def  switch(n,val):
     schicht[n].value(val)
 
 def stop():
     d.clearAll()
     d.writeAt("ALLES GUT",4,2)
     for i in range(L):
         switch(i,0)
 
 def alle():
     d.clearAll()
     d.writeAt("ZU LAUT!!",0,0)
     for i in range(L):
         sleep(0.5)
         switch(i,1)
 
 def soundDetected(pin):
     global n
     if pin==Pin(17):
         sound.irq(handler=None)
         if n:
             return
         n=True
         ST.init(period=15000mode=Timer.ONE_SHOTcallback=soundDone)
         print("begin",time())
         alle()
 
 def soundDone(t):
     global n
     n=False
     print("ende",time())
     stop()
     sound.irq(handler=soundDetectedtrigger=Pin.IRQ_FALLING)
 
 n=False
 sound.irq(handler=soundDetectedtrigger=Pin.IRQ_FALLING)

Il suono è trasmesso da rapide fluttuazioni di pressione dell'aria. Un segnale sonoro si propaga a circa 340 m/s. In una stanza, praticamente senza alcun ritardo percepibile. Il microfono nel modulo sonoro converte le fluttuazioni di pressione in un segnale elettrico. A differenza del contatto reed, però, queste oscillazioni non possono più essere rilevate tramite il polling della porta GPIO; questa procedura è troppo lenta. Pertanto, qui usiamo una tecnica diversa, la programmazione degli interrupt. Un'interruzione è l'interruzione di un programma da parte di un evento specifico. Useremo due diverse fonti di interruzione. Si attiva un interrupt quando il livello su un pin GPIO cambia, da 0 a 1 o viceversa. L'altra fonte IRQ è un timer hardware dell'ESP32. Attiva l'IRQ quando la sveglia suona.

Ora entrambi si passano la palla a turno. Il GPIO17 attende un segnale dal modulo audio. Se arriva un fronte di discesa, la funzione soundDetected() inizia e prima controlla se è dovuto al pin del parametro passato. Se n è True, allora un ciclo è già in corso e non c'è altro da fare. Se invece n è Falso, allora è un lavoro fresco. L'IRQ di cambio pin è spento e n è impostato su True per sopprimere gli impulsi immediatamente successivi al GPIO17. Poi viene avviato il timer, che specifica il tempo di esecuzione dell'illuminazione dell'albero. L'illuminazione si accende chiamando all().

Una volta che il timer è scaduto, viene attivato l'interrupt associato, che avvia la funzione soundDone(). n è impostato su False, le luci si spengono e l'IRQ di cambio pin viene riattivato.

Il programma principale consiste di due sole linee. n è impostato su False in modo che l'IRQ di cambio pin attivato in seguito possa essere attivato.

La cosa interessante è che gli IRQ sono ancora attivi anche se il programma principale è già finito. Per disattivarlo, l'ESP32 deve essere resettato con il pulsante STOP/RESTART.

Per l'IDE Arduino

Scaricare noisy.ino o opzionalmente noisy_ticker_h.ino (con la libreria Ticker.h)

Qui sono state usate due varianti per implementare gli interrupt del timer. Nel noisy.ino, solo le variabili binarie sono scambiate in ciascuna delle due routine di servizio d'interruzione. Il cambiamento viene poi rilevato nel normale ciclo principale. In alternativa, potete includere la libreria Ticker.h. Le sue impostazioni sono un po' più facili da fare. È incluso nel core ESP32. Non è necessario installarlo separatamente. Se non viene trovato durante la compilazione, potrebbe essere necessario aggiornare il core ESP32.

9. Sulle tracce del furto dell' albero

Si suppone che ci siano persone che rubano gli alberi di Natale - dalla foresta. Bene, cari forestali, perché non fate come noi e costruite una guardia nei vostri alberi come quella che stiamo per descrivere.

OK, è vero che questo sarà difficile come il monitoraggio di altri divieti se non c'è personale. Che senso ha vietare qualcosa se non si può controllare? In ogni caso, sia come sia.

Il nostro piccolo albero ottiene un supervisore - cioè se stesso! È aiutato da un sensore che viene da un angolo completamente diverso. Il modulo GY-521 utilizzato con il componente MPU6050 è un accelerometro con un giroscopio. Può misurare accelerazioni, forze e rotazioni. Sì, e se vuoi portare via qualcosa, devi sollevarla e metterla in moto. In entrambi i casi si accelera l'oggetto, anche quando lo si inclina.

Figura 19: il ribaltamento della luce è sufficiente per attivare l'allarme

Figura 19: Una leggera inclinazione è sufficiente per far scattare l'allarme.

Anche cambiamenti molto lievi nella posizione producono forze e quindi fanno sì che il nostro sensore risponda. Il resto è facile: l'allarme scatta, l'albero si illumina e il potenziale ladro spera di scappare. A proposito, un interrupt del timer è responsabile della durata dell'allarme.

Figura 20: unità Antiklau

Figura 20: unità antifurto

alarm.py

# alarm.py
 # RED-ALLERT by movement
 import esp32
 from os import uname
 from machine import TimerPinI2C
 from oled import OLED
 from time import sleep,ticks_msticks_ussleep_ms
 from gy521rc import GY521
 
 # Initialisieren der Schnittstellen **********************
 i2c=I2C(-1,scl=Pin(22),sda=Pin(21))
 d=OLED(i2c)
 
 AT=Timer(0)
 acc=GY521(i2c)
 limit=36
 dauer=5000
 
 schichtPin = [32,33,25,27,26,12]
 L=len(schichtPin)
 schicht=[0]*L
 for i in range(L):
     schicht[i]=Pin(schichtPin[i],Pin.OUT)
     schicht[i].value(0)
 
 # Funktionen defnieren ***********************************
 def TimeOut(t):
     start=ticks_ms()
     def compare():
         return int(ticks_ms()-start>t
     return compare
 
 def  switch(n,val):
     schicht[n].value(val)
 
 def stop():
     d.clearAll()
     d.writeAt("ALLES GUT",4,2)
     for i in range(L):
         switch(i,0)
 
 def alle():
     d.clearAll()
     d.writeAt("DIEBSTAHL",0,0)
     for i in range(L):
         sleep(0.5)
         switch(i,1)
 
 def hasMoved(delay):
     xs,ys,zs=0,0,0
     for i in range(100):
         x,y,z=acc.getXYZ()
         xs+=x
         ys+=y
         zs+=z
     xs//=100
     ys//=100
     zs//=100
     #print(xs,ys,zs)
     n=0
     while 1:
         x,y,z=acc.getXYZ()
         x=abs(xs-x)
         y=abs(ys-y)
         z=abs(zs-z)
         #print(x,xs//limit)
         if x > abs(xs//limit) :
             print("*******",n)
             n+=1
             alle()
             # Optional Nachricht via UDP
             AT.init(period=delaymode=Timer.ONE_SHOTcallback=alertDone)
         sleep(0.3)
 
 def alertDone(t):
     stop()
 
 print("Diebstahlschutz gestartet")
 hasMoved(dauer)

Anche in questo caso ci sono buone conoscenze del programma. Ciò che è nuovo, tuttavia, è l'inizializzazione del GY521. Per il modulo, dobbiamo caricare un altro modulo sull'ESP32, gy521rc.py. La classe che contiene ha lo stesso nome del modulo.

Come il display OLED, anche il GY521 funziona tramite il bus I2C. Passiamo lo stesso oggetto I2C al costruttore, impostiamo la soglia di attivazione dell'allarme e la sua durata in millisecondi.

La soglia è la quantità assoluta di deviazione del valore misurato dal valore medio della misurazione dell'accelerazione in direzione x. Il sensore è allineato in modo che l'asse x positivo punti verticalmente verso l'alto. Il valore misurato è di circa 16000 conteggi e in questo caso corrisponde all'accelerazione dovuta alla gravità g=9,81m/s².

La funzione hasMoved() rappresenta qui il ciclo principale. All'ingresso, il valore medio è determinato da 100 misurazioni. È chiaro che il sensore non deve muoversi.

Poi va nel ciclo principale, si misura l'accelerazione attuale e si calcolano le deviazioni dai valori medi. Se la differenza supera il limite predefinito, scatta un allarme e si attiva il timer. L'allarme significa che l'albero va a piena luminosità.

La routine di servizio dell'IRQ del timer spegne le luci. La soluzione tramite l'IRQ assicura che il circuito sia attivato di nuovo immediatamente dopo l'attivazione dell'allarme. Se la durata dell'allarme fosse specificata da un comando sleep nel ciclo principale, il circuito sarebbe guasto per quella durata.

I contatti vibranti menzionati nella lista delle componenti sarebbero collegati all'ESP32 in modo simile al contatto reed, ma non permettono di impostare la sensibilità.

Per l'IDE Arduino.

Scarica alarm.ino

La libreria GY521 è integrata qui per il sensore del giroscopio. Puoi anche installarlo tramite l'amministrazione della libreria. Inoltre, anche la libreria Ticker.h è usata qui. A differenza del modello MicroPython, qui vengono considerati tutti gli assi del sensore.

Se non siete sicuri di quale indirizzo I2C utilizza il sensore, potete caricare il programma I2C_Scanner.ino sull'ESP. In questo caso, due indirizzi dovrebbero essere mostrati nel monitor seriale (per il display e il sensore). Sul sensore stesso avete la possibilità di scegliere tra gli indirizzi 0x68 e 0x69. Dovete collegare il pin A0 o a GND o a 3,3V dell'ESP.

10. avere un piacevole soggiorno ESP32 e DHT22

Un clima piacevole nella stanza fa parte dell'atmosfera di festa. Ora, in questa semplice applicazione, l'ESP32 non può cambiare il clima della stanza, ma può riferire su di esso. I valori esatti di temperatura e umidità sono mostrati sul display OLED, i valori approssimativi sono indicati dall'alberello. A passi di 2 gradi, riporta i valori della temperatura ambiente attraverso diversi numeri di livelli di LED accesi.

Figura 21: temperatura media - metà illuminazione

Figura 21: Temperatura media - mezza illuminazione

Figura 22: misurazione della temperatura e dell'umidità in un modulo

Figura 22: misurazione della temperatura e dell'umidità in un solo modulo

Ci sono 2 versioni di DHT22, alias AM2302. Il modulo nell'illustrazione di sinistra contiene già la resistenza di pull-up necessaria per il bus a un filo, che, a proposito, non deve essere confuso con il sistema del modulo Dallas DS18B20. L'autobus di Dallas ha una tempistica completamente diversa. Per la versione nuda nell'illustrazione di destra, una resistenza da 4,7kΩ a 10kΩ deve essere installata contro Vcc.

Il funzionamento del programma è molto semplice. I tre comandi necessari sono forniti dal modulo dht già integrato in MicroPython.

roomclimate.py

 import esp32, dht
 from os import uname
 import sys
 from machine import PinI2C
 from oled import OLED
 from time import sleep
 
 # Initialisieren der Schnittstellen **********************
 i2c=I2C(-1,scl=Pin(22),sda=Pin(21))
 d=OLED(i2c)
 
 taste=Pin(0,Pin.IN,Pin.PULL_UP)
 dhtPin=Pin(13)
 dht22=dht.DHT22(dhtPin)
 
 # LED-Schichten einrichten *******************************
 schichtPin = [32,33,25,26,27,12]
 schicht=[0]*6
 for i in range(6):
     schicht[i]=Pin(schichtPin[i],Pin.OUT)
     schicht[i].value(0)
 
 # Funktionen defnieren ***********************************
 def  switch(n,val):
     schicht[n].value(val)
 
 def stop():
     d.writeAt("TEMP TO LOW",4,2)
     for i in range(6):
         switch(i,0)
 
 def alle():
     for i in range(6):
         sleep_ms(300)
         switch(i,1)
         
 def tree(n):
     for i in range(6):
         if i <=n:
             switch(i,1)
         else:
             switch(i,0)
     
 # Hauptprogramm ******************************************
 d.clearAll()
 d.writeAt("***RAUMKLIMA***",0,0)
 while True:
     sleep(0.3)
     dht22.measure()
     t=dht22.temperature()
     h=dht22.humidity()
     d.rect(0,10,126,38,1)
     d.clearFT(1,2,14,3)
     d.writeAt("TEMP: {:.1f} *C".format(t),1,2)
     d.writeAt("HUM : {:.1f} %".format(h),1,3)
     tree(int(((t-15)//2)%6))
     sleep(2.7)

A parte i soliti sospetti, il programma offre solo l'importazione del modulo dht, l'istanza dell'oggetto dht22 e il ciclo principale con il compito di misurazione dht22.measure() e la lettura dei valori di temperatura e umidità. Conosciamo già l'uscita sul display e la visualizzazione dell'albero. Interessante e poco appariscente è forse la conversione della temperatura da °C all'indice del livello di illuminazione. con il termine int(((t-15)//2)%6). Dal valore del quoziente della divisione intera della deviazione della temperatura da 15 °C in su e 2, il resto di 6 divisioni è determinato e rappresentato come un intero per essere al sicuro. Ancora una volta, molto lentamente.

Esempio:
t = 18 °C
18-15 =3
3//2 = 1
1 % 6 =1 also Stufenindex 1

per 28°C il risultato sarebbe: 28-15=13; 13//2=6; 6%6 = 0; L'ultimo passo è necessario perché non esiste un passo con il numero 6.

Per Arduino IDE.

Scaricare Roomclimate.ino.

Per questo sensore, si prega di installare la libreria di sensori DHT e la Adafruit Unified Sensor Library attraverso la gestione della libreria. A differenza di Python, in C/C++ bisogna prestare molta attenzione ai tipi di dati. I valori misurati del sensore vengono restituiti di tipo float. Di conseguenza, dovete impostare l'uscita formattata e il calcolo per il controllo dei LED può anche essere difettoso se tralasciate il tipo di dati.

11 La (un po' diversa) lotteria di Natale

Lo so ancora dai miei giorni di scuola. Ognuno ha portato un pacco durante l'Avvento e nella settimana prima delle vacanze è iniziata la lotteria - ogni biglietto vince.

Ho scelto carte RFID neutre come lotti riciclabili. Il sorteggio è fatto dall'ESP32 insieme al kit RFID. Devi solo occuparti dei premi da solo. Naturalmente, anche l'alberello è incluso. Attraverso la sua luminosità, annuncia il suo premio al rispettivo giocatore. Affinché non ci siano dubbi sull'interpretazione, il display indica inequivocabilmente la posizione di ogni sorteggio: Friburgo, Berlino, Amburgo ... Sono necessari sei biglietti della lotteria e una carta master.

Figura 23: L'altezza del numero di scattatura determina la forza luminosa

Figura 23: L'altezza del numero di hit determina la luminosità

Figura 24: Lotteria

Figura 24: Lotteria

Figura 25: Lettore di schede RFID

Figura 25: lettore di carte RFID

A causa del bus SPI, il cablaggio è un po' più complesso che con il bus I2C con le sue due linee. I dispositivi del bus SPI non hanno un indirizzo di dispositivo hardware, ma hanno una connessione chip select che deve essere impostata su LOW se il dispositivo deve essere indirizzato. Il trasferimento dei dati è anche un po' diverso; i dati sono sempre inviati e ricevuti simultaneamente. Non è necessario chiarire qui la procedura, perché la classe MFRC522 lo fa per noi. Diciamo solo al costruttore le assegnazioni delle porte e la velocità di trasferimento. Il trasferimento funziona con una velocità di 3.2MHz. Per confronto, I2C lavora a 400kHz.

La funzione readUID() legge e restituisce l'identificatore unico della carta come valore esadecimale e come numero decimale. Le carte vengono richieste tramite il display OLED. Per evitare che la funzione blocchi l'intero processo, un timeout assicura un ritiro ordinato. In questo caso, viene restituito il valore None invece dell'ID della carta.

Figura 26: carte e chip RFID

Figura 26: carte e chip RFID

Affinché le carte del lotto entrino in gioco, abbiamo bisogno di una carta master. Per fare questo, prendiamo qualsiasi carta o chip dallo stack, leggiamo l'ID e lo usiamo per assegnare la variabile con il valore decimale proprio all'inizio del programma:

MasterID=4217116188.

Al primo avvio, l'ESP32 rileva che non esiste ancora un file con i dati della scheda del lotto e richiede la scheda master. Dopo che questo è stato riconosciuto, viene richiesta la carta del lotto. Dopo aver letto l'ID, questo viene scritto nel file e la carta master viene richiesta di nuovo. La lettura continua fino alla lettura dell'ultima carta del lotto. Se nessuna carta del lotto viene offerta per 10 secondi dopo la richiesta della carta master, il sistema si riavvia da solo. Il prerequisito per questo è che il programma rfid.py sia stato inviato all'ESP32 come boot.py. Il capitolo 2 - Autostart spiega esattamente come farlo. Per ricominciare completamente da zero, possiamo cancellare il file slavecards.txt con gli ID delle carte del lotto tramite la console di Thonny. Dopo un reset, le carte del lotto possono essere lette di nuovo.

rfid.py

  # rfid.py
 # workes with RC522 13,2MHz
 import mfrc522
 import esp32dht
 from os import uname
 from machine import TimerPinI2CADCreset
 from oled import OLED
 from time import sleep,ticks_msticks_ussleep_ms
 from gy521 import GY521
 
 # Initialisieren der Schnittstellen **********************
 if uname()[0] == 'esp32':
     #                     sck, mosi, miso, cs=sda
     rdr = mfrc522.MFRC522(14,  16,   15,   5baudrate=3200000)
 elif uname()[0] == 'esp8266':
     #                     sck, mosi, miso, cs=sda
     #                     D3   D4   D2   D5
     rdr = mfrc522.MFRC522(0,   2,    4,    14baudrate=100000)
 else:
     raise RuntimeError("Unsupported platform")
 MasterID=4217116188  # 0XFB5C161C
 
 i2c=I2C(-1,scl=Pin(22),sda=Pin(21))
 d=OLED(i2c)
 
 schichtPin = [32,33,25,27,26,12]
 schicht=[0]*6
 for i in range(6):
     schicht[i]=Pin(schichtPin[i],Pin.OUT)
     schicht[i].value(0)
 gewinn=[
         "Freiburg",
         "Berlin",
         "Hamburg",
         "Augsburg",
         "Ratzeburg",
         "Erfurt",
         "Essen",
         "Bonn",
        ]
 # Funktionen defnieren ***********************************
 def TimeOut(t):
     start=ticks_ms()
     def compare():
         return int(ticks_ms()-start>t
     return compare
 
 def readUID(display,kartentyp,timeout):
     display.clearFT(0,1,15,show=False)
     display.writeAt("Put on "+kartentyp,0,1)
     readTimeOut=TimeOut(timeout)
     while not readTimeOut():
        (stattag_type) = rdr.request(rdr.REQIDL)
         if stat == rdr.OK:
            (statraw_uid) = rdr.anticoll()
             if stat == rdr.OK:
                 display.clearFT(0,2,15,show=False)
                 display.writeAt("Card OK",0,2)
                 sleep(1)
                 userID=0
                 for i in range(4):
                     userID=(userID<<8| raw_uid[i]
                 userIDS="{:#X}".format(userID)
                 print(userIDS)
                 return userID,userIDS
     return None
 
 def addUID(display):
     display.clearAll()
     m=readUID(display,"Master",3000)
     if m is not None:
         mid,_m
         if mid==MasterID:
             sleep(3)
             u=readUID(display,"Slavecard",3000)
             if u is not None:
                 uid,uids=u
                 if uid is not None and uid !MasterID:
                     with open("slavecards.txt","a"as f:
                         f.write("{}\n".format(uids))
                         display.writeAt("New slave written",0,3)
                         sleep(3)
                         return True
             else:
                 display.writeAt("ERROR!!!",0,3)
                 display.writeAt("Card not added!",0,4)
                 return False
         else:
             display.writeAt("ERROR!!!",0,3)
             display.writeAt("Not mastercard",0,4)
             sleep(3)
     return False
 
 def  switch(n,val):
     schicht[n].value(val)
 
 def stop():
     d.writeAt("GOOD BYE",4,2)
     for i in range(6):
         switch(i,0)
 
 def alle():
     for i in range(6):
         sleep_ms(300)
         switch(i,1)
         
 def tree(n):
     for i in range(6):
         if i <=n:
             switch(i,1)
         else:
             switch(i,0)
     
 # ******************* Hauptprogramm *********************
 d.clearAll()
 d.writeAt("*XMAS LOTTERIE*",0,0)
 d.rect(0,20,127,28,1)
 cards=[]
 try:
     with open("slavecards.txt","r"as f:
         for line in f:
             cards.append(line.strip("\n"))
     closed=TimeOut(60000)
     while not closed():
         u=readUID(d,"LOSKARTE",5000)
         d.clearFT(1,3,14,4,False)
         if u is not None:
             uid,uids=u
             try:
                 n=cards.index(uids)
                 d.writeAt("TREFFER {}".format(n),1,3False)
                 d.writeAt(gewinn[n],1,4)
             except ValueError as e:
                 d.writeAt("TROSTPREIS",1,3)
                 n=-1
             tree(n)
             closed=TimeOut(60000)
             sleep(10)
             stop()
 except OSError as e:
     print("keine Datei, keine Daten!")
     allRead=TimeOut(10000)
     while not allRead():
         if addUID(d):
             allRead=TimeOut(10000)
     print("Alle Karten eingelesen und gespeichert")
     d.clearFT(0,3,15,4,False)
     d.writeAt(" ALL CARDS READ",0,3)
     d.writeAt("**R E B O O T**",0,4)
     reset()
 d.clearFT(0,1,15,3,False)
 d.writeAt("Lotterie neu",0,2)
 d.writeAt("starten",0,3)

Per un ciclo di gioco, 6 vittorie sono determinate, le 6 carte sono mischiate e distribuite e il nuovo turno è iniziato con il pulsante PROG sull'ESP32.

Per Arduino IDE.

Scaricare rfid.ino

Nota: in questo caso, le connessioni ai pin dell'ESP32 devono essere cambiate. La ragione di questo è che viene utilizzata l'interfaccia SPI hardware. I suoi pin non possono essere cambiati.

MOSI  =  23
MISO  =  19
SCK   =  18

SDA  =  5
RST  = 17

Per lo scanner RFID, installate la libreria MFRC522.

Per un confronto diretto con MicroPython, potete cambiare questa linea in modo da non dover cambiare i pin ogni volta:

rdr = mfrc522.MFRC522(14,  16,   15,   5baudrate=3200000)

in

rdr = mfrc522.MFRC522(18,  23,   19,   5baudrate=3200000)

Per memorizzare il file di testo con gli ID, viene creato un file system nella memoria flash dell'ESP utilizzando la libreria LittleFS (il successore di SPIFS). I file possono quindi essere memorizzati lì. La libreria è ora parte del core ESP32. Non dovete nemmeno installarlo separatamente. Il programma è scritto in modo tale da non dover modificare il file di testo sul PC.

Se volete ancora farlo, potete installare l'ESP32 Upload Plugin. Tuttavia, lo scambio di dati funziona solo in una direzione (come dice già il nome).

La struttura del programma è stata cambiata un po' qui. Tuttavia, il comportamento del programma dovrebbe essere lo stesso. Sono state aggiunte alcune funzioni. È possibile leggere la scheda master quando il programma inizia. È anche possibile cancellare il file di testo dal flash. Per fare questo, potete collegare un cavo o un pulsante a GND sul pin indicato (vedi codice sorgente). Tienilo premuto e riavvia l'ESP. Poi il file sarà cancellato se esiste. Poi disconnetti e rileggi le carte vincenti. Il numero massimo di carte vincenti corrisponde ai livelli di LED dell'albero di Natale. Se volete usare meno carte, potete aspettare il timeout durante il processo di lettura.

12. L'alberello nella LAN/WLAN

Riempiamo la dozzina e colleghiamo l'alberello alla rete. Perché se si usa un ESP32 per il controllo, allora ci deve essere anche un accesso LAN o WLAN per il controllo. Ho deciso di implementare un server web sull'ESP32 perché i livelli dell'albero possono essere controllati con quasi tutti i browser. In alternativa, sarebbe stato possibile un server UDP sul controller e un'applicazione per cellulari. Tuttavia, questo sarebbe andato oltre lo scopo di questo blog, quindi mi sono astenuto dal farlo. Per chi fosse interessato, ho già descritto un tale tipo di controllo in altri post, per esempio qui e qui.

Per il circuito, abbiamo bisogno della configurazione del capitolo 5, a cui aggiungiamo un LED RGB e tre resistenze da 1,0 kΩ.

Figura 27: Struttura Web

Figura 27: struttura web

Dopo aver importato i moduli necessari, definiamo i pin per il LED RGB, che ci dice lo stato della rete in modo visibile a lunga distanza. Poi selezioniamo la modalità di rete, WLAN o il punto di accesso dell'ESP32. WLAN è l'impostazione predefinita. Per accedere al router WLAN, i dati di accesso devono essere inseriti qui. La definizione dei livelli è estesa da tre liste, testo semplice per on/off, colore di sfondo per la tabella nella pagina web e gli stati di commutazione dei livelli.

Nelle funzioni, quelle bloccanti sono state rimosse, swell(), swell(), wave() e tree(). Nuove aggiunte sono hexMac(), blink(), ledsOff() e web_page(). hexMac emette l'indirizzo MAC dell'ESP32 in modalità stazione, blink() segnala gli stati della rete e del server. ledsOff() spegne il LED RGB e web_page() raccoglie le richieste del browser, esegue gli ordini e restituisce una risposta come testo di pagina web.

La richiesta del browser va al server come una stringa di query. La stringa ha la forma ?a, ?p o ?e=x&v=y. In esso, x sta per il numero di livello e y per lo stato di commutazione, 0 o 1.

web_page() converte la richiesta in lettere maiuscole, prima controlla per "A" e "P". Se la richiesta contiene più di 2 caratteri, cerca di determinare il livello e lo stato di commutazione. Se si verifica un errore, non viene attivata nessuna azione e viene chiamata la pagina iniziale nuda. Questo accade anche se non è stata specificata alcuna stringa di query. In seguito, la pagina web viene costruita come una stringa e restituita al ciclo principale.

Dopo le definizioni delle funzioni, la connessione di rete viene stabilita, sia come punto di accesso proprio che come connessione al router WLAN. Questo è controllato dalle due variabili ownAP e WLANconnect. In entrambi i casi, viene assegnato un indirizzo IP fisso (10.0.1.181), poiché è un server. Gli indirizzi dinamici del router WLAN non sono adatti, poiché possono cambiare di volta in volta. La connessione al router è segnalata dal lampeggiamento del LED blu. Il display ci informa che la connessione è stabilita e la presa di connessione s è anche pronta ad accettare richieste.

Nel ciclo principale, il ciclo di ricezione del metodo accept() attende una richiesta. Se non arriva nulla entro il timeout, accept() lancia un'eccezione, che catturiamo con il precedente try.

Se c'è una richiesta, accept() restituisce un socket di comunicazione c e l'indirizzo della macchina richiedente. c è usato per gestire lo scambio di dati tra client e server, mentre s diventa di nuovo libero per accettare ulteriori richieste in arrivo. Il metodo c.recv() restituisce il testo della richiesta, di cui ci interessano solo i primi caratteri. Nella fase di sviluppo, si possono inserire richieste web_page() a mano per testare il parser. ownAP e WLANconnect devono quindi essere entrambi impostati su False.

L'oggetto byte richiedente del testo ricevuto ora sarà in una stringa R Decodi che possono essere gestiti più facilmente. Stiamo cercando un "Get /" all'inizio della stringa r e dopo la posizione in cui segue "HTTP". Entrambi vengono trovati, quindi isolamo il testo dopo il "/" di "ottenere" nello spazio di "HTML" e inviarlo come una stringa di query al parser pagina web(). La cui risposta riceviamo nelle variabili risposta. Quindi invieremo l'intestazione HTML e il testo della pagina HTML con la risposta contenuta al chiamante. I seguenti due. Altro e il tranne Servizi per la cattura e il trattamento di eventuali errori. Importante è la finale C. Chiudi.() Quale sedile delle comunicazioni C Chiude.

Dopo una richiesta di tasti per annullare il programma, il LED verde ci mostra con il suo breve lampeggio come un battito cardiaco che il sistema è ancora vivo.

webControl.py.

  # webcontrol.py
 # Fernsteuerung vom Browser via TCP
 # (C) 2021 Jürgen Grzesina
 # released under MIT-License (MIT)
 # http://www.grzesina.de/az/weihnachtsbaum/MIT-License.txt
 #
 from machine import PinI2C
 from oled import OLED
 
 # ******************** Network stuff ********************
 from time import sleep,ticks_mssleep_ms
 try:
   import usocket as socket
 except:
   import socket
 import ubinascii
 import network
 
 statusLed=Pin(18,Pin.OUT,value=0# blau=2
 onairLed=Pin(19,Pin.OUT,value=0)  # gruen=1
 errorLed=Pin(23,Pin.OUT,value=0)  # rot=0
 led=[errorLed,onairLed,statusLed ]
 red,green,blue=0,1,2
 request = bytearray(50)
 response=""
 taste=Pin(0,Pin.IN,Pin.PULL_UP)
 
 # Auswahl der Betriebsart Netzwerk oder Tastatur:
 # --------------------------------------------------------
 # Netzwerk: Setzen Sie genau !_EINE_! Variable auf True
 WLANconnect=True  # Netzanbindung ueber lokales WLAN
 ownAP=False       # Netzanbindung ueber eigenen Accessppoint
 # beide False ->> Befehlseingabe ueber PC + USB in Testphase
 # Falls WLANconnect=True:
 # Geben Sie hier die Credentials Ihres WLAN-Accesspoints an
 mySid = 'YOUR_SSID'myPass = "YOUR_PASSWORD"
 myIP="10.0.1.181"
 myPort=9002
 
 # Initialisieren der Schnittstellen **********************
 i2c=I2C(-1,scl=Pin(22),sda=Pin(21))
 d=OLED(i2c)
 
 #schichtPin = [32,33,25,27,26,12] # sortiert
 schichtPin = [32,26,33,27,25,12]   # verteilt
 schicht=[0]*6
 for i in range(6):
     schicht[i]=Pin(schichtPin[i],Pin.OUT)
     schicht[i].value(0)
 zustand=["aus","an "]
 color=["red","lightgreen"]
 eState=[0,0,0,0,0,0]
 
 connectStatus = {
     1000"STAT_IDLE",
     1001"STAT_CONNECTING",
     1010"STAT_GOT_IP",
     202:  "STAT_WRONG_PASSWORD",
     201:  "NO AP FOUND",
     5:    "GOT_IP"
    }
 
 # Funktionen defnieren ***********************************
 def TimeOut(t):
     start=ticks_ms()
     def compare():
         return int(ticks_ms()-start>t
     return compare
 
 def  switch(n,val):
     schicht[n].value(val)
 
 def stop():
     d.writeAt("ALL LEDS OFF",2,5)
     for i in range(6):
         switch(i,0)
 
 def alle():
     d.writeAt("ALL LEDS ON ",2,5)
     for i in range(6):
         sleep_ms(300)
         switch(i,1)
         
 def tree(n):
     d.writeAt("TREE PROGR. ",2,5)
     for i in range(6):
         if i <=n:
             switch(i,1)
         else:
             switch(i,0)
 
 def hexMac(byteMac):
   """
  Die Funktion hexMAC nimmt die MAC-Adresse im Bytecode  
  entgegen und bildet daraus einen String fuer die Rueckgabe
  """
   macString =""
   for i in range(0,len(byteMac)):     # Fuer alle Bytewerte
     macString += hex(byteMac[i])[2:]  # ab Position 2 bis Ende
     if i <len(byteMac)-1 :            # Trennzeichen
       macString +="-"
   return macString
 
 def blink(pulse,wait,col,inverted=False):
     if inverted:
         led[col].off()
         sleep(pulse)
         led[col].on()
         sleep(wait)
     else:
         led[col].on()
         sleep(pulse)
         led[col].off()
         sleep(wait)
 
 def ledsOff():
     for i in range(3):
         led[i].value(0)
 
 def web_page(q):
     global eState
     q=q.upper()
     print("Anfrage: ",q)
     if q=="?A":
         alle()
         for i in range(6):
             eState[i]=1
     elif q=="?P":
         stop()
         for i in range(6):
             eState[i]=0
     elif len(q)>2:
         try:
             ebene,state=q[1:].split("&")
             _,ebeneebene.split("=")
             _,statestate.split("=")
             ebene=(int(ebeneif 0<=int(ebene)<=5 else 0)
             state=(int(stateif 0<=int(state)<=1 else 0)
             switch(ebene,state)
             eState[ebene]=state
         except:
             pass
     else:
         pass
     antwort="<tr>"
     for i in range(6):
         h="<td bgcolor={}><H3>E{} {}.</H3></td>".format(color[eState[i]],izustand[eState[i]])
         antwort=antwort+h
     antwort=antwort+"</tr>"
     html1 = """<html>
    <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
    <h2>Hallo, <br>ich bin dein Weihnachtsb&auml;umchen</h2>"""
     html2="""<table border=2 cellspacing=2>
    """
     html3="""
    <tr>
    <td>
    <a href='http://10.0.1.181:9002/?e=0&v=1'><H3>E0 An </H3> </a>
    </td>
    <td>
    <a href='http://10.0.1.181:9002/?e=1&v=1'><H3>E1 An </H3> </a>
    </td>
    <td>
    <a href='http://10.0.1.181:9002/?e=2&v=1'><H3>E2 An </H3> </a>
    </td>
    <td>
    <a href='http://10.0.1.181:9002/?e=3&v=1'><H3>E3 An </H3> </a>
    </td>
    <td>
    <a href='http://10.0.1.181:9002/?e=4&v=1'><H3>E4 An </H3> </a>
    </td>
    <td>
    <a href='http://10.0.1.181:9002/?e=5&v=1'><H3>E5 An </H3> </a>
    </td>
    <td>
    <a href='http://10.0.1.181:9002/?a'><H3>ALLE AN </H3> </a>
    </td>
    </tr>
    <tr>
    <td>
    <a href='http://10.0.1.181:9002/?e=0&v=0'><H3>E0 Aus</H3> </a>
    </td>
    <td>
    <a href='http://10.0.1.181:9002/?e=1&v=0'><H3>E1 Aus</H3> </a>
    </td>
    <td>
    <a href='http://10.0.1.181:9002/?e=2&v=0'><H3>E2 Aus</H3> </a>
    </td>
    <td>
    <a href='http://10.0.1.181:9002/?e=3&v=0'><H3>E3 Aus</H3> </a>
    </td>
    <td>
    <a href='http://10.0.1.181:9002/?e=4&v=0'><H3>E4 Aus</H3> </a>
    </td>
    <td>
    <a href='http://10.0.1.181:9002/?e=5&v=0'><H3>E5 Aus</H3> </a>
    </td>
    <td>
    <a href='http://10.0.1.181:9002/?p'><H3>ALLE AUS</H3> </a>
    </td>
    </tr>
    """
     html9 = "</table> </body> </html>"
     html=html1+html2+antwort+html3+html9
     return html
 
 if taste.value()==0:
     print("Mit Flashtaste abgebrochen")
     ledsOff()
     d.writeAt("Abbruch d. User ",0,5)
     sys.exit()    
 
 # ********************************************************
 # Netzwerk einrichten
 # ********************************************************
 # Eigener ACCESSPOINT
 # ********************************************************
 if ownAP and (not WLANconnect):
     #
     nic = network.WLAN(network.AP_IF)
     nic.active(True)
     ssid="christbaum"
     passwd="don't_care"
 
     # Start als Accesspoint
     nic.ifconfig((myIP,"255.255.255.0",myIP,\
                   myIP))
 
     print(nic.ifconfig())
 
     # Authentifizierungsmodi ausser 0 werden nicht unterstuetzt
     nic.config(authmode=0)
 
     MAC=nic.config("mac"# liefert ein Bytes-Objekt
     # umwandeln in zweistellige Hexzahlen
     MAC=ubinascii.hexlify(MAC,"-").decode("utf-8")
     print(MAC)
     nic.config(essid=ssidpassword=passwd)
 
     while not nic.active():
       print(".",end="")
       sleep(0.5)
 
     print("Unit1 listening")
 # *************** Setup accesspoint end *****************
 
 # ********************************************************
 # WLAN-Connection
 # ********************************************************
 if WLANconnect and (not ownAP):
     nic = network.WLAN(network.STA_IF# erzeuge WiFi-Objekt
     nic.active(True)  # Objekt nic einschalten
     #
     MAC = nic.config('mac')  # binaere MAC-Adresse abrufen +
     myMac=hexMac(MAC)        # in Hexziffernfolge umwandeln
     print("STATION MAC: \t"+myMac+"\n"# ausgeben
     # Verbindung mit AP im lokalen Netzwerk aufnehmen,
     # falls noch nicht verbunden, dann
     # connect to LAN-AP
     if not nic.isconnected():
       nic.connect(mySidmyPass)
       # warten bis die Verbindung zum Accesspoint steht
       print("connection status: "nic.isconnected())
       while not nic.isconnected():
         blink(0.8,0.2,0)
         print("{}.".format(nic.status()),end='')
         sleep(1)
     # zeige Verbindungsstatus & Config-Daten
     print("\nconnected: ",nic.isconnected())
     print("\nVerbindungsstatus: ",connectStatus[nic.status()])
     print("Weise neue IP zu:",myIP)
     nic.ifconfig((myIP,"255.255.255.0",myIP\
                   myIP))
     STAconf = nic.ifconfig()
     print("STA-IP:\t\t",STAconf[0],"\nSTA-NETMASK:\t",\
           STAconf[1],"\nSTA-GATEWAY:\t",STAconf[2] ,sep='')
 
 # *********** Setup Router connection end ***************
 
 # ********************************************************
 # TCP-Web--Server
 # ********************************************************
 # ----------------- Server starten --------------------------
 if WLANconnect or ownAP:
     s = socket.socket(socket.AF_INETsocket.SOCK_STREAM)
     s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
     s.bind((''myPort))
     print("Socket established, waiting on port",myPort)
     d.clearAll()
     #         0123456789012345
     d.writeAt("SOCK ESTABLISHED",0,0)
     d.writeAt("LISTENING AT",0,1)
     d.writeAt(myIP+":"+str(myPort),0,2)
     s.settimeout(0.9)
     s.listen(2)
     
 if taste.value()==0:
     print("Mit Flashtaste abgebrochen")
     ledsOff()
     d.writeAt("Abbruch d. User ",0,5)
     sys.exit()
 
 # ------------------- Serverschleife ----------------------
 while True:
     try:  # wegen timeout
         r=""
         if WLANconnect or ownAP:
             caddr = s.accept()
             print('Got a connection from {}:{}\n'.\
                   format(addr[0],addr[1]))
             request=c.recv(1024)
         else:
             request=input("Kommando:")
             addr="999.999.999.999:99999"
         try:  # decodieren und parsen
             r=request.decode("utf8")
             getPos=r.find("GET /")
             if r.find("favicon")==-1:
                 print("***********************************")
                 print("Position:",getPos)
                 print("Request:")
                 print(r)
                 print("***********************************")
                 pos=r.find(" HTTP")
                 if getPos == 0 and pos !-1:
                     query=r[5:pos# nach ? bis HTTP
                     print("*********QUERY:{}*********\n\n".\
                           format(query))
                     response = web_page(query)
                     print("---------------\n",response,\
                           "\n----------------")
                     c.send('HTTP/1.1 200 OK\n'.encode())
                     c.send('Content-Type: text/html\n'.encode())
                     c.send('Connection: close\n\n'.encode())
                     c.sendall(response.encode())
                 else:
                     print("##########\nNOT HTTP\n###########")
                     c.send('HTTP/1.1 400 bad request\n'.encode())
             else:
                 print("favicon request found")
                 c.send('HTTP/1.1 200 OK\n'.encode())
         except:  # decodieren und parsen
             request = rawRequest
             c.send('HTTP/1.1 200 OK\n'.encode())
         c.close()
     except:  # wegen timeout
         pass    
         
     if taste.value()==0:
         print("Mit Flashtaste abgebrochen")
         ledsOff()
         d.writeAt("Abbruch d. User ",0,5)
         sys.exit()
     blink(0.05,0.05,1)

Figura 28: Live dal browser

Figura 28: In diretta dal browser

Questo è come il sito web appare in realtà su Google Chrome. Opera offre un'immagine simile dopo aver inserito l'URL 10.0.1.181:9002. Firefox sta facendo storie perché i produttori si sono messi in testa di dover vessare gli utenti facendo accettare al loro browser solo indirizzi https. Ma ci sono alternative. Se le cose si mettono davvero male, si potrebbe anche scrivere il proprio frontend per il PC con CPython.

Bene, credo che ora abbiate abbastanza da fare con i progetti dell'albero fino a Natale. Sono sicuro che c'è qualcosa per tutti. L'importante è che vi piaccia farli e che io sia riuscito a suscitare il vostro interesse. In ogni caso, vi auguro un meraviglioso periodo d'Avvento.

Per Arduino IDE.

Scaricare webcontrol.ino

L'interfaccia nel browser sembra leggermente diversa qui. La funzione è la stessa.

A seconda che vogliate usare il vostro access point o la WLAN locale, dovete commentare l'opzione inutilizzata nel codice sorgente nelle #defines all'inizio.

// #define WLANconnect true
#define ownAP true

Non dimenticare di inserire i tuoi dati di accesso se scegli l'opzione WLAN.

A questo punto vi auguriamo un felice 1° Avvento.

DisplaysEsp-32Projekte für anfängerSensoren

6 commenti

Jürgen

Jürgen

@ Niko Germer
Natürlich können Sie die Flacker-LEDs gegen normale Kandidaten austauschen. Aber Sie haben recht, für unterschiedliche Farben brauchen Sie unterschiedliche Widerstände. Das liegt einerseits an den unterschiedlichen Durchlassspannungen, rote LEDs haben eine niedrigere als blaue. Aber entscheidender ist die Helligkeit der LEDs. Geringe Helligkeit bei rot und gelb steht der blendenden Helligkeit der blauen und vor allem grünen LEDs gegenüber. Ich beziehe mich hier auf auf die LED aus dem LED Assortment Kit. Für die roten schlage ich 150 Ohm vor, blau 560 Ohm und grün 1,5kOhm für jeweils sechs parallele LEDs am Bäumchen. Die normalen LEDs lassen sich dann auch dimmen, wenn an die Basiswiderstände ein PWM-Signal gelegt wird. Der ESP32 kann das Signal an allen digitalen Ausgängen zur Verfügung stellen.

Niko Germer

Niko Germer

Hallo,
ich würde das Bäumchen gerne mit normale LEDs bestücken. Kann man dann die LEDs dimmen? Was muss ich beachten, bei die Vorwiderstände? Bleiben die gleich?

Andreas Wolter

Andreas Wolter

Die Aktion für das Bundle ist leider abgelaufen. Danke für den Hinweis. Den Link haben wir entfernt.

Michael Beckmann

Michael Beckmann

Hallo
wenn man auf das Bild zur Teileliste klickt kommt ein HTTP 404 :-(

Miguel Torres

Miguel Torres

Un articulo muy bueno con muchos ejemplos con un elemento común.

bit.picker

bit.picker

Sehr schöner Artikel. Besonders interessant finde ich das Kapitel mit der Web-Steuerung. Dannke!

Lascia un commento

Tutti i commenti vengono moderati prima della pubblicazione