Gestione Esp8266

buonasera, possiedo una serra domotizzata, ma avevo pensato di aggiungere un modo esp8266 per poter controllare i valori di ogni sensore e azionare i diversi dispositivi che fanno si che le condizioni della serra siano stabili sui valori preimpostati. Vorrei fare tutto ciò al di fuori della rete domestica che possiedo.
La mia domanda è : è possibile collegarmi tramite il mio telefono/computer a qualsiasi distanza e interagire con Arduino?
Aspetto vostri consigli e soluzioni.

Vincenzo

La cosa NON dipende né dall'ESP, né da qualsiasi altra scheda di rete WiFi ...
... la cosa dipende dal tuo "router"; ti deve permettere di fare quello che tecnicamente è chiamato NAT (Network Address Translation) ovvero di mappare un indirizzo IP esterno ed un dato port in un indirizzo IP interno su un dato port.

Il secondo problema è che l'indirizzo IP esterno (ovvero quello verso il "mondo"), salvo tu non abbia un collegamento con IP fisso (piuttosto difficile), viene assegnato dinamicamente e quindi cambia nel tempo. Anche qui la soluzione è o l'acquisto di un IP fisso (se il provider lo permette) o, più semplicemente, l'utilizzo di un servizio esterno (gratis o a pagamento) tipo dyndns.org .

Comunque, per fare bene la cosa ... devi "masticare" di reti ... altrimenti chiedi aiuto ad un amico che sa dove mettere le mani :wink:

Guglielmo

P.S.: Ah, dimenticavo, tutto quanto su scritto apre l'accesso al tuo Arduino a ... tutto il mondo, quindi, o usi un Arduino di un certo livello (NON sicuramente una UNO) e implementi un meccanismo di sicurezza ed autenticazione, o tutto il mondo potrà accedere al tuo sistemino con le conseguenze che puoi ben immaginare !

quindi devo aprire le porte del mio router, creare il programma arduino, creare la pagina web o l'applicazione e potrò controllare fuori dalla rete, giusto?

SI, tramite NAT un indirizzo&port esterno può essere reindirizzato ad indirizzo&port interno ... con i rischi che ne conseguono.

Guglielmo

va bene grazie mille

usi un telegrambot, non apri alcuna porta e lasci tutta la gestione della sicurezza a telegram
certo che così devi lavorare in modo testo

gpb01:
o, più semplicemente, l'utilizzo di un servizio esterno (gratis o a pagamento) tipo dyndns.org .

Guglielmo

a proposito di dyndns, ma ci sono client per arduino: ovvero ci sono programmi "funzionanti" per arduino che aggiornano il dyndns?

perché quelli che ho trovato in giro per monnezzanet non sono riuscito a farli andare

edit

Standardoil:
usi un telegrambot,

per intanto vado a vedermelo, detta così sembra una cosa furba, dove lo trovo?

Ducembarr:
a proposito di dyndns, ma ci sono client per arduino ?

Mai utilizzati ... io imposto le credenziali nel "router" (Fritz!Box) ed è poi lui che fa login e mantiene aggiornato dyndns, non certo le singole macchine sulla rete :wink:

Guglielmo

gpb01:
Mai utilizzati ... io imposto le credenziali nel "router" (Fritz!Box) ed è poi lui che fa login e mantiene aggiornato dyndns, non certo le singole macchine sulla rete :wink:

Esattamente :wink:
Io, su un mio server, ho creato un mio "provider" al quale faccio inviare l'IP dal router.
Poi richiamo un indirizzo sul server, dove un servizio reindirizza l'ultimo IP registrato.
In pratica quello che fa dyndns :wink:

Federico

di quello che ha detto federico ho capito pochino

comunque ammettiamo che il router non sia mio, ad esempio che debbo fare tele-manutenzione one-shot ad una macchina remota

non mi metto a ravanare nel router, che magari sta in piedi per miracolo

ci metto un arduino con un client dyndns e per tutto il tempo che mi serve lo lascio li, poi lo spengo

