Topic: Python 2 su raspberry pi orologio e sensore.  (Letto 79 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline johnwick

  • python unicellularis
  • *
  • Post: 12
  • Punti reputazione: 0
    • Mostra profilo
Python 2 su raspberry pi orologio e sensore.
« il: Marzo 03, 2021, 19:38 »
Buonasera a tutti. Con python2 su raspberry pi zero w ho creato un orologio più sensore di temperatura e umidità che viene visualizzato su un display waveshare 1.44 TFT. Il codice sorgente che ho creato funziona, ma ha un piccolo difetto. All'ultima riga c'è: time.sleep(1.0) che serve ad aggiornare il display ogni secondo, ma l'orologio si sposta con i secondi a volte di 2, 3, 5 secondi alla vota. Questo perché ci mette un pò di tempo per leggere il sensore.

C'è un modo che l'orologio si aggiorna ogni secondo e il sensore ogni 10 secondi? Posto sotto il codice:



#for DHT22
sensor = 22
 
pindht = 4

LCD = LCD_1in44.LCD()

Lcd_ScanDir = LCD_1in44.SCAN_DIR_DFT  #SCAN_DIR_DFT = D2U_L2R
LCD.LCD_Init(Lcd_ScanDir)
LCD.LCD_Clear()

font = ImageFont.truetype("/home/pi/.fonts/aAhaWow.ttf", 20)
font2 = ImageFont.truetype("/home/pi/.fonts/Stay and Shine.ttf", 17)
font3 = ImageFont.truetype("/home/pi/.fonts/Stay and Shine.ttf", 25)

while True:
 
        humidity, temperature = Adafruit_DHT.read_retry(sensor, pindht)
        temperature_f = temperature * (9 / 5) + 32
         
        if humidity is not None and temperature is not None and temperature_f is not None:
            print("Temp: {0:0.1f}°F / {1:0.1f}°C  Humidity: {2:0.1f} %" .format(temperature_f, temperature, humidity))
            localtime_data = time.strftime("%d/%m/%Y")
            print("Data :"), localtime_data
            localtime_ora = time.strftime("%H:%M:%S")
            print("Ora :"), localtime_ora
                       
            celsius = str(round(temperature, 1)) + " .C"           
            umidita = str(round(humidity, 1)) + " %"           
            fahrenheit = str(round(temperature_f, 1)) + " .F"
            localtime_data = str(time.strftime("%d/%m/%Y"))
            localtime_ora = str(time.strftime("%H:%M:%S"))           

            image = Image.new("RGB", (LCD.width, LCD.height), "BLACK")
            draw = ImageDraw.Draw(image)
                       
            #draw.text((5, 10), ' Ora ', font=font, fill = "YELLOW")
            draw.text((20, 10), localtime_ora, font=font3, fill = "YELLOW")
            #draw.text((1, 45), ' Data: ', font=font, fill = "BLUE")
            draw.text((1, 40), localtime_data, font=font, fill = "WHITE")
            #draw.text((1, 60), ' Fahrenheit ', fill = "BLUE")
            #draw.text((76, 65), fahrenheit, font=font, fill = "WHITE")
            draw.text((1, 70), ' Temper. ', font=font2, fill = "YELLOW")
            draw.text((62, 70), celsius, font=font2, fill = "RED")
            draw.text((5, 93), ' Umidita: ', font=font2, fill = "WHITE")
            draw.text((70, 93), umidita, font=font2, fill = "GREEN")
           

            LCD.LCD_ShowImage(image,0,0)
            LCD_Config.Driver_Delay_ms(500)
        else:
            print("Failed to get reading. Check the sensor connection!")
#        sys.exit(15)
        time.sleep(1.0)

Offline nuzzopippo

  • python neanderthalensis
  • ****
  • Post: 381
  • Punti reputazione: 0
    • Mostra profilo
Re:Python 2 su raspberry pi orologio e sensore.
« Risposta #1 il: Marzo 09, 2021, 17:40 »
Ciao @Johnwick,
Buonasera a tutti. Con python2 su raspberry pi zero w ...
Come mai hai utilizzato la 2.x? Oramai è fuori supporto

...
C'è un modo che l'orologio si aggiorna ogni secondo e il sensore ogni 10 secondi? Posto sotto il codice:...

Purtroppo, non conosco il Tuo strumento e non avendolo disponibile non ho alcuna possibilità di valutare il Tuo codice, posso solo dare delle indicazioni a livello generico, ho cercato di prepararTi un esempietto, quale spunto, ho avuto poco tempo e mi è stato difficile sintetizzare in poche righe di codice (cause della risposta dopo così tanto tempo).
Fermo restando che per le operazioni di input la libreria più indicata forse sarebbe asyncio, con la quale ho fatto qualche esperimento ma non padroneggio, per fare ciò che chiedi penso sia possibile utilizzare anche il multiprocessing od anche i thread ... probabilmente c'è molto altro che possa usarsi, gli esperti, se bontà loro vorranno, sapranno dare indicazioni migliori.
Sono tutti argomenti di una certa complessità, utilizzarli decentemente non è immediato.

Comunque, un modo che ho cercato di sviluppare per farTi un semplicissimo esempio (ho omesso molte cose, p.e. non ho utilizzato le queue, etc.) è tramite i thread.
Il codice che segue utilizza giusto i thread per definire due classi "produttrici" di dati (TimeProducerThread e ClimateSimThread) ove la prima simula il Tuo orologio e la seconda il Tuo aggeggio (producendo dati random) il tutto esposto in una "finestra", finestra per modo di dire, ho evitato il classico tkinter (che è thread-safe) per utilizzare curses che NON È thread-safe e che dovresti avere disponibile sul raspberry, ammesso il s.o. sia di tipo linux, come di norma è, in ogni caso, se vuoi "vedere" il funzionamento sotto windows fatti uun venv ed installaci windows-curses (testato 'sta mattina, funziona anche li), vedrai una finestra azzurrina con un orologio che si attiva/disattiva se premi "T" ed un settore che, se premi "C", espone una successione di stringhe con data, ora, temperatura (simulata) ed umidità (simulata), di colori alternati, per rendere evidente un eventuale "scorrimento" dei dati se si raggiunge il bordo della finestra, l'aggiornamento dei dati avviene esattamente ad 1 secondo per il "timer" ed a 10 secondi per il "simulatore climatico" ... ovvio, l'input da un "aggeggio" terzo non è detto che sia così liscio, magari considerare lo I/O asincrono (ed una queue) non sarebbe male ma è proprio un esempio striminzito al minimo ... una "gestione" decente non è cosa da due righe.
Nota il loop infinito nel metodo _intercvept() della classe MasterWin, è li che vengono istanziati (e distrutti) i thread produttori di dati, le classi consumatrici si limitano a rappresentarli quando li ricevono, nota anche come, uscito dal ciclo infinito (premendo "Q") venga verificata l'esistenza dei thread (variabili self.timer e self.climate) che, nel caso, vengono distrutti, non facendo così l'applicazione continuerebbe a funzionare.

Il codice è python 3 (non saprei esattamente come andrebbe nel 2)
import threading
import locale
import curses
from datetime import datetime
import time
import random


class TimeProducerThread(threading.Thread):
    def __init__(self, target=None):
        super().__init__()
        self.target = target
        self.active = False

    def run(self):
        self.active = True
        while self.active:
            now = datetime.now()
            current_time = now.strftime('%H:%M:%S')
            if self.target: self.target.update(current_time)
            time.sleep(1)

    def stop(self):
        self.active = False


class TimeConsumer:
    def __init__(self, win, colour):
        self.win = win
        self.height, self.width = self.win.getmaxyx()
        self.colour = colour
        self.win.bkgd(' ', curses.color_pair(self.colour))
        self.update('')

    def update(self, msg):
        self.win.clear()
        if msg: msg = msg[:self.width-2]
        self.win.addstr(0, 1, msg)
        self.win.refresh()


class ClimateSimThread(threading.Thread):
    def __init__(self, target=None):
        super().__init__()
        self.target = target
        self.active = False

    def run(self):
        self.active = True
        while self.active:
            # crea un messaggio con data, ora, pseudo-temperatura
            # e pseudo-umidità
            now = datetime.now()
            msg = now.strftime('%d/%m/%Y')
            msg += ' ' + now.strftime('%H:%M:%S') + ' - '
            temp = round(random.uniform(-30.0, 60.0), 2)
            msg += '%.1f°C ' % temp
            um = round(random.uniform(10.0, 100.0), 2)
            msg += 'umidità {:0.1f}%'.format(um)
            if self.target: self.target.update(msg)
            time.sleep(10)

    def stop(self):
        self.active = False


class ClimateConsumer:
    def __init__(self, win, colours):
        self.win = win
        self.height, self.width = self.win.getmaxyx()
        self.colours = colours
        self.win.bkgd(' ', curses.color_pair(self.colours[0]))
        self.items = []
        self.pivot = 0
        self.update('')

    def update(self, msg):
        if msg:
            msg = msg[:self.width-2]
        else:
            return
        cl_index = (len(self.items) + self.pivot) % len(self.colours)
        item = (self.colours[cl_index], msg)
        if len(self.items) >= self.height - 1:
            self.items.pop(0)
            self.pivot += 1
        self.items.append(item)
        self.win.clear()
        for r in range(len(self.items)):
            self.win.move(r+1, 1)
            self.win.addstr(self.items[r][1],
                            curses.color_pair(self.items[r][0]))
        self.win.refresh()
   

class MasterWin:
    def __init__(self, stdscr):
        # inizializzazione generale dello schermo
        curses.noecho()
        curses.cbreak()
        curses.curs_set(0)
        # inizializzazione set colori
        curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
        curses.init_pair(2, curses.COLOR_YELLOW, curses.COLOR_BLUE)
        curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLUE)
        curses.init_pair(4, curses.COLOR_BLUE, curses.COLOR_WHITE)
        # inizializzazione finestra
        self.win = stdscr
        self.height, self.width = self.win.getmaxyx()
        self._paint_win()
        self.win.refresh()
        # oggetti sussidiari
        self.timer = None
        self.climate = None
        self._def_win_timer()
        self._def_win_climate()
        # ciclo di comando
        self._intercept()
   
    def _paint_win(self):
        ''' Disegna la finestra principale.'''
        # Bordi e sezioni come piacciono a me
        self.win.bkgd(' ', curses.color_pair(1))
        self.win.addstr(1, 2, 'Ora:')
        self.win.addstr(4, 2, 'Letture:')

    def _def_win_timer(self):
        win_timer = self.win.subwin(1, 10, 1, 7)
        self.time_consumer = TimeConsumer(win_timer, 4)

    def _def_win_climate(self):
        win_climate = self.win.subwin(self.height - 6,
                                      self.width - 2,
                                      5, 1)
        colours = [1, 2, 3]
        self.climate_consumer = ClimateConsumer(win_climate, colours)

    def _intercept(self):
        k = 0
        msg = ''
        while True:
            k = self.win.getch()
            if k == ord('t') or k == ord('T'):
                # attiva/disattiva il thread timer
                if self.timer:
                    self.timer.stop()
                    self.timer = None
                else:
                    self.timer = TimeProducerThread(self.time_consumer)
                    self.timer.start()
            elif k == ord('c') or k == ord('C'):
                # attiva/disattiva il thread simulazione letture
                if self.climate:
                    self.climate.stop()
                    self.climate = None
                else:
                    self.climate = ClimateSimThread(self.climate_consumer)
                    self.climate.start()
            elif k == ord('q') or k == ord('Q'):
                break
        # IMPORTANTE : se attivi i thread vanno fermati
        if self.timer:
            self.timer.stop()
            self.timer = None
        if self.climate:
            self.climate.stop()
            self.climate = None


def main(stdscr):
    locale.setlocale(locale.LC_ALL, '')
    stdscr.encoding = locale.getpreferredencoding()
    MasterWin(stdscr)


if __name__ == '__main__':
    curses.wrapper(main)


è solo uno spunto, ovvio, prova a vedere se Ti è utile.

Ciao :)