Desenvolvimento

28 mar, 2018

Pomodoro com ESP32 – um projeto “The Melee – Side by Side”

Publicidade

Neste mês houve um grande evento chamado The Melee – Side by side (muito obrigado a @ojoven e @diversius).

O evento foi um tipo de hackathon onde um grupo de pessoas se reuniu um dia para compartilhar projetos paralelos e para trabalhar juntas (também houve um almoço e cervejas). O formato do evento é apenas uma cópia do evento que nossos colegas de Bilbao chamaram de “El Comité”.

@ibaiimaz falou sobre um projeto para criar um pomodoro colaborativo, no qual as pessoas de uma equipe poderiam compartilhar seu status e verem o status do restante da equipe. Quando ouvi pomodoro e status, imediatamente pensei em um servo movendo uma flag e alguns LEDs ligando e desligando. Nós tivemos um projeto. @penniath e @tatai também se juntaram a nós. Nós também tínhamos uma equipe.

Nós tínhamos um projeto e também um prazo. Tivemos que mostrar um protótipo funcional no final do dia. Isso significa que não tivemos muito tempo. Primeiro, decidimos a maquete do projeto, reduzindo o escopo inicial (mais ambicioso) para encaixá-lo em nosso horário. Discutimos intensamente por 10 minutos e, finalmente, descrevemos um projeto ultradetalhado. Este era o plano completo do projeto:

Era hora de começar a trabalhar.

@penniath e @tatai trabalharam no backend. Ele deve ser o responsável pelos timers pomodoro, ouvir eventos MQTT e criar uma API para o frontend. O backend também deve fornecer uma interface WebSockets para permitir eventos em tempo real dentro do frontend. Eles decidiram usar node e socket.io para os WebSockets. Você pode ver o código-fonte aqui.

@ibaiimaz começou com o frontend. Ele decidiu criar um aplicativo web em Angular para ouvir eventos socket.io para mostrar o status do pomodoro. Você pode ver o código-fonte aqui.

Finalmente trabalhei com o hardware. Eu criei um protótipo com um ESP32, dois LEDs RGB, um botão, um servo e um par de resistores.

 

Aqui está o código-fonte:

#include <WiFi.h>
#include <PubSubClient.h>
 
int redPin_g = 19;
int greenPin_g = 17;
int bluePin_g = 18;
 
int redPin_i = 21;
int greenPin_i = 2;
int bluePin_i = 4;
 
#define SERVO_PIN 16
 
const int buttonPin = 15;
int buttonState = 0;
 
int channel = 1;
int hz = 50;
int depth = 16;
 
const char* ssid = "SSID";
const char* password = "password";
const char* server = "192.168.1.105";
const char* topic = "/pomodoro/+";
const char* clientName = "com.gonzalo123.esp32";
 
WiFiClient wifiClient;
PubSubClient client(wifiClient);
 
void wifiConnect() {
  Serial.print("Connecting to ");
  Serial.println(ssid);
 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print("*");
  }
 
  Serial.print("WiFi connected: ");
  Serial.println(WiFi.localIP());
}
 
void mqttReConnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect(clientName)) {
      Serial.println("connected");
      client.subscribe(topic);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}
 
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
 
  String data;
  for (int i = 0; i < length; i++) {
    data += (char)payload[i];
  }
 
  int value = data.toInt();
 
  if (strcmp(topic, "/pomodoro/gonzalo") == 0) {
    Serial.print("[gonzalo]");
    switch (value) {
      case 1:
        ledcWrite(1, 3400);
        setColor_g(0, 255, 0);
        break;
      case 2:
        setColor_g(255, 0, 0);
        break;
      case 3:
        ledcWrite(1, 6400);
        setColor_g(0, 0, 255);
        break;
    }
  } else {
    Serial.print("[ibai]");
    switch (value) {
      case 1:
        setColor_i(0, 255, 0);
        break;
      case 2:
        setColor_i(255, 0, 0);
        break;
      case 3:
        setColor_i(0, 0, 255);  // green
        break;
    }
  }
 
  Serial.print("] value:");
  Serial.println(data);
}
 
void setup()
{
  Serial.begin(115200);
 
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(redPin_g, OUTPUT);
  pinMode(greenPin_g, OUTPUT);
  pinMode(bluePin_g, OUTPUT);
 
  pinMode(redPin_i, OUTPUT);
  pinMode(greenPin_i, OUTPUT);
  pinMode(bluePin_i, OUTPUT);
 
  ledcSetup(channel, hz, depth);
  ledcAttachPin(SERVO_PIN, channel);
  wifiConnect();
  client.setServer(server, 1883);
  client.setCallback(callback);
 
  delay(1500);
}
 
void mqttEmit(String topic, String value)
{
  client.publish((char*) topic.c_str(), (char*) value.c_str());
}
 
void loop()
{
  if (!client.connected()) {
    mqttReConnect();
  }
 
  client.loop();
 
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
    mqttEmit("/start/gonzalo", (String) "3");
  }
 
  delay(200);
}
 
void setColor_i(int red, int green, int blue)
{
  digitalWrite(redPin_i, red);
  digitalWrite(greenPin_i, green);
  digitalWrite(bluePin_i, blue);
}
 
void setColor_g(int red, int green, int blue)
{
  digitalWrite(redPin_g, red);
  digitalWrite(greenPin_g, green);
  digitalWrite(bluePin_g, blue);
}

O servidor MQTT (um servidor mosquitto) estava rodando inicialmente no meu laptop, mas como eu também tinha um Raspberry Pi Zero na minha bolsa, decidimos usar o Pi Zero como um servidor e rodar o servidor mosquitto MQTT com o Raspbian. Tudo é melhor com um Raspberry Pi. @tatai me ajudou a configurar o servidor.

Aqui você pode ver o protótipo em ação:

Esse é o tipo de projeto paralelo que eu normalmente crio sozinho, mas definitivamente é mais divertido fazer isso com outros colegas, mesmo que eu precise acordar cedo em uma manhã de sábado.

  • Código-fonte do ESP32 aqui.

***

Gonzalo Ayuso faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela Redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: https://gonzalo123.com/2018/03/26/pomodoro-with-esp32-one-the-melee-side-by-side-project/