Go Down

Topic: Arduino eth (Read 950 times) previous topic - next topic

Bonjour
Ayant fait l acquisition d'un arduino ethernet ( et non le module shield ethernet ) je tente de récupérer des valeur de variable via une page html mais ayant essayé via un formulaire html je n arrive a rien, es que quelqu un pourrait me venir en aide

Le serait d avoir un formulaire par ex : variable avec une case ou je peu entrer ma valeur via une page web.

Salutation

skywodd

Bonjour,

La solution la plus simple c'est d'utiliser webduino : https://github.com/sirleech/Webduino
Il gére tout ce qui est formulaire, page web, etc ...
Des news, des tutos et plein de bonnes choses sur http://skyduino.wordpress.com !

skizoh

Bonjour,

je ne sais pas ce que tu pense de cette technique, du moins moi je la trouve un peu compliquée :s moi j'ai une solution un peu plus simple qui fonctionne pas mal, je te donnerai ça demain de retour à mon bureau, tu pourra utiliser les champs à remplir des boutons des liens des checkboxs etc..
(si tu veux voir ce que j'arrive a faire avec va voir la :http://arduino.cc/forum/index.php/topic,102195.0.html en bas de page tu a des photos de ma page web ! )
Je te mets ça demain si ça technique est trop sophistiquer pour toi comme elle l'est pour moi ^^

Skizo !
Un tien vaux mieux que deux tu l'auras !

skizoh

je t'envoie mon code ou c'est pas nécessaire? à toi de voir ^^

Skizo !
Un tien vaux mieux que deux tu l'auras !

jhonnyy

moi je veux bien le code c'est toujours intéressent  :smiley-eek:

skizoh

ok alors tien :)

Code: [Select]

#include <SPI.h>
#include <Ethernet.h>
#include <avr/pgmspace.h>
#include <string.h>


byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x33 };
byte ip[] = { 192, 168, 0, 111 };
byte broadcast[] = { 255, 255, 255, 255};


#define STRING_BUFFER_SIZE 128
char buffer[STRING_BUFFER_SIZE];

#define STRING_LOAD_SIZE 128
char load[STRING_LOAD_SIZE];

#define STRING_VARS_SIZE 128
char vars[STRING_VARS_SIZE];

int time_preset_1[6],time_preset_2[6],time_preset_3[6],time_preset_4[6],time_preset_5[6],time_preset_6[6],time_preset_7[6],time_preset_8[6],time_preset_9[6];
int retien_pages=0;
int ronde_active=0;
int num_preset=0;
int time_saved_preset[10];
int time_of_ronde=0;
int switch_ronde=1;
int rcv_pupitre=0;
int ID_ronde_modif=0;
int ID_ronde=0;
int ID_dome=1;

boolean envoie_para_arduino2=0;
boolean ronde1_chrono=0,ronde2_chrono=0,ronde3_chrono=0,ronde4_chrono=0,ronde5_chrono=0;
boolean fin_tempo=1,Gauche=0,Droite=0,Stop=0,Haut=0,Bas=0,Zoom_plus=0,Zoom_moin=0;

char reception_pupitre;
char IP_pupitre[15];
char h_start_ronde1[6],h_start_ronde2[6],h_start_ronde3[6],h_start_ronde4[6],h_start_ronde5[6];
char h_fin_ronde1[6],h_fin_ronde2[6],h_fin_ronde3[6],h_fin_ronde4[6],h_fin_ronde5[6];


unsigned int localPort = 1234;

#define NUM_PAGES 4

PROGMEM prog_char content_404[] = "HTTP/1.1 404 Not Found\n Erreure \nContent-Type: text/html\n\n<html><head><title>STS Gestion des rondes - Error </title></head><body><h1>Une erreure est survenue veuillez nous en excusez...</h1></body>";
PGM_P page_404[] PROGMEM = {
 content_404 }; // table with 404 page

