Thread Rating:
  • 1 Vote(s) - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Risolto! Comandare upanel in modo asincrono anche da browser
#1
Ciao a tutti,
volevo farvi una domanda:
è possibile inviare stringhe get al modulo per far commutare i pin ?
Per esempio pensavo una cosa del genere:
scrivere nella barra degli indirizzi cosi' 192.168.1.5:2020/?#W11  e far cambiare stato anche all'app in base al comando ricevuto.
Cordiali saluti
Enzo
Reply
#2
Ciao Enzo,

si, è possibile inviare comandi tramite browser utilizzando le socket TCP. Per prima cosa devi installare un server su una porta, ad esempio 2020:

$TCP0:LAHQ::2020:OK

in pratica questo comando installa sulla porta 2020 un server che processa richieste HTTP. Appena il browser si collega, legge la richiesta GET e la invia ad Arduino (flag H), rispondendo al browser con il messaggio "OK" e chiudendo la connessione subito dopo (flag Q).

A questo punto devi processare la richiesto con Arduino. Ad esempio, inserendo nel browser:

http://192.168.1.103:2020/CMD?W10 

la risposta sarà del tipo:

Code:
$TCP0:CONNECTED
$TCP0:>H:GET /CMD?W11 HTTP/1.1
$TCP0:SENT:1
$TCP0:DISCONNECTED

Basta quindi andare a processare la seconda riga, estraendo tutto quello che segue il punto di domanda fino al primo spazio. 
Il codice che segue ad esempio preleva il testo dopo il punto di domanda, aggiunge il simbolo # e lo invia al modulo uPanel.


Code:
 if (WaitMessage(1))
 {
   if (Msg.substring(0,18).equals("$TCP0:>H:GET /CMD?"))
   {
     int p = Msg.substring(18).indexOf(" ");
     if (p > 0) Serial1.println("#"+Msg.substring(18,18+p));
   }
 }

Con questo codice potrai inviare qualunque aggiornamento del pannello da browser. Ad esempio:

http://192.168.1.103:2020/CMD?W10
http://192.168.1.103:2020/CMD?W11
http://192.168.1.103:2020/CMD?L11

etc..

Per ragioni di sicurezza cambierei CMD con una stringa più lunga, che funge da password.

Per completezza, allego tutto il codice provato su KIT3 (Cactus)


Code:
#define PIN_GPIO_0   12
#define PIN_CH_PD    13
#define PIN_RESET    22

void setup() {
 // put your setup code here, to run once:

 pinMode(PIN_GPIO_0, OUTPUT);
 pinMode(PIN_CH_PD,  OUTPUT);
 pinMode(PIN_RESET,  OUTPUT);
 
 digitalWrite(PIN_GPIO_0,1);
 digitalWrite(PIN_CH_PD,1);
 
 digitalWrite(PIN_RESET,0);  // Reset
 
 Serial.begin(57600);
 
 delay(250);
 
 digitalWrite(PIN_RESET,1);  // Release Reset
 
 delay(5000);
 Serial1.begin(57600);
 
 delay(5000);
 
 Serial1.println("$TCP0:LAHQ::2020:OK");
 Serial1.println("$P:W1:0;L1G:0:Test Led;");
 
}


String Msg = "";
/*****************************************************
* This function waits a data message from the uPanel
*
* Input: timeout_ms time to wait for message
*        -1 for forever
* Return: 0 = Timeout, 1 = Message received
******************************************************/
int WaitMessage(int timeout_ms)
{
 int c;                                // the received byte
 unsigned long entrytime = millis();   // Read the time at the function entry
 static char KeepBuffer = 0;           // This tells if we have a partial message in the buffer

 if (!KeepBuffer) Msg = "";            // If Keepbuffer is false than clear the old message
 KeepBuffer = 0;                       // in any case set now the keep buffer to false
 
 do
 {
   while ((c = Serial1.read()) > '\n') {Msg += (char) c;}  // Read incoming chars, if any, until new line
   if (c == '\n')                                       // is message complete?
   {
     //Serial.println(Msg);
     if (Msg.substring(0,1).equals("#")) return 1;      // if it is a data message return 1
     if (Msg.substring(0,1).equals("$")) return 1;      // if it is a data message return 1
     Msg = "";                                          // otherwise, wait for another one
   }
 } while ((timeout_ms < 0) || (millis()-entrytime < timeout_ms));  // has max time passed?
 
 KeepBuffer = 1;                                                   // Keep the partial buffer content
 return 0;                                                         // if time passed, return 0
}


void loop() {
 // put your main code here, to run repeatedly:

 int c = 0;
 
 if (WaitMessage(1))
 {
    if (Msg.substring(0,18).equals("$TCP0:>H:GET /CMD?"))
   {
     int p = Msg.substring(18).indexOf(" ");
     if (p > 0)
     {
       Serial1.println("#"+Msg.substring(18,18+p));
     }
   }
   
 }
 
 c = 0;  
 while(c >= 0)
 { c = Serial.read();  if (c >= 0) Serial1.write(c); }

}
Reply
#3
(06-11-2016, 06:26 PM)Simone Wrote: Ciao Enzo,

si, è possibile inviare comandi tramite browser utilizzando le socket TCP. Per prima cosa devi installare un server su una porta, ad esempio 2020:

$TCP0:LAHQ::2020:OK

in pratica questo comando installa sulla porta 2020 un server che processa richieste HTTP. Appena il browser si collega, legge la richiesta GET e la invia ad Arduino (flag H), rispondendo al browser con il messaggio "OK" e chiudendo la connessione subito dopo (flag Q).

A questo punto devi processare la richiesto con Arduino. Ad esempio, inserendo nel browser:

http://192.168.1.103:2020/CMD?W10 

la risposta sarà del tipo:

Code:
$TCP0:CONNECTED
$TCP0:>H:GET /CMD?W11 HTTP/1.1
$TCP0:SENT:1
$TCP0:DISCONNECTED

Basta quindi andare a processare la seconda riga, estraendo tutto quello che segue il punto di domanda fino al primo spazio. 
Il codice che segue ad esempio preleva il testo dopo il punto di domanda, aggiunge il simbolo # e lo invia al modulo uPanel.


Code:
 if (WaitMessage(1))
 {
   if (Msg.substring(0,18).equals("$TCP0:>H:GET /CMD?"))
   {
     int p = Msg.substring(18).indexOf(" ");
     if (p > 0) Serial1.println("#"+Msg.substring(18,18+p));
   }
 }

Con questo codice potrai inviare qualunque aggiornamento del pannello da browser. Ad esempio:

http://192.168.1.103:2020/CMD?W10
http://192.168.1.103:2020/CMD?W11
http://192.168.1.103:2020/CMD?L11

etc..

Per ragioni di sicurezza cambierei CMD con una stringa più lunga, che funge da password.

Per completezza, allego tutto il codice provato su KIT3 (Cactus)


Code:
#define PIN_GPIO_0   12
#define PIN_CH_PD    13
#define PIN_RESET    22

void setup() {
 // put your setup code here, to run once:

 pinMode(PIN_GPIO_0, OUTPUT);
 pinMode(PIN_CH_PD,  OUTPUT);
 pinMode(PIN_RESET,  OUTPUT);
 
 digitalWrite(PIN_GPIO_0,1);
 digitalWrite(PIN_CH_PD,1);
 
 digitalWrite(PIN_RESET,0);  // Reset
 
 Serial.begin(57600);
 
 delay(250);
 
 digitalWrite(PIN_RESET,1);  // Release Reset
 
 delay(5000);
 Serial1.begin(57600);
 
 delay(5000);
 
 Serial1.println("$TCP0:LAHQ::2020:OK");
 Serial1.println("$P:W1:0;L1G:0:Test Led;");
 
}


String Msg = "";
/*****************************************************
* This function waits a data message from the uPanel
*
* Input: timeout_ms time to wait for message
*        -1 for forever
* Return: 0 = Timeout, 1 = Message received
******************************************************/
int WaitMessage(int timeout_ms)
{
 int c;                                // the received byte
 unsigned long entrytime = millis();   // Read the time at the function entry
 static char KeepBuffer = 0;           // This tells if we have a partial message in the buffer

 if (!KeepBuffer) Msg = "";            // If Keepbuffer is false than clear the old message
 KeepBuffer = 0;                       // in any case set now the keep buffer to false
 
 do
 {
   while ((c = Serial1.read()) > '\n') {Msg += (char) c;}  // Read incoming chars, if any, until new line
   if (c == '\n')                                       // is message complete?
   {
     //Serial.println(Msg);
     if (Msg.substring(0,1).equals("#")) return 1;      // if it is a data message return 1
     if (Msg.substring(0,1).equals("$")) return 1;      // if it is a data message return 1
     Msg = "";                                          // otherwise, wait for another one
   }
 } while ((timeout_ms < 0) || (millis()-entrytime < timeout_ms));  // has max time passed?
 
 KeepBuffer = 1;                                                   // Keep the partial buffer content
 return 0;                                                         // if time passed, return 0
}


void loop() {
 // put your main code here, to run repeatedly:

 int c = 0;
 
 if (WaitMessage(1))
 {
    if (Msg.substring(0,18).equals("$TCP0:>H:GET /CMD?"))
   {
     int p = Msg.substring(18).indexOf(" ");
     if (p > 0)
     {
       Serial1.println("#"+Msg.substring(18,18+p));
     }
   }
   
 }
 
 c = 0;  
 while(c >= 0)
 { c = Serial.read();  if (c >= 0) Serial1.write(c); }

}

Ciao Simone,
intanto ti ringrazio per la risposta,
ho provato a modificare il mio sketch cosi':
Code:
void setup() {

 // Initialize Serial Port
 Serial.begin(57600);
 
 // Let uPanel start
 delay(3000);

 // Discharge old partial messages
 Serial.println("");
 
 // Send The Panel (A LED and a Switch)
 Serial.println("$P:Dg21;/5T*25fb:Prova;=*16/30{mL1G:0;|*12W1:0;|T:Relè 1;}/{mL2G:0;|*12W2:0;|T:Relè 2;}/30*20T#FF0ht3,000:Prova relè;");
 //server
 Serial.println("$TCP0:LAHQ::2020:OK");
 // Initialize digital output pin
 digitalWrite(8, 0);
 pinMode(8,OUTPUT);
 digitalWrite(9, 0);
 pinMode(9,OUTPUT);
 
}

String Msg;

void loop() {

 int c;
 while ((c = Serial.read()) > '\n') Msg += (char) c;  // Read incoming chars, if any, until new line
 if (c == '\n')                                       // is the message complete?
 {
   if (Msg.equals("#W20")) {digitalWrite(9,0); Serial.println("#L20");}
   if (Msg.equals("#W21")) {digitalWrite(9,1); Serial.println("#L21");}    
   if (Msg.equals("#W10")) {digitalWrite(8,0); Serial.println("#L10");}    
   if (Msg.equals("#W11")) {digitalWrite(8,1); Serial.println("#L11");}  
   if (Msg.substring(0,18).equals("$TCP0:>H:GET /CMD?"))
  {
    int p = Msg.substring(18).indexOf(" ");
    if (p > 0)
    {
      Serial.println("#"+Msg.substring(18,18+p));
    }
  }
   Msg = "";
 }
   
}
 forse ho dimenticato qualcosa, perchè quando invio questa stringa da browser:http://192.168.1.2:2020/CMD?W11
cambia sato solo l'interuttore ma il relè non commuta e il led di stato non cambia, stessa cosa se invio http://192.168.1.2:2020/CMD?L11 , il led diventa verde ma non commuta nulla.
Dove sbaglio?
Cordiali saluti
Enzo

Specifico che sto usando arduino uno e quindi ho modificato il serialprint1
Reply
#4
Dipende forse dal tipo di relè che usi che potrebbero essere a logica invertita. Quindi nel setup li devi impostare con digitalWrite(8,1) e metterli a 0 quando invii la stringa
Reply
#5
(06-13-2016, 10:25 PM)Dok Wrote: Dipende forse dal tipo di relè che usi che potrebbero essere a logica invertita. Quindi nel setup li devi impostare con digitalWrite(8,1) e metterli a 0 quando invii la stringa

Ciao Dok,
non è questo il problema,  perché se premo i tasti manualmente sull'applicazione i relè commutano correttamente. 
C'è qualcosa di sbagliato a livello di sketch che ho dovuto adattare su arduino uno e sicuramente manca qualcosa.
Reply
#6
Enzo,

il codice che ti ho riportato, aggiorna soltanto lo stato della grafica, ma non agisce sui rele. Quello lo deve fare Arduino in base al messaggio che riceve. Il modo più semplice è modificare il tuo sketch come segue:

Code:
void setup() {

 // Initialize Serial Port
 Serial.begin(57600);
 
 // Let uPanel start 
 delay(3000);

 // Discharge old partial messages
 Serial.println("");
 
 // Send The Panel (A LED and a Switch)
 Serial.println("$P:Dg21;/5T*25fb:Prova;=*16/30{mL1G:0;|*12W1:0;|T:Relè 1;}/{mL2G:0;|*12W2:0;|T:Relè 2;}/30*20T#FF0ht3,000:Prova relè;");
 //server
 Serial.println("$TCP0:LAHQ::2020:OK");
 // Initialize digital output pin
 digitalWrite(8, 0);
 pinMode(8,OUTPUT);
 digitalWrite(9, 0);
 pinMode(9,OUTPUT);
 
}

String Msg;

void loop() {

 int c;
 while ((c = Serial.read()) > '\n') Msg += (char) c;  // Read incoming chars, if any, until new line
 if (c == '\n')                                       // is the message complete?
 { 

   if (Msg.substring(0,18).equals("$TCP0:>H:GET /CMD?"))
   {
    int p = Msg.substring(18).indexOf(" ");
    if (p > 0)
    {
      Msg = "#"+Msg.substring(18,18+p);
      Serial.println(Msg);
    } 
   } 

   if (Msg.equals("#W20")) {digitalWrite(9,0); Serial.println("#L20");}
   if (Msg.equals("#W21")) {digitalWrite(9,1); Serial.println("#L21");}    
   if (Msg.equals("#W10")) {digitalWrite(8,0); Serial.println("#L10");}    
   if (Msg.equals("#W11")) {digitalWrite(8,1); Serial.println("#L11");}  
   Msg = "";
 } 
   
}

In pratica ho spostato in alto la gestione del messaggio della socket TCP e ho inserito il comando ricevuto in Msg in modo che i test successivi
funzionino come se il messaggio arrivasse da pannello.
Reply
#7
Grazie mille Simone,
adesso funziona correttamente.
Effettivamente non ho pensato che era meglio mettere il codice prima degli if in modo che arduino interpetra ed agisce in base al comando ricevuto.
Funziona perfettamente.
Presto pubblichero' un mio nuovo progetto sul forum usando proprio questa funzione in modo tale che puo' tornare utile anche ad altri.
Buona giornata
Enzo

Ho ancora un ultima domanda:
e se volessimo leggere gli stati da remoto?
Reply
#8
Prendendo spunto dai contributi del forums, ho provato a creare un semplice pannello di prova per poter comandare il led on board di arduino nano in maniera asincrona da APP che da browser.
Il mio provider è Fastweb ed attraverso il mapping del router ho aperto le porte stadar del upanel 80 e 81 su porte interne 5555 e 9999

Attraverso l'IP pubblico (2.227.18.135:5555) riesco a raggiungere il modulo tramite internet tanto che con la APP (connessa su APN Vodafone) i comandi impartiti vengono correttamente eseguiti.

Per quanto riguarda invece l'invio attraverso richiesta HTTP, non c'è verso di far leggere la richiesta GET utilizzando nel browser l'URL con public IP 2.227.18.135:5555/CMD?W21, diversamente è perfettamente funzionante in maniera asincrona con la APP se nel browser inserisco l'indirizzo LAN del modulo (192.168.1.130:5555).

Questo è lo sketch:

void setup()
{
Serial.begin(57600);
digitalWrite(13, 0);
pinMode(13,OUTPUT);
delay(3000);
Serial.println("");
Serial.println("$PING 200");
Serial.println("$config");
Serial.println("$STAIP 192.168.1.130 192.168.1.254 255.255.255.0"); //setto l'indirizzo IP fisso,Gatway,Subnet
Serial.println("$CONNECT:user:password"); //Si collega alla rete wifi esistente
Serial.println("$CONNSTA");
Serial.println("$NOROUTER");
Serial.println("$ROUTER:5555:9999"); //setta le porte del router per accesso TCP da Internet
Serial.println("");
Serial.println("$PBig Gring21;/5T*25fbTonguerova;=*16/30{mL2G:0;|*12W2:0;|T:Rele 2;}/30*20T#FF0ht3,000Tonguerova rele;");
Serial.println("$TCP0:LAHQ::6888:OK");
}
String Msg;
void loop()
{
int c;
while ((c = Serial.read()) > '\n') Msg += (char) c;
{
if (Msg.substring(0,18).equals("$TCP0:>H:GET /CMD?"))
{
int p = Msg.substring(18).indexOf(" ");
if (p > 0)
{
Msg = "#"+Msg.substring(18,18+p);
Serial.println(Msg);
}
}
if (Msg.equals("#W20")) {digitalWrite(13,0); Serial.println("#L20");}
if (Msg.equals("#W21")) {digitalWrite(13,1); Serial.println("#L21");}
Msg = "";
}
}
Potete aiutarmi a risolvere il problema.
Grazie.
Reply
#9
Ciao,
devi aprire una terza porta tcp nel router per raggiungere il webserver miupanel.
Nel tuo caso hai impostato questo: Serial.println("$TCP0:LAHQ::6888:OK");
Quindi sta a significare che tramite il tuo ip pubblico + la porta 6888 raggiungi il server che hai creato sul miupanel.
Cosi':2.227.18.135:5555/CMD?W21 non è corretto.
Cosi' SI : 2.227.18.135:6888/CMD?W21.
Tra l'altro se hai una versione di firmware miupanel almeno A004A, ti basta sbaffare la voce connect via cloud e non hai bisogno di aprire le porte tcp e udp per raggiungere il modulo da remoto, farà tutto automaticamente.
Se invece crei un webserver sul modulo dovrai sempre aprire la porta tcp che hai impostato nello sketch per impartire i comandi anche da un qualsiasi browser.
Spero di esserti stato d'aiuto
Ciao
Enzo
Reply
#10
Grazie Enzo,
purtroppo ho riportato una versione dello sketch errata, quella giusta riporta la riga Serial.println("$TCP0:LAHQ::5555:OK");
e quindi il sistema dovrebbe essere in grado di rispondere sia alla chiamata il LAN 192.168.1.130:5555//CMD?W21 che in WAN 2.227.18.135:5555/CMD?W21.
Quello che non riesco a comprendere è perché il modulo è raggiungibile da IP pubblico con la App [settata su 2.227.18.135 (5555,9999)] e non lo è invece dal browser sullo stesso indirizzo [2.227.18.135:5555].
Vorrei riuscirci senza aggiornare la versione del firmware, dovrebbe funzionare.
Grazie.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)