lunedì 28 dicembre 2020

DHT11 ESP8266 NEOPIXEL e Micropython

 Ho ripreso in mano il mio ESP8266 per approfondirne la conoscenza. Nell'ultimo post ho imparato a caricare il Micropython ed a collegare il mio ESP8266 da remoto con WebREPL.


In questo modo e' possibile caricare i file di programma nel file system del ESP8266, in modo da poterli poi far "girare" chiamandoli direttamente da termionale o madandoli in esecuzione direttamente al boot, utilizzando il file di sistema boot.py.

Infatti il MicroPython, gia' dalla sua istallazione prevede il file boot.py che in automatico la macchina chiama ad ogni reboot, quindi e' facile poter far partire tutti i programmi che vogliamo opportunamente impostando solamente  quest'ultimo file.


Avevo in un cassetto un ESP8266 superstite da alcuni altri passati esperimenti, al quale era gia' collegato e funzionante una barretta di 8 led Neopixel ed un sensore DHT11.

Niente di meglio per fare amicizia con il sistema Micropython.

Ho iniziato ad impostare la rete in modo fisso, in maniera che ad ogni reboot l'ESP si colleghi in automatico con il router di casa, semplicemente copiando le istruzioni necessarie nel file  boot.py (le stesse che abbiamo visto nel post di ieri).

Fatto questo e reso automatica la partenza del sistema WebREPL come visto ieri, impostando la password.

Ho iniziato a caricare tramite WebREPL il file di un semplice programma che legge la temperatura dal sensore e la stampa sulla consolle.

TEMP.PY :

#questo programma legge la temperatura e l'umidita' dal sensore DHT11 
#collegato al Pin 14 del ESP8266 (il pin contrassegnato con D5)

from machine import Pin
#from time import sleep
import dht 
#sensor = dht.DHT22(Pin(14))
sensor = dht.DHT11(Pin(14))

def get_temp():
    sensor.measure()
    temp = sensor.temperature()
    hum = sensor.humidity()
    return [temp,hum]


def leggi_temp():
    sensor.measure()
    temp = sensor.temperature()
    hum = sensor.humidity()
    print('Temperature: %3.1f C' %temp)
    print('Humidity: %3.1f %%' %hum)
    


Poi ho caricato un secondo file leds.py che gestira' i leds della barretta di Neopixel con a bordo il famoso led WS2812B.

LEDS.PY :

# questo programma scrive colori su neopixel ws2812B
# i neopixel sono collegati al Pin 5 che e' marcato D1 sulla scheda esp8266

import machine, neopixel
from time import sleep
import temp
n = 8 #numero dei pixel disponibili
p = 5 #pin sul quale sono collegati i led

np = neopixel.NeoPixel(machine.Pin(p), n)

def temp_leds():
    lista = temp.get_temp()
    if lista[0] <= 16:
        np[0] = (0,0,5)
        np[1] = (0,0,0)
        np[2] = (0,0,0)
        np[3] = (0,0,0)
        np[4] = (0,0,0)
        np[5] = (0,0,0)
        np[6] = (0,0,0)
        np[7] = (0,0,0)
        np.write()
    elif lista[0] == 17:
        np[0] = (0,0,5)
        np[1] = (0,0,5)
        np[2] = (0,0,0)
        np[3] = (0,0,0)
        np[4] = (0,0,0)
        np[5] = (0,0,0)
        np[6] = (0,0,0)
        np[7] = (0,0,0)
        np.write()
    elif lista[0] == 18:
        np[0] = (0,5,3)
        np[1] = (0,5,3)
        np[2] = (0,5,0)
        np[3] = (0,0,0)
        np[4] = (0,0,0)
        np[5] = (0,0,0)
        np[6] = (0,0,0)
        np[7] = (0,0,0)
        np.write()
    elif lista[0] == 19:
        np[0] = (0,5,3)
        np[1] = (0,5,3)
        np[2] = (0,5,0)
        np[3] = (0,5,0)
        np[4] = (0,0,0)
        np[5] = (0,0,0)
        np[6] = (0,0,0)
        np[7] = (0,0,0)
        np.write()
    elif lista[0] == 20:
        np[0] = (0,5,0)
        np[1] = (0,5,0)
        np[2] = (0,5,0)
        np[3] = (0,5,0)
        np[4] = (5,5,0)
        np[5] = (0,0,0)
        np[6] = (0,0,0)
        np[7] = (0,0,0)
        np.write()
    elif lista[0] == 21:
        np[0] = (0,5,0)
        np[1] = (0,5,0)
        np[2] = (0,5,0)
        np[3] = (0,5,0)
        np[4] = (5,5,0)
        np[5] = (5,0,0)
        np[6] = (0,0,0)
        np[7] = (0,0,0)
        np.write()
    elif lista[0] == 22:
        np[0] = (0,5,0)
        np[1] = (0,5,0)
        np[2] = (0,5,0)
        np[3] = (0,5,0)
        np[4] = (5,5,0)
        np[5] = (5,0,0)
        np[6] = (5,0,0)
        np[7] = (0,0,0)
        np.write()
    elif lista[0] == 23:
        np[0] = (0,5,0)
        np[1] = (0,5,0)
        np[2] = (0,5,0)
        np[3] = (0,5,0)
        np[4] = (5,5,0)
        np[5] = (5,0,0)
        np[6] = (5,0,0)
        np[7] = (5,0,0)
        np.write()
    else:
        np[0] = (3,0,0)
        np[1] = (3,0,0)
        np[2] = (3,0,0)
        np[3] = (3,0,0)
        np[4] = (5,0,0)
        np[5] = (5,0,0)
        np[6] = (5,0,0)
        np[7] = (5,0,0)
        np.write()
