Neste artigo vamos alavancar as capacidade de IoT da Raspberry Pi Pico W e construir um Relógio Inteligente que apresenta em um display gráfico colorido a hora atual e a previsão do tempo (obtidos da Internet) e a temperatura local (obtida de um sensor) .

Materiais Necessários para montar o Relógio com Raspberry Pi Pico W
Para criar um Relógio Inteligente com Raspberry Pi Pico W, você irá precisar dos seguintes componentes:
- Raspberry Pi Pico W
- Display IPS LCD 0.96” Colorido
- Sensor de Humidade e Temperatura DHT11
- Protoboard
- Jumpers
- Resistor de 4.7KΩ
Preparativos – Instalando o Interpretador MicroPython
Siga os passos abaixo para preparar a sua Pi Pico para usar o MicroPython:
- Baixe e instale no seu computador a IDE Thonny (https://thonny.org/).
- Entre em Tools Options, selecione a aba Interpreter e escolha MicroPython (Raspberry Pi Pico).

- Aberte o botão BOOTSEL da Pi Pico e, mantendo o botão apertado, conecte a Pi Pico ao seu PC. Aguarde a placa ser reconhecida como uma unidade de disco.
- Clique no link “Install or update firmware”

- Selecione “Raspberry Pi Pico W / Pico WH”
- Click no botão Install e aguarde aparecer a mensagem Done!
- Click no botão Close
Instalando o Driver do Display e Fontes
Para escrever no display precisamos instalar um driver e de dois fontes (um deles com os ícones para a previsão de tempo). Para realizar a instalação, execute o Thonny com a Pico W conectada ao micro e siga os passos abaixo:
- Baixe os arquivos necessários de https://github.com/dquadros/RelogioPico/archive/refs/heads/main.zip
- Expanda o zip em um diretório do seu micro
- No Thonny, use View Files para apresentar os diretórios no micro e na placa
- Navega na área de aquivo do micro para o diretório onde estão os arquivos da biblioteca, clique com o botão direito e escolha Focus into
- Clique com o botão direito no diretório lib nos arquivos do micro e escolha Upload to /
Obtendo a URL de Consulta à Previsão do Tempo
Vamos obter a previsão do tempo do serviço Open-Meteo acessa a página https://open-meteo.com/en/docs e faça as seguintes seleções:
- Coloque o nome da sua cidade em Select City (ou forneça a latitude e longitude):
- Desmarque Temperature em Hourly Weather Variables:
- Marque Weathercode, Sunrise e Sunset em Daily Weather Variables:
- Em Settings, selecione o fuso horário (Timezone)
- Copie e salve a API URL
Esquemático relógio com Raspberry Pi Pico W
A figura abaixo mostra a montagem do projeto.

Obs: ao invés do sensor DHT-11 avulso, você pode usar um módulo com ele (como este aqui). Neste caso, acerte as conexões conforme a pinagem do módulo, não é necessário o resistor de 4.7KΩ pois ele já está no módulo.
Programação do relógio com Raspberry Pi Pico W
O nosso programa vai estar dividido em vários módulos. Cada módulo deve ser copiado no Thonny e salvo na placa com o nome indicado (ou você pode copiar diretamente do micro para a placa a partir do diretório onde você colocou o driver do display.
O primeiro módulo, secrets.py contem o nome e a senha da rede WiFi que será usada:
ESSID = 'MinhaRede' PASSWD = 'segredo'
O módulo weather.py contém as funções para obter a previsão de tempo.
# Módulo para consulta do Clima em https://open-meteo.com/ import network import urequests import json import time url = 'https://api.open-meteo.com/v1/forecast?latitude=-23.53&longitude=-46.79&daily=weathercode,sunrise,sunset&timezone=America%2FSao_Paulo' # converte hora de formato ISO para interno def _conv_time(iso): return time.mktime((int(iso[0:4]), int(iso[5:7]), int(iso[8:10]), int(iso[11:13]), int(iso[14:16]), 0, 0, 0)) # obtem a previsão de tempo para hoje def previsao(): r = urequests.get(url) if r.status_code == 200: resposta = json.loads(r.text) r.close() sunrise = _conv_time(resposta['daily']['sunrise'][0]) sunset = _conv_time(resposta['daily']['sunset'][0]) return resposta['daily']['weathercode'][0], sunrise, sunset else: r.close() print ('ERRO: {0}'.format(r.status_code)); return None, 0, 0 from display_ips import DISPLAY_IPS WHITE = DISPLAY_IPS.rgb(255,255,255) GRAY = DISPLAY_IPS.rgb(127,127,127) BLACK = DISPLAY_IPS.rgb(0,0,0) BLUE = DISPLAY_IPS.rgb(0,0,255) YELLOW = DISPLAY_IPS.rgb(255, 216, 0) # conversão do código do tempo em caracter e cores tabWeather = { 0: [ (0x0d, YELLOW), (0x2e, WHITE) ], # clear sky 1: [ (0x0d, YELLOW), (0x2e, WHITE) ], # mainly clear 2: [ (0x02, YELLOW), (0x86, WHITE) ], # partly cloudy 3: [ (0x13, WHITE), (0x13, WHITE) ], # overcast 45: [ (0x14, WHITE), (0x14, WHITE) ], # fog 48: [ (0x14, WHITE), (0x14, WHITE) ], # depositing rime fog 51: [ (0x17, WHITE), (0x17, WHITE) ], # light drizzle 53: [ (0x17, WHITE), (0x17, WHITE) ], # moderate drizzle 55: [ (0x17, WHITE), (0x17, WHITE) ], # dense drizzle 56: [ (0x17, WHITE), (0x17, WHITE) ], # light freezing drizzle 57: [ (0x17, WHITE), (0x17, WHITE) ], # dense freezing drizzle 61: [ (0x19, WHITE), (0x19, WHITE) ], # slight rain 63: [ (0x19, WHITE), (0x19, WHITE) ], # moderate rain 65: [ (0x19, WHITE), (0x19, WHITE) ], # heavy rain 66: [ (0x19, WHITE), (0x19, WHITE) ], # light freezing rain 67: [ (0x19, WHITE), (0x19, WHITE) ], # heavy freezing rain 71: [ (0x1b, WHITE), (0x1b, WHITE) ], # slight snow 73: [ (0x1b, WHITE), (0x1b, WHITE) ], # moderate snow fall 75: [ (0x1b, WHITE), (0x1b, WHITE) ], # heavy snow fall 77: [ (0x1b, WHITE), (0x1b, WHITE) ], # snow grains 80: [ (0x19, WHITE), (0x19, WHITE) ], # slight rain shower 81: [ (0x19, WHITE), (0x19, WHITE) ], # moderate rain shower 82: [ (0x19, WHITE), (0x19, WHITE) ], # violent rain shower 85: [ (0x1b, WHITE), (0x1b, WHITE) ], # slight snow shower 86: [ (0x1b, WHITE), (0x1b, WHITE) ], # heavy snow shower 95: [ (0x1e, GRAY), (0x1e, GRAY) ], # thunderstorm 96: [ (0x1e, GRAY), (0x1e, GRAY) ], # thunderstorm with slight hail 99: [ (0x1e, GRAY), (0x1e, GRAY) ] # thunderstorm with heavy hail } def decodeWeather(code, ehDia): if code in tabWeather: fundo = BLUE if ehDia else BLACK ind = 0 if ehDia else 1 return tabWeather[ind][0], tabWeather[ind][1], fundo else: return None, 0, 0
O módulo dht.py contém uma classe para acesso ao sensor DHT11 (extraída do artigo “Como utilizar o PIO da Raspberry Pi Pico para Comunicar sensores DHT11 ou DHT22”).
# Módulo para leitura de sensor DHt11/DHT22 import utime import rp2 from rp2 import PIO, asm_pio from machine import Pin # Programa para o PIO # coloca automaticamente na fila a cada 8 bits recebidos @asm_pio(set_init=(PIO.OUT_HIGH),autopush=True, push_thresh=8) def DHT_PIO(): # aguarda uma solicitação do programa pull() # mantem dado em 0 pelo tempo informado pelo programa set(pindirs,1) #set pin to output set(pins,0) #set pin low mov (x,osr) label ('waitx') nop() [25] jmp(x_dec,'waitx') # espera tempo*26/clock=x # inicia leitura da resposta set(pindirs,0) # muda o pino para entrada wait(1,pin,0) # aguarda voltar ao nível alto wait(0,pin,0) # aguarda pulso inicial wait(1,pin,0) wait(0,pin,0) # aguarda inicio do primeiro bit # lê os bits label('readdata') wait(1,pin,0) # espera o sinal ir para nivel alto set(x,20) # registrador x é o timeout para descer label('countdown') jmp(pin,'continue') # continua contando se sinal permanece alto # pino foi para o nível baixo antes da contagem terminar -> bit 0 set(y,0) in_(y, 1) # coloca um 'zero' no resultado jmp('readdata') # ler o próximo bit # pino continua no nível alto label('continue') jmp(x_dec,'countdown') # decrementar a contagem # contagem terminou -> bit 1 set(y,1) in_(y, 1) # coloca um 'um' no resultado wait(0,pin,0) # espera voltar ao nível baixo jmp('readdata') # ler o próximo bit DHT11 = 0 DHT22 = 1 class DHT: # Construtor # dataPin: pino de dados # modelo: DHT11 ou DHT22 # smID: identificador da máquina de estados def __init__(self, dataPin, modelo, smID=0): self.dataPin = dataPin self.modelo = modelo self.smID = smID self.sm = rp2.StateMachine(self.smID) self.ultleitura = 0 self.data=[] # faz uma leitura no sensor def leitura(self): data=[] self.sm.init(DHT_PIO,freq=1400000,set_base=self.dataPin,in_base=self.dataPin,jmp_pin=self.dataPin) self.sm.active(1) if self.modelo == DHT11: self.sm.put(969) # espera 18 milisegundos else: self.sm.put(54) # espera 1 milisegundo for i in range(5): # lê os 5 bytes da resposta data.append(self.sm.get()) self.sm.active(0) total=0 for i in range(4): total=total+data[i] if data[4] == (total & 0xFF): # checksum ok, salvar os dados self.data = data self.ultleitura = utime.ticks_ms() return True else: return False # le ou usa dados já existentes def obtemDados(self): # garante ter dados while len(self.data) == 0: if not self.leitura(): utime.sleep_ms(2000) # só tenta ler se já passou pelo menos 2 segundos da última leitura agora = utime.ticks_ms() if self.ultleitura > agora: self.ultleitura = agora # contador deu a volta if (self.ultleitura+2000) < agora: self.leitura() # informa a umidade def umidade(self): self.obtemDados() if self.modelo == DHT11: return self.data[0] + self.data[1]*0.1 else: return ((self.data[0] << 8) + self.data[1]) * 0.1 # informa a temperatura def temperatura(self): self.obtemDados() if self.modelo == DHT11: return self.data[2] + self.data[3]*0.1 else: s = 1 if (self.data[2] & 0x80) == 1: s = -1 return s * (((self.data[2] & 0x7F) << 8) + self.data[3]) * 0.1
Por último, o módulo main.py contém o programa principal.
# Relogio Inteligente - Módulo Principal import rp2 import network import time import gc import secrets import dht from sys import exit from machine import Pin, SPI TIMEOUT = 20 # Inicia o display from display_ips import DISPLAY_IPS import fonts.freesans20 as freesans20 import fonts.weather_font as wfont pdc = Pin(14, Pin.OUT, value=0) prst = Pin(13, Pin.OUT, value=1) pcs = Pin(9, Pin.OUT, value=1) gc.collect() # Precaution before instantiating framebuf spi = SPI(1, sck=Pin(10), mosi=Pin(11), baudrate=1_000_000) disp = DISPLAY_IPS(spi, pcs, pdc, prst, 80, 160) WHITE = DISPLAY_IPS.rgb(255,255,255) GRAY = DISPLAY_IPS.rgb(127,127,127) BLACK = DISPLAY_IPS.rgb(0,0,0) BLUE = DISPLAY_IPS.rgb(0,0,255) YELLOW = DISPLAY_IPS.rgb(255, 216, 0) disp.fill(BLUE) disp.print(20, 30, "Conectando...", freesans20, WHITE, BLUE) disp.show() # Prepara acesso ao sensor dht_data = Pin(15, Pin.IN, Pin.PULL_UP) sensor = dht.DHT(dht_data, dht.DHT11, 0) # Conecta à rede WiFi rp2.country('BR') wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect(secrets.ESSID, secrets.PASSWD) print ('Conectando...') timeout = time.ticks_add(time.ticks_ms(), TIMEOUT*1000) while not wlan.isconnected() and wlan.status() >= 0 and \ time.ticks_diff(timeout, time.ticks_ms()) > 0: time.sleep(0.2) if not wlan.isconnected(): disp.fill(BLUE) disp.print(0, 30, "SEM CONEXAO", freesans20, WHITE, BLUE) disp.show() print ('Não conseguiu conectar, abortando') exit() print ('Conectado') print('IP: '+wlan.ifconfig()[0]) # Obter a hora atual import ntptime UTC_OFFSET = -3 * 60 * 60 ntptime.settime() # Iniciacoes para o laco principal import weather clima = None atlWeather = time.time() + UTC_OFFSET INTERVALO_HORA = 20 # tempo entre atualizacoes da hora INTERVALO_WEATHER = 5*60 # tempo entre atualizacoes do clima # Laco Principal while True: # Obtem a hora atual now = time.time() + UTC_OFFSET agora = time.localtime(now) hora = "{:02}:{:02}".format(agora[3], agora[4]) # Obtem previsão do tempo if now >= atlWeather: code,sunrise,sunset = weather.previsao() if not code is None: print ("Weathercode: {}".format(code)) clima, frente, fundo = weather.decodeWeather(code, (now > sunrise) and (now < sunset)) atlWeather = atlWeather + INTERVALO_WEATHER # Obtem a temperatura t = sensor.temperatura() temp = "{:.1f} C".format(t) # Atualiza a tela disp.fill(BLUE) disp.print(80, 10, hora, freesans20, WHITE, BLUE) disp.print(80, 40, temp, freesans20, GRAY, BLUE) if not clima is None: disp.print(20, 4, chr(clima), wfont, frente, fundo) disp.show() # Dá um tempo entre atualizações da hora time.sleep (INTERVALO_HORA)
Note que o programa principal utiliza o módulo ntptime (que já vem instalado no MicroPython) para obter a hora atual da internet.
Como o programa principal foi salvo com o nome main.py, ele será automaticamente executado quando a Pi Pico for ligada. Para interromper a execução, digite Control C no Thonny.
Conclusão
Neste artigo vimos como usar o MicroPython para alavancar o recurso de comunicação da Pi Pico e construir um relógio que apresenta um agregado de informações obtidas via internet (hora e clima) com obtidas localmente (temperatura).
Algumas sugestões de mudanças para você implementar:
- Apresentar a informação de umidade do sensor DHT11
- Apresentar outras informações obtidas da open-meteo
- Acrescentar outros sensores locais (como um sensor de pressão BMP280) e apresentar suas informações
- Acrescentar um buzzer e implementar uma função de alarme
- Apresentar outras informações obtidas de outras APIs disponíveis na internet
E então, gostou deste projeto? Deixe um comentário abaixo contando se você pretende montá-lo (ou já montou) e o que acrescentaria nele.