Arduino klient - ovládanie z webu

H107
Příspěvky: 10
Registrován: 21 bře 2018, 17:51
Reputation: 0

Arduino klient - ovládanie z webu

Příspěvek od H107 » 12 dub 2018, 10:10

Zdravím,

potrebujem pomoc s programovaním arduina, išiel som podľa tohto návodu:

https://arduino.cz/programovani-webovyc ... o-arduino/

Výstup z php stránky je ako v návode "led:1: resp. led:0:" ale arduino nereaguje. Napadlo mi, či to nie je spôsobené free hostingom, ktorý na stránku pridáva reklamu a tým pádom to arduino neprečíta..

Večer skúsim podľa rady autora článku vypísať obsah client.read(). Inak kde ešte hľadať chybu, resp. ak mi niekto vie poradiť iný spôsob, budem rád...

Vďaka

martinius96
Příspěvky: 579
Registrován: 01 srp 2017, 19:29
Reputation: 0
Bydliště: Poprad
Kontaktovat uživatele:

Re: Arduino klient - ovládanie z webu

Příspěvek od martinius96 » 12 dub 2018, 10:15

Ja si to ukladám do .txt súboru cez PHP ten stav LED-ky (výstupu) a ten čítam.. ale dá sa to použiť aj na PHP stránku.
Dôležité je si odrátať riadky, aby to prečítalo iba ten riadok, ktorý má a nie celú response, ktorá aj tak prichádza po jednom znaku.
Potrebuješ si obsah parsovať.
https://arduino-forum.cz/viewtopic.php?f=38&t=432

H107
Příspěvky: 10
Registrován: 21 bře 2018, 17:51
Reputation: 0

Re: Arduino klient - ovládanie z webu

Příspěvek od H107 » 12 dub 2018, 17:33

Toto je použitý kód:

Kód: Vybrat vše

#include <SPI.h>
#include <Ethernet.h>

#define BUFF_DELKA 255

byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x9C, 0xB7}; //MAC adresa
IPAddress ip(10,0,0,3); //IP adresa
char server[] = "xxx"; //URL adresa serveru   

char buffer[BUFF_DELKA]; //zásobník na příchozí řetězec

EthernetClient client;

void setup() {
    pinMode(8, OUTPUT);
    
    Serial.begin(9600);
    
    if (Ethernet.begin(mac) == 0) {
        Ethernet.begin(mac, ip);
    }
    delay(1000);
}

void loop() {
    if(client.connect(server, 80)){
        delay(1000);
        client.println("GET xxx.php");
        client.println("Host: xxx");
        client.println("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        client.println("Connection: close");
        client.println();

        delay(1000);

        int inBuffer = 0;

        for(int i = 0; i < BUFF_DELKA; i++){ //vyprázdní buffer
            buffer[i] = '\0'; //nastaví všechny prvky buffer na znak konce řetězce
        }
        
        while(client.available()){
            buffer[inBuffer] = client.read();    
            inBuffer++;
        }
        
        if(inBuffer == 6){
            if(buffer[0] == 'l' && buffer[1] == 'e' && buffer[2] == 'd'){
                if(buffer[4] == '1'){
                    digitalWrite(8, HIGH);
                }
                else{
                    digitalWrite(8, LOW);
                }
                Serial.println(buffer[4]);
            }
        }

        client.stop();
    }

    delay(1000);
}

za časť buffer[inBuffer] = client.read(); som podľa rady autora dal Serial.print(buffer[inBuffer]);

ale seriova linka vôbec nič nezobrazuje, takže asi problém s pripojením?

H107
Příspěvky: 10
Registrován: 21 bře 2018, 17:51
Reputation: 0

Re: Arduino klient - ovládanie z webu

Příspěvek od H107 » 12 dub 2018, 20:40

Skušal som to takto: https://arduino-forum.cz/viewtopic.php?f=38&t=432

a funguje mi to. Keď som ale použil namiesto txt súboru pôvodné php (len aby som zistil, čo vypíše serial, lebo hodnoty by aj tak nesedeli), tak sa zobrazil celý html kód asi stránky, na ktorú sa dopyt, neviem prečo, presmeroval..

zbysek
Site Admin
Příspěvky: 125
Registrován: 22 úno 2017, 15:18
Reputation: 0

Re: Arduino klient - ovládanie z webu

Příspěvek od zbysek » 14 dub 2018, 15:55

Tak ještě zkuste za

Kód: Vybrat vše

if(client.connect(server, 80)){
dát nějaký výpis - třeba:

Kód: Vybrat vše

Serial.println("pripojeno")
do else bloku k tomuto ifu si dejte výpis "nepřipojeno", at víte, jestli se připojení povedlo.

H107
Příspěvky: 10
Registrován: 21 bře 2018, 17:51
Reputation: 0

Re: Arduino klient - ovládanie z webu

Příspěvek od H107 » 14 dub 2018, 22:27

Po úprave sériová linka teraz vypisuje:

pripojene
<!DOCTYPE html>
<html>
<head>
<script>
dataLayer = [];
</script>
<script>

(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.cr⸮

zbysek
Site Admin
Příspěvky: 125
Registrován: 22 úno 2017, 15:18
Reputation: 0

Re: Arduino klient - ovládanie z webu

Příspěvek od zbysek » 15 dub 2018, 15:58

Tak je to jasné. Je problém v tom, že server vrátí navíc balast, který arduino nečeká.
Musíte tedy načítat znaky, dokud nenarazíte na text "led:" a pak přečíst další znak -> to bude ta 0/1.
Jde to udělat různě, jeden ze způsobů navrhl martinius.

Taky by to šlo tak, že si vytvoříte pole na čtyři znaky a budete přidávat nový znak vždy na konec.
Před načtením tedy posunete všechny prvky doleva a na poslední pozici načtete nový znak.
Poté porovnáte, jestli jsou znaky rovné ['l','e','d',':']. Pokud ano, načtete další znak a to bude 0/1, pokud ne, načítáte takto pořád dokola příchozí znaky.

H107
Příspěvky: 10
Registrován: 21 bře 2018, 17:51
Reputation: 0

Re: Arduino klient - ovládanie z webu

Příspěvek od H107 » 23 črc 2018, 20:57

Priebežne som na svojom "projekte" pracoval ale, nakoľko som ho počas zostavovania priebežne menil, až teraz som sa k niečomu skoro funkčnému dopracoval. K zostave arduino + ethernet shield mám pripojené senzory atm. tlaku, teploty a vlhkosti - údaje arduino posiela každých cca 30 min. na web, ďalej modul s relé na zapínanie vonk. led svietidla cez web (osvetlenie priestoru pred IP kamerou) - použil som návod od martinusa a čítam stav 0/1 z txt súboru.. Zároveň mám cez iné relé pripojený obyč. senzor pohybu, ktorý spúšťa prostredníctvom arduina "poplach" - php kód na webe pošte mail. Touto cestou sa chcem poďakovať za rady a návody aj z tohto fóra. Doma všetko funguje ako má, avšak na chalupe, kde som minulý týždeň celé zariadenie testoval vznikol problém so stabilitou - po určitom čase (2 - 5 hod.) sa zariadenie zasekne, po reštarte znova dočasne funguje atd... Prípájam celý kód:

Kód: Vybrat vše

#include <SPI.h>
#include <Ethernet.h>
#include "DHT.h"
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
#define pinDHT 9
#define BMP280_ADRESA (0x76)
#define typDHT22 DHT22
byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x9C, 0xB7}; //MAC adresa
IPAddress ip(10,0,0,3); //IP adresa
char server[] = "SERVER"; //URL adresa serveru   
EthernetClient client;
String readString;
int x=0; //pocitadlo riadkov
char lf=10; //line feed character
Adafruit_BMP280 bmp;
int korekce = 0;
DHT mojeDHT(pinDHT, typDHT22);
unsigned long kon;
unsigned long cas_aktMs;
unsigned long cas_preMs;
unsigned long cas_aktSv;
unsigned long cas_preSv;
unsigned long cas_aktPo;
unsigned long cas_prePo;
int poc;
int zap;
int popl = 0;
int tlac2 = 0;
int t1State = 0;    // proměnná pro čtení stavu tlačítka 
int t2State = 0;
int t3State = 0;
int r1State = 0;
int r2State = 0;

void setup() {
 pinMode(7, OUTPUT);
 pinMode(5, OUTPUT);
 pinMode(2, OUTPUT);
 digitalWrite(2, HIGH);
 pinMode(3, OUTPUT);
 digitalWrite(3, HIGH);
 pinMode(8, INPUT);
 pinMode(6, INPUT);
 pinMode(4, INPUT);
 pinMode(A2, INPUT);
 pinMode(A3, INPUT);
 Serial.begin(9600); 
  mojeDHT.begin();
  bmp.begin(BMP280_ADRESA);
  if (Ethernet.begin(mac) == 0) {
       Ethernet.begin(mac, ip);
   }
   delay(1000);
}

//ODOSIELANIE METEODÁT
void loop(){
  cas_aktMs = millis();
   if(cas_aktMs - cas_preMs > 1800000) {
    Serial.println("Chyba konfiguracie cez DHCP");
    cas_preMs = cas_aktMs;
    if (Ethernet.begin(mac) == 0) {                  //V PRIPADE ZLYHANIA NASTAVENIA MAC ADRESY VYPIŠ  
     }
     for (int i = 0; i < 4; i++) {                   //CYKLUS FOR, VYKONA SA 4-KRAT S BLIKANIM LED DIODY (IMITACIA PRIPAJANIA NA WEBSERVER)  
     }                                               // POZDRZANIE STAVU NA 150ms    
     if (client.connect(server, 80)) {               // AK SA NAPOJI NA SERVER NA PORTE 80 (HTTP)  
      Serial.println("Odosielanie meteodát - pripojené");
      client.print("GET /zapis.php?temp1=");         //ZAČIATOK HTTP REQUEST --> client.print GET METODOU s oznacenim premennej, do ktorej pridame hodnotu v URL  
      client.print(mojeDHT.readTemperature());    // VYPIS HODNOTY 1. SENZORU NA INDEXE 0 DO URL  
      client.print("&temp2=");                     //TEXTOVE DOPLNENIE DRUHEJ PREMENNEJ DO KTOREJ UVEDIEME COMU SA ROVNA TAKTIEZ V URL  
      client.print(bmp.readTemperature());    // VYPIS HODNOTY 2. SENZORU NA INDEXE 1 DO URL  
      client.print("&hum1=");                      //TEXTOVE DOPLNENIE TRETEJ PREMENNEJ DO KTOREJ UVEDIEME COMU SA ROVNA TAKTIEZ V URL  
      client.print(mojeDHT.readHumidity());          // VYPIS VLHKOMERU DO LINKU, HODNOTA, KTOREJ SA ROVNA PREMENNA HUM1  
      client.print("&pres1=");                     //TEXTOVE DOPLNENIE STVRTEJ PREMENNEJ DO KTOREJ UVEDIEME COMU SA ROVNA TAKTIEZ V URL  
      client.print((bmp.readPressure()/100.00) + korekce); // VYPIS BAROMETRA DO LINKU + PRIPOCITANA KONSTANTA NA ZAKLADE NADMORSKEJ VYSKY PRE SPRAVNY PREPOCET NA RELATIVNY TLAK  
      client.println(" HTTP/1.1");                 // UKONCENIE REQUESTU ZALOMENIM RIADKA A DOPLNENIM HLAVICKY HTTP S VERZIOU  
      client.println("Host: SERVER"); // ADRESA HOSTA, NA KTOREHO BOL MIERENY REQUEST (NIE PHP SUBOR)  
      client.println("Connection: close");         //UKONCENIE PRIPOJENIA ZA HTTP HLAVICKOU  
      client.println();                            //ZALOMENIE RIADKA KLIENTSKEHO ZAPISU  
      for (int i = 0; i < 3; i++) {                 //CYKLUS FOR, VYKONA SA 3-KRAT S BLIKANIM LED DIODY MODREJ (IMITACIA ODOSLANIA HTTP REQUESTU S HODNOTAMI)  
      delay(400);                                // POZDRZANIE STAVU NA 400ms  
      delay(150);  // POZDRZANIE STAVU NA 150ms 
      }
      client.stop(); // UKONCENIE PRIPOJENIA ETHERNET SHIELDU  
     }
    }
//OVLÁDANIE SVETLA
  cas_aktSv = millis();
   if(cas_aktSv - cas_preSv > 1000) {
    cas_preSv = cas_aktSv; 
    if (client.connect(server, 80)) {  //starts client connection, checks for connection
    Serial.println("Stav svetla - pripojené");
    client.println("GET /ss.txt HTTP/1.1"); //download text
    client.println("Host: SERVER");
    client.println("Connection: close");  //close 1.1 persistent connection  
    client.println(); //end of get request
  } 
  while(client.connected() && !client.available()) delay(1); //cakaj na data
  while (client.connected() || client.available()) { //pramenna
    char c = client.read(); //dostan bity z buffera
    if (c==lf) x=(x+1); //pocitaj 
    else if (x==10) readString += c; //nasa premenna
   }
  if(readString=="1"){
  if(zap==0){
  kon=millis()+30000;
}
while(readString=="1" && millis()<=kon){
  readString = ("");
  zap=2;
  digitalWrite(7, HIGH);
  digitalWrite(3, LOW);
  }
if(readString=="0" || millis()>=kon){
  digitalWrite(7, LOW);
  digitalWrite(3, HIGH);
  zap=1;
  kon=0;
}
  }else if(readString=="0"){
  digitalWrite(7, LOW);
  digitalWrite(3, HIGH);
  zap=0;
    }
  readString = ("");
  x=0;
  client.stop(); //ukonc spojenie
//Nastavenie premennej na "Vypnuté"
    if (zap==1 && client.connect(server, 80)) {  //starts client connection, checks for connection
    client.println("GET /avs.php HTTP/1.1"); //download text
    client.println("Host: SERVER");
    client.println("Connection: close");  //close 1.1 persistent connection  
    client.println(); //end of get request
  } 
  client.stop(); //ukonc spojenie
    }
  cas_aktPo = millis();
   if(cas_aktPo - cas_prePo > 1000) {
    cas_prePo = cas_aktPo;
// Načítanie stavu tlačidiel a vstupných relé:
    t1State = digitalRead(8);
    t2State = digitalRead(6);
    t3State = digitalRead(4);
    r1State = digitalRead(A2);
    r2State = digitalRead(A3);

//ZAČIATOK POPLACHU
    if (r2State == HIGH && popl == 0) {
    if (client.connect(server, 80)) {  //starts client connection, checks for connection
    Serial.println("Začiatok poplachu - pripojené");
    client.println("GET /pz.php HTTP/1.1"); //download text
    client.println("Host: SERVER");
    client.println("Connection: close");  //close 1.1 persistent connection  
    client.println(); //end of get request
    Serial.println("Začiatok poplachu SPUSTENÝ");
    popl = 1;
    digitalWrite(5, HIGH);
  } 
    Serial.println("Odpojené (začiatok poplachu)");
  } //KONIEC r2State == HIGH
  client.stop(); //ukonc spojenie
  
//KONIEC POPLACHU
  if (r2State == LOW && popl == 1) {
    if (client.connect(server, 80)) {  //starts client connection, checks for connection
    Serial.println("Koniec poplachu - pripojené");
    client.println("GET /pk.php HTTP/1.1"); //download text
    client.println("Host: SERVER");
    client.println("Connection: close");  //close 1.1 persistent connection  
    client.println(); //end of get request
    Serial.println("Koniec poplachu SPUSTENÝ");
    popl = 0;
    digitalWrite(5, LOW);
  }
    Serial.println("Odpojené (koniec poplachu)");
  } //KONIEC r2State == LOW
  client.stop(); //ukonc spojenie

//TLAČIDLÁ
    if (t1State == HIGH) {
        //zapne LED1 a výstupné RELÉ1 na 15s
        digitalWrite(7, HIGH);
        digitalWrite(3, LOW);
        delay(15000);
        digitalWrite(7, LOW);
        digitalWrite(3, HIGH);
      }
    if (t2State == HIGH && tlac2 == 0) {
        //zapne 2x LED2 a odošle mail
        tlac2 = 1;
        digitalWrite(5, HIGH);
        delay(300);
        digitalWrite(5, LOW);
        delay(300);
        digitalWrite(5, HIGH);
        delay(300);
        digitalWrite(5, LOW);
          if (client.connect(server, 80)) {  //starts client connection, checks for connection
          Serial.println("Odoslanie e-mailu - pripojené");
          client.println("GET /pt2.php HTTP/1.1"); //download text
          client.println("Host: SERVER");
          client.println("Connection: close");  //close 1.1 persistent connection  
          client.println(); //end of get request
          Serial.println("E-mail odoslaný");
          }
          Serial.println("Odpojené (e-mail)");        
    } //KONIEC t2State == HIGH
    client.stop(); //ukonc spojenie
      if (t2State == LOW && tlac2 == 1) {
      tlac2 = 0;
     }
        if (t3State == HIGH) {
        // zapne LED1 a LED2 1x na 2s
        digitalWrite(5, HIGH);
        digitalWrite(7, HIGH);
        delay(2000);
        digitalWrite(5,LOW);
        digitalWrite(7, LOW);
    }
    }
 }
  
Popisy nie sú vždy presné.. prípadne môžem vysvetliť.

Predpokladám problém z pripojením na internet, aj keď na chalupe je ip kamera, ktorá funguje spoľahlivo, aj mobil cez wifi sa pripája, síce pomalšie ale funguje.

Mám teda pár otázok:
Kde hľadať chybu? - skúšal som nechať spustený NB pripojený k arduinu a vypisovať niektoré údaje po sériovej linke a vtedy to fungovalo celú noc (nemohol som tam NB nechať dlhšie) takže som nič nezistil..
Je možné v kóde arduina ošetriť nejakou formou "soft reset"?
Potreboval by som vysvetliť spôsob fungovania "časovania" jednotlivých častí kódu pomocou porovnávania uplynutého času s millis(), hlavne, či nenastane problém pri pretečení..

Zároveň budem rád za každý návrh na optimalizáciu celého kódu. Vďaka.

MichalCzEJ
Příspěvky: 17
Registrován: 03 bře 2018, 21:38
Reputation: 0

Re: Arduino klient - ovládanie z webu

Příspěvek od MichalCzEJ » 23 črc 2018, 23:11

Předem se omlouvám, pokud budu říkat nějaké blbosti, ale nepracuji s ethernet shieldami na arduinu, využívám ESP, ale nesedí mi určitě podmínka

Kód: Vybrat vše

if (Ethernet.begin(mac) == 0) {                  //V PRIPADE ZLYHANIA NASTAVENIA MAC ADRESY VYPIŠ  
     }
Něco ověříš, ale nic nevykonáš?

Já bych to udělal tak, že bych +/- každou půl minutu nebo při stahování /uploadu nějakých dat na server, zjišťoval, jestli je přístup k internetu, např

Kód: Vybrat vše

if (client.connect(server, 80)) { xxxx (tady posíláš data na server) }
else { restart arduina (nevím přesně, jaký je na to "příkaz") }
  
Snad ti to pomůže.

//edit: a ještě jedna věc, z čeho máš napájené to arduino? Jestli není náhodou chyba v napájení.

martinius96
Příspěvky: 579
Registrován: 01 srp 2017, 19:29
Reputation: 0
Bydliště: Poprad
Kontaktovat uživatele:

Re: Arduino klient - ovládanie z webu

Příspěvek od martinius96 » 24 črc 2018, 01:29

Rekapitulácia:
Ethernet.begin() --> myslím, že najväčší problém si mal tu, napríklad ak vypršala adresa na DHCP, tak už to nedokázalo nastaviť adresu, zvyčajne sa adresa mení po 2 hodinách, ja som si napr všimol, že tá adresa, čo dávam Arduinu napevno, tak ju nie vždy má, niekedy mu to pridelí DHCP, ten proces sa deje zrejme niekde na pozadí.

Kód: Vybrat vše

if (Ethernet.begin(mac) == 0) {                  //ak nie je nastavena mac adresa, tak ju nastav vratane ip
Ethernet.begin(mac, ip); //tato podmienka opravuje nefunkcne spojenie vramci siete da sa povedat a to tym, že nastavi ip k mac adrese..
     }
Ak potrebujem softvérový reset, napríklad mam na webe button, ktorý zmení obsah .txt súboru pre akciu reštartu, tak mam klasické pripojenie na ten subor, podmienku:
Najprv si defingujem funkciu na reštart:

Kód: Vybrat vše

void softReset(){
asm volatile ("  jmp 0"); //ak sa zavola, kod skoci na zaciatok za bootloader cast na tzv. aplikacnu (takto som to pochopil)
}
Potom mám už len podmienku, ak je v textovom subore napr "RST", tak zavolám softReset(); --> reštartne to program, nie cele Arduino ako take.

Ak potrebuješ hardvérový reset, ak sa ti to sekne, tak potrebuješ watchdog, nevedel som mu pochopiť, ale veľmi mi pomohol tento jednoduchý príklad:

Kód: Vybrat vše

#include <avr\wdt.h>

void setup() {
  Serial.begin(9600);
  // set watchdog to 8s
  wdt_enable(WDTO_8S);
  Serial.println("V setupe");
}

void loop() {
  wdt_reset();
  digitalWrite(13, HIGH);
  Serial.println("ZAP");
  delay(10000);
  digitalWrite(13, LOW);
  Serial.println("VYP");
  Serial.println("Dosli sme za vyp");
  wdt_reset();

}
Trošku ma mrzí, že to nič o reštarte nevypíše :-D nejaku hlašku ako napr ESP..

V kóde je knižnica, a watchdog nastaveny na 8 sekund. To znamená, že ak do 8 sekund nereštartuješ watchdog, (aby jeho hodnota nepresiahla 8 sekund), tak potrebuješ volať wdt_reset. Nakoľko ale mám za zapnutou diódou 10 sekund delay, tak nám watchdog reštartuje dosku, ak si otvoríš serial monitor, tak uvidíš iba výpis: V setupe a ZAP, do VYP, respektíve Dosli sme za vyp sa kód nedostane.
Ak by sme však chceli, aby to fungovalo a reštartovalo dosku iba pri zamrznutí, použili by sme:

Kód: Vybrat vše

#include <avr\wdt.h>

void setup() {
  Serial.begin(9600);
  // set watchdog to 8s
  wdt_enable(WDTO_8S);
  Serial.println("V setupe");
}

void loop() {
  wdt_reset();
  digitalWrite(13, HIGH);
  Serial.println("ZAP");
  for(int i=0; i<=4; i++){
  delay(2000);
  wdt_reset();
  }
  digitalWrite(13, LOW);
  Serial.println("VYP");
  Serial.println("Dosli sme za vyp");
  wdt_reset();

}
A nakoľko mi millis nejde, tak s tým ti neporadím.. Keď ja využívam nejaké časové eventy, urobím to v php :D a Arduino si vždy stiahne iba ZAP/VYP pre dany vystup atď, respektíve dá výpis podľa toho, čo si prečíta.


Ten watchdog by mal byť funkčný na akékoľvek Arduino. Pred 3 týždňami som ho implementoval pre projekt, kde pánovi mrzlo Arduino a vyžadovalo sa, aby to bežalo 24/7. Tretí týždeň a kľud, vravel, že to resetuje cca 1-2x denne. Takže je to funkčné :P

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 3 hosti