[Resolvido] Duvida - Como fazer Split com strings no Arduino

Boa noite garagistas, estou com um projeto e pretendo usar esse código do André Michelon do canal internet e coisas, e nesse código ele dispõe de uma caixa de texto para inserção de comandos de agendamento. Eu preciso criar um comando novo, para acionamento em intervalos curtos nos horários definidos, ex: string comando + string hora + intervalo em millis 

Ex: AL 12:00 1000

como faço para criar uma função que recupere o valor em millis da string para usar como uma variável "inteiro"?

Abaixo os exemplos de comandos aceitos pelo código.

FUNÇÕES DO SISTEMA DE AGENDA  - Scheduller
10/2018 - Andre Michelon
Opções:
- Agenda para data/hora específica
On (High): SH yyyy-mm-dd hh:mm
Off (Low): SL yyyy-mm-dd hh:mm
- Mensal
On (High): MH dd hh:mm
Off (Low): ML dd hh:mm
- Semanal
On (High): WH d hh:mm
Off (Low): WL d hh:mm
- Diário
On (High): DH hh:mm
Off (Low): DL hh:mm
- Intervalo
On (High): IH hh:mm
Off (Low): IL hh:mm
Exemplos:
SH 2018-10-12 16:30 - Ligar em 12/10/2018 16:30
MH 12 16:30 - Ligar mensalmente no dia 12 às 16:30
WL 6 16:30 - Desligar semanalmente nas sextas-feiras às 16:30
DH 16:30 - Ligar diariamente às 16:30
IH 00:30 - Desligar após estar ligado por 30 minutos
IL 00:10 - Ligar após estar desligado por 10 minutos
*******************************************************************************/

https://www.youtube.com/watch?v=8rGYdIECf5s&t=303s link do video

código utilizado

https://internetecoisas.com.br/download/IeC111-IeCRele.zip

Exibições: 335

Responder esta

Respostas a este tópico

olá Tiago.

      Acho que pode te ajudar olhando um tópico aqui mesmo no LDG.  No tópico, vc encontrará o código em um link ali postado.

      No código implementei uma função com nome "ajustar_DATA_HORA",  que recebe uma String de Comando via Serial,  e então extrai diversas informações da mesma.  Basta procurar exatamente por essa função "ajustar_DATA_HORA". Logo quando vc olhar a função, irá perceber imediatamente como foram extraídas as informações, pois está bastante claro o funcionamento, além de manter uma grande simplicidade na implementação.

      O tópico é este:   "Luzes - Aquário"

      Espero ter ajudado.

      Abrçs.

      Elcids

Elcids, muito obrigado pela dica, muito didático o exemplo, com vários exemplos de uso de structs, cases e muito bem comentado, me ajudou a entender vários itens que eu ainda tinha um pouco de duvida sobre programação.

Mas verificando o seu exemplo, percebi que os itens que fazem o que eu preciso, são o indexOf() e o .substring(), até ai eu achei tranquilo, mas considerando o código do scheduller(agendador) usado no exemplo do André Michelon, o parâmetro de data vem da variável String dt

sendo a variável "dt" obtida da seguinte função

// Data/Hora como "yyyy-mm-dd hh:mm"
String dt = String(year(nowTZ)) + '-';
         if (month(nowTZ) < 10) {
dt += '0';
}
dt += String(month(nowTZ)) + '-';
       iif (day(nowTZ) < 10) {
dt += '0';
}
dt += String(day(nowTZ)) + ' ';
       iif (hour(nowTZ) < 10) {
dt += '0';
}
dt += String(hour(nowTZ)) + ':';
       iif (minute(nowTZ) < 10) {
dt += '0';
}
dt += String(minute(nowTZ));

sendo todos os comandos "comando + dt"

Onde o parâmetro hora atual é obtido usando substring

// Data/Hora como "hh:mm"
dt = dt.substring(2);

estou desde as 5 da manhã mexendo  tentei vários métodos, mas ainda não consegui fazer  reconhecer as variável em millis, mas vou estudar melhor o conceito.

olá novamente Tiago.

      Analisei a função "scheduleChk".  Inclusive dei uma organizada nela (o arquivo está no final deste post). Infelizmente também tenho que dizer que usaram algumas práticas de programação consideradas "ruins", mas fazer o que (é triste que mesmo aqueles que se consideram catedráticos, empreguem tais práticas, e acabem por fazer uma espécie de "desserviço").

      Apesar disso,  a função "scheduleChk"  é funcional e faz o que se propõe. Ela simplesmente recebe uma String de Comando (ou um "evento" se preferir) e então decodifica este comando, considerando a Data/Hora atuais.  Se o comando for válido, então ele é executado.  Na saída, a rotina também informa qual comando foi executado (ou se nenhum foi executado).

      Além disso,  a  função é temporizada,  e executa comandos apenas a intervalos de 10 segundos.  A forma como isto foi feito, provavelmente não é a mais adequada (é quase certo que esta temporização deveria estar fora da rotina), mas funciona.

      Agora sobre sua questão.

      É fácil incluir novos comandos na função "scheduleChk", e pelo que vc escreveu,  acredito seja isto que vc precisa.

      Porém,  achei meio estranha a funcionalidade do comando que vc passou como exemplo "AL 12:00 1000".  Veja:  vc especifica o comando "AL",  e informa a hora (no caso "12:00"),  e o tal "millis" (seria o "1000").  Assim, seguindo a lógica dos demais comandos existentes na função "scheduleChk",  o Relé  seria desligado às 12:00,  mas pergunto:  como o valor "1000" se encaixa nisso?

      Seria talvez isso:  às 12:00 desligar o Relé por 1000 mili-segundos. Algo assim?

      Lembre-se que a função é temporizada, e só executa comandos a cada 10 segundos.

      Segue a função "scheduleChk", que eu dei uma "ajeitada" na organização (mas não mudei em nada a lógica), e incluí comentários para facilitar o entendimento da mesma:    "funcao_scheduleChk_01.h"

      Abrçs,

      Elcids

Elcids, fantástico, muito obrigado ficou muito melhor, ja faz um bom tempo que eu estudo essa função "scheduleChk, agora ficou bem mais fácil. 

Quanto a meu pedido de ajuda seria isso:  às 12:00 ligar o Relé por 1000 mili-segundos.

o intervalo em segundos é por uma necessidade que gostaria de atender com esse código, que é acionar um alimentador de aquário que possuo, pois com certa frequência preciso alterar os parâmetros de tempo, mas poderia ter outros uso como verificação temperatura ou umidade, pois desta forma o programa teria um uso mais genérico, que poderia usar em vários outros controles na minha chácara

Mas pelo estudo feito provavelmente terei que alterar mais coisas, mas posso tranquilamente refazer o programa muito obrigado pela ajuda

olá Tiago.

      Se os comandos que vc quer implementar (como o "AL 12:00 1000"), são da forma como interpretei, irei postar uma implementação de forma que vc pode depois criar outros comandos.

      O importante, é não alterar o restante do funcionamento do Sistema (ou seja: sem efeitos colaterais para o restante do Sistema), mas isso é tranquilo de se fazer.

      Para a implementação será necessário acrescentar uma temporização mais refinada no "loop"  principal (o próprio "loop" do Arduino), e algum controle na função "scheduleChk".

      Organizei também o "loop" principal  (mas nenhuma lógica foi alterada) e vc pode ver como ele funciona originalmente, conforme figura a seguir:

(clique na figura para "zoom")

      Observe que a própria função "scheduleChk" é chamada a cada segundo. Mas vimos que lá dentro dela, que a execução dos comandos é apenas a cada 10 segundos.  Tranquilo, isso não será um problema.

      Dei uma olhada no restante do código, e ficou claro para mim, que a string de comando "schedule" que é passada para a função "scheduleChk", é uma sequência única  que inclui todos os comandos (ou se vc preferir, todos os itens da "Agenda").  Ou seja:  todos os comandos estão juntos em uma mesma String, a "schedule".  Isto está longe de ser a forma mais eficiente de implementação (pois gasta tempo de execução e memória). Mas é uma forma simples e funciona, e foi a forma como escolheram para implementar. De qualquer forma, isso não afeta em nada a implementação que vc quer fazer.

      Irei fazer a implementação usando como base o comando que vc sugeriu, o "AL 12:00 1000", ou seja,  um "ON/OFF" executado no horário determinado,  e que liga/desliga o Relé pelos mili-segundos  informados no comando. Ok?

      Assim que concluir, posto aqui.

      Abrçs,

      Elcids

Muito interessante esse conceito de "dividir" strings. Em linguagens mais complexas, como Java, temos funções próprias para esse fim, a .split(). Que funciona da seguinte forma:

String texto = "Meu texto aqui";

String vetor[2]  = texto.split(" ");

Com isso nas posições da variável vetor estão: 

[0] = "Meu";

[1] = "texto";

[2] = "aqui";

Tendo esse conceito em mente, criei uma função bem simples para executar o mesmo conceito da .split(). Só que deixando meio que pré definido a forma de usar, onde ela sempre vai dividir em 3 a string recebida e sempre vai usar o " "(espaço em branco como divisor). Própria para o que vc esta pedindo.

void splitMSG(String comandoRecebido) {

int passo = 0;
int tamanho = comandoRecebido.length();
//Limpando variáveis
comando = "";
hora = "";
tempo = "";
hold(100);
//Crio um vetor temporário com o tamanho do comandoRecebido
char letras[comandoRecebido.length()];

//Converte o comando em um Array de Char
comandoRecebido.toCharArray(letras, comandoRecebido.length());

int i = 0;

while (i <= comandoRecebido.length() + 1) {
if (letras[i] != ' ') {
if (passo == 0) {
comando += letras[i];
} else if (passo == 1) {
hora += letras[i];
} else if (passo == 2) {
tempo += letras[i];
} else if (passo == 3) {
break;
}
} else {
passo++;
}
hold(100);
i++;
}

hold(100);

Serial.println("Comando recebido: " + comandoRecebido);
Serial.println("Comando: " + comando);
Serial.println("hora: " + hora);
Serial.println("tempo: " + tempo);
}


Para melhor exemplificar o uso, criei um exemplo onde vc digita uma frase no monitor serial e é retornado o comando da forma que vc pediu, separando cada parte do comando. SplitString3.ino

Muito bom, obrigado pela ajuda Tales, parece simples vou ver se consigo fazer rodar aqui o que eu preciso com usando a contribuições apresentadas, a noite eu vou ter tempo de mexer nisso.

olá Tiago.

      Fiz a implementação dos dois comandos,  o "AH hh:mm xxxx"  que liga o Relé pelo tempo de "xxxx" mili-segundos,  e o comando "AL hh:mm xxxx"  que desliga o Relé pelo tempo de "xxxx" mili-segundos.  O valor "xxxx" pode ser qualquer qualquer um que vc precise. Se especificar tempo igual a "0" (zero), então o comando não é executado, uma vez que não tem sentido. E claro, tempos muito pequenos (ex.:  5 ms) poderão não ser muito precisos, uma vez que o todo o restante do processamento do ESP (WiFi, Server, etc) pode causar imprecisão nestes períodos muito pequenos. E claro o "xxxx" não precisa ter 4 dígitos, pode ser por exemplo "51".

      Assim vc pode por exemplo, usar "AH 17:35 500"  para ligar o Relé por 500 ms (meio segundo) às 17:35 horas.  A mesma ideia se aplica ao comando "AL".

      A forma como implementei, deixa totalmente intacto o funcionamento dos demais comandos que já existiam no Sistema original.

      E durante o tempo que fica ligado ou desligado o Relé, não há bloqueio das demais  tarefas executadas no Sistema (rede, servidor, etc). Logo não há efeito colateral no funcionamento.

      No entanto, observe que a maneira como estes comandos funcionam, é uma espécie de "bate e volta",  já que quando termina o tempo, o Relé volta para o mesmo estado que estava. Por isso,  optei por não "registrar" este acionamento temporário do Relé (seja ON ou OFF) nas variáveis "schHighDT" e "schLowDT", pois isto certamente causaria confusão com os comandos que usam estas variáveis. Ao meu ver, isso faz muito mais sentido.

      Também, é registrado o evento de execução dos comandos "AH" e "AL", exatamente como ocorre para os demais comandos.  Porém quando a temporização do "AH" e "AL" termina,  devido ao comportamento "bate e volta"  eu optei por não fazer esse registro, pois isto me pareceu desnecessário.

      Para a implementação, vc precisa substituir a função "loop" do Arduino  no arquivo original "IeC111-IeCRele.ino".  Também precisa substituir a função "scheduleChk" que está no arquivo original "IeC111-IeCReleLib.h". Apenas essas duas funções precisam ser substituídas (nenhuma outra alteração é necessária).

      Para vc implementar outros comandos, siga o modelo para o "AH" ou o "AL", conforme mostro na figura a seguir (isto está dentro da função "scheduleChk"):

(clique na figura para "zoom")

      Se vc precisar de algum esclarecimento sobre como funciona o mecanismo, ou precisar de alguma orientação, só perguntar aqui.

      Para curiosidade,  veja como ficou o "loop" do Arduino, na figura a seguir:

(clique na figura para "zoom")

      E não se esqueça:  as funções "loop" e "scheduleChk"  devem ser totalmente substituídas.

      Assim, segue o arquivo com estas funções:    comandos_Millis_02.zip

      Observe que são arquivos tipo "txt", cada um com uma das funções a ser substituída.  Então basta selecionar o texto e dar "Control C" e "Control V".

      Importante:  não tenho o Hardware aqui (e também não tenho algumas bibliotecas),  por isso fiz algumas artimanhas pra compilar e me certificar que não haviam erros de compilação.  Logo, o teste "real" ficará por sua conta.  Acredito que irá funcionar, mas se algo não estiver Ok,  me avise que daremos o tratamento adequado.

      Abrçs,

      Elcids

Elcids, meus parabéns, fiz o upload e os comandos funcionaram , só teve um pequeno imprevisto o comando "AH" funcionou como um blink enquanto esteve dentro do intervalo desejado, ou seja até o final da contagem do minuto. desta forma inseri um hold() de 1 min depois do acionamento do rele em "process", vai atrapalhar um pouco durante o acionamento, mas não vai prejudicar o uso , agora funcionou que uma beleza rsrs.

Muito obrigado pelo empenho

Em anexo o arquivo funcional testado

IeC112-IeCRele.rar

olá novamente Tiago.

      Realmente,  existe este problema, mas já o resolvi sem precisar do "hold ".

      Ocorre que me esqueci que os comandos são executados em "unidades inteiras de minutos". Por este motivo, quando a verificação no "scheduleChk" é executada novamente após ter-se finalizado o "AH" ou o "AL" no código que postei, os minutos ainda não mudaram, o que acaba fazendo o comando ser executado novamente (ou seja, diversas vezes num período de 1 minuto).

      Para eliminar esse bug, registrei o minuto em que o comando é executado, de forma a impedir sua reexecução dentro daquele minuto. Esta correção também não afeta os comandos originais.

      Por favor, altere seu código pelo que estou postando agora,  pois este não tem o "hold " , e portanto dessa forma não bloqueia outras funções dentro do "loop" do Arduino (como o pisca do LED, check do WiFi, gerenciamento do "Server", etc).

      O código corrigido está aqui:   comandos_Millis_03.zip

      Obs.:  vc não precisa alterar novamente a função "loop" do Arduino,  embora ela também esteja no link acima (é o mesmo arquivo que postei antes, apenas mudei o nome para "funcao_loop_03.txt ").  Mas a função "scheduleChk" precisa ser substituída por completo pela "nova" que está no arquivo "funcao_scheduleChk_03.txt".

      Fico no aguardo de sua confirmação de que esta correção deixou o Sistema funcional (e sem o "hold").

      Abrçs,

      Elcids

Bom dia Elcids, agora ficou perfeito, fiz os testes e funcionou certinho muito obrigado pela ajuda, estava quebrando a cabeça com esse sistema a alguns meses.  Muito obrigado mesmo.

Em anexo a versão final testada

Anexos

RSS

© 2021   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço