Programação de Interfaces e Aplicações


Tarefa em grupo

Tarefa individual


Objetivos de aprendizagem:


Você:


Software usado


Tarefa em grupo

Para as outras tarefas em grupo, vá para a página das tarefas em grupo.

Esta tarefa foi feita inteiramente por mim, já que sou o único aluno na Algarve FabFarm este ano.

O app

MIT App Inventor

O MIT App Inventor é uma ferramenta ótima, simples e gratuita que permite criar apps para celular. Existem duas versões: uma que precisa de instalação e a mais recente, que é totalmente online.

Arquivos

Código-fonte

APK

Passos:

  1. Para acessar a versão online, vá para este link.
  2. Depois, faça login com a sua conta Google.
  3. Clique em "Start new project".

    MIT App Inventor: começar um novo projeto

  4. Dê um nome ao projeto. O meu é "groupproject".

    Dando nome ao projeto

  5. O #1, no centro, é a área reservada para o design do app; o #2 é usado caso você queira ter mais de uma tela; o #3, à esquerda, é a paleta, que tem todos os objetos, como botões ou um player de vídeo, usados na construção visual do app; no #4, a área à direita, dá para editar as propriedades de cada objeto; o #5 muda para a área de blocos, onde é criada a lógica do app.

    Interface de design do app

  6. Neste exemplo rápido, eu arrasto um botão do lado esquerdo para a tela.

    Arrastando um botão

  7. Aqui eu também mostro como adicionar um texto do mesmo jeito que o botão, mas não vou usar o texto no meu app.

    Adicionando texto

  8. Usando o aplicativo Paint 3D do Windows 10, desenhei rapidinho um grande botão vermelho.

    Desenhando um botão vermelho

  9. Depois, faço o upload do botão vermelho para o MIT App Inventor. Esse procedimento vai ser usado toda vez que um elemento de mídia for usado.

    Fazendo upload do botão vermelho

  10. Aí eu edito as propriedades dele, como altura, largura e texto. No #3 eu defino a imagem que vai servir de botão, no meu caso o grande botão vermelho.

    Editando as propriedades do botão

  11. Aí eu arrasto um objeto de som para a área da tela. O processo para ligar esse objeto à sua mídia é o mesmo de antes. Vou repetir isso também para um vídeo.

    Adicionando um objeto de som

  12. Depois, vou para a área do editor de blocos, no canto superior direito. Clicando no botão, aparecem os blocos que posso adicionar à lógica do app. Aí adiciono um bloco de clique do botão.

    Adicionando um bloco de clique do botão

  13. Clicando no bloco de som e escolhendo "call sound1.play" entre as opções, consigo adicionar ao botão um comando que vai ser executado quando ele for clicado.

    Adicionando o comando para tocar o som

  14. Faço o mesmo de antes para adicionar um vídeo e depois para abri-lo em tela cheia.

    Adicionando um vídeo

  15. Com o app pronto, gero um APK e salvo no sistema de arquivos do meu celular para instalar o programa.

    Gerando o APK

    Salvando o APK

    Instalando o APK

  16. No celular, fui até o local onde salvei o APK e instalei. O Play Protect vai tentar bloquear o app, mas dá para ignorar.

    Instalando no celular

    Aviso do Play Protect

  17. Este é o app resultante, feito na tarefa em grupo.


Arquivos

  1. Código

Introdução

Esta tarefa faz parte do desenvolvimento do meu projeto final.

Como o meu projeto final mudou para um sistema de irrigação, comecei a desenvolver a interface web dele.

É bem complicado separar as competências e deixar aqui só a parte do meu projeto que tem a ver com a interface, então em alguns pontos vou ter assuntos relacionados com outras semanas.

Hero shot Hero shot

O design até agora é o de cima. Ainda preciso modificá-lo para o projeto final, porque não quero que ele só ligue/desligue as bombas; também quero agendamento por zonas, entre outras funções.

Vou juntar abaixo os passos que me trouxeram até aqui, que em parte se sobrepõem ao meu Project Update 2.

No momento em que escrevo isto, não há arquivos de design atuais, há um esboço de código e há um protótipo numa protoboard!

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 registro 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 poder relacionar o relé com a área de interesse, ou pelo menos renomear os relés com as áreas reais da fazenda.

Desenvolvimento

7 de junho de 2020

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

Montagem inicial O meu 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 por água, preciso trocar alguns relés.

O código que roda nesta 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 repo aqui. Por causa da pandemia ele teve que ir embora às pressas e não teve tempo de testar o código dele, então funcionava mas não era estável, porque ele heroicamente tentou compartilhar o pino analógico com o WiFi, o que causava quedas do WiFi que deixavam o sistema quase impossível de usar. Foi com esse código que eu 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 fazer tudo 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 me custou muitas horas.

Passos:

  1. Separei tudo o que já era função no seu próprio arquivo, 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 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 no início desta manhã: 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 direto na fonte de bancada, com 5 volts aplicados no pino de sinal, acredito que isso seja por causa da tensão baixa fornecida pelo ESP32, ou da tensão do sinal.

Aí assisti o vídeo do Great Scott no YouTube sobre relés e optoacopladores.

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

Montagem 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 rodá-lo sem medição de corrente até resolver isso.


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 tem que 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. Coloquei nomes reconhecíveis na interface HTML dos relés;
  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 os horários de 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 se dá para usar o relógio interno com uma bateria externa para o caso de falta de energia.

Segundo esta discussão de issue fechada no repo do ESP no GitHub e este tópico sobre a precisão do ESP, o relógio interno vai atrasar/adiantar: "Internal RTC clock frequency error is about 5%". Isso pode ser resolvido com um cristal externo de 32,768 kHz montado de acordo com o esquema abaixo:

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

Esquema do cristal do relógio RTC

Atualização depois de acordar:

Hoje fui instalar a montagem provisória de teste. Resolvi alguns problemas.

  1. A montagem não funcionava quando desconectada do computador. Solução: a fiação de alimentação não estava correta; 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 do mesmo jeito.

O protótipo agora está assim:

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

Espero que as vespas não liguem para a invasão Espero que as vespas não liguem para a invasão

Ligando os fios do sistema Ligando os fios do sistema

testando...testando...

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

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

Basicamente, fui pesquisar 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 esta função, eu 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 de novo e de novo. 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 o vídeo sobre 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 feliz, porque está funcionando 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:

No fim consegui gravar um arquivo na SPIFFS usando o PlatformIO. Eu já tinha conseguido 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 novo arquivo de projeto na área da aba "Projects" no PlatformIO;
  2. Depois criei uma pasta data no mesmo nível da pasta src. Outra opção é incluir no arquivo platformio.ini um caminho diferente para a pasta data;
  3. Depois, com a placa conectada, rodo pio run -t uploadfs;
  4. Tive que tirar a biblioteca Time do PlatformIO, porque ela estava em conflito com a ESPAsyncWebServer, e aqui foi onde encontrei a informação relevante.

Funcionou.

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

Depois encontrei 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 "/" 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 endereço se especificado no platformio.ini.

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

Atualmente está assim:

Interface atual

A aparência e o código agora são bem parecidos com os do site Random Nerd Tutorials para relés controlados com ESP32.

A principal diferença para o 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 na 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 atual instalado na fazenda. O motivo é que o código está bagunçado e repetitivo demais; as abordagens das fontes de ontem me fizeram perceber que é mais rápido adicionar as funções ao código mais recente uma por uma do que recodificar tudo a partir do código que está rodando na fazenda.

Hoje vou tentar adicionar informações atualizadas, como temperatura e umidade. Estou de novo 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 para ligar o DHT22 é do site dele:

Ligação do DHT22

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

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

Interface atualizada

Acho que a temperatura agora está negativa porque o sensor de temperatura e umidade está com defeito ou a minha fiação está um pouco solta. Acredito que, quando eu fresar a minha própria placa e soldar tudo, em vez de espetar numa protoboard, isso 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 da rede; agora preciso descobrir um jeito de pegar o valor da hora e mostrar na interface web. Por enquanto estou mandando pelo código a palavra TESTE, e é ela 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, quem sabe, 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 com a hora

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

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

Segue 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, transformando-a de uma função void numa 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 agendado. Vamos ver se consigo terminar hoje...


Conclusão

Quanto a esta tarefa, estou feliz com o ponto em que estou agora, mas vou desenvolver mais a interface web para o projeto final. Você pode continuar de onde esta tarefa para em 16 de junho de 2020, na página de Desenvolvimento do Projeto.

Tive uma reunião com um amigo meu, o Jeff Knight, que é programador profissional, e ele me ajudou a rascunhar um plano de para onde quero levar o meu projeto final e de onde estamos. Ele está abaixo e faz parte do README.md da página no GitHub que criei para o software que estou escrevendo para o meu projeto final.

No vídeo abaixo mostro o funcionamento.

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

Esboço do plano

HTML <--> JavaScript <--> C++

Interface web Microprocessador (ESP32)
Define por zona: Recebe:
[ ] horários de início [ ] horários de início
[ ] duração do ciclo, máx. 1 hora [ ] Duração do ciclo
[ ] Botão de override
Mostra [ ] Guarda as informações acima na SPIFFS (csv?)
[x] hora do dia teste lógico:
[x] Umidade fica checando: ({
[x] Temperatura - eu ('zona x') estou numa janela ligada ('hora + duração')?
Sim: 'garantir' que estou ligada
Não: garantir que estou desligada
[ ] programas atuais da zona guardados -esperar o botão de override e interromper o ciclo se receber
[ ] botão de override esperar o botão de override e ligar/desligar a qualquer momento
[ ] estado atual da zona (ON/OFF) Atualiza/manda a situação atual:
[x]Hora do dia;
[x]Estado da zona (ON/OFF)
[x]informações dos sensores (umidade/temperatura)

microprocessador

Na inicialização:

Problema:

arquivo csv: zone1, 20200101 00:00:00.0000, 1234, 1, 12 zone2, 20200101 00:00:00.0000, 1234, 1, 16 zone3, 20200101 00:00:00.0000, 1234, 1, 18

Quando mexo nisso?

ler o arquivo csv. para cada linha: dividir em ',' num array ....

Precisamos salvar o estado:

Este foi um primeiro plano para a interface web do projeto final, e quando você estiver lendo isto ela já vai estar mais desenvolvida.

← (06 mai) Redes e Comunicação · todas as semanas · Projeto Mecânico, Projeto de Máquina (20 mai) →