Módulos Wifi

Interpretador de Expressões Aritméticas com ESP32

Eletrogate 12 de setembro de 2025

Introdução

Este projeto tem como objetivo implementar uma biblioteca para interpretar expressões aritméticas no ESP32/ESP8266 visando o uso na tomada de decisão em cenários de automação em geral. O projeto também demonstra a utilização da biblioteca.


Motivação

À primeira vista, o desenvolvimento de um interpretador de expressões aritméticas para microcontroladores pode parecer um exercício acadêmico ou de pouca utilidade. No entanto, à medida que aplicações embarcadas se tornam mais complexas e conectadas, cresce a necessidade por configurações dinâmicas, ajustes em tempo de execução e flexibilidade na lógica de controle, especialmente em soluções de automação residencial, industrial e agrícola.

Ao permitir a avaliação de expressões matemáticas diretamente no dispositivo, abre-se a possibilidade de criar sistemas altamente parametrizáveis. Por exemplo, um usuário pode ajustar condições de ativação de relés, alarmes ou outros atuadores a partir de expressões envolvendo múltiplos sensores — tudo isso sem necessidade de regravação do firmware.

Mais ainda, ao integrar esse interpretador a uma interface web, é possível fornecer ao usuário final um painel para editar regras ou fórmulas diretamente do navegador. Essas regras podem ser armazenadas no próprio dispositivo (via SPIFFS ou LittleFS ou Banco de Dados) e verificadas periodicamente para acionar lógicas de decisão, criando uma base de regras configurável, similar a um mini motor de inferência, mas leve e prático.

A motivação principal, portanto, é oferecer uma ferramenta flexível e em forma de biblioteca, compatível com plataforma ESP32/ESP8266 uma vez que existem restrições críticas de memória no Arduino Uno/Nano. O interpretador proporciona um grau de liberdade na reconfiguração de comportamentos em sistemas embarcados, tornando-os mais flexíveis, modulares e adaptáveis a longo prazo.

Aplicações Práticas

A utilidade de um interpretador de expressões em microcontroladores vai muito além de calcular operações matemáticas simplesmente. Ele pode ser o núcleo de sistemas embarcados que tomam decisões com base em expressões configuráveis, permitindo que o comportamento do sistema seja ajustado facilmente, sem necessidade de recompilar o firmware.

Veja alguns cenários práticos:

  1. Automação de Irrigação com Lógica Condicional

Imagine um sistema de irrigação com sensores de umidade, temperatura e hora atual. Em vez de codificar regras fixas, o usuário pode inserir expressões como:

(UMIDADE < 40 && HORA >= 6 && HORA <= 8) || (TEMPERATURA > 30 && UMIDADE < 50)

Essa expressão, salva em SPIFFS e avaliada periodicamente, define se a irrigação deve ser ativada, oferecendo flexibilidade total na lógica de controle.

  1. Controle de Energia em Ambientes Residenciais

Um sistema com sensores de corrente e tensão pode avaliar:

POTENCIA > 800 && DIA_DA_SEMANA != 0

e desligar cargas não prioritárias quando o consumo ultrapassar determinado valor. O interpretador atua como motor de decisão baseado em expressões simples, fáceis de editar via interface web.

  1. Configuração Remota de Alarmes

Em ambientes monitorados por sensores (como temperatura, gás, fumaça, portas), as condições para disparo de alarme podem ser definidas com expressões do tipo:

GAS > 200 || (TEMP > 60 && PORTA_ABERTA == 1)

Essas regras podem ser modificadas sem reprogramar o ESP32/ESP8266, apenas editando via uma interface web.

  1. Dashboard com Avaliações Customizadas

Em uma aplicação com painel web (AsyncWebServer), o usuário pode testar expressões diretamente na interface, como uma calculadora técnica:

cos(PI/3)^2 + sin(PI/3)^2

Esse uso combina a força do interpretador com visualização imediata de resultados e serve tanto para testes quanto para aprendizado ou depuração em campo.

  1. Mini Motor de Regras

Com a combinação de variáveis, funções matemáticas e a possibilidade de expansão com funções externas registradas por call-back, é possível montar um mini motor de inferência baseado em regras, útil para sistemas de automação com requisitos leves e alta flexibilidade.


