Datas do diário

06/06/2020 07/06/2020 08/06/2020 09/06/2020 10/06/2020 13/06/2020 14/06/2020 15/06/2020 16/06/2020 17/06/2020 27/06/2020 28/06/2020

Diário do Projeto Final e Atualização do Conceito

6 de junho de 2020

Hoje decidi mudar meu projeto final de novo!

Eu precisava da irrigação funcionando na fazenda, e não precisava de mais galinhas agora, então, bom, mudei de novo. Isso não quer dizer que desisti da chocadeira de ovos de galinha. Só quer dizer que talvez eu tenha DOIS projetos finais :-). Bom, talvez não, a realidade é que vou focar na irrigação: minhas árvores frutíferas precisam de água, a estufa também. Preciso tanto disso agora, e preciso que funcione bem, que a mudança vale muito a pena.

Então nada de Galinhas! SIM ÁGUA! Talvez Galinhas também.


Design da minha nova proposta

Enquanto escrevo isto, não há arquivos de design no momento; há um esboço do código e há um protótipo numa breadboard!

Por outro lado, há requisitos para o hardware e para o software:

Requisitos de Software e estágio

  1. Simplificar o código criando mais funções;
  2. Tentar separar a parte do HTML para ter um código mais limpo;
  3. Melhorar a aparência/interface do código;
  4. Adicionar leituras ao HTML;
  5. Adicionar um log de ocorrências, como sobrecorrente;
  6. Adicionar mais segurança para o equipamento;
  7. Adicionar uma interface para celular (APP);
  8. Adicionar uma função para acertar a hora atual;
  9. Adicionar uma função para renomear cada relé, para dar para relacionar o relé com a área de interesse, ou pelo menos renomear os relés com as áreas reais da fazenda.

Requisitos de Design e situação

  1. Precisa ser pelo menos resistente à água;

7 de junho de 2020

Hoje, 7 de junho de 2020, o desenvolvimento está assim.

Montagem inicial do sistema de irrigação O ponto de partida é um sistema que funciona num Uno e é uma tortura num ESP8266; além disso, tem risco de choque, e por causa de dano de água preciso trocar alguns relés.

O código que roda nessa montagem está no GitHub da Fabfarm: Autovalve.

O Shakeel, um dos nossos voluntários, conseguiu criar uma versão que roda num ESP8266, que está no mesmo repositório aqui. Por causa da pandemia ele teve que ir embora às pressas e não teve tempo de testar o código, então funcionava mas não era estável, porque ele heroicamente tentou compartilhar o pino analógico com o Wi-Fi, o que causava quedas no Wi-Fi que deixavam o sistema quase impossível de usar. Foi com esse código que comecei.


8 de junho de 2020

Depois de muitas horas tentando entender o código, consegui portar o código do Shakeel para um ESP32 e também dividir o arquivo, com cada função num arquivo separado.

Neste vídeo mostro o progresso que fiz até agora em juntar os códigos e fazê-los funcionar no ESP32.

Veja a versão em alta resolução no YouTube

Portar o código para o ESP32 pode ser simples para um programador, mas para mim levou muitas horas.

Passos:

  1. Separei tudo o que já era função em arquivo próprio, para ficar mais legível;
  2. Depois abri outra sessão da Arduino IDE e comecei a copiar cada parte do código, linha por linha, para a nova sessão; nessa sessão renomeei o arquivo principal para "esp32irrigation"
  3. Remapeei os pinos para os pinos do ESP32
  4. Rodei o Beautify no HTML no Brackets
  5. Organizei o código para os pinos ficarem no topo
  6. Criei variáveis para os pinos do RTC
  7. Comentei as partes do código que imprimem erros no monitor serial

O código é grande demais para mostrar no HTML, então vou deixar um link para o estado do código nesta madrugada: código aqui.

Neste vídeo dá para ver a montagem de teste do sistema de irrigação atual da fazenda.

Veja a versão em alta resolução no YouTube


9 de junho de 2020

Hoje, depois de testar os relés, percebi que alguns relés funcionam e outros não. Depois de testar na fonte de bancada do lab, com 5 volts aplicados direto no pino de sinal, acho que isso é por causa da tensão baixa fornecida pelo ESP32, ou da tensão do sinal.

Aí assisti ao vídeo do GreatScott! no YouTube sobre relés e optoacopladores.

Vou garantir que os relés tenham uma alimentação de pelo menos 5 volts, que é a tensão exigida segundo o datasheet. O sinal deve funcionar bem com 3,3 V. Vai ser testado no local.

Montagem de teste dos relés

O outro ponto é a leitura de corrente, que está completamente errada. Para ter o sistema de irrigação funcionando, vou ter que rodar sem medir a corrente até depurar.


10 de junho de 2020

Depois dos testes, a conclusão sobre o problema de tensão é que o ESP32 não deve alimentar o relé; isso deve vir de uma fonte externa, ajustada em 5 volts. O sinal pode vir do ESP32 sem mudança, mas o ESP32 tem que compartilhar o mesmo terra.

Mais mudanças no código:

  1. Aumentei o intervalo em que a hora é mostrada de 3000 para 5000 ms (5 s) na variável RTCtimeInterval
  2. Aumentei o intervalo em que a configuração é mostrada de 10000 para 30000 ms (30 s) na variável configTimeInterval
  3. Dei nomes reconhecíveis aos relés na interface HTML
  4. Limpei mais um pouco o monitor serial, tirando os segundos da exibição das configurações

Vou colocar a montagem para funcionar de novo hoje de manhã, definir horários para cada irrigação e testar em campo o módulo de irrigação com ESP32.

Estranhamente, o relógio RTC externo não está mantendo a hora certa. Vou ver como usar o relógio interno com uma bateria externa para o caso de falta de energia.

Segundo esta discussão de issue fechada no repositório do ESP32 no GitHub e este tópico sobre a precisão do ESP, o relógio interno vai derivar ("Internal RTC clock frequency error is about 5%"); dá para resolver isso com um cristal externo de 32,768 kHz, montado segundo o esquema abaixo:

Outra solução seria deixar o ESP sempre conectado à Internet, pegando a hora da Internet para compensar a imprecisão.

Esquema do relógio RTC

Atualização depois de acordar

Hoje fui instalar a montagem de teste temporária. Resolvi alguns problemas.

  1. A montagem não funcionava desconectada do computador. Solução: a fiação de alimentação não estava certa; acabei ligando 2 cabos USB, um para o ESP32 e outro para os relés, e os dois compartilham o mesmo terra. Talvez eu também tenha resolvido o problema do relógio RTC com a mesma abordagem.

É assim que o protótipo está agora:

Montagem do protótipo Ainda falta ligar a bomba e as válvulas solenoides.

Montagem do protótipo com vespas Espero que as vespas não se importem com a invasão

Ligando a fiação do sistema Ligando a fiação do sistema

Testando...testando...

Depois dos testes voltei ao código para personalizar mais.

Primeiro assisti a uma série de vídeos no YouTube sobre como as funções funcionam de verdade, e depois comecei a criar ainda mais funções.

Basicamente, fui ver como reduzir a repetição de código e como mandar um valor para uma função.

A partir do código disponível criei esta função:

void turnOffRelay(int valveHere){
  // wait then turn valve relay OFF
  Serial.print("Waiting ");
  Serial.print(waitTimeValveOff / 1000);
  Serial.println("s before deactivating Valve Relay 3.");
  delay(waitTimeValveOff);
  digitalWrite(valveHere, LOW);
  valveHere = 0;
  Serial.print("*** Valve Relay ");
  Serial.print(valveHere);
  Serial.println("3 turned OFF ***");
}

Atenção: valveHere = 0; roda antes de Serial.print(valveHere);, então a mensagem sai sempre "Valve Relay 03 turned OFF", seja qual for a válvula. O "3" também está fixo nas duas mensagens. Imprima valveHere antes de zerar (ou tire essa linha) e tire o "3" fixo dos textos.

Toda vez que quero chamar essa função, uso:

      {
        int valveHere = valveRelay3;
        turnOffRelay (valveHere);
      }

O motivo de eu usar as {} é que eu tinha que declarar a variável local valveHere; assim eu podia trocar só esse pedaço de código cada vez que chamava a função.

Tecnicamente, chamar essa função seria só ter este código aqui, turnOffRelay (valveHere);, mas isso não funcionaria sozinho, porque estou sempre trocando o pino do relé da válvula com int valveHere = valveRelay3;

Atenção: as {} e a variável local não são necessárias: o pino já vai como argumento, então só turnOffRelay(valveRelay3); faz a mesma coisa.

Ainda não testei o comportamento, mas pelo menos compila :-)


9 de junho de 2020

Gravei no ESP32 e o comportamento é inesperado. A função fica imprimindo sem parar; acho que preciso devolver o estado de uma variável e não fiz isso. Vou tentar usar o código return variable; para isso e depois testar, mas antes vou assistir de novo ao vídeo de funções para entender melhor.


13 de junho de 2020

Argh... OK, muito tempo sem atualizações. Bom, o último código enviado funciona e tenho algumas funções, mas ainda não estou contente, porque funciona no Arduino mas não no PlatformIO. O que aprendi até agora é que a Arduino IDE faz muita coisa "por baixo dos panos", e no PlatformIO você precisa configurar com mais detalhe.

Leia o seguinte:

Acabei conseguindo gravar um arquivo no SPIFFS usando o PlatformIO. Eu já conseguia fazer isso com o Arduino, mas sem entender direito como; agora acho que talvez tenha entendido. Para isso, tive que configurar o arquivo platformio.ini e a árvore de diretórios seguindo uma série de passos, então vamos ver:

  1. Criei um projeto novo na área da aba "Projects" do PlatformIO
  2. Depois criei uma pasta data no mesmo nível da pasta src. Outra opção é definir um caminho diferente para a pasta data no arquivo platformio.ini.
  3. Depois, com a placa conectada, rodei pio run -t uploadfs
  4. Tive que tirar a biblioteca Time do PlatformIO, porque dava conflito com a ESPAsyncWebServer, e aqui foi onde achei a informação.

Funcionou.

Com isso comecei a entender o quanto eu não sabia o que estava fazendo. O código com que comecei tinha o HTML incluído no sketch do Arduino. Isso me incomodava. Agora, com esse novo entendimento, posso deixar o HTML separado do arquivo do sketch.

Depois achei este tutorial: ESP32 Web Server using SPIFFS

E este, caso eu queira usar o plugin da Arduino IDE para o upload.

Queria muito ter entendido isso melhor antes! Passei tantos dias nisso!

O código C++ até agora.


            /****************************************************************************
            *                                  Aknowledments                           * 
            *                                  by LucioPGN                             * 
            ****************************************************************************/
           /*  Up to this date: 07th of June 2020 I don't consider myself a programer 
            *  so I need to stand on top of giants sholders for my programing projects:
            *  A Portion of this code was based on Rui Santos Code;
            *  A Portion of this code was based on losely based Shakeels code for ESP8266;
            *  A Portion of this code was based on several websites I lost track of....!
            *  My contributions: 
            *     -So far I made it work on platformio :), that took me quite a lot of time
            *     -That means:
            *        +created a new project;
            *        +created a folder named data under the main folder (fabfarm_irrigation)
            *        +linked the platformio.ini to the folder of the project + the data folder
            *        +linked the needed libraries to their github repo in the platformio.ini
            *        +found a conflict with time library and ESPAsyncWebserverLibrary can be solved by renaming time library or by removing it
            *        +Made it work with a separate HTML file under the data folder using SPIFFS
            *        +I can load the data to Spiffs inside platformio
            *  Things I still want to program for my final project:
            *    -so far I ported Shakeels code into ESP32;
            *    -simplify the code creating functions rather than repeating the code;
            *    -try to separate the HTML part for a cleaner code (this applies to maybe mix up the other previous code to this);
            *    -Improve the appearance/Interface of the code
            *    -Add readings to HTML
            *    -Add a log of occurrences like over current
            *    -Add more safety for the equipment
            *    -Add a phone interface (APP)
            *    -Add function to set current time
            *    -Add renaming function to each relay so one can relate the relay to the area of interest or at least rename relays to actual areas of the farm.
            * 
            ****************************************************************************/
            
           
           //Required Libraries
           #include "WiFi.h"
           #include "ESPAsyncWebServer.h"
           #include "SPIFFS.h"
           #include <AsyncTCP.h>
           
           // Network Credentials
           const char* ssid = "rato";
           const char* password = "imakestuff";
           
           //Start the Async Web Server listening on port 80
           AsyncWebServer server(80);
           
           // Set to true to define Relay as Normally Open (NO)
           #define RELAY_NO false
           
           // Set number of relays, will be used in the array
           #define NUM_RELAYS  4
           
           // Assign each GPIO to a relay
           int relayGPIOs[NUM_RELAYS] = {26, 25, 33, 32};
           
           //
           const char* PARAM_INPUT_1 = "relay";  
           const char* PARAM_INPUT_2 = "state";
           
           // Replaces placeholder with button section in your web page
           String processor(const String& var){
             //Serial.println(var);
             if(var == "BUTTONPLACEHOLDER"){
               String buttons ="";
               for(int i=1; i<=NUM_RELAYS; i++){
                 String relayStateValue = relayState(i);
                 //Here parts of the HTML will be parsed to index.html like Relay # followed by its value in variable for the GPIO numbers
                 buttons+= "<h4>Turn on water on " + String(i) + "</h4><h4>Valve (relay) #" + String(i) + " - GPIO " + relayGPIOs[i-1] + "</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"" + String(i) + "\" "+ relayStateValue +"><span class=\"slider\"></span></label>";
               }
               return buttons;
             }
             return String();
           }
           
           String relayState(int valveRelayNum){
             if(RELAY_NO){
               if(digitalRead(relayGPIOs[valveRelayNum-1])){
                 return "";
               }
               else {
                 return "checked";
               }
             }
             else {
               if(digitalRead(relayGPIOs[valveRelayNum-1])){
                 return "checked";
               }
               else {
                 return "";
               }
             }
             return "";
           }
           
           void setup(){
             // Serial port for debugging purposes
             Serial.begin(9600);
             // Initialize SPIFFS
             if(!SPIFFS.begin(true)){
               Serial.println("An Error has occurred while mounting SPIFFS");
               return;
             }
             // Set all relays to off when the program starts - if set to Normally Open (NO), the relay is off when you set the relay to HIGH
             for(int i=1; i<=NUM_RELAYS; i++){
               pinMode(relayGPIOs[i-1], OUTPUT);
               if(RELAY_NO){
                 digitalWrite(relayGPIOs[i-1], HIGH);
               }
               else{
                 digitalWrite(relayGPIOs[i-1], LOW);
               }
             }
             
             // Connect the ESP to the Wi-Fi using the credentials entered before
             WiFi.begin(ssid, password);
             while (WiFi.status() != WL_CONNECTED) {
               delay(1000);
               Serial.println("Connecting to WiFi..");
             }
           
             // Print ESP32 Local IP Address
             Serial.println(WiFi.localIP());
           
           /*
           *Now we are going to configure the route where server will be listening for incoming HTTP requests 
           and a function that will be executed when a request is received on that route.
           We specify this by calling the "on" method on the server object. With server.on(){}; 
           As first input, this method receives a string with the path where it will be listening. 
           We are going to set it to listen for requests on the "root" route. This could be anything. 
           It is basically what you write after the ip adress when in the browser or an APP.
           This website has a great explanation of the ESP32 Arduino: Asynchronous HTTP web server
           https://techtutorialsx.com/2017/12/01/esp32-arduino-asynchronous-http-webserver/
           So... 
           - First parameter here is: "/" thats the root directory.
           - Second parameter is HTTP_GET thats an enum of type WebRequestMethod a method defined in the library here --> https://github.com/me-no-dev/ESPAsyncWebServer/blob/63b5303880023f17e1bca517ac593d8a33955e94/src/ESPAsyncWebServer.h
           - Third parameter is a the function AsyncWebServerRequest
           So there is this c++ lambda function used here. My litle understanding is that they are locally declared unamed function this means they dont have a name and are declared locally :-)
            I don't grasp the concept fully haha.
            the syntax is [captures](params){body} where in here [] is empity
           */
           
             // Route for root / web page
             server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
               request->send(SPIFFS, "/index.html", String(), false, processor);
             });
           
            // Send a GET request to <ESP_IP>/update?relay=<inputMessage>&state=<inputMessage2>
             server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request) {
               String inputMessage;
               String inputParam;
               String inputMessage2;
               String inputParam2;
               // GET input1 value on <ESP_IP>/update?relay=<inputMessage>
               if (request->hasParam(PARAM_INPUT_1) & request->hasParam(PARAM_INPUT_2)) {
                 inputMessage = request->getParam(PARAM_INPUT_1)->value();
                 inputParam = PARAM_INPUT_1;
                 inputMessage2 = request->getParam(PARAM_INPUT_2)->value();
                 inputParam2 = PARAM_INPUT_2;
                 if(RELAY_NO){
                   Serial.print("NO ");
                   digitalWrite(relayGPIOs[inputMessage.toInt()-1], !inputMessage2.toInt());
                 }
                 else{
                   Serial.print("NC ");
                   digitalWrite(relayGPIOs[inputMessage.toInt()-1], inputMessage2.toInt());
                 }
               }
               else {
                 inputMessage = "No message sent";
                 inputParam = "none";
               }
               Serial.println(inputMessage + inputMessage2);
           
               //This is the last part of the lambda function. 
               //This method receives as first input the HTTP response code, which will be 200 in our case.  This is the HTTP response code for "OK".
               request->send_P(200, "text/plain", "OK");
             });
           
             // Start server here
             server.begin();
           }
           
           void loop(){
           
           }
        

Atenção: hasParam(PARAM_INPUT_1) & hasParam(PARAM_INPUT_2) usa o & bit a bit; o E lógico é &&. Com dois bool o resultado acaba sendo o mesmo, mas não faz curto-circuito, e o operador certo é &&.

Versão atual deste código (E-SPlash no GitHub)

O código HTML até agora.


<!DOCTYPE HTML><html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    html {font-family: Arial; display: inline-block; text-align: center;}
    h2 {font-size: 3.0rem;}
    p {font-size: 3.0rem;}
    body {max-width: 600px; margin:0px auto; padding-bottom: 25px;}
    .switch {position: relative; display: inline-block; width: 120px; height: 68px} 
    .switch input {display: none}
    .slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 34px}
    .slider:before {position: absolute; content: ""; height: 52px; width: 52px; left: 8px; bottom: 8px; background-color: #fff; -webkit-transition: .4s; transition: .4s; border-radius: 68px}
    input:checked+.slider {background-color: #2196F3}
    input:checked+.slider:before {-webkit-transform: translateX(52px); -ms-transform: translateX(52px); transform: translateX(52px)}
  </style>
</head>
<body>
  <h2>Fab Farm Irrigation System</h2>
  %BUTTONPLACEHOLDER%
<script>function toggleCheckbox(element) {
  var xhr = new XMLHttpRequest();
  if(element.checked){ xhr.open("GET", "/update?relay="+element.id+"&state=1", true); }
  else { xhr.open("GET", "/update?relay="+element.id+"&state=0", true); }
  xhr.send();
}</script>
</body>
</html>
                
O arquivo HTML precisa ficar numa pasta chamada "data", ou em outro caminho se estiver definido no platformio.ini.

Versão atual deste código (E-SPlash no GitHub)

No momento está assim:

Interface web atual

A aparência e o código agora são praticamente iguais aos do site Random Nerd Tutorials sobre relés controlados por ESP32.

A principal diferença do código original é que ele roda no PlatformIO para VS Code, e também usa uma estrutura de pastas separada para o arquivo HTML, que é gravado no SPIFFS do ESP.


14 de junho de 2020

Depois de toda essa descoberta pessoal, decidi que preciso começar o código do zero e usar só o algoritmo geral do sistema de irrigação que está instalado na fazenda. O motivo é que o código está bagunçado e repetitivo demais; as abordagens que achei nas fontes de ontem me fizeram perceber que é mais rápido adicionar os recursos ao último código um por um do que reescrever tudo a partir do código que roda hoje na fazenda.

Hoje vou tentar adicionar informações atualizadas, como temperatura e umidade. De novo, estou me baseando no trabalho do Rui Santos nesta página sobre uma estação meteorológica. Com essa abordagem, acho que também vou conseguir incluir a hora do dia usando um relógio RTC.

O esquema de ligação do DHT22 é do site dele:

Esquema de ligação do DHT22

Ele usa um resistor de 4,7 kOhm como pull-up.

Depois de algum trabalho, a página ficou assim:

Interface web com temperatura e umidade

Acho que o motivo de a temperatura agora estar negativa é que o sensor de temperatura e umidade está com defeito ou a minha fiação está meio frouxa. Acho que quando eu fresar minha própria placa e soldar tudo, em vez de espetar numa breadboard, vai ficar mais confiável. De qualquer forma, estou recebendo os valores e consigo mostrá-los na interface web.

No monitor serial já consigo mostrar a hora da Internet e as informações de rede; agora preciso achar um jeito de pegar o valor da hora e mostrar na interface web. No momento estou mandando a palavra TESTE pelo código, e é isso que aparece no lugar da hora.

Saída do monitor serial


15 de junho de 2020

Hoje vou focar em mostrar a hora na interface web e talvez criar uma função para ligar o relé num horário definido.

Atualização das 20:44:

- Depois do dia inteiro tentando, consegui mostrar a hora da máquina e a hora do sistema de irrigação (ESP32).

Agora a interface está assim:

Interface web mostrando a hora

Quando eu crescer quero ser programador :-) e não passar um dia inteiro numa coisa que alguém monta em poucas linhas!

Meu sofrimento acabou graças a um santo, com esta resposta no Arduino Stack Exchange.

Aqui vai a função original postada lá:


void printLocalTime()
{
  time_t rawtime;
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo))
  {
    Serial.println("Failed to obtain time");
   return;
  }
  char timeStringBuff[50]; //50 chars should be enough
  strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
  //print like "const char*"
  Serial.println(timeStringBuff);

  //Optional: Construct String object 
  String asString(timeStringBuff);
}

Com pequenas modificações, mudando de uma função void para uma função String e adicionando um return que chamei de "timeAsAString":


//this function was found here https://arduino.stackexchange.com/questions/52676/how-do-you-convert-a-formatted-print-statement-into-a-string-variable
//I did a minor change so instead of a void function it now returns a string to be used to show time in the webinterface
String printFarmTime()
{
  time_t rawtime;
  struct tm timeinfo;
  getLocalTime(&timeinfo);
  char timeStringBuff[50]; //50 chars should be enough
  strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
  //print like "const char*"
  Serial.println(timeStringBuff);

  //Construct to create the String object
  String timeAsAString(timeStringBuff);
  return timeAsAString;
}

Atenção: esta versão tirou a verificação if(!getLocalTime(&timeinfo)), então, se o NTP ainda não respondeu, ela formata uma hora vazia (lixo). Mantenha a verificação e devolva algo como "time not set" quando falhar.

Então, com isso resolvido, vou tentar criar as funções para ligar e desligar os relés de acordo com o horário programado. Vamos ver se consigo terminar hoje...


16 de junho de 2020

Não, não trabalhei nisso, estava cansado, então hoje fiz alguns esboços.

Esboço do formato da caixa e da interface web

Neste esboço mostro como vai ser o formato da caixa e como vai ser a interface web também.

Também estou lendo sobre String e sobre a sua manipulação.

Eu poderia seguir a abordagem de dividir as datas como String e converter para outros tipos de valores para as operações que pretendo fazer. Outra possibilidade é pegar os dados já no tipo que preciso desde o começo. Mesmo gostando mais da segunda opção, ainda não achei solução para ela, porque ainda não entendo bem a função getLocalTime(). Então vou ler mais sobre ela agora.

Espera... essa foi rápida! Achei um post que resolve o que eu preciso. Aqui está:

Post no Fórum do Arduino do usuário Abhay Post no Fórum do Arduino do usuário Abhay

Então me baseei no post acima para criar a função abaixo:


          
      int gimeTime(char what) {

          int OnlyYear;
          int onlyMonth;
          int onlyDay;
          int onlyHour;
          int onlyMin;
          int onlySec;
      
          struct tm timeinfo;
          if(!getLocalTime(&timeinfo)){
            Serial.println("Failed to obtain time");
            //return;
            }
          onlyHour = timeinfo.tm_hour;
          onlyMin  = timeinfo.tm_min;
          onlySec  = timeinfo.tm_sec;
          onlyDay = timeinfo.tm_mday;
          onlyMonth = timeinfo.tm_mon + 1;
          OnlyYear = timeinfo.tm_year +1900;
      
          switch (what) {
            case 1:
            return onlyHour;
            break;
            case 2:
            return onlyMin;
            break;
            case 3:
            return onlySec;
            break;
            default:
          // if nothing else matches, do the default
          // default is optional
          break;
          }
      }
    
    

Atenção: o default termina sem return, então a função devolve um valor indefinido para qualquer coisa que não seja 1, 2 ou 3 (ponha return -1; ali). O mesmo quando o getLocalTime() falha: com o return comentado, ela segue lendo um timeinfo sem hora válida.

É isso, agora finalmente posso trabalhar no código de agendamento dos timers. Aliás, passei quase o dia inteiro tentando achar um jeito mais simples de pegar as horas, mas não consegui, porque estou apanhando para entender o tipo (struct). Bom, talvez eu volte nisso no futuro, mas por enquanto está bom.


17 de junho de 2020

Atualização de madrugada:

Estou muito frustrado, preciso passar para os átomos e fechar a parte dos bits do meu projeto.

Tarde da noite, o máximo que avancei foi fazer uma pequena função para desligar os relés; aqui está:


        int zoneStartStop (int zone, int startStop){
        int waitTime = 1000;
        if (startStop == 1){
        digitalWrite(relayGPIOs[zone], startStop);
        Serial.print("*** Zone Valve");
        Serial.print(zone);
        Serial.println("ON ***");
        delay(waitTime);
        digitalWrite(pumpGpio, startStop);
        Serial.print("*** Pump turned ON ***");
        }
        else{
        digitalWrite(pumpGpio, startStop);
        Serial.println("*** Pump turned OFF ***");
        delay(waitTime);
        digitalWrite(relayGPIOs[zone], startStop);
        Serial.print("*** Zone Valve");
        Serial.print(zone);
        Serial.println("OFF ***");
        }
        }

(Código corrigido depois: ao parar, agora a bomba desliga antes de a válvula fechar, para nunca empurrar contra a válvula fechada, e a mensagem diz OFF.)

É um começo, mas ainda não chegou lá, e não testei.

Atualização da manhã:

Então agora vou olhar outro exemplo para configurar um timer, de novo do Rui Santos, está aqui; talvez eu consiga mudar um pouco, integrar no meu código e adicionar uma hora de início, e depois usar o slider para definir quanto tempo, em minutos, vai rodar. Isso já bastaria por enquanto!

Até agora deixei o código compatível com o PlatformIO, e também separei o arquivo index.html do código C++ e coloquei numa pasta própria, para ser gravado pela rotina de salvar no SPIFFS que descrevi em 13/06/2020.

Referências

Biblioteca Eagle do ESP32

Barduino

Nota de rodapé

Links:

Recursos do Rui Santos sobre o ESP32

Last Minute Engineers

Random Nerd Tutorials