impostare timer via bluetooth

Ciao ragazzi,

devo ampliare un progetto già funzionante. Ho già questa config:

ARDUINO UNO + HC-05 + MODULO RELE'

via smartphone android piloto il tutto accendendo, spegnendo o temporizzando lo spegnimento del carico collegato al relè. Ora se montassi nel progetto un RTC posso inviare una precisa ora di accensione e spegnimento?

Nicola

droidprova:
C... Ora se montassi nel progetto un RTC posso inviare una precisa ora di accensione e spegnimento?

Perché no ? Il BT è una normale comunicazione seriale ... tutt'è saper gestire questo tipo di comunicazione, il resto è semplice :slight_smile:

Guglielmo

Forse mi sono espresso male, anzi sicuramente mi sono espresso male. Mettendo un rtc nel circuito e sapendo come inviare dei dati al BT di Arduino, come interagisco con la libreria del RTC?

Pensavo di dichiarare delle variabile del tipo:

H=hour.now();
M=minute.now();

e poi con degli if imposto la condizione per accendere il relè e quello x spegnerlo. Giusto o esiste un sistema migliore?

Grazie

Il bluetooth è anche bidirezionale.
Con la app blueterm si può capire quali valori stai trattando.
In generale è arduino che va programmato per capire i comandi. Per esempio potresti inviare un comando T3ON-NOW+60SEC.
Si estrapola dal comando che il timer 3 (forse l’ uscita 3) si avvia da ora per 60 secondi. Ma è ovvio che arduino deve leggere il comando, quindi:

  • T3 significa che è il timer tre sulla uscita 3 (forse)
  • NOW significa che deve andare a prendere l’ orario del RTC e metterlo in una variabile
  • Oppure impostare un allarme dentro l’ RTC che dal calcolo di NOW somma il periodo e lo salva
  • 60SEC/MIN/HOUR si definisce quanto e che misura si vuole impostare

Sarebbe meglio se mostri il codice che hai preparato, al massimo gli si aggiunge qualche correzione.

Devo ampliare un’ app che ho scritto con app inventor. Attraverso l’attributo datapicker, riesco ad avere una finestra pop-up con la quale poter selezionare l’ora (eventualmente anche la data), il fatto è che come output ottengo del testo tipo:

8:56 PM ; 11:32 AM ecc ecc

con del testo così posso in qualche modo istruire arduino affinchè interpreti questo input e lo possa confrontare con quello del RTC?

Puoi già definire che il carattere punto-virgola è un delimitatore. i due-punti sono separatori tra ore e minuti.
Poi dovresti fare la decodifica tra ASCII e binario, vedere in che maniera sono salvati dentro l' RTC. Da queste due informazioni devi convertire in un formato uguale che potrai usare.
Beh, piuttosto scontato che sia numerico. Ma a quanto pare quello della app è in formato ASCII.

aspetta il carattere ; non esiste, i due orari separati dal ; erano degli esempi per mostrare il tipo di formattazione oraria che mi restituisce l'app.

Sono già riuscito ad ottenere una formattazione sulle 24 H, cioè:

08:00 oppure 23:49 ecc ecc cioè senza AM e PM. Inoltre le ore 24 le faccio risultare 00 come fa la libreria adafruit per l'RTC.

Che dici così è più semplice gestire questo formato?

Dipende da cosa ricavi dall' RTC. Che consiglio di scaricarti il foglio dati, per vedere come sono salvati e ricavati i dati interni. Sebbene lo trovi su modulino, ti sarà utile capire che circuito integrato monta per poterlo usare correttamente.
Si potrebbe anche sommare tutti i valori per ricavare una long, a scopo di confronto e calcolo. Però da questa poi dovresti anche ritornare indietro ai valori separati delle ore, minuti e secondi, se li vorrai modificare nell' RTC.

Se via BT dalla app invio una stringa del tipo:

Nora60+minuti --> per accendere
Fora
60+minuti --> per spegnere

dove l'ora e i minuti x l'accensione/spegnimento sono espressi sotto forma di una stringa formata da una lettera e da un unico numero che esprime solo i minuti.

Mentre dal lato arduino scrivo questo:

if (!bluetooth.available()) {
    if (message != "") { 

      if ((message == "N") && (now.hour() * 60 + now.minute() == bluetooth.parseInt())) {
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        delay(20);
      }
      if ((message == "F") && (now.hour() * 60 + now.minute() == bluetooth.parseInt())) {
        digitalWrite(rele, LOW);
        digitalWrite(LED, LOW);
        delay(20);
      }
  }
}

che dite può funzionare?

Io ho usato un altro metodo.
Innanzitutto ci vuole un buffer che contiene la stringa da ricevere. Poi puoi partizionare il contenuto e fare le dovute comparazioni e/o conversioni da ASCII a binario.
Comunque, prova a farci vedere come è il message.

Poi il progetto come il tuo l' ho già sviluppato e può pilotare fino a 8 relè, fissi o temporizzati.
Solo ha il limite di 9 ore massime. Salvo modificare il tipo di memorizzazione che è solo una int, si può anche aumentare per una long

Ciao Experiment dunque io dichiaro:

String message = "";

e questo è il loop:

if (!bluetooth.available()) {
    if (message != "") { 
      if (message == "H") {
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        delay(50);
        message = ""; //clear the data
      }
      if (message == "L") {
        digitalWrite(rele, LOW);
        digitalWrite(LED, LOW);
        delay(50);
        message = ""; //clear the data
      }
      if (message == "1") {
        OldMillis = millis();
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        delay(50);
        message = "";
        stato = 1;
      }
      if (message == "2") {
        OldMillis = millis();
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        delay(20);
        message = "";
        stato = 2;
      }
      if (message == "3") {
        OldMillis = millis();
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        delay(20);
        message = "";
        stato = 3;
      }
      if ((message == "N") && (now.hour() * 60 + now.minute() == bluetooth.parseInt())) {
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        delay(20);
      }
      if ((message == "F") && (now.hour() * 60 + now.minute() == bluetooth.parseInt())) {
        digitalWrite(rele, LOW);
        digitalWrite(LED, LOW);
        delay(20);
      }
    }
  }
  if (stato == 1) {

    if (millis() - OldMillis > 7200000) {      // temporizzazione 2H
      //if (millis() >= (OldMillis + 7200000)) {
      digitalWrite(rele, LOW);
      digitalWrite(LED, LOW);
      OldMillis = millis();
      stato = 0;
    }
  }
  if (stato == 2) {

    if (millis() - OldMillis > 14400000) {      // temporizzazione 4H
      //if (millis() >= (OldMillis + 14400000)) {
      digitalWrite(rele, LOW);
      digitalWrite(LED, LOW);
      OldMillis = millis();
      stato = 0;
    }
  }
  if (stato == 3) {                            // temporizzazione 6H

    if (millis() - OldMillis > 21600000) {
      //if (millis() >= (OldMillis + 21600000)) {
      digitalWrite(rele, LOW);
      digitalWrite(LED, LOW);
      OldMillis = millis();
      stato = 0;
    }
  }
}

come vedi ho un comado di ON e OFF secco e tre temporizzazioni a 2, 4 e 6 ore gestite tramite millis. Il tutto è funzionante. L'input arriva dalla mia app che invia i comandi via BT. Ora vorrei aggiungere un comando di ON e OFF con l'ora personalizzata.A tal punto trovi la parte di codice verso la fine del loop. Dal lato Android sono ok, i comandi partono correttamente inviando stringhe del tipo:

N750 che significa N=ON 750 è la risultante di 12Hx60+30 minuti. Per far l'ON alle 12:30.

La modalità scelta è flessibile, nel senso che risulta errata posso rivederla senza indugio.

Ora siccome il mio attuatore BT è inserito in un circuito, vorrei smontarlo fare l'aggiornamento dello sketch e riposizionarlo subito dov'è. Per cui chiedo se l'idea del serial.parseint (letta dal libro di Banzi dove presenta la comunicazione seriale come possibile invio di stringhe per comandare delle valvole), può funzionare.

Ciao

Mentre questa è l'interfaccia grafica dell'app:

e pigiando "Imposta ora ON" o "Imposta ora OFF" richiama il componente data picker che apre a sua volta il popup di selezione:

la Serial.ParseInt dice che inizia ad interpretare tutte le cifre dalla prima incontrata a quando non è più una cifra od a raggiungimento di timeout. Se la scansione inizia con un meno, allora verrà incluso.
Nel tuo caso, se hai un N750, ParseInt ti ritorna 750. Se fosse N-750abcd ti ritorna -750.

Bello il programma di Android, dove si scarica?

Perfetto, allora ho inteso bene e per di più dovrebbe funzionare ciò che ho scritto. L'app l'ho fatta io con mit app inventor 2. Grazie per aver gradito.

Ragazzi vi posto un codice, si tratta di una sorta di attuatore comandato via BT. Le funzioni sono di ON e OFF secco più tre comandi temporizzati da 2, 4 e 6 ore gestiti tramite millis().
Bene, finchè l’oggetto è installato in casa e si inviano semplici comandi di ON e OFF secchi, va tutto bene, non perde un colpo. Da qualche giorno, l’oggetto è sul balcone per pilotare delle luci a led natalizie. Sul balcone in questi giorni specie di notte si scende sotto zero e c’è molto umido. L’elettronica è racchiusa in una cassetta stagna.
Vengo al dunque, se utilizzo i comandi di temporizzazione, l’indomani se provo ad inviare un ON secco, Arduino non risponde. Idem se interrompo un comando di temporizzazione con un Off secco, Arduino non risponde e c’è bisogno di un reset.

Vi posto il codice, a me sembra tutto ok. E’ solo colpa della temperatura bassa oppure ho scritto delle cavolate?

/*===================================================================

  Collegamenti del HC-05 (ZS0-40/GW0-40) ad Arduino:
  Vcc -> +5V
  GND -> GND
  TXD  -> D10
  RXD  -> D11
  State -> D4
  Collegamenti del modulo relè:
  IN -> D8
  Vcc -> +5V
  GND -> GND

  ==================================================================== */


#include <SoftwareSerial.h>
int rxPin = 10;
int txPin = 11;
SoftwareSerial bluetooth(rxPin, txPin);
#define LED 4
#define rele 8
String message = ""; //string that stores the incoming message
unsigned long OldMillis = 0;
int stato = 0;

void setup()
{
  bluetooth.begin(9600); //set baud rate
  pinMode(rele, OUTPUT);
  pinMode(LED, OUTPUT);
  digitalWrite(rele, LOW);
  digitalWrite(LED, HIGH);
  delay(250);
  digitalWrite(LED, LOW);
}

void loop()
{
  while (bluetooth.available()) {
    message += char(bluetooth.read());
  }
  if (!bluetooth.available())
  {
    if (message != "")
    { //if data is available
      if (message == "H") {
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        delay(50);
        message = ""; //clear the data
      }
      if (message == "L") {
        digitalWrite(rele, LOW);
        digitalWrite(LED, LOW);
        delay(50);
        OldMillis = millis();
        stato = 0;
        message = ""; //clear the data
      }
      if (message == "1") {
        OldMillis = millis();
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        delay(50);
        message = "";
        stato = 1;
      }
      if (message == "2") {
        OldMillis = millis();
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        delay(20);
        message = "";
        stato = 2;
      }
      if (message == "3") {
        OldMillis = millis();
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        delay(20);
        message = "";
        stato = 3;
      }
    }
  }
  if ((stato == 1) && (millis() - OldMillis > 7200000)) {      // temporizzazione 2H
    digitalWrite(rele, LOW);
    digitalWrite(LED, LOW);
    delay(20);
    OldMillis = millis();
    stato = 0;
    message = "";
  }
  if ((stato == 2) && (millis() - OldMillis > 14400000)) {    // temporizzazione 4H
    digitalWrite(rele, LOW);
    digitalWrite(LED, LOW);
    delay(20);
    OldMillis = millis();
    stato = 0;
    message = "";
  }
  if ((stato == 2) && (millis() - OldMillis > 21600000)) {    // temporizzazione 6H
    digitalWrite(rele, LOW);
    digitalWrite(LED, LOW);
    delay(20);
    OldMillis = millis();
    stato = 0;
    message = "";
  }
}

Grazie Nicola

Ma funzione con AppInventor ?
Io ho usato altri programmi dl playstore, il quale ho riscontrato il problema che non inviano nessun carattere di terminazione della stringa. Ma credo che nel tuo caso la risposta è immediata perché si aspetta solo un singolo carattere.

Se vuoi ti passo il mio progetto.

Si, i comandi vengono inviati dall' app scritta con app inventor. In merito allo sketch, come ti sembra, vedi errori?

Grazie

Quello che mi ha colpito è un if (message != “”) che in breve si traduce con if (!message)
Poi avrei messo un switch

switch message {
    case "H":
         // fa qualcosa ;
      break;
    case "L": {
         // fa qualcosa ;
     }
     break;
     case "1": {
         // fa qualcosa ;
     }
     break;
     case "2": {
         // fa qualcosa ;
      }
      break;
}
switch stato {
    case 1: {
        digitalWrite(rele, LOW);
        digitalWrite(LED, LOW);
    }
    break;
   case 2: {
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
    }
    break;
}

Ti evita anche di cancellare in tutti gli if il message = “”.
Ovvero con lo switch cogli il solo valore che vuoi monitorare e salta tutti gli altri. Con if else if else invece puoi verificare con un specchio di valori come viene permesso dalla formula di un if. Per esempio if ((x>0) && (x<9)), che non si può fare con un switch.

Capisco che, come me, ci sono ancora diverse cose che non ho imparato e si adotta la prima che funziona.

Grazie per il suggerimento, provo a riscrivere l'intero sketch adottando gli switch case e vediamo se il tutto risulta più stabile.

Nicola

Giusto per parlare...premetto che non ho provato il codice e non l'ho nemmeno inserito nell'ide, quindi sicuramente ci sono castronerie di sintassi, ma uno switch case può comandare un secondo switch case?

switch (message) {
    
    case "H":
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        delay(50);
      break;

    case "L": 
        digitalWrite(rele, LOW);
        digitalWrite(LED, LOW);
        delay(50);
     break;

     case "1": 
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        delay(50);
        stato = 1;
     break;

     case "2": 
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        delay(50);
        stato = 2;
      break;
     case "3": 
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        delay(50);
        stato = 3;
      break;
}

switch (stato) {
    case 1: 
       if (millis() - OldMillis > 7200000){      // temporizzazione 2H
       digitalWrite(rele, LOW);
       digitalWrite(LED, LOW);
       delay(20);
       OldMillis = millis();
       stato = 0;
      } 
     break;

   case 2: 
      if (millis() - OldMillis > 14400000){    // temporizzazione 4H
      digitalWrite(rele, LOW);
      digitalWrite(LED, LOW);
      delay(20);
      OldMillis = millis();
      stato = 0;
     }  
    break;

   case 3: 
      if (millis() - OldMillis > 21600000){    // temporizzazione 6H
      digitalWrite(rele, LOW);
      digitalWrite(LED, LOW);
      delay(20);
      OldMillis = millis();
      stato = 0;
     }  
    break;
}