Princípio de Funcionamento

A partir de uma dada expressão aritméticas em notação infixada (padrão standard da matemática usado em calculadoras científicas), a biblioteca faz a análise sintática da expressão dividindo em tokens (partes que compõem a expressão) e, em seguida, transformando na notação pós fixada (padrão utilizado nas calculadoras HP) para avaliar o resultado. Se na expressão existirem variáveis ou funções, a biblioteca procura numa lista interna, existindo, o valor é recuperado para entrar na avaliação do resultado. As variáveis podem ser registradas (via função pública da classe) ou serem definidas através de atribuição na própria expressão (ex: A=10;A/2), sendo que múltiplas expressões podem ser definidas na expressão usando-se o separador ‘;’. Quando uma variável é alterada para um novo valor, um call-back poder ser definido para tratar qual variável sofreu alteração e tomar alguma decisão. Caso a função não seja encontrada e, se um call-back estiver definido, o nome da função e parâmetros são passados para o call-back retornar o valor a ser considerado no cálculo da expressão. Desta forma, a aplicação que utiliza a biblioteca participará do cálculo da expressão recebendo do call-back os valores a serem considerados para compor o resultado da expressão (como se fosse macro expansão), para isso consultando sensores, bases de dados ou fazendo outros cálculos. Uma planilha eletrônica, como EXCEL por exemplo, nada mais é do que um interpretador de expressões ou fórmulas que são organizadas em linhas e colunas.

Exemplo de expressão Infixada: (2*3 + 5*4)

Exemplo da conversão pós fixada: 2  3  *  5  4 * +


Detalhes da Implementação da Biblioteca

A implementação foi para a família ESP32/ESP8266 pois a análise sintática consome um pouco mais de memória devido ao uso de estruturas mais complexas e, na família AVR (NANO/UNO), tais estruturas não existem, restando o uso de estruturas de alocação estática que consome mais recursos e só há 2K de SRAM. Com isso inviabilizou-se a portabilidade para esta plataforma.

Visão geral da arquitetura

A biblioteca é composta por três etapas principais:

  1. Tokenização (léxico)
    Converte a String infixa em uma lista de tokens (números, variáveis, operadores, parênteses e chamadas de função).
  2. Conversão para Pós-Fixa (parser)
    Usa o algoritmo Shunting-Yard para transformar a sequência infixa em notação pós-fixa (RPN) respeitando precedência e associatividade dos operadores.
  3. Avaliação da Pós-Fixa (execução)
    Percorre os tokens RPN empilhando operandos e aplicando operadores/funções via applyOperator() e call-backs registrados.

Principais estruturas (conforme o cabeçalho):

  • std::vector<String> tokenize(const String&)
  • std::vector<String> infixToPostfix(const std::vector<String>&)
  • double evaluatePostfix(const std::vector<String>&)
  • int precedence(const String& op) / float applyOperator(const String& op, float a, float b)
  • Registro de variáveis e funções com contadores internos (variableCount, functionCount).

Tipo numérico: a API pública retorna float em evaluate(…) por eficiência no ESP32; internamente podem existir cálculos em double. O valor NAN é usado para sinalizar resultados inválidos/indefinidos.

Tokenização