def smooth_red():
    for led in range(8):
        for i in range(50):
            np[led] = (i, 0, 0)
            np.write()
            sleep(0.025)

def spengi_leds():
    for i in range(8):
        np[i] = (0, 0, 0)
    np.write()

def smooth_green():
    for led in range(8):
        for i in range(50):
            np[led] = (0, i, 0)
            np.write()
            sleep(0.025)

def smooth_blu():
    for led in range(8):
        for i in range(50):
            np[led] = (0, i, 0)
            np.write()
            sleep(0.025)
        

Inizialmente ho fatto amicizia con i colori (attenzione a non far partire alla massima intensita' tutti i led assieme che potrebbe essere dannoso per l'alimentazione del computer al quale e' collegato l'ESP, a causa del  troppo assorbimento - circa 60 mA per ogni led)

Infine li ho inseriti nel file di boot.py per far si che possano funzionare gia' dal reboot:

Il sistema cosi impostato, legge la temperatura una sola volta all'accensione, e in funzione del valore letto, accende i led di colore blu se la temperatura e' al di sotto dei 16 - 17 gradi
di colore verde per valori tra i 17 ed i 20 gradi e di rosso se la temperatura supera i 20 gradi.
I led si accendono in modo che la scala sia "parlante" in funzione dell'aumento della temperatura.
Cioe' < 16 gradi solo il primo led - poi via via fino a 24 gradi con tutti e 8 i led accesi.

E' ovvio che il tutto e' fatto per test e per fare conoscenza! Per fare un device intelligente, la temperatura va letta ad iintervalli costanti ed aggiornata la scla dei led in conseguenza. Ma non era questo lo scopo dei miei test di oggi (comunque bastano altre due righe di codice per farlo!)


BOOT.PY


# This file is executed on every boot (including wake-boot from deepsleep)
#import esp
#esp.osdebug(None)
import uos, machine
#uos.dupterm(None, 1) # disable REPL on UART(0)
import gc
import webrepl
import network
import temp
import leds
sta_if = network.WLAN(network.STA_IF)
sta_if.connect("XXXXXXXXXXXXXXXXXX","XXXXXXXXXXX") # Connect to an AP
print("LA mia connessione e' attiva e questo e' il mio indirizzo: ", sta_if.ifconfig())
webrepl.start()
gc.collect()
temp.leggi_temp()

leds.temp_leds()


Oggi sono arrivato fino qui!
A domani (forse ) per la prossima puntata.
TecnoGeppetto

domenica 27 dicembre 2020

Programmare Esp32Cam con Python anche da remoto

La parte discorsiva la faro' in un secondo momento. 

Collegare Esp32Cam completo di modulo seriale alla USB del pc tramite cavo USB-C tenendo premuto il tasto IO0, che deve essere premuto per mettere il microcontrollore in flash mode. far partire il tools predisposto da Espressif.