// HTML Header for pages
PROGMEM prog_char content_main_header[] = "HTTP/1.0 200 OK\nServer: arduino\nCache-Control: no-store, no-cache, must-revalidate\nPragma: no-cache\nConnection: close\nContent-Type: text/html\n";
PROGMEM prog_char content_main_top[] = "<html><head><title>STS Reglage des presets et des ronde </title><style type=text/css>a:link,a:visited { font-weight:bold; color:black; background-color:grey; width:120px;border-radius: 10px; text-align:center; padding:5px; border-radius: 10px;text-decoration:none; } a:hover,a:active { border-radius: 10px;background-color:silver; } table{border-collapse:collapse;}td{padding:0.55em 0.5em;border:0.5em solid #C8C8C8;}";
PROGMEM prog_char content_main_top2[] = "body {border-radius: 10px; }h33 {border-radius: 10px;display:block;float:left;font-family:Verdana, Arial, Helvetica, sans-serif;font-size:40px;font-weight:bold;padding:10px 10px 10px 10px;background:LimeGreen;} h22 {border-radius: 10px;float:left;display:block;font-family:Verdana, Arial, Helvetica, sans-serif;font-size:40px;font-weight:bold;margin:0;padding:10px 10px 10px 10px;;background:DarkOrange;}h11 {border-radius: 10px;float:left;display:block;font-family:Verdana, Arial, Helvetica, sans-serif;font-size:40px;font-weight:bold;margin:0;padding:10px 10px 10px 10px;;background:DodgerBlue;}hr {border:none;border-top:1px solid #CCCCCC;height:1px;margin-bottom:25px;}";
PROGMEM prog_char content_main_top3[] = "div.gros{width:650px;padding:15px;border:8px solid black;margin:0px;background: silver;border-radius: 10px;}#tabs {border-radius: 10px;float:center;width:580px;background:#E4E6EB;font-size:93%;line-height:normal;}#tabs li {display:inline;margin:0;padding:0;}#tabs a {float:left;background:#FFFFFF no-repeat center top ;margin:0;padding:1px 12px 1px 12px;";
PROGMEM prog_char content_main_top4[] = "text-decoration:none;}div.debut{width:520px;padding:15px;border:8px solid grey;margin:0px;background: silver;border-radius: 10px;}#tabs a span {float:left;display:block;background:#444455 no-repeat center top;padding:4px 25px 4px 25px;color:#FFF; border-radius: 10px;}#tabs a span {float:none;}#tabs a:hover span {color:#FFF;}#tabs a:hover {background-position:0% -42px;}#tabs a:hover span {background-position:100% -42px; background: black;}</style></head><body><h11>S</h11><h22>T</h22><h33>S</h33><br><center><br/><br/><br/><div class=debut><h1>Menu de gestion des rondes</h1></div><br/><br/> ";

PROGMEM prog_char content_main_menu[] = "<div class=gros><br/><div id=tabs><center><li><a href=page1><span>Gestion general</span></a></li><li><a href=page2><span>Composition rondes</span></a></li><li><a href=page3><span>Definition preset</span></a></li><li><a href=page4><span>Ronde automatique</span></a></li></center></div>";
PROGMEM prog_char content_main_footer[] = "</div></body></html>";


PGM_P contents_main[] PROGMEM = {
  content_main_header, content_main_top, content_main_top2, content_main_top3, content_main_top4, content_main_menu, content_main_footer }; // table with 404 page
#define CONT_HEADER 0
#define CONT_TOP 1
#define CONT_TOP2 2
#define CONT_TOP3 3
#define CONT_TOP4 4
#define CONT_MENU 5
#define CONT_FOOTER 6

// Page 1
PROGMEM prog_char http_uri1[] = "/page1";
PROGMEM prog_char content_title1[] = "<center><br/><br/><h2>Configuration general</h2>";
PROGMEM prog_char content_page1[] = "Cette onglet est mis a votre disposition afin de Changer d'adresse IP, d'enclencher, arreter une ronde.<br/><FORM ACTION=/page1 METHOD=GET> Adressage IP de la carte : <br/><br/><INPUT NAME=IP TYPE=TEXT /><br/><br/><input type=submit value=Enregistrer /><br/><br/><br/>Mode Ronde<br/><br/>Cochez une case afin d'enclencher ou d'arreter une ronde, presciser son numero et celui du dome puis clicker sur enregistrer :<br/><br/>On - Off<br/><INPUT TYPE=checkbox NAME=Ronde value=1 /> - <INPUT TYPE=checkbox NAME=Ronde value=0 /><br/><br/>Ronde ID: <INPUT NAME=YD_ronde TYPE=TEXT /><br/>Dome ID  :  <INPUT NAME=ZD_dome TYPE=TEXT /><br/><br/></form></center>";

