capa do post blog desenvolvendo um sistema de lista de tarefas com raspberry pi pico e display e paper por daniel quadros

Desenvolvendo um Sistema de Lista de Tarefas com Raspberry Pi Pico e Display e Paper Deixe um comentário

Neste post vamos ver um projeto que aproveita as qualidades de um display ePaper e da placa Raspberry Pi Pico para apresentar uma lista de tarefas. O Raspberry Pi Pico e Display ePaper se destacam por ter uma grande legibilidade (inclusive sob luz intensa) e serem capazes de manter a imagem sem nenhum consumo de energia.

A Pico W possui respeitáveis capacidades de processamento e memória, o que permite a execução de interpretador da linguagem Python diretamente na placa (o MicroPython). Ela possui também um módulo WiFi, que permite acessar informações na internet.

Sob o comando de uma aplicação MicroPython, a capacidade de WiFi da Pico W é usada neste projeto para obter uma lista de tarefas de uma aplicação na internet (Todoist) e apresentá-la no display ePaper.

raspberry pi pico design by MH-ET LIVE 190124

Como funciona um display ePaper?

O objetivo de um display ePaper é simular a aparência da escrita de tinta no papel. O display que vamos usar é baseado na tecnologia Active Matrix Electrophoretic Display (AMEPD) e apresenta uma resolução de 200 por 200 pontos em um quadrado com diagonal de 1,54”.

O fenômeno de eletroforese consiste na movimentação de partículas eletricamente carregadas quando submetidas a um campo elétrico. Nos displays AMEPD, este fenômeno é usado para mover partículas imersas em líquido dentro de micro-capsulas. Parte das partículas tem cor branca e a outra parte cor preta; partículas com cor diferente tem polaridade diferente. Desta forma, através da geração de um campo elétrico, é possível posicionar as particulas de uma cor para cima e as das outras para baixo, selecionando assim a cor apresentada no display.

partículas brancas líquido transparente partículas pretas

O resultado desta forma de apresentação assemelha a aparência de tinta sobre o papel. Outras vantagens é que o display é legível mesmo sob luz forte e o conteúdo do display é mantido mesmo quando ele não está alimentado.

Uma desvantagem do display ePaper é que ele impõe algumas restrições ao processo de atualização. Para evitar que parte do texto anterior permaneça levemente visível, é necessário um processo de apagamento onde a tela toda fica momentaneamente preta, o que é visivel. Outra limitação é que deve-se dar um intervalo entre as atualizações.

O display que vamos usar é um módulo que incorpora não somente o display propriamente dito, mas também um controlador. A interface deste controlador utiliza os seguintes sinais:

  • Vcc e GND são a alimentação (3,3V) do display
  • SDI, SCLK e CS são os sinais para comunicação serial SPI
  • D/C indica se o que está sendo transmitido pela SPI são dados ou comandos
  • Reset permite colocar o controlador no seu estado inicial
  • Busy indica quando o controlador está ocupado e quando está pronto para receber comandos ou dados

O intervalo entre as atualizações recomendado pelo fabricante deste display é 180 segundos.

Como funciona o Todoist e como acessá-lo?

O todoist é um gerenciador de lista de tarefas. A lista de tarefas pode ser manipualda tanto através das aplicações da própria Doist como por aplicações de terceiros graça a uma interface para programas (API).

Para usar o todist, acesse https://todoist.com/pt-BR e crie uma conta grátis. Usando o próprio site você pode criar listas (“projetos”) e colocar tarefas nestas listas.

Todoist Meus Projetos

 

Para acessar estas informações a partir de um programa próprio existe um conjunto de APIs RESTful. Estas APIs são usadas através do protocolo https (o mesmo usado para acessar recursos na internet), com as informações codificadas em JSON. A documentação das APIs do todoist pode ser vista em https://developer.todoist.com/sync/v9/#overview

Para poder usar estas APIs é necessária uma chave, a API token. Na seção preparativos veremos como obter esta chave.

A API que vamos usar é

https://api.todoist.com/rest/v2/tasks?project_id=<id>

Onde <id> é o código que identifica a lista de tarefas.

O retorno tem um formato como o abaixo (retirei alguns dos campos que não vamos usar):

[
    {
        "id": "7573093287",
        "order": 1,
        "content": "Criar post ePaper",
        "description": "",
        "is_completed": false,
        "priority": 1,
        "due": {
            "date": "2024-01-22",
            "string": "Jan 22",
            "lang": "pt",
            "is_recurring": false
        },
        "duration": null
    },
    {
        "id": "7602704777",
        "order": 2,
        "content": "BT no Uno R4 WiFi",
        "description": "",
        "is_completed": false,
        "priority": 1,
        "due": null,
        "duration": null
    }
]

Na nossa aplicação vamos usar somente os campos ‘id’ e ‘content’. Os outros campos que coloquei acima podem ser úteis para aperfeiçoamentos do projeto (veja algumas ideias no final).

Materiais necessários

Montagem