Controllare tra i dispositivi di Windows che nome e' stato asseganto alla seriale, nel mio caso COM7 

Ho cancellato completamente la Flash con l'apposito tasto rifatto il boot  del device scollegandolo e ricollegandolo tenendo premuto il tasto IO0 . 
A questo punto fatto il download del firmware col tasto START.

 Se tutto e' andato a buon fine adesso ci ritroviamo con un device esp32 che risponde , se interrogato via seriale, con il prompt di python. 

Quindi collegare il device alla seriale, chiamarlo con un programma che legge i dati da seriale, per esempio putty su windows o minicom su debian, con la velocita' settata a 115200b e rispondera' il classico >>> di python.

Per poter lavorare sul nostro ESP32 senza connetterlo al pc tramite cavo vanno fatti due passi importanti: 

Collegare il device ad una rete (la stessa dove si trovera' anche il tuo pc) Abilitare la funzione WebREPL del micropython che consente di "parlare" con il prompt tramite una connessione wifi. 

Qui tutte le piu' importanti comandi per lavorare con l'interfaccia wifi :

import network

wlan = network.WLAN(network.STA_IF) # create station interface
wlan.active(True)       # activate the interface
wlan.scan()             # scan for access points
wlan.isconnected()      # check if the station is connected to an AP
wlan.connect('essid', 'password') # connect to an AP
wlan.config('mac')      # get the interface's MAC address
wlan.ifconfig()         # get the interface's IP/netmask/gw/DNS addresses

ap = network.WLAN(network.AP_IF) # create access-point interface
ap.config(essid='ESP-AP') # set the ESSID of the access point
ap.config(max_clients=10) # set how many clients can connect to the network
ap.active(True)         # activate the interface

Qui invece come attivare il WebREPL:
  import webrepl_setup
import webrepl
webrepl.start()

# or, start with a specific password
webrepl.start(password='mypass')



Attivato WebREPL andra' impostata la password che l'utente dovra' digitare all'accesso da remoto, per poter programmare il device.
Buon divertimento
TecnoGeppetto

domenica 27 gennaio 2019

Controllo del TV con Arduino con Led Infrarossi

Da qualche tempo mi sono trasferito in Grosseto e sono venuto ad abitare in una piccola mansarda nel Parco della Maremma. La mansardina è piccola ed essenziale, ma riesce sempre a nascondere alcune cose fondamentali, come per esempio il Telecomando del TV. Quando lo cerchi non lo trovi mai!
Mosso dall'esigenza di poter controllare la TV senza doversi sempre preoccupare della localizzazione dello scettro dei tempi moderni (leggi telecomando TV) mi sono messo alla ricerca tra i componenti sparsi nei miei cassetti freschi di trasloco (sigh!).
Ho trovato un sensore di gesture che non avevo ancora mai testato. Quale migliore occasione di farci amicizia!??
Il sensore in questione è APDS 9960 che riesce a discriminare ben 6 movimenti diversi, destra,
sinistra, alto, basso, vicino e lontano, sufficienti per poter regolare il volume, l'avanzamento dei programmi, la selezione del canale più ascoltato ed il Mute per escludere velocemente l' ascolto.

Quindi definite le specifiche del progetto sono passato alla ricerca di qualche tutorial in rete per capire meglio utilizzo del sensore, ho trovato questo https://learn.sparkfun.com/tutorials/apds-9960-rgb-and-gesture-sensor-hookup-guide/all  che è molto interessante e mi ha messo in condizione di poter fare subito i primi test.
Caricata la libreria specifica del sensore basta far girare il firmware di test che nella finestra seriale della IDE di Arduino possiamo già vedere riconosciuti i movimenti di UP DOWN LEFT RIGHT NEAR  e FAR.

Ho preso integralmente il firmware di test che fa proprio al mio caso e sono passato a fare dei test sulla parte Infrarossi. Qui ho già una discreta esperienza fatta durante alcuni altri progetti conclusi negli scorsi anni, quindi sono subito andato a scaricarmi la libreria IRremote direttamente dal repository della IDE di Arduino.
Nei file di esempio c'è già tutto quello che serve per poter facilmente cambiare canale ed agire sul volume del tuo televisore.
Ho montato un circuito di test per registrare il codice Infrarosso che trasmette il mio telecomando, collegando un ricevitore IR



Attraverso la lettura dei codici trasmessi dal mio telecomando ed intercettati dal sensore IR qui in foto, ho potuto registrare i codici dei 6 comandi necessari al progetto.
Ho quindi montato il  Led trasmettitore Infrarossi per controllare la correttezza dei comandi inviati al TV dal mio circuito e quando tutto finalmente funziona, mi sono dedicato a montare tutto il software assieme per ottenere la prima versione del progetto funzionante.

Guardando il risultato però non ero ancora completamente soddisfatto, perchè, anche se non sono amante delle lucine messe dappertutto, non avere nessun riscontro delle operazioni effettuate e del corretto riconoscimento del gesture, mi sembrava troppo scarno, allora mi sono deciso a mettere la mano adi nuovo nel cassetto per vedere come abbellire il mio telecomando.
Ho deciso quindi di aggiungere un display 1602 con il suo circuito I2C per evitare di non cablare in modo parallelo  il display stesso.
Naturalmente l'appetito vien mangiando, con un diusplay a disposizione è un peccato non vedere l'ora esatta, viene da sè che diventa indispensabile inserimento nel progetto di una RTC per fornire l'ora esatta al sistema e poterla quindi avere a disposizione sul display a cristalli liquidi.
Anche con l'RTC ho già fatto amicizia durante una serie di altri progetti, quindi sono partito avvantaggiato!!, nei file di esempio della libreria RTClib ci sono tutti ritagli software che sono necessari per poter programmare l'ora esatta (una tantum) e interrogare la RTC per visualizzare sul display l'ora sul display ad ogni loop del firmware.

Per quanto riguarda il firmware per la gestione del display ho utilizzato questa guida, molto utile per l'uso congiunto della interfaccia I2C con il display a cristalli liquidi 1602...https://www.instructables.com/id/Using-PCF8574-backpacks-with-LCD-modules-and-Ardui/

quindi ho istallato la seguente libreria  https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads

Questo e' il risultato del primo prototipo completo montato sulla scrivania. Nel pomeriggio (forse) provvedero' alla posa in una scatolina per mettere in uso il sistema completo. (vedremo, di solito alla catola non ci arrivo mai, ma passo subito al prossimo progetto!! vedrfemo... e vedrete, forse)

Sotto alle foto il firmware funzionante

   





















codice:
*****************************************************

//sistema di trasmissione  dei codici IR della mia TV gestito da sensore di movimento
//sono registrati alcuni movimenti che corrispondono a comendi TV definiti
//dal basso all'alto == Aumenta Volume ++   funzione alzaVolume     2FD58A7
//dal'alto al basso == Abbassa Volume --    funzione abbassaVolume  2FD7887
// da destra a sinistra == Programmi --     funzione Programmameno  2FDD827
//da sinistra a destra == Programmi ++      funzione Programmapiu   2FDF807
//da vicino a lontano veloce                funzione VolumeNO       2FD08F7
//da lontano a vicino veloce                funzione Canale 48  2FD20DF  +  2FD10EF
// Date and time functions using a DS1307 RTC connected via I2C and Wire lib
//Sensore APDS9960 connesso ad SDA SCL 3,3Volts GND e PIN 2 interrupt
//IR LED connesso a PWM pin 3.

#include
#include "RTClib.h"
#include  
#include

LiquidCrystal_I2C  lcd(0x26,2,1,0,4,5,6,7);  // set the LCD address to 0x27 for a 16 chars and 2 line display

#include
#include
#include
IRsend irsend;
// Pins
#define APDS9960_INT    2 // Needs to be an interrupt pin
// Global Variables
SparkFun_APDS9960 apds = SparkFun_APDS9960();
int isr_flag = 0;
RTC_DS1307 rtc;

void setup() {
   lcd.begin (16,2); // for 16 x 2 LCD module
   lcd.setBacklightPin(3,POSITIVE);
   lcd.setBacklight(HIGH);
   lcd.backlight();
   // Set interrupt pin as input
  pinMode(APDS9960_INT, INPUT);

  // Initialize Serial port
  //Serial.begin(9600);
    // Initialize interrupt service routine
  attachInterrupt(0, interruptRoutine, FALLING);

  // Initialize APDS-9960 (configure I2C and initial values)
  if ( apds.init() ) {
    lcd.print(F("9960 init complete"));
        delay(1000);

  } else {
    lcd.print("Some went wrong");
        delay(1000);

  }
   lcd.clear();
  // Start running the APDS-9960 gesture sensor engine
  if ( apds.enableGestureSensor(true) ) {
    lcd.print("Gest now running");
        delay(1000);

  } else {
    lcd.print("Int APDS wrong");
        delay(1000);

  }
   lcd.clear();

      if (! rtc.begin()) {
    lcd.print("NON TROVO RTC");
    while (1);
  }
  lcd.clear();
  if (! rtc.isrunning()) {
    lcd.print("RTC NOT run!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    delay(1500);
    }else{lcd.clear(); lcd.print("RTC is OK");delay(1500);}
    lcd.clear();
    lcd.home (); // set cursor to 0,0
    lcd.print(" TecnoGeppetto");
    delay(1000);
    lcd.setCursor(1,1);
    lcd.print("telecomando TV");
//****************************************************************
    //per rimettere l'ora se rtc ha perso qualche colpo!!
   // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
//****************************************************************

   
}

void loop() {
  if( isr_flag == 1 ) {
    detachInterrupt(0);
    handleGesture();
    isr_flag = 0;
    attachInterrupt(0, interruptRoutine, FALLING);
  }
 
   DateTime now = rtc.now();
   lcd.setCursor(0,0);
   lcd.print("ORARIO: ");
   lcd.print(now.hour());
   lcd.print(":");
   lcd.print(now.minute());
   lcd.print(":");
   lcd.print(now.second());
}



void alzaVolume(){
//Qui inserire il RAW del Volume ++  2FD58A7
for (int i = 0; i < 3; i++) {
    irsend.sendNEC(0x2FD58A7, 32);
    delay(40);
  }

}

void abbassaVolume(){
//Qui inserire il RAW del Volume --  2FD7887
for (int i = 0; i < 3; i++) {
    irsend.sendNEC(0x2FD7887, 32);
    delay(40);
  }

}


void Programmapiu(){
//Qui inserire il RAW del Programmi ++  2FDD827
for (int i = 0; i < 3; i++) {
    irsend.sendNEC(0x2FDD827, 32);
    delay(40);
  }

}

void Programmameno(){
//Qui inserire il RAW del Programmi --  2FDF807
for (int i = 0; i < 3; i++) {
    irsend.sendNEC(0x2FDF807, 32);
    delay(40);
  }

}


void VolumeNO(){
//Qui inserire il RAW del VolumeNO  .. 2FD08F7
for (int i = 0; i < 3; i++) {
    irsend.sendNEC(0x2FD08F7, 32);
    delay(40);
  }

}


void Canale48(){
//Qui inserire il RAW del Canale48 :  2FD20DF  +  2FD10EF
for (int i = 0; i < 3; i++) {
    irsend.sendNEC(0x2FD20DF, 32);
    delay(40);
  }
for (int i = 0; i < 3; i++) {
    irsend.sendNEC(0x2FD10EF, 32);
    delay(40);
  } 

}
void interruptRoutine() {
  isr_flag = 1;
}

void handleGesture() {
    if ( apds.isGestureAvailable() ) {
    switch ( apds.readGesture() ) {
      case DIR_UP:
      lcd.clear();
      lcd.setCursor(0,1);
      lcd.print("LastCom= Vol +");
       alzaVolume();
        break;
      case DIR_DOWN:
      lcd.clear();
      lcd.setCursor(0,1);
      lcd.print("LastCom= Vol -");
        abbassaVolume();
        break;
      case DIR_LEFT:
      lcd.clear();
      lcd.setCursor(0,1);
      lcd.print("LastCom= Prog -");
      Programmameno();
        break;
      case DIR_RIGHT:
      lcd.clear();
      lcd.setCursor(0,1);
      lcd.print("LastCom= Prog +");
      Programmapiu();
        break;
      case DIR_NEAR:
      lcd.clear();
      lcd.setCursor(0,1);
      lcd.print("LastCom= NO Vol");
      VolumeNO();
        break;
      case DIR_FAR:
      lcd.clear();
      lcd.setCursor(0,1);
      lcd.print("LastCom= C 48");
      Canale48();
        break;
      default:
      lcd.clear();
      lcd.setCursor(0,1);
      lcd.print("LastCom= NONE !");
    }
  }
}