// Page 2
PROGMEM prog_char http_uri2[] = "/page2";
PROGMEM prog_char content_title2[] = "<center><br/><br/><h2>Composition des rondes</h2>";
PROGMEM prog_char content_page2[] = "Inscriver la duree de l'arret par preposition et le numero de ronde consernee (en Seconde 0 - 999)<br /><br/><FORM ACTION=/page2 METHOD=GET>ID ronde : <INPUT NAME=ID_ronde TYPE=TEXT /><br/><br/>Preset 1 :  <INPUT NAME=1_t_p TYPE=TEXT /><br />Preset 2 :  <INPUT NAME=2_t_p TYPE=TEXT /><br />Preset 3 :   <INPUT NAME=3_t_p TYPE=TEXT /><br />Preset 4 : <INPUT NAME=4_t_p TYPE=TEXT /><br />Preset 5 :  <INPUT NAME=5_t_p TYPE=TEXT /><br />Preset 6 : <INPUT NAME=6_t_p TYPE=TEXT /> <br />Preset 7 : <INPUT NAME=7_t_p TYPE=TEXT /><br />Preset 8 : <INPUT NAME=8_t_p TYPE=TEXT /><br />Preset 9 : <INPUT NAME=9_t_p TYPE=TEXT /><br /><br /><input type=submit value=Valider /><br /><br /></center></form>";

//Page 3
PROGMEM prog_char http_uri3[] = "/page3";
PROGMEM prog_char content_title3[] = "<center><br /><br /><h2>Reglage des presets</h2>";
PROGMEM prog_char content_page3[] = "Positioner votre dome video sur la position souhaitee<br /><br/><FORM ACTION=/page3 METHOD=GET><a href=\"./page3?H\"> Haut </a><br /><br /><a href=\"./page3?G\">Gauche</a> - <a href=\"./page3?S\">Stop</a> - <a href=\"./page3?D\">Droite</a><br /><br /> <a href=\"./page3?B\"> Bas </a><br /><br /><a href=\"./page3?P\">Zoom +</a>     <a href=\"./page3?M\">Zoom -</a><br/><br /><br />Donner un numero entre 1 et 9 a votre preposition :<br/><br /><INPUT NAME=new_preset TYPE=TEXT /><br/><br/><input type=submit value=Enregistrer /><br/><br/></center></form>";

PROGMEM prog_char http_uri4[] = "/page4";
PROGMEM prog_char content_title4[] = "<center><br /><br /><h2>Configuration des rondes</h2>";
PROGMEM prog_char content_page4[] = " Rentrez l'heur de depart et de fin des ronde (01h20 pour 1h20, x pour ne pas faire la ronde)<br/><FORM ACTION=/page4 METHOD=GET><br />Ronde 1 - Debut: <INPUT NAME=0ronde TYPE=TEXT /> Fin: <INPUT NAME=1ronde TYPE=TEXT /><br/><br/>Ronde 2 - Debut: <INPUT NAME=2ronde TYPE=TEXT /> Fin: <INPUT NAME=3ronde TYPE=TEXT /><br/><br/>Ronde 3 - Debut: <INPUT NAME=4ronde TYPE=TEXT /> Fin: <INPUT NAME=5ronde TYPE=TEXT /><br/><br/>Ronde 4 - Debut: <INPUT NAME=6ronde TYPE=TEXT /> Fin: <INPUT NAME=7ronde TYPE=TEXT /><br/><br/>Ronde 5 - Debut: <INPUT NAME=8ronde TYPE=TEXT /> Fin: <INPUT NAME=9ronde TYPE=TEXT /><br/><br/><input type=submit value=Enregistrer /><br/><br/></center></form>";