ruoter ancora illibato e problema evitato

Ducembarr:
perché quelli che ho trovato in giro per monnezzanet non sono riuscito a farli andare

Hai per caso provato anche QUESTO? ... io NO, ma conosco l'autore ed è persona degna di fiducia ... ::slight_smile:

Guglielmo

Domani spero di poter provare

Grazie

Ma vedo che usa String...

Ducembarr:
Domani spero di poter provare

Quell'arduino ti serve solo per inviare a dyndns l'IP dinamico del router, ma se non apri il router, non serve a molto visto che non accedi alla rete.

Per fare manutenzione ogni tanto, si possono usare altri sistemi per accedere direttamente alla macchina, magari via web.

Federico

Federico66:
Quell'arduino ti serve solo per inviare a dyndns l'IP dinamico del router...

Vero,

Mi sono sbagliato...

gpb01:
Hai per caso provato anche ....

ho scoperto che lo avevo già provato e NO, non andava e non va ancora

adesso starei provando a capire cos'ha

ma mi sembra un po' ...strano

anche solo il fatto che è pieno di codici HTML, usa stringhe e non ha aggiornato l'indirizzo IP dei server che usa non mi piace molto

Ducembarr:
ho scoperto che lo avevo già provato e NO, non andava e non va ancora

... quando sento l'autore (non spessissimo, ma mi capita di sentirlo), provo a chiedere se a suo tempo lo aveva provato.

Ho visto che è fatto per dydns.it ... non so se può essere usato anche per altri (io , ad esempio, uso dyndns.org) ... ::slight_smile:

Guglielmo

gpb01:
Ho visto che è fatto per dydns.it ... non so se può essere usato anche per altri...

Si è fatto per dyndns.it, per altri basta verificare qual'è l'url per l'update e modificare le variabili.

Ducembarr:
anche solo il fatto che è pieno di codici HTML...

Ti allego il codice ripulito.
Il programma non fa altro che aprire la pagina checkip.dyndns.com che ritorna una stringa del tipo "Current IP Address: x.x.x.x", dove x.x.x.x è l'ip assegnato al tuo router.

A questo punto costruisce l'url (documentazione)
"http://username:password@update.dyndns.it/nic/update?hostname=yourhostname&myip=ipaddress"
username:password -> dalla configurazione userpwdb64(attenzione è in base64)
yourhostname -> dalla configurazione: hostname
ipaddress -> x.x.x.x

e la richiama (GET) per aggiornare ipaddress dell'host hostname

non ho un modulo Ethernet quindi non posso testarlo, ma dovrebbe funzionare.

Federico

/* DynDNS
  created 2011
  by Boris Landoni
  Modified 2015
  Impulso srl
  This example code is in the public domain.
*/

//http://username:password@update.dyndns.it/nic/update?hostname=yourhostname&myip=ipaddress

#include <Ethernet.h>
//#include <EthernetDNS.h>
#include <WString.h>
#include <EEPROM.h>

#define UPDATE_INTERVAL            30000    // if the connection is good wait 30 seconds before updating again - should not be less than 5

int ledR =  8;
int ledG =  9;

unsigned long pubblica = 0;

byte mac[] = { 0x54, 0x55, 0x58, 0x10, 0x00, 0x24 };
byte ip[] = { 192, 168, 0, 98 };

//http://checkip.dyndns.com/
byte domainaddrip[] = { 208, 78, 70, 70 };
byte ipAddr[4];

byte domaindydns[] = { 81, 29, 198, 108 };
char hostname[ ]   = "xxxxxxx.homepc.it";
//http://www.functions-online.com/base64_encode.html    use->   username:password
char userpwdb64[ ] = "xxxxxxxxxxxxxxxxxx";



String ipadsl     = String(20);
String ipadslold  = String(20);
String inString   = String(51);

//Client client(server, 80);
const char* ip_to_str(const uint8_t*);
//void nameFound(const char* name, const byte ipAddr[4]);

Client client(domainaddrip, 80);
Client clientdyn(domaindydns, 80);

