Arduino Ethernet e Javascript

Salve a tutti, è da un po' di tempo che utilizzo arduino ethernet per i miei esperimenti e tutti decisamente positivi. Ho realizzato da poco (seguendo le varie guide) un controllo di temperatura: modello 1 con una pagina memorizzata nello sketch di arduino, e modello 2 con invio dei dati ad una pagina php che risiede su un server separato per memorizzarli su db mysql.

Adesso invece vorrei sfruttare la sd card per memorizzare le pagine html senza dover modificare lo sketch ad ogni modifica, ma il mio grosso problema è caricare i file javascript, sempre dalla sd

Grazie

Ciao, prova a dare un occhio a questa guida:

:grin:

il mio grosso problema è caricare i file javascript

se son di piccole dimensioni, puoi inglobare il js direttamente nella pagina html, per esempio:

<script language="JavaScript" type="text/javascript">tuo codice js</script>

..oppure potresti hostarli su altro server (in lan o in internet, in base a dove devono essere accessibili), per esempio:

<script language="JavaScript" type="text/javascript" src="http://url/path/tuoscript.js"></script>

@Pandagoal: ho preso spunto proprio dal link che mi hai postato... utilissimo

@Pitusso: la soluzione di mettere tutto su sd era proprio per evitare server/pc esterni, altrimenti avrei realizzato un'applicazione in php e mysql

la soluzione di mettere tutto su sd era proprio per evitare server/pc esterni, altrimenti avrei realizzato un'applicazione in php e mysql

..puoi quindi inglobare il tuo js sulla pagina html.

Se il problema è che vuoi utilizzare, per esempio, dei framewirk js tipo dojo, jquery, etx o altro, rimane valida l'alternativa all'hosting esterno: esistono versioni hostate ufficialmente di quasi tutti i framework.

ma scusate, colleghi l'SD al PC e ci carichi tutti i file necessari.

poi però dovrai anche occuparti del fatto di inserire gli script all'interno dell'HTML, quindi dovrai fare un piccolo parser delle pagine HTML. Non dovrebbe essere difficile

L'ultimo post (di Lesto) non mi è molto chiaro..... quello che ho fatto è appunto caricare index.hml e i file js (jquery.js, jquery.flot.js e jquery.crosshair.js) nella root della mia sd naturalmente riformattando i nomi dei file da pc. Quando poi però vado ad interrogare arduino, con la scheda sd inserita, mi risponde con la pagina index (corretta) ma senza aver caricato i file javascript

In pratica quello che cerco di realizzare è un controllo della temperatura via web che mi risponda non solo con un numero (della temperatura) ma possibilmente con un grafico delle ultime temperature che ho precedentemente memorizzato in un file, il tutto in una intranet senza internet quindi senza possibilità di reperire i file dall'esterno

Sono arrivato alla conclusione di inserire la pagina index all'interno dello sketch (per gestire meglio la parte dinamica dei dati) ma a questo punto non so se riesco a leggere i file js per la creazione del grafico

in allegato ci sono i file che ho utilizzato per le prove (html + js)

Grazie mille a tutti

Archivio.zip (56 KB)

quando tu scrivi:

<script language="javascript" type="text/javascript" src="jquery.js"></script>

il browser richiederà all'arduino il file jquery.js, che a quanto pare tu non gli fornisci (il post di prima è errato, pensavo che il codice js venisse aggiunto alla pagina html al momento dell'invio)

comuque noterai che ora hai una richiesta "GET /jquery.js blablabala" che non soddisfi (e lo stesso vale per gli altri file)... mi fai vedere il codice arduino?

Ciao Lesto, il codice è il seguente:

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
 
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x66, 0x5F };
byte ip[] = { 192,168,0,180 };
File htmlFile;
Server server(80);
 
void setup()
{
  Ethernet.begin(mac, ip);
  server.begin();
  if (!SD.begin(4)) { return; }
  Serial.begin(9600);
}
 
void loop()
{
  Client client = server.available();
  if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (c == '\n' && currentLineIsBlank) {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          htmlFile = SD.open("index.htm");
          if (htmlFile) {     
            Serial.print("file trovato");
            while (htmlFile.available()) {
                client.print(htmlFile.read(), BYTE);
            }
            // close the file:
            htmlFile.close();
          }
          break;
        }
        if (c == '\n') {
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }
    delay(1);
    client.stop();
  }
}

lo stesso segnalato da Pandagoal Tutorial Arduino Ethernet e SD Card - Mauro Alfieri Wearable Domotica Robotica Elettronica
Non sarà il codice finale in quanto sono ancora all'inizio del progetto, ma lo prendo come spunto per rendermi conto di come cumunica l'arduino webserver con il browser.

PS: non sono informatico, sono solo una persona con una forte passione per l'informatica

ti spiego cosa dovresti fare:

  1. tutto quello che leggi attraverso la variabile c, lo dovresti mettere all'interno di una stringa
  2. questa stringa contiene delle richieste GET: se le stampi a video dovresti notare subito che nella loro struttura son richiesti dei file
  3. leggendo la stringa, devi recuperare su SD il file corrispondente

buona fortuna, non è molto difficile, in pratica in base al contenuto della get devi modificare solo la riga

htmlFile = SD.open("index.htm");

con la pagina richiesta

..boh, secondo me la strada più semplice e veloce (senza considerare il minor carico di lavoro per Arduino) rimane quella di linkare i file da repository pubblici.
Anche perchè si tratta del framework jquery con un paio di plugin..

Se ti può servire questo tipo ha fatto un web server con tutti i file nella sd che vengono uploadati quando ti connetti
comprende file di classe, jquery.js, un main.js creato da lui, immagini, e un index.html con una libreria tutta sua,

http://www.webweavertech.com/ovidiu/weblog/archives/000484.html

io sono riuscito a modificarlo in parte ed è l'unico che non mi fa schiantare la ethernet shield, tutti gli esempi postati qui e su quelli in arduino.cc dopo 2 refresh si tromba tutto e non c'e' reset che tenga, beato te che tutte le prove sono andate con successo :slight_smile:

In questo tiny ho eliminato i css, i png e il main.js rifacendolo e inglobandolo nell'html, aggiunto altre 4 pagine html credo e spero di aver allegerito il lavoro di arduino di spedire troppi file alla connessione, se le prende solo se servono, per ora funzia al 90% perchè non sono capace a fare pag web e non voglio postare aiuti su html qui che lo riguarda poco.

bhe dai un occhio se fai qualcosa del genere interesserebbe anche a me, ormai ci sono dietro da un mese ottenendo poco e niente.

download qui

Ciao

Intanto grazie a tutti per il supporto, è il primo forum dove trovo tanta disponibilità

Tornando al problema in questione:
ho riscritto lo sketch aggiungendo le seguenti righe

.
.
.
File js1_File;
File js2_File;
File js3_File;
.
.
.
        Serial.print(c);
          .
          .
          htmlFile = SD.open("index.htm");
          js1_File = SD.open("/jquery.js");
          js2_File = SD.open("/flot.js");
          js3_File = SD.open("/croshair.js");
.
.
.

ho eseguito vari test e prove ma tutte con esito negativo

il Serial.print(c) mi mostra

GET/ HTTP/1.1
Host: 192.168.0.180
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.51.22 (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Cache-Control: max-age=0
Accept-Language: it-it
Accept-Encoding: gzip, deflate
Connection: keep-alive

GET /flot.js HTTP/1.1
Host: 192.168.0.180
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.51.22 (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22
Accept: */*
Referer: http://192.168.0.180/
Cache-Control: max-age=0
Accept-Language: it-it
Accept-Encoding: gzip, deflate
Connection: keep-alive

GET /croshair.js HTTP/1.1
Host: 192.168.0.180
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.51.22 (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22
Accept: */*
Referer: http://192.168.0.180/
Cache-Control: max-age=0
Accept-Language: it-it
Accept-Encoding: gzip, deflate
Connection: keep-alive

GET /jquery.js HTTP/1.1
Host: 192.168.0.180
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.51.22 (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22
Accept: */*
Referer: http://192.168.0.180/
Cache-Control: max-age=0
Accept-Language: it-it
Accept-Encoding: gzip, deflate
Connection: keep-alive

osserviamo le GET (ci basta la prima riga per ognuna):

GET / HTTP/1.1

come puoi notare il browser ti ha richiesto la pagina /, e tu gli hai (giustamente) fornito il file index.html.

ora il browser, analizzando la pagina, si accorge che gli servono altri 3 file:

GET /flot.js HTTP/1.1

GET /croshair.js HTTP/1.1

GET /jquery.js HTTP/1.1

come puoi notare sta richiedendo i 3 file mancanti.

quindi tu non devi a priori aprire tutti i file: devi semplicemente aprire e inviare il file richiesto dalla get, al resto ci pensa il browser.

quindi, una volta che hai letto la GET, analizzi la pagina richiesta: se è solo "/", allora ci aggiungi "index.html", se non è / allora estrapoli il file richiesto (per esempio "/flot.js"), poi fai una SD.open sul file che è stato richiesto e lo trasmetti al browser (insomma il resto del codice rimane identico)

ps. scrivere SD.open("index.htm"); oppure SD.open("/index.htm"); è la stessa cosa

scusate se mi intrometto, ma non vorrei aprire un post su html inutile e magari OT, come fai da sketch quando cambia lo stato di una porta a inviare il dato a uno script js, ad esempio stamparli dentro un textbox?
Da http ad arduino ho risolto e per ora funziona bene, ma il contrario non so come mandarglielo e non vorrei che fosse il client a fare la richiesta con la risposta, ma che fosse arduino di sua spontanea volontà a inviare i dati sempre che IF client.connected sia true :slight_smile:

grazie ciao

l'HTTP è un sistema di comunicazione molto particolare, il client si connette, invia le sue info e il server gli risponde. e basta.
Noterai che quindi per essere un protocollo bidirezionale è molto macchinoso.

Quì si parla di arduino usato come server HTTP, a te serve un client HTTP. apri la tua discussione e posta l'HTML della pagina che vorresti far compilare da arduino.

Ho capito, quindi per avere un aggiornamento da remoto mi conviene far si che una volta ogni tanto il client faccia una richiesta di stato delle porte e arduino gliele manda, notavo pero' che quando faccio refresh o autorefresh che sia, in questo modo arduino oltre inviare il dato gli ripassa di nuovo tutti file librerie, html e compagnia bella, dovrei da sketch trovare la scorciatoia facendogli saltare questi passaggi visto che la connessione è presente (dico bene o dico giusto?) .
Grazie, perdona i termini poco tecnici, uno puo' studiare libri quanto vuole, ma un chiarimento su una parola può sbloccare i capitoli successivi.

ciao

np, la connessione non è presente, infatti l'HTTP è un sistema connection-less (senza connessione persistente), e a dirla tutta ogni richiesta è difficile individuare da chi è stata fatta (si usano o i coockie o sistemi basati sui dei codici inclusi in ogni get o post)

per quello che vorresti fare una connessione TCP sarebbe molto meglio, e apriti una discussione, stiamo incasinando una discussione già incasinata di per sé.

Salve a tutti, navigando sul sito ho trovato proprio uno sketch che fa al caso mio da cui ho preso spunto
http://arduino.cc/playground/Code/WebServer

Ho modificato qua e la il codice rendendolo a me più leggibile ma non riesco più a caricare la pagina

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

/**********************************************************************************************************************
*                                   MAC address and IP address.
***********************************************************************************************************************/
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x66, 0x5F };
byte ip[] = { 192, 168, 0, 180 };

/**********************************************************************************************************************
*                                   Memory space for string management and setup WebServer service
***********************************************************************************************************************/

// For sending HTML to the client
#define STRING_BUFFER_SIZE 128
char buffer[STRING_BUFFER_SIZE];

// to store data from HTTP request
#define STRING_LOAD_SIZE 128
char load[STRING_LOAD_SIZE];

// POST and GET variables
#define STRING_VARS_SIZE 128
char vars[STRING_VARS_SIZE];

/**********************************************************************************************************************
*                                   Strings stored in flash of the HTML we will be transmitting
***********************************************************************************************************************/

#define NUM_PAGES 4

// Page 1
char http_uri1[] = "/";
char file1[] = "index.html";

// Page 2
char http_uri2[] = "/jquery.js";
char file2[] = "jquery.js";

// Page 3
char http_uri3[] = "/flot.js";
char file3[] = "flot.js";

// Page 4
char http_uri4[] = "/croshair.js";
char file4[] = "croshair.js";

// declare tables for the pages
char* files[] = { file1, file2, file3, file4 }; // files
char* http_uris[] = { http_uri1, http_uri2, http_uri3, http_uri4 }; // URIs

/**********************************************************************************************************************
*                                        define HTTP return structure ID for parsing HTTP header request
***********************************************************************************************************************/
struct HTTP_DEF {
  int pages;
  char vars[20];
} ;

/**********************************************************************************************************************
*                                                        Shared variable
***********************************************************************************************************************/
Server server(80);

void setup() {
  Ethernet.begin(mac, ip);
  server.begin();
  if (!SD.begin(4)) { return; }
  Serial.begin(9600); // DEBUG
}

/**********************************************************************************************************************
*                                                           Main loop
***********************************************************************************************************************/

void loop() {
  Client client = server.available();
  if (client) { // now client is connected to arduino

    // read HTTP header request... so select what page client are looking for
    HTTP_DEF http_def = readHTTPRequest(client);

    if (http_def.pages > 0) {
      sendPage(client,http_def);
    } 

    // give the web browser time to receive the data
    delay(1);
    client.stop();
  }

}

/**********************************************************************************************************************
*                                              Method for read HTTP Header Request from web client
***********************************************************************************************************************/
struct HTTP_DEF readHTTPRequest(Client client) {
  char c;
  int i;

  // use buffer, pay attention!
  int bufindex = 0; // reset buffer
  int loadindex = 0; // reset load

  int contentLength = 0; // reset POST content length
  char compare[50]; // page comparison (URI selection)

  HTTP_DEF http_def; // use the structure for multiple returns

  http_def.pages = 0; // default page selection... error

  // reading all rows of header
  if (client.connected() && client.available()) { // read a row
    buffer[0] = client.read();
    buffer[1] = client.read();
    bufindex = 2;

    // read the first line to determinate the request page
    while (buffer[bufindex-2] != '\r' && buffer[bufindex-1] != '\n') { // read full row and save it in buffer
      c = client.read();
      if (bufindex<STRING_BUFFER_SIZE) buffer[bufindex] = c;
      bufindex++;
    }
    
    // select the page from the buffer (GET and POST) [start]
    for(i = 0; i < NUM_PAGES; i++) {
      strcpy_P(load, http_uris[i]);
      // GET
      strcpy(compare,"GET ");
      strcat(compare,load);
      strcat(compare," ");
      Serial.print("GET compare: "); // DEBUG
      Serial.println(compare); // DEBUG
      if (strncmp(buffer,compare, strlen(load)+5)==0) {
        http_def.pages = i+1;
        break;
      }

      // POST
      strcpy(compare,"POST ");
      strcat(compare,load);
      strcat(compare," ");
      Serial.print("POST compare: "); // DEBUG
      Serial.println(compare); // DEBUG
      if (strncmp(buffer,compare, strlen(load)+6)==0) {
        http_def.pages = i+1;
        break;
      }

    }
    // select the page from the buffer (GET and POST) [stop]

    // read other stuff (for POST requests) [start]
    if (strncmp(buffer, "POST /", 5)==0) {
      processRequest:
      loadindex = 2; // reset load

      memset(load,0,STRING_LOAD_SIZE);
      load[0] = client.read();
      load[1] = client.read();
      while (load[loadindex-2] != '\r' && load[loadindex-1] != '\n') {
        c = client.read();
        if (loadindex<STRING_BUFFER_SIZE) load[loadindex] = c;
        loadindex++;
      }
      if (strncmp(load, "Content-Length: ",16)==0) {
        loadindex = 16;
        for(i = loadindex; i< strlen(load) ; i++) {
          if (load[i] != ' ' && load[i] != '\r' && load[i] != '\n') {
            vars[i-loadindex] = load[i];
          } else {
            break;
          }
        }

        contentLength = atoi(vars);
        memset(vars,0,STRING_VARS_SIZE);
        client.read(); client.read(); // read null line
        i = 0;
        while (i<contentLength) {
          c = client.read();
          vars[i] = c;
          ++i;
        }

      } else {
      	goto processRequest;
      }
    }
    // read other stuff (for POST requests) [stop]


    // clean buffer for next row
    bufindex = 0;
  }

  Serial.print("Grepped page: "); // DEBUG
  Serial.println(http_def.pages); // DEBUG

  strncpy(http_def.vars,vars,STRING_VARS_SIZE);

  return http_def;
}

/**********************************************************************************************************************
*                                                              Send Pages
***********************************************************************************************************************/

File htmlFile;

void sendPage(Client client,struct HTTP_DEF http_def) {
  
  htmlFile = SD.open(files[http_def.pages-1]);
  if (htmlFile) {     
    while (htmlFile.available()) {
      client.print(htmlFile.read(), BYTE);
    }
  } 
  
  client.print("
");
  // send POST variables
  client.print(vars);

}

gran parte del codice lo comprendo ma non del tutto e adesso non capisco proprio dove trovare l'errore....

Immagino la tua sia una richiesta GET, in tal caso qual'é il valore stampato da seriale di:

Serial.print("GET compare: "); // DEBUG
Serial.println(compare); // DEBUG

anzi posta proprio l'output da seriale....

ma comunque mi pare errato il semplice fatto che non vengono inviati gli header: ovvero manca

client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");

nella funzione sendPage