voila j'espère que ça t'aidera, normalement tu a déjà des champs des checks box des liens qui font passer une variable à 1, etc.., j'ai testé dépanné compilé ça fonctionne, vient me demander si tu a des questions, pour le moment le programme fait page web et rempli les variables lié au champ c'est tout, à toi de le compléter et bien sur de changer mes pages web hein ;)

ps: désolé pour les pages web rempli en une ligne.. c'est dégueulasse je sais mais c'est une vielle version je l'ai re mise en marche et vidé pour toi ^^

ps2: 2 parties, trop gros :s

Skizo !
Un tien vaux mieux que deux tu l'auras !

skizoh

Code: [Select]


// declare tables for the pages
PGM_P contents_titles[] PROGMEM = {
 content_title1, content_title2, content_title3, content_title4};//, content_title5 }; // titles
PGM_P http_uris[] PROGMEM = {
 http_uri1, http_uri2, http_uri3, http_uri4};//, http_uri5 }; // URIs
PGM_P contents_pages[] PROGMEM = {
 content_page1, content_page2, content_page3, content_page4};//, content_page5 }; // real content


struct HTTP_DEF
{ int pages;
 char vars[STRING_VARS_SIZE]; //size needs to match the global variable 'vars' otherwise program crashes due to index overrun
};

EthernetServer server(80);

void setup()
{
 Ethernet.begin(mac, ip);
 server.begin();
 Serial.begin(2400);


}


void loop() {


 EthernetClient client = server.available();
 if (client)
 { HTTP_DEF http_def = readHTTPRequest(client);

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

   delay(1);
   client.stop();
 }

}


struct HTTP_DEF readHTTPRequest(EthernetClient client) {
 char c;
 int i;
 int bufindex = 0; // reset buffer
 int loadindex = 0; // reset load



 boolean pres_value = 0;
 boolean pres_id=0;
 boolean fin_val=0;
 boolean oui=0;
 int recuperation = 0;
 int start = 0;
 int cpt = 0;
 int contentLength = 0;
 int U=0,D=0,C=0;

 char num_pages = '0';
 char time_preset_id = 'x';
 char tempo[3]; tempo[0]='*'; tempo[1]='*'; tempo[2]='*';
 char direc_prepo;
 char compare[50];

/*****************************************************************************************************************************************
                                         Balayage URL pour récupération des donnee web (FORM) <===================
***********************************************************************************************************************************************/

 HTTP_DEF http_def; // use the structure for multiple returns
 retien_pages=http_def.pages;
 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;

   while (buffer[bufindex-1] != '\r' && buffer[bufindex] != '\n')
   {
     cpt++;
     c = client.read();
     if (bufindex<STRING_BUFFER_SIZE) buffer[bufindex] = c;
     bufindex++;

     if ( cpt > 7 && start==0 ) { num_pages=c; start=1; }
     if ( c=='&' || c==' ') { pres_value=0; recuperation=0; }// détection des début de valeur ou fin de valeur ou début d'identifiant etc

     switch (num_pages)
     {    
     case '0':  
                   break;

/*******************************************************************************************************************************************
                                     Récupération des donné dans des variable
***********************************************************************************************************************************************/

     case '1':
                   if (pres_value==1 && time_preset_id=='I') { IP_pupitre[recuperation]=c;  recuperation++; }
                   if (pres_value==1 && time_preset_id=='R') { ronde_active=int(c)-48; }
                   if (pres_value==1 && time_preset_id=='Y') { ID_ronde=int(c)-48; }
                   if (pres_value==1 && time_preset_id=='Z') { ID_dome=int(c)-48; }
                   if (pres_id==1) { time_preset_id=c; pres_id=0; }
                   
                   break;                          

     case '2':      
                  if (fin_val==1 && oui==1)
                  {
                     if(tempo[2]=='*' && tempo[1]=='*') { U=(int(tempo[0])-48); }
                     else if(tempo[2]=='*') { D=10*(int(tempo[0])-48);  U=(int(tempo[1])-48); }
                     else { C=100*(int(tempo[0])-48); D=10*(int(tempo[1])-48);  U=(int(tempo[2])-48); }
           
                     switch (time_preset_id)
                     {
                         case '1': time_preset_1[ID_ronde_modif]=C+D+U;
                                   break;  
                         case '2': time_preset_2[ID_ronde_modif]=C+D+U;
                                   break;  
                         case '3': time_preset_3[ID_ronde_modif]=C+D+U;
                                   break;  
                         case '4': time_preset_4[ID_ronde_modif]=C+D+U;
                                   break;  
                         case '5': time_preset_5[ID_ronde_modif]=C+D+U;
                                   break;  
                         case '6': time_preset_6[ID_ronde_modif]=C+D+U;
                                   break;  
                         case '7': time_preset_7[ID_ronde_modif]=C+D+U;
                                   break;  
                         case '8': time_preset_8[ID_ronde_modif]=C+D+U;
                                   break;  
                         case '9': time_preset_9[ID_ronde_modif]=C+D+U;
                                   break;
                                   
                         default : break;                
                     }
                     C=0; D=0; U=0; oui=0; fin_val=0; recuperation=0; tempo[0]='*'; tempo[1]='*'; tempo[2]='*';            
                       
                 }
                 
                 if (pres_id==1){ time_preset_id=c; pres_id=0; }
                 else if ( pres_value==1 && fin_val!=1 ) { oui=1; tempo[recuperation]=c;  recuperation++; }
                 if (time_preset_id=='I' && pres_value==1) { ID_ronde_modif=int(c)-48; }
                 break;            


       case '3':  
                 if ( pres_value == 1 ) { num_preset=int(c)-48; pres_value=0;}  
                 if ( pres_id == 1 )  { direc_prepo = c ; pres_id=0; }
                 
                 switch (direc_prepo)
                 {
                   case 'H':  Haut=1; break;
                   case 'G':  Gauche=1;break;
                   case 'D':  Droite=1; break;
                   case 'B':  Bas=1; break;
                   case 'S':  Stop=1; break;
                   case 'P':  Zoom_plus=1; break;
                   case 'M':  Zoom_moin=1; break;
                   default :  break;
                 }
                 break;




bon bas 3 parties ^^

Skizo !
Un tien vaux mieux que deux tu l'auras !

skizoh

voila =)


Code: [Select]


 
       case '4':
                 if ( pres_value==1 )
                 {
                     switch (time_preset_id)
                     {
                       case '0':
                               if (time_preset_id=='0' && recuperation < 5) {h_start_ronde1[recuperation]=c; recuperation++; }
                               break;
                             
                       case '1':
                               if (time_preset_id=='1' && recuperation < 5) { h_fin_ronde1[recuperation]=c; recuperation++; }
                               break;

                       case '2':
                               if (time_preset_id=='2' && recuperation < 5) { h_start_ronde2[recuperation]=c; recuperation++; }
                               break;
                             
                       case '3':
                               if (time_preset_id=='3' && recuperation < 5) { h_fin_ronde2[recuperation]=c; recuperation++; }
                               break;
                               
                       case '4':
                               if (time_preset_id=='4' && recuperation < 5) { h_start_ronde3[recuperation]=c; recuperation++; }
                               break;
                             
                       case '5':
                               if (time_preset_id=='5' && recuperation < 5) { h_fin_ronde3[recuperation]=c; recuperation++; }
                               break;
                               
                       case '6':
                               if (time_preset_id=='6' && recuperation < 5) { h_start_ronde4[recuperation]=c; recuperation++; }
                               break;
                             
                       case '7':
                               if (time_preset_id=='7' && recuperation < 5) { h_fin_ronde4[recuperation]=c; recuperation++; }
                               break;
                               
                       case '8':
                               if (time_preset_id=='8' && recuperation < 5) { h_start_ronde5[recuperation]=c; recuperation++; }
                               break;
                             
                       case '9':
                               if (time_preset_id=='9' && recuperation < 5) {h_fin_ronde5[recuperation]=c; recuperation++; }
                               break;

                       default :  break;
                       }
                     }
                     
                     if (pres_id==1) {  time_preset_id=c;  pres_id=0;  fin_val=0;  recuperation=0; }                      
                     break;

       default :     break;  
     }

     fin_val=0;
     if ( c=='=' ) { pres_value=1; recuperation=0; }
     if ( c=='&' || c=='?' ) { pres_id=1; fin_val=1; }
     if ( c==' ' || c=='\n' || c=='\r' ) { fin_val=1; }
 }
       
   start = 0 ;
   cpt = 0 ;
   pres_id=0;
   num_pages='0';
   pres_value=0;
   fin_val=0;
   oui=0;
   tempo[0]='*';
   tempo[1]='*';
   tempo[2]='*';
   recuperation=0;
   time_preset_id = 'x';
   U=0;
   D=0;
   C=0;



   // select the page from the buffer (GET and POST) [start]
  for(i = 0; i < NUM_PAGES; i++)
   {
     strcpy_P(load, (char*)pgm_read_word(&(http_uris[i])));

    // GET
     strcpy(compare,"GET ");
     strcat(compare,load);
     strcat(compare," ");
     if (strncmp(buffer,compare, strlen(load)+5)==0)
     {
       http_def.pages = i+1;
       break;
     }

     // POST
     strcpy(compare,"POST ");
     strcat(compare,load);
     strcat(compare," ");
     if (strncmp(buffer,compare, strlen(load)+6)==0)
     {
       http_def.pages = i+1;
       break;
     }
   }
 }
 delay(10);
 strncpy(http_def.vars,vars,STRING_VARS_SIZE);
 return http_def;
}


void sendPage(EthernetClient client,struct HTTP_DEF http_def) {

 // send HTML header
 // contentPrinter(client,(char*)pgm_read_word(&(contents_main[CONT_HEADER])));
 contentPrinter(client,(char*)pgm_read_word(&(contents_main[CONT_TOP])));
 contentPrinter(client,(char*)pgm_read_word(&(contents_main[CONT_TOP2])));
 contentPrinter(client,(char*)pgm_read_word(&(contents_main[CONT_TOP3])));
 contentPrinter(client,(char*)pgm_read_word(&(contents_main[CONT_TOP4])));
 //Serial.println ("buf);
 // send menu
 contentPrinter(client,(char*)pgm_read_word(&(contents_main[CONT_MENU])));

 // send title
 contentPrinter(client,(char*)pgm_read_word(&(contents_titles[http_def.pages-1])));

 // send the body for the requested page
 sendContent(client,http_def.pages-1);

 contentPrinter(client,(char*)pgm_read_word(&(contents_main[CONT_FOOTER])));
}

void contentPrinter(EthernetClient client, char *realword) {
 int total = 0;
 int start = 0;
 char buffer[STRING_BUFFER_SIZE];
 int realLen = strlen_P(realword);

 memset(buffer,0,STRING_BUFFER_SIZE);

 while (total <= realLen) {
   // print content
   strncpy_P(buffer, realword+start, STRING_BUFFER_SIZE-1);
   client.print(buffer);

   // more content to print?
   total = start + STRING_BUFFER_SIZE-1;
   start = start + STRING_BUFFER_SIZE-1;

 }
}

void sendContent(EthernetClient client, int pageId) {
 contentPrinter(client,(char*)pgm_read_word(&(contents_pages[pageId])));
}




et voila tu colle les 3 à la suite tout connement ^^


Skizo !
Un tien vaux mieux que deux tu l'auras !

jhonnyy

thanks j'analyse tous sa ce week end et je reviens vers toi!

merci encore

skizoh

de rien, même le week end n'hésite pas je passerai t'aider !

Skizo !
Un tien vaux mieux que deux tu l'auras !

barbudor

@Skizoh
Tu sais que tu peux attacher un fichier à un post ?
C'est plus pratique pour les gros sources plutôt que de s'embêter à couper en petit morceaux.....
En bas de la zone d'édition de ton message : "|> Additional options ..."

Houlahop, Barbatruc
Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

skizoh

"barbatruc" xDDD ouai je sais c'est vrai que j'y pense pas :s désolé ça pourri un peux le topic :x j'y penserai à l'avenir promis !  XD

Skizo !
Un tien vaux mieux que deux tu l'auras !

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy