irrigação — Esp32 Devkit C V4 simulation

An interactive Esp32 Devkit C V4 circuit simulation you can run free in your browser on Velxio, by pedroairtonsf.

Components

Sketch code

#include <Arduino.h>
#include <WiFi.h>
#include <time.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>

#define MAX_PERIODOS 10

//definição dos pinos
#define rele 26
#define botao 27
#define led 12

// Wi-Fi do simulador
const char* wifi = "Velxio-GUEST";
const char* senha = "";

const char* TB_HOST = "thingsboard.cloud";
const int TB_PORT = 1883;
const char* TB_TOKEN = "CjXH5FQTG2o3D9C80jFj";

WiFiClient wifiClient;
PubSubClient mqtt(wifiClient);

// -------- ESTRUTURA DOS PERÍODOS --------

// Os horários são armazenados como minutos
// decorridos desde a meia-noite.

struct Periodo {
    int inicio;
    int fim;
};

Periodo periodos[MAX_PERIODOS];
int quantidadePeriodos = 0;

bool travado;
bool ledOnline = false;
bool ligado = false;
bool manualAtivo = false;
bool estadoBotaoAnterior = LOW;

// -------- CONVERSÃO DE HORÁRIOS --------

bool converterHorario(const char* texto, int& minutos) {
    if (texto == nullptr) {
        return false;
    }

    // Exige exatamente o formato HH:MM.
    if (strlen(texto) != 5 || texto[2] != ':') {
        return false;
    }

    for (int i : {0, 1, 3, 4}) {
        if (texto[i] < '0' || texto[i] > '9') {
            return false;
        }
    }

    int hora = (texto[0] - '0') * 10
             + (texto[1] - '0');

    int minuto = (texto[3] - '0') * 10
               + (texto[4] - '0');

    if (hora > 23 || minuto > 59) {
        return false;
    }

    minutos = hora * 60 + minuto;
    return true;
}

// -------- INTERPRETAÇÃO DO JSON --------

bool interpretarPeriodos(JsonVariantConst valor) {
    // Aceita tanto um array JSON quanto
    // uma string contendo um array JSON.

    JsonDocument documentoTexto;

    if (valor.is<const char*>()) {
        DeserializationError erro = deserializeJson(
            documentoTexto,
            valor.as<const char*>()
        );

        if (erro) {
            Serial.println("JSON de periodos invalido.");
            return false;
        }

        valor = documentoTexto.as<JsonVariantConst>();
    }

    if (!valor.is<JsonArrayConst>()) {
        Serial.println("Periodos deve ser uma lista.");
        return false;
    }

    JsonArrayConst lista = valor.as<JsonArrayConst>();

    if (lista.size() > MAX_PERIODOS) {
        Serial.println("Quantidade de periodos excedida.");
        return false;
    }

    // Primeiro valida tudo em um vetor temporário.
    // Só substitui os horários atuais se tudo
    // estiver correto.

    Periodo novos[MAX_PERIODOS];
    int quantidade = 0;

    for (JsonVariantConst item : lista) {
        if (!item.is<JsonObjectConst>()) {
            return false;
        }

        const char* inicio = item["inicio"];
        const char* fim = item["fim"];

        int minutoInicio;
        int minutoFim;

        if (!converterHorario(inicio, minutoInicio) ||
            !converterHorario(fim, minutoFim)) {
            Serial.println("Horario invalido.");
            return false;
        }

        if (minutoInicio == min