A tokenização percorre a expressão e emite tokens:

  • Números: decimais com . (ex.: 2, -10, 3.14, 2.5e-3).
  • Identificadores: variáveis e nomes de função. A biblioteca normaliza (recomenda-se upper-case interno) para case-insensitive.
  • Operadores e símbolos: + – * / % # ( ) , = & | ! ^ < > <= >= == != ;
  • Chamadas de função: reconhecidas pelo padrão NOME(, com argumentos separados por vírgula até o limite de MAX_ARGS.

 

Observações de ambiguidade

  • Unário vs binário: o menos unário (ex.: -3) é tratado na tokenização/precedência para não virar “subtração binária”.
  • != vs !: o léxico prioriza pares de símbolos (!=, <=, >=, ==) antes do ! unitário para evitar quebrar o != em ! + =.
  • Fatorial: quando implementado como operador pós-fixo !, a tokenização precisa diferenciá-lo do ! (NOT). Em implementações que não suportam o fatorial como operador, recomenda-se expô-lo como função FACT(x).

Conversão infixa → pós-fixa (Shunting-Yard)

A função infixToPostfix(…) usa uma pilha de operadores:

  • Envia operandos diretamente para a saída.
  • Operadores entram na pilha conforme precedência/associatividade.
  • Parênteses abrem/fecham contextos.
  • Funções são tratadas como operadores especiais com maior precedência, e seus argumentos contam via vírgula.

Precedência e associatividade

Da maior para a menor:

  1. Parênteses / função(…)
  2. Unários: ! (NOT), + unário, – unário (normalmente right-assoc)
  3. Potência: # (tipicamente right-assoc)
  4. * / %
  5. + –
  6. Relacionais: < <= > >=
  7. Igualdade: == !=
  8. Lógicos: & (AND), ^ (XOR), | (OR)
  9. Atribuição: = (right-assoc)
  10. Separador: ; (geralmente tratado fora da RPN: split em subexpressões)

Avaliador (RPN)

A evaluatePostfix(…) percorre os tokens pós-fixos:

  • Operandos (números/variáveis): empilha valores; variáveis são buscadas em tabela interna (case-insensitive) e/ou via call-back (ver abaixo).
  • Operadores binários: desempilha b, depois a, aplica applyOperator(op,a,b), empilha o resultado.
  • Unários: desempilha a, aplica e empilha.
  • Funções: lê n argumentos esperados (contabilizados na montagem RPN) e invoca a Call-back registrada para aquele nome.

Erros de execução (divisão por zero, função não encontrada, aridade incorreta etc.) chamam reportError(…) e o resultado final tende a ser NAN.

Variáveis e funções

Variáveis

  • Registro explícito: registerVariable(name, float value) adiciona/atualiza no mapa interno.
  • Consulta: isVariable(token)/variableExists(name) e getVariableValue(name).
  • Atribuição em expressão: quando o parser encontra IDENT = <expr>, avalia <expr> e salva no mapa. A função registerVariable(…) é reutilizada no fluxo.
  • A biblioteca mantém variableCount para depuração/telemetria.

Funções

  • Registro: registerFunction(name, CallbackType func), onde CallbackType é um callable C++ (ex.: std::function<bool(const double* args, int n, double& out)>, ajuste conforme seu .h).
  • Consulta: getFunctionCallback(name), functionExists(name), listRegisteredFunctions(Stream&).
  • Execução: durante a RPN, ao encontrar o token de função, a biblioteca conta/retira n argumentos e chama o call-back. Em falha, chama reportError(…).
  • A biblioteca mantém functionCount.

Múltiplas expressões com ;

O método público evaluate(const String& expression):

  • Divide por ; (respeitando parênteses) e avalia em sequência cada subexpressão.
  • Retorna o último valor.
  • Se alguma subexpressão falhar, reportError(…) guarda o contexto; o valor final será NAN (política comum) e getLastError() (se exposto) indica o motivo.

Operadores suportados e applyOperator()

A implementação provê applyOperator(const String& op, float a, float b) para binários e tratamento específico para unários no parser.
Operadores previstos no projeto:

  • Aritméticos: + – * / % # (potência)
  • Relacionais: == != < <= > >= (retornam 0.0 ou 1.0)
  • Lógicos: & | ^ ! (retornam 0.0 ou 1.0; ! é unário)
  • Atribuição: = (armazenamento no mapa de variáveis; retorna o valor atribuído)

Divisão por zero resulta em NAN e emite reportError(F(“Division by zero”), token).
Potência com expoente fracionário e base negativa pode virar NAN (sem partes complexas).

Erros e depuração

  • reportError(const __FlashStringHelper* msg, const String& token): registra/propaga o erro, economizando RAM com mensagens em PROGMEM (F(“…”)).
  • printPostfix(const String& expression): imprime a forma pós-fixa para depuração.
  • DEBUG (macro): habilita traços adicionais (token list, pilha da RPN, etc.) via Serial.

Política típica de erro:

  • evaluate(…) retorna NAN em erro e mantém a última mensagem em getLastError() (se presente).
  • Call-backs de função podem retornar false para sinalizar falha sem travar o avaliador.

Convenções de nomenclatura

  • Variáveis e funções: case-insensitive (normalizadas para upper-case).
  • Números especiais: NAN significa “sem valor”/erro, útil para encadear regras; o chamador decide o que fazer.
  • Constantes: recomenda-se registrar PI, E etc. via registerVariable(…) em setup().

Complexidade e consumo

  • Tokenização / Parser / Execução: O(n) no número de tokens.
  • Estruturas usam std::vector<String> e std::map, com alocação dinâmica;
  • As mensagens de erro usam __FlashStringHelper para economizar RAM.

      Contrato público (resumo)

      • Construção: ExpressionParser()
      • Registro: registerVariable(name, value), registerFunction(name, CallbackType)
      • Consulta: isVariable(…), variableExists(…), getVariableValue(…), functionExists(…), getFunctionCallback(…), listRegisteredFunctions(…)
      • Execução: float evaluate(const String& expr), printPostfix(const String& expr)
      • Erros: reportError(F(“msg”), token), getLastError() (se exposto)

      Operadores Aritméticos

      SímboloOperaçãoExemplo
      +Soma2+3
      Subtração5-1
      *Multiplicação3*4
      /Divisão6/2
      %Módulo7%4
      #Potência2#3 = 8

       

      Operadores Relacionais

      SímboloOperaçãoExemplo
      ==Igualdadea == b
      !=Diferentea != b
      Maiora > b
      Menora < b
      >=Maior ou iguala >= b
      <=Menor ou iguala <= b

       

      Operadores Lógicos

      SímboloFunção LógicaExemplo
      &E lógico (AND)a > 0 & b < 10
      ||OU lógico (OR)
      !NÃO lógico (NOT)!a == 1
      ^OU Exclusivo (XOR)a ^ b

       

      Operadores Auxiliares

      SímboloFunçãoExemplo
      =Atribuição de valora = 2 + 3
      (Abre parêntese(a + b) * c
      )Fecha parêntese(a + b) * c
      ;Separador de expressõesa=2; b=3; a+b

       

      Números:

      Você pode definir números com dígitos de 0 a 9. Adicionalmente, você deve usar o ponto para separar a parte decimal.

      Ex: 2.1 + 10.333

      Variáveis:

      Você pode definir variáveis usando letras de A a Z e números de 0 a 9 começando com letra não superando 15 caracteres. Não faz diferença se as letras sejam maiúsculas ou minúsculas.

      Ex: Temp1, Temp2, Umidade, Luminosidade

      Funções:

      Você pode definir funções usando letras de A a Z até 15 caracteres. Não faz diferença se as letras sejam maiúsculas ou minúsculas. As funções podem conter até 10 parâmetros numéricos.

      Ex: MMC(2,5), MDC(2,5). MAX(2,4,5,-1)

      Funções Pré-Definidas:

      Função (assinatura)DescriçãoExemploDomínio / Notas
      SIN(x)Seno de um ânguloSIN(PI/6) = 0.5
      COS(x)Cosseno de um ânguloCOS(PI/3) = 0.5
      TAN(x)Tangente de um ânguloTAN(PI/4) = 1x ≠ PI/2 + k·PI
      ASN(x)Arco-seno (inverso do seno)ASN(0.5) = PI/6x ∈ [-1, 1]
      ACS(x)Arco-cosseno (inverso do cosseno)ACS(0.5) = PI/3x ∈ [-1, 1]
      ATN(x)Arco-tangente (inverso da tangente)ATN(1) = PI/4x ∈ ℝ
      INT(x)Parte inteira (trunca em direção a 0)INT(-2.9) = -2
      ABS(x)Valor absolutoABS(-3) = 3
      FRAC(x)Parte fracionáriaFRAC(3.75) = 0.75Para negativos, definir política (ex.: x - floor(x))
      LOG(x)Logaritmo na base 10LOG(100) = 2x > 0
      LN(x)Logaritmo natural (neperiano)LN(E) = 1x > 0
      EXP(x)Exponencial e^xEXP(1) = E
      SQR(x)Raiz quadradaSQR(16) = 4x ≥ 0 (sem complexos)
      CUR(x)Raiz cúbicaCUR(27) = 3x ∈ ℝ
      SGN(x)Sinal do númeroSGN(-5) = -1Retorna 1 (positivo), 0 (zero) ou -1 (negativo)
      FACT(n)FatorialFACT(5) = 120n inteiro, n ≥ 0
      HYPSIN(x)Seno hiperbólico (sinh)HYPSIN(0) = 0
      HYPCOS(x)Cosseno hiperbólico (cosh)HYPCOS(0) = 1
      HYPTAN(x)Tangente hiperbólica (tanh)HYPTAN(0) = 0
      HYPASN(x)Arco-seno hiperbólico (asinh)HYPASN(1) ≈ 0.8814x ∈ ℝ
      HYPACS(x)Arco-cosseno hiperbólico (acosh)HYPACS(1) = 0x ≥ 1
      HYPATN(x)Arco-tangente hiperbólica (atanh)HYPATN(0.5) ≈ 0.5493`
      PRIME(n)Verifica se n é primo (1=verdadeiro, 0=falso)PRIME(23) = 1, PRIME(22) = 0n inteiro

       

      Variáveis Pré-Definidas:

      VariávelDescrição
      PINúmero PI
      ENúmero neperiano
      LastÚltimo valor calculado

       

      Exemplos de Expressões:

      ExpressãoResultadoComentário
      A=cos(PI/3);B=sin(PI/3);A#2+B#2A=0.50  B=0.87  1Define A e B; soma dos quadrados → identidade trigonométrica cos²+sin²=1.
      2*3+2*210Precedência: multiplicações antes da soma (6 + 4).
      CUR(27)3Raiz cúbica.
      LOG(10)1Log base 10.
      ln(E)1Log natural; funções são case-insensitive.
      PRIME(23)123 é primo → verdadeiro (1).
      PRIME(22)022 é composto → falso (0).
      FACT(3)6Fatorial de 3.
      SQR(16)4Raiz quadrada.
      (-1)+(2-3)-2Parênteses e números negativos.
      -10-20-30Menos unário seguido de subtração.

       

      Observação importante: existe uma diretiva de compilação no ExpressionParser.h que pode ser “descomentada” durante o desenvolvimento da aplicação que utiliza a biblioteca. Assim mensagens adicionais poderão ser geradas e  mostradas  na console.

      //#define DEBUG  // Comente esta linha para desativar DEBUG
      

      Notas importantes sobre o uso da Biblioteca

      A biblioteca foi projetada para ser uma ferramenta para o desenvolvedor produzir aplicações mais ricas e foi pensada para “regras-como-dados”. Em vez de codificar if/else fixos no firmware, você expõe indicadores do negócio objeto da aplicação a ser desenvolvida (sensores, estados, configurações) como VARIÁVEIS e FUNÇÕES resolvidas/implementadas por call-backs. Assim, as variáveis/funções possibilitam a criação de regras que viram expressões editáveis (em arquivo, NVS/Preferences, OTA, web UI) — sem recompilar e flexibilizando a usabilidade da aplicação pelo usuário final.

      Como pensar “indicadores do negócio” → VARIÁVEIS e FUNÇÕES

      • Identifique medidores: tudo que o usuário final usa para decidir algo. Ex.: TEMP, HUM, LUX, PRESSAO, FLOW, VAZAO, EFICIENCIA, PRODUTIVIDADE, etc.

      • Mapeie estados e modos: LED, PUMP, ALARM, MODE, SETPOINT, HYST.

      • Extraia utilidades de negócio como funções: MAP(x,inMin,inMax,outMin,outMax), HYST(x,low,high), MEDIANA(a,b,c), IN_RANGE(x,a,b), DEBOUNCE(x,ms), etc.

      • Persistência e ajustes: exponha parâmetros que o usuário salva por expressão, ex.: THRESH=30, PERIODO=900, MODO=1.

      Regra prática: variáveis retornam um valor atual; funções calculam/transformam a partir de argumentos. Use nomes case-insensitive e retorne NAN quando algo não se aplicar (a LIB trata como erro/ausência).


      Tabela de Call-backs

      Call-backAssinaturaPapel na avaliaçãoRetorno/EfeitoUso típico
      VariableCallbackfloat(const String& nameUpper)Resolver variáveis lidas na expressão.Retorne o valor; NAN se desconhecida/indisponível.Sensores (TEMP, HUM), estados (LED), relógio (EPOCH, HOUR), constantes (PI).
      FunctionCallbackfloat(const String& nameUpper, const std::vector<String>& args)Implementar funções de domínio chamadas na expressão.Retorne resultado; NAN para erro/assinatura inválida.MAP(...), HYST(...), MEDIANA(...), utilidades de processo.
      SettingVarCallbackvoid(const String& nameUpper, const float value)Tomar decisões quando atribuições são feitas na expressão.Efeito colateral (p.ex. salvar em NVS, alterar setpoint).THRESH=30, MODO=1, KP=2.1.
      ErrorCallbackvoid(const String& message)Receber mensagens de erro da avaliação.Log/telemetria/alerta.Print em Serial, buffer circular, envio via WS.
      CallbackTypefloat(const String&, const std::vector<String>&)Alias geral compatível com funções.Igual ao FunctionCallback.Compatibilidade/legado.

      Notas:

      • Converta nameUpper para maiúsculas (ou já trate como maiúsculo) para facilitar case-insensitive.

      • Em FunctionCallback, os argumentos vêm como String; converta para float (ex.: strtof(args[i].c_str(), nullptr) ou args[i].toFloat()).


      Boas práticas (essenciais)

      • Allowlist: reconheça apenas nomes esperados. Tudo o que não corresponder → NAN (falha segura).

      • Sem efeitos nas funções: mantenha FunctionCallback puro (sem side-effects). Use SettingVarCallback para mudar estado/salvar.

      • Perfomance: se a mesma expressão roda com alta frequência, considere usar CACHE ou temporização (ex.: suponha DOLAR como variável. Só recupere a cotação do DOLAR externamente uma vez no dia ou estabeleça intervalos menores para a atualização).

      • Persistência: para parâmetros de usuário, escreva em Preferences com debounce (p.ex. 3–10 s) para reduzir desgaste de flash.

      • Observabilidade: logue via ErrorCallback para acompanhamento na interface.


      Com esses call-backs, você organiza o firmware como plataforma de execução, e deixa a “regra” virar dados (expressões). Resultado: parametrização real, mais reuso entre projetos e ajustes de produção sem recompilar.


      Detalhamento das aplicações DEMO

      Foram desenvolvidas duas aplicações para a demonstração do uso da biblioteca: uma BasicDemo que implementa a interação via Console Serial e uma mais avançada, WebDemo, utilizando uma interface HTML demonstrando a aplicabilidade em Automação.

      Materiais Necessários (WebDemo)

      1x Módulo WiFi ESP32 Bluetooth 30 pinos
      1x Protoboard 400 Pontos
      1x Sensor de Umidade e Temperatura DHT11
      1x Sensor Fotoresistor LDR de 5mm
      1x Led Difuso 5mm Vermelho
      1x Resistor 10K 1/4W (10 Unidades)  (LDR)
      1x Resistor 4K7 1/4W (10 Unidades)  (DHT)
      1x Resistor 220R 1/4W (10 Unidades)(LED)

      Opcional (BasicDemo)

      1x Módulo WiFi ESP8266 NodeMcu v3 – Lolin
      1x Protoboard 400 Pontos

      WebDemo

      A aplicação WebDemo utiliza um HTML com 3 abas:

      1. A aba Expressões para permitir a entrada de expressões e avaliar o resultado, como se fosse uma calculadora científica. As expressões que não apresentaram erros são adicionadas ao histórico com a possibilidade de limpar o histórico através do botão LIMPAR. Se o usuário der um duplo click em um dos itens do histórico, a expressão correspondente é colocada no campo de entrada de expressões para uma nova submissão evitando a redigitação.
      2. A aba Automação utiliza o LED como um atuador que será acionado avaliando-se uma REGRA definida na interface em um intervalo de tempo dado pela constante CICLO_REGRA. As informações dos sensores são mostradas num intervalo dado pela constante CICLO_SENSORES. As variáveis suportadas são apresentadas na interface assim como os valores obtidos dos sensores. A Regra e o Histórico são persistidos usando-se “Preferences” e são recuperados na reinicialização da aplicação.
      3. A aba Informações mostra as sintases suportadas nas expressões e conceitos necessários para a usabilidade da biblioteca.

      Outras características da aplicação WebDemo:

      1. Conecta-se na Rede Wifi conhecendo-se o SSID/Senha (precisam ser informados em tempo de compilação)
      2. Faz a sincronização do Relógio interno do ESP32 via servidor NTP.
      3. Adiciona o alias no mDNS para permitir o acesso via rede local usando-se a URL http://expression.local.

      A seguir estão as telas do HTML:

      Figura 1 – Aba Expressões do HTML

       

      Figura 2 – Aba Automação do HTML

      Figura 3 – Aba Informações do HTML

      Figura 4 – Diagrama do Circuito WebDemo

      BasiDemo

      A aplicação BasicDemo foi projetada para interagir com a Console Serial recebendo expressões digitadas na Console e esperando um NEWLINE. Adicionalmente, nenhum componente é utilizado, mas apenas o microcontrolador.

      Características:

      1. Estende a biblioteca implementando as funções MMC (Mínimo Múltiplo Comum) e MDC (Máximo Divisor Comum) de números inteiros através do uso de call-back de funções. A função MMC é implementada através de call-back genérico e a função MDC com o call-back específico.
      2. Estende a biblioteca implementando a variável X devolvendo um número randômico entre 0 e 1000 através do uso de call-back de variáveis.
      3. Implementa o call-back de erro para mostrar o erro na console e o call-back de atribuição para mostrar na console as atribuições usadas nas expressões fornecidas.

      A seguir a tela do IDE do Arduino mostrando a interação com a console:

      Figura 5- Tela da Console do IDE

      Figura 6- Diagrama do Circuito BasicDemo

       


      Download da Biblioteca com os Fontes

      A biblioteca é distribuída seguindo o padrão do Arduino IDE no formato ZIP. A instalação é feita através do IDE conforme figura a seguir. Dentro do ZIP estão também as duas aplicações de demonstração BasicDemo e WebDemo.

      ExpressionParser

      Figura 7 – Instalação da Biblioteca no IDE do Arduino


      Conclusão

      A ExpressionParser transforma lógica de controle em dados configuráveis. Em vez de “recompilar” regras no firmware, você descreve expressões que o dispositivo interpreta em tempo real — com variáveis (sensores, relógio, estado), funções (pré-definidas e/ou estendidas) e atribuições. Esse modelo eleva substancialmente a parametrização de aplicações de automação, com ganhos claros:

      • Agilidade sem recompilar: as regras em forma de expressões podem ser ajustadas como texto (em EEPROM/Preferences, JSON, etc.), reduzindo ciclos de manutenção e time-to-fix em campo.
      • Separação de responsabilidades: o firmware foca em I/O, segurança e estabilidade; a “lógica de negócio” fica em expressões “versionáveis”. Menos if-elses espalhados, mais clareza e “testabilidade”.
      • Escalabilidade funcional: novas necessidades viram novas regras (ex.: HYST(x,y), MAP(v,inMin,inMax,outMin,outMax), MEDIANA(…), DEBOUNCE(…)), reaproveitáveis entre projetos e dispositivos.
      • Portabilidade e interoperabilidade: o mesmo motor atende diferentes SKUs de produto e cenários (iluminação, HVAC, irrigação, monitoração), integrando facilmente com NTP, storage local, OTA, WebSocket, mDNS, etc.

      Em síntese: a biblioteca promove um “regras-como-dados” para automação embarcada. Possibilita flexibilidade, manutenibilidade e velocidade de iteração. Ao combinar expressões parametrizáveis com um conjunto enxuto de regras, o projeto passa a escalar com menos risco e mais previsibilidade — do protótipo ao produto.


      Sobre o Autor


      Alberto de Almeida Menezes
      [email protected]

      Bacharel em Engenharia de Áudio e Produção Musical pela Berklee College of Music.


      Dailton de Oliveira Menezes
      [email protected]

      Bacharel em Ciência da Computação pela Universidade Federal de Minas Gerais.


      Eletrogate

      12 de setembro de 2025

      A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.

      Os comentários estão desativados.

      Tenha a Metodologia Eletrogate dentro da sua Escola! Conheça nosso Programa de Robótica nas Escolas!

      Eletrogate Robô

      Assine nossa newsletter e
      receba  10% OFF  na sua
      primeira compra!