O esquemático eletrônico abaixo mostra a interligação do display à Raspberry Pi Pico.

display raspberry pi pico

Preparativos

Os primeiros preparativos são relacionados ao Todoist:

  1. Efetue o seu cadastro em em https://app.todoist.com/auth/signup
  2. Uma vez cadastrado e logado, abra o painel esquerdo, clique no seu nome e selecione Configurações e Integrações/Desenvolvedor.  Clique em Copiar token API. Cole o token em um documento, ele será usado no código.
  3. De volta ao painel esquerdo, clique no ‘+’ ao lado de “Meus Projetos” e crie uma lista. Cloque no ‘>’ ao lado do ‘+’ e selecione a lista que você criou. Na barra de endereços do seu navegador você vai ter algo como ‘https://app.todoist.com/app/project/nome-id’, onde id é um código numérico. Anote este código pois vamos usá-lo no código.
  4. Na parte principal da tela, clique em ‘Adicionar Tarefa’ para criar uma tarefa. Dê às tarefas nomes curtos e não use acentuação.

Daniel Quadros Todois App

Token API

Os preparativos seguintes dizem respeito à Raspberry Pi Pico:

  1. Acesse https://thonny.org, baixe a versão para o sistema operacional do seu micro e a instale.
  2. Pressione e mantenha pressionado o botão Bootsel da Pi Pico e a conecte ao micro através de um cabo USB. Solte o botão Bootsel.
  3. Execute o Thonny, clique em Tools, Options e selecione a aba Interpreter
  4. Clique em ‘Install or Update MicroPython’. Selecione PicoW na variante e clique em install.Clique em Close e ok.
  5. Acesse drive e baixe o arquivo listatarefas.zip. Expanda este arquivo em um diretório do seu micro.
  6. No Thonny, clique em View Files. Na parte de cima da seção de arquivos, navegue até o diretório onde você expandiu o zip, clique com o botão direito e selecione ‘Focus into’.
  7. Ainda na parte de cima, use Ctrl+botão esquerdo do mouse para selecionar todos os arquivos e diretórios que foram expandidos. Clique com o botão direito e selecione ‘Upload to /’ para copiar estes arquivos e diretórios para a Pi Pico.

Thonny Options

Install or update MicroPython

Código

O código da aplicação utiliza algumas bibliotecas inclusas no próprio MicroPython e mais o MicroPython nano-gui (https://github.com/peterhinch/micropython-nano-gui). Para usar adaptar o nano-gui para o display ePaper eu criei um driver (epd_mhetlive_154.py) e editei o arquivo de configuração (color_setup.py).

Para usar o código, você precisa editar o arquivo secrets.py, para colocar as informações de acesso à sua rede WiFi (ssid e password), o token do Todist (apitoken) e a identificação da lista de tarefas (apitoken):

ssid = 'XXXX'
password = 'XXXXXXXX'
apitoken = 'xxxxxxxxxxx'
project_id = '99999999'

Abaixo está a listagem do programa principal (main.py):
# Lista de Tarefas

import ntptime
import utime
import time
import rp2
import network
import secrets
import gc

import urequests

from color_setup import epd
from gui.core.nanogui import refresh

# Importa os módulos e fontes para escrita no display
from gui.core.writer import CWriter
import gui.fonts.freesans20 as freesans20
import gui.fonts.arial35 as arial35
from gui.core.colors import *
from gui.widgets.label import Label

# Ajuste para o fuso horário
UTC_OFFSET = -3 * 60 * 60

# Tempo entre atualizações do display
# Fabricante recomenda pelo menos 3 minutos
TEMPO_ATL = 3*60

# Conecta WiFi e acerta o relogio
def conecta():
    # Conecta à rede WiFi
    print("Conectando...")
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(secrets.ssid, secrets.password)
    while wlan.isconnected() == False:
        time.sleep(1)
    print ("Conectado")
    # Acerta o relogio
    ntptime.settime()
    print("Data/Hora atual:%s" %str(time.localtime(time.time() + UTC_OFFSET)))    
    
# Inicia o display
def iniciaDisplay():
    print("Iniciando display")
    refresh(epd, True)
    epd.sleep()
    print("Display iniciado")
    gc.collect()
    utime.sleep(TEMPO_ATL)

# Prepara a tela
lblTitulo = None
lblTarefa = []
def preparaTela():
    global lblTitulo, lblTarefa
    CWriter.set_textpos(epd, 0, 0)
    wrTarefa = CWriter(epd, freesans20, verbose=False)
    wrTarefa.set_clip(True, True, False)
    wrTitulo = CWriter(epd, arial35, verbose=False)
    wrTitulo.set_clip(True, True, False)
    lblTitulo = Label (wrTitulo, 2, 40, "")
    for i in range(7):
        lblTarefa.append(Label(wrTarefa, 40+i*20, 4, ""))

# Atualiza a lista de tarefas
url='https://api.todoist.com/rest/v2/tasks'
if secrets.project_id != '':
    url = url + '?project_id=' + secrets.project_id
headers = {"Authorization": "Bearer "+secrets.apitoken}
def atlTarefas():
    global tarefas
    mudou = False
    print()
    print("Atualizando tarefas")
    response = urequests.get(url, headers=headers)
    print("response code {}".format(response.status_code))
    if response.status_code == 200:
        tarefasAtl = response.json()
        atual = {}
        for tarefa in tarefasAtl:
            id = tarefa['id']
            atual[id] = tarefa['content']
            if not id in tarefas or tarefas[id] != atual[id]:
                mudou = True
        for id in tarefas:
            if not id in atual:
                mudou = True
        if mudou:
            print('Nova lista de tarefas')
            tarefas = atual
    return mudou

# Atualiza a tela
def atlTela():
    epd.fill(0)
    agora = time.localtime(time.time() + UTC_OFFSET)
    lblTitulo.value("{:02}/{:02}/{:02}".format(agora[2], agora[1], agora[0]%100))
    linha = 0    
    for nome in tarefas.values():
        if linha < 7:
            if len(nome) > 18:
                nome = nome[:18]
            lblTarefa[linha].value('* '+nome)
            linha = linha+1
    epd.init()
    refresh(epd)
    epd.sleep()
    print ("update")
    gc.collect()

# Programa Principal
iniciaDisplay()
conecta()
preparaTela()
tarefas = {}
while True:
    if atlTarefas():
        atlTela()
    utime.sleep(TEMPO_ATL)

Os comentários descrevem o que cada parte do programa faz. Alguns pontos de destaque:

  • O módulo ntptime obtem a data e hora da internet e atualiza o relógio do MicroPython. Esta data e hora são UTC e precisam ser acertadas conforme o fuso horário.
  • Os objetos Label da pico-gui definem uma região da tela onde será escrito um texto. No momento da criação definimos o objeto que será responsável pela escrita, o que determina o fonte de letra utilizado.
  • Cada atualização do display consiste em cinco partes: 
    • fill(0) limpa a imagem da tela
    • label.value() escreve o label na imagem da tela
    • init() inicia o controlador. O método init() precisa ser chamado a cada atualização porque o controlador foi desligado ao final da atualização anterior.
    • refresh() envia a imagem da tela ao controlador
    • sleep() desativa o controlador (e o display). 
  • O módulo urequest é usado para fazer as chamadas à API. urequests.get() faz a chamada a um endereço web (url), colocando no cabeçalho da requisição o token da API. A resposta é encapsulada em um objeto do qual obtemos o status (sucesso ou falha) e os dados propriamente ditos (em caso de sucesso).
  • Os nomes e ids das tarefas são guardados em um dictionary (tarefas). Após uma consulta à API, é verificado se alguma tarefa foi criada, destruída ou teve o nome alterado. Em caso afirmativo, o display será atualizado.

Colocando para funcionar o projeto

No Thonny, dê um duplo clique no main.py (na parte inferior da lista de arquivos) e depois clique em  botão play .

Obs: como este arquivo se chama main.py, ele será executado automaticamente sempre que a Raspberry Pi Pico e Display ePaper for ligada.

O andamento da execução pode ser acompanhado pela janela shell na parte inferior do Thonny. Tenha um pouco de paciência, pois após a iniciação do display é aguardado 3 minutos antes de apresentar a lista de tarefas (seguinda as recomendações do fabricante). A lista de tarefas será atualizada a cada 3 minutos. 

shell editor content

Próximos Passos com Raspberry Pi Pico e Display ePaper

Para este post não ficar muito longo, este projeto possui algumas limitações. Algumas ideias de aperfeiçoamento:

  • O fonte utilizado possui apenas caracteres ASCII normais, caractecteres acentuados serão apresentados como ‘?’
    • Converta os caracteres acentuados no nome das tarefas para os correspondentes não acentuados, para eles serem apresentados com o fonte utilizado.
    • Acrescente os caracteres acentuados ao fonte e altere o código para converter e apresentar corretamente os caracteres acentuados
  • São apresentados todas as tarefas, independente do seu estado
    • Filtre somente as tarefas pendentes
    • Coloque um indicador na frente de cada tarefa para indicar se ela foi feita, está atrasada ou está pendente.
    • Acenda o LED da Pico quando uma tarefa estiver atrasada
    • Ligue um LED RGB à Pico e o acenda em verde quando todas as tarefas estão feitas, amarelo se existem tarefas pendentes e vermelho se existe uma tarefa atradas.
  • Trate o caso da conexão WiFi ser perdida durante a exeução

O tempo entre atualizações do display ePaper impede um funcionamento interativo. Trocando o display por um LCD ou OLED e acrescentando botões, você pode fazer coisas como:

  • Apresentar um tela para selecionar a lista (existe uma API para obter a lista de projetos)
  • Permitir selecionar uma tarefa e marcá-la como executada.

Estas são apenas algumas ideias, dê asas a sua imaginação!

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.

Faça seu comentário

Acesse sua conta e participe