void setup()
{
  pinMode(ledR, OUTPUT);
  pinMode(ledG, OUTPUT);
  Ethernet.begin(mac, ip);

  //EthernetDNS.setDNSServer(dnsServerIp);
  Serial.begin(9600);

  Serial.println("*****************************************Start***************************************************");
  delay(1000);

  //risolviip();
  //delay(1000);
}

void loop()
{

  if (millis() < pubblica) pubblica = millis(); if ((millis() - pubblica) > UPDATE_INTERVAL) {
    //Serial.print("Passati ");
    //Serial.print(UPDATE_INTERVAL);
    //Serial.println(" ms");
    Serial.print("tempo trascorso dall'accensione ");
    Serial.println(millis());
    Serial.println(pubblica);
    pubblica = millis();

    acquisisciip();
  }

}

void acquisisciip()
{

  int timeout = 0;
  int skip = 0;
  ipadsl = "";
  inString = "";
  digitalWrite(ledG, HIGH);

  Serial.print("connecting to ");
  //Serial.print(domain);
  //Serial.print(" = ip ");
  //Serial.println(ip_to_str(domainaddrip));

  if (client.connect()) {

    Serial.println("connected");
    client.println("GET / HTTP/1.0");
    //client.println("GET / HTTP/1.0");
    client.print("HOST: ");
    client.println("www.dyndns.it");
    //client.println(ip_to_str(domainaddrip));
    client.println();
  } else {
    Serial.println("connection failed");
  }

  while (!client.available() && timeout < 50) {
    timeout++;
    Serial.print("Time out ");
    Serial.println(timeout);
    delay(100);
  } while (client.available()) { //Serial.println("client.available"); //if (client.available()) //{ char c = client.read(); //Serial.print(c); skip++; if (skip>220)
    {
      if ((inString.length()) < 50) inString.append(c);
    } //} } client.flush(); if ((inString.length())>5)
    {
      //Serial.print("inString: ");
      //Serial.println(inString);
      if (inString.contains("Address"))
      {
        int from = (inString.indexOf("Address") + 9);
        int lunghe = inString.length();
        int to = (lunghe - 16);
        /*Serial.print("Lunghezza instring    = ");
          Serial.println(lunghe);
          Serial.print("Posizione address + 9 = ");
          Serial.println(from);
          Serial.print("Posizione fine   - 16 = ");
          Serial.println(to);
        */
        //strcpy(ipadsl,(inString.substring((inString.indexOf("Address")+9),(inString.length()-16))));
        ipadsl = inString.substring(from, to);
        //Serial.print("Lunghezza ipadsl      = ");
        //Serial.println(ipadsl.length());
        Serial.print("IP rilevato dal sito: >");
        Serial.print(ipadsl);
        Serial.println("<");
      }
    } if (!client.connected()) {
      Serial.println("disconnecting."); client.stop(); delay (1000); Serial.print("lunghezza IP "); //Serial.println(strlen(ipadsl)); Serial.println(ipadsl.length()); if ((strlen(ipadsl))!=0) { Serial.print("IP nuovo : >");
      Serial.print(ipadsl);
      Serial.println("<");

      for (int i = 0; i < (ipadsl.length()); i++) { //salva in memoria l'indirizzo acquisito ipadslold[i] = EEPROM.read(i); //Serial.print("carattere : >");
        //Serial.print(ipadslold[i]);
        //Serial.println("<"); } Serial.print("IP vecchio: >");
        Serial.print(ipadslold);
        Serial.println("<"); if (strcmp(ipadsl, ipadslold)) {
          Serial.println("IP diverso PUBBLICO");
          digitalWrite(ledR, HIGH);
          pubblicaip();
          digitalWrite(ledR, LOW);
        } else {
          Serial.println("IP uguale");
        } digitalWrite(ledG, LOW); //ipadslold=""; //ipadslold.append(ipadsl); //ipadslold=""; //Serial.print("IP vecchio azzerato: >");
        //Serial.print(ipadslold);
        //Serial.println("<");
        //strcpy(ipadslold,ipadsl);
        for (int i = 0; i < (ipadsl.length()); i++) { //salva in memoria l'indirizzo acquisito
          EEPROM.write(i, ipadsl[i]);
        }

      }

    }

  }

  void pubblicaip()
  {
    int timeout = 0;
    Serial.print("connecting to ");
    Serial.println(ip_to_str(domaindydns));

    Serial.print("IP da pubblicare ");
    Serial.println(ipadsl);

    if (clientdyn.connect()) {
      Serial.println("connected");
      clientdyn.print("GET /nic/update?hostname=");
      clientdyn.print(hostname);
      clientdyn.print("&myip=");
      clientdyn.print(ipadsl);
      clientdyn.println(" HTTP/1.0 ");
      //clientdyn.println("Host: update.dyndns.it ");

      clientdyn.print("Host: ");
      clientdyn.println(ip_to_str(domaindydns));

      clientdyn.print("Authorization: Basic ");
      clientdyn.println(userpwdb64);

      clientdyn.println("User-Agent: impulso - arduinodydns - 1.2");
      clientdyn.println();
    } else {
      Serial.println("connection failed");
    }

    //   delay(3000);

    while (!clientdyn.available() && timeout < 50)
    {
      timeout++;
      Serial.print("Time out ");
      Serial.println(timeout);
      delay(100);
    }

    while (clientdyn.available())
    {
      if (clientdyn.available())
      {
        char c = clientdyn.read();
        Serial.print(c);
      }
    }

    if (!clientdyn.connected())
    {
      Serial.println();
      Serial.println("disconnecting.");
      clientdyn.stop();
    }

  }

  // This is just a little utility function to format an IP address as a string.
  const char* ip_to_str(const uint8_t* ipAddr)
  {
    static char buf[16];
    sprintf(buf, “%d.%d.%d.%d\0”, ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3]);
    return buf;
  }

Sì, magari funzionerebbe, dopo aver corretto gli indirizzi Ip hard code, che sono errati

Ma comunque rimane una cosa brutta, con oggetti String e usati anche in abbondanza

Vabbè, lasciamo, tanto non posso utilizzarlo per la teleassistenza

Ducembarr:
Sì, magari funzionerebbe, dopo aver corretto gli indirizzi Ip hard code, che sono errati
Ma comunque rimane una cosa brutta, con oggetti String e usati anche in abbondanza

Scusa, ma sei hai le competenze per criticarlo, avrai anche le competenze per ri-scriverlo come meglio ti piace :wink:

Per quanto mi riguarda, quel che conta, è l'idea di utilizzare un micro per gestire il dns dinamico, visto che tanti router, se lo permettono, solitamente sono legati a provider noti, che io non uso.
Ho in mente di implementarlo su ESP in un progetto futuro.

Quindi, grazie a @Guglielmo per la segnalazione.

Federico

Su', non litigate: aggiornare quella cosa è inutile, perché dyndns.it richiede o un pagamento oppure il rinnovo ogni 30 giorni, che diventa una menata, specie se si è come me in CIG, ops ferie ,spesso (e mi dispiace per gli altri)
altri servizi simili sono macchinosi o poco documentati o richiedono anch'essi riti voodoo per usarli stabilmente
l'unico con il quale mi son trovato bene è change-ip, che non richiede il rinnovo sul sito e non rompe troppo le balle
Ricorderete che io ho solo una nodeMcu (ESP12E) che usavo per il termoremoto
ricorderete anche che prima di trovarmi con due pesi e due misure stavo trasformando il termoremoto in una sorta di maggiordomo via bot di telegram:

........telegram ho speso 150 euri in donnaccie........
centocinquanta euro segnati sul conto divertimenti, signore
ad adesso il conto divertimenti vale 758 euro, signore

mi piace la parte dove mi chiama signore...........
altro che "Mercedes ho freddo", molto meglio

comunque mi son trovato comodo a gestire anche il dns dinamico con questo coso
come sapete il termoremoto andava su una nodeMcu, anche maggiordomo gira li'
però non dovrebbe essere difficile il porting su altro, ho usato solo roba standard
per prima cosa, una cosina che mi mancava

IPAddress nslookup(char * nome)
{
    IPAddress ip;
    WiFi.hostByName(nome, ip);
    return ip;
}

non sono sicuro che wifi.hostbyname esiste anche fuori da un 8266 però nslookup sarebbe comunque facile da riscrivere, e non nemmeno vitale per il programma
per prima cosa serve di schedulare l'azione, una cosa semplice con l'uso di millis, basta fare un test ogni 10 minuti o anche più
basta una sola chiamata

sincronizzadns();

la sincronizzadns:

IPAddress sincronizzaddns(void)
{
    static IPAddress vecchioip = {0, 0, 0, 0};
    IPAddress mioip = myip();
    IPAddress nullo = {0, 0, 0, 0};

    if (mioip != nullo)
    {
        if (mioip != vecchioip)
        {
            vecchioip = mioip;
            aggiornadyndns(vecchioip);
        }
    }

    return vecchioip;
}

come vedete restituisce un indirizzo IP (quello attuale), viene comodo per usarla contestualmente ad una stampa

naturalmente myip() restituisce l'indirizzo ip attuale, leggendolo dal sito di change-ip

IPAddress myip(void)
{
    IPAddress ipaddr;
    char trigger[] = "<!--IPADDR=";
    char fine = '-';
    char server[] = "ip.ChangeIP.com";
    WiFiClient cl;

    if (cl.connect(server, 80))
    {
        unsigned long int tempo = millis();
        cl.println("GET / ");
        cl.println();
        byte index = 0;
        int point = 0;

        while (millis() - tempo < 1500)
        {
            if (cl.available())
            {
                char c = cl.read();

                if (trigger[index])
                {
                    if (trigger[index] == c)
                    {
                        index++;
                    }
                    else
                    {
                        index = 0;
                    }
                }
                else
                {
                    // se !trigger[index] abbiamo finito il trigger
                    if (c == fine)
                    {
                        index = 0;
                        cl.stop();
                        return ipaddr;
                    }

                    if (c == '.')
                    {
                        point++;
                        continue;
                    }

                    ipaddr[point] = ipaddr[point] * 10 + c - '0';
                }
            }
        }

        cl.stop();
    }
    else
    {
        // nulla da fare la connessione era già giu
    }

    return {0, 0, 0, 0};
}

come vedete sia il nome del server che i due trigger di inizio e fine sono parametrizzati
e ricordate la mia libreria di salvataggio variabili (BtW, per questo la ho scritta, non per altro)
Se vi ricordate il mio grep non vuol dire greppia.... vi ci ritroverete, è lo stesso meccanismo, ma ricerca una sola stringa per volta

e quindi la aggiornadyndns

void aggiornadyndns(IPAddress ip)
{
    char server[] = "nic.ChangeIP.com";
    char dominio[] = "xxxxxxxxxxxxxxxxx";
    char user[] = "yyyyyyyyyyyyyy";
    char password[] = "zzzzzzzzzzzzz";
    WiFiClient cl;

    if (cl.connect(server, 80))
    {

        cl.print("GET /nic/update?u=");
        cl.print(user);
        cl.print("&p=");
        cl.print(password);
        cl.print("&cmd=update&hostname=");
        cl.print(dominio);
        cl.print("&myip=");
        cl.print(ip);
        cl.print("&useragent=Nelson-Arduino");
        cl.println("");
        unsigned long int tempo = millis();

        while (millis() - tempo < 1500)
        {
            if (cl.available())
            {
                char c = cl.read();
                //  Serial.print(c);
            }
        }

        cl.stop();
    }
    else
    {
    }
}

anche qui come vedete i dati sensibili sono su stringhe (di C) e facilemente importabili con la libreria di prima

credo che questo sia soddisfacente

PS: sia ben chiaro: non venitemi a dire che non va, la sto usando da mesi