Ho raggiunto i primi due obiettivi che mi ero posto con l’Arduino, ovvero
- prendere l’ora da internet tramite il Net Time Protocol
- accendere la macchina del caffè all’ora prefissata
Ma non è finita: adesso bisogna (bisogna!) che l’ora di accensione venga impostata via web, non inserita banalmente a mano nel codice. Per fare questo occorre che sia contemporaneamente attivo il cliente NTP e il server web, e grosse nubi si addensano sul mio orizzonte di entusiasta ignorante.
Inoltre non è bello che l’Arduino debba autisticamente chiedere l’ora a NTP ogni minuto: meglio sarebbe se chiedesse solo una volta al giorno per sincronizzare con un suo orologio interno.
Come dire che ho le sere impegnate fino a primavera. Il codice fino a questo punto, dopo il salto: come sempre, eventuali commenti, critiche e suggerimenti sono molto bene accetti.
/* Arduino, fammi il caffè! V.0.1 created 4 Sep 2010 by Michael Margolis modified 17 Sep 2010 by Tom Igoe modified 18 Feb 2012 by Gaspar Torriero This code is in the public domain. */ #include <SPI.h> #include <Ethernet.h> #include <EthernetUdp.h> int cHH; // current hour int cMM; // current minute int cSS; // current second int outPin = 8; // connected to coffee machine via relè // Enter a MAC address for your controller below byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; unsigned int localPort = 8888; // local port to listen for UDP packets IPAddress timeServer(192, 43, 244, 18); // time.nist.gov NTP server const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets // A UDP instance to let us send and receive packets over UDP EthernetUDP Udp; void setup() { // Serial.begin(9600); // uncomment for testing digitalWrite(outPin, LOW); // start Ethernet and UDP if (Ethernet.begin(mac) == 0) { // Serial.println("Failed to configure Ethernet using DHCP"); // uncomment for testing // no point in carrying on, so do nothing forevermore: for(;;) ; } Udp.begin(localPort); } void loop() { sendNTPpacket(timeServer); // send an NTP packet to a time server // wait to see if a reply is available delay(1000); if ( Udp.parsePacket() ) { // We've received a packet, read the data from it Udp.read(packetBuffer,NTP_PACKET_SIZE); // read the packet into the buffer //the timestamp starts at byte 40 of the received packet and is four bytes, // or two words, long. First, esxtract the two words: unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); // combine the four bytes (two words) into a long integer // this is NTP time (seconds since Jan 1 1900): unsigned long secsSince1900 = highWord << 16 | lowWord; // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: const unsigned long seventyYears = 2208988800UL; // subtract seventy years: unsigned long epoch = secsSince1900 - seventyYears; // print the hour, minute and second: cHH = (epoch % 86400L) / 3600 + 1; cMM = (epoch % 3600) / 60; cSS = epoch %60; /* uncomment for testing Serial.print("Local time is "); Serial.print(cHH); Serial.print(" hours, "); Serial.print(cMM); Serial.print(" minutes, and "); Serial.print(cSS); Serial.println(" seconds."); */ // Turns on the coffee machine // at a fixed time. // Next goal: set time via web. if((cHH == 6) && (cMM > 44)) { digitalWrite(outPin, HIGH); } } // wait 60 seconds before asking for the time again // Next goal: let Arduino Keep the time // and synchronize daily. delay(60000); } // send an NTP request to the time server at the given address unsigned long sendNTPpacket(IPAddress& address) { // set all bytes in the buffer to 0 memset(packetBuffer, 0, NTP_PACKET_SIZE); // Initialize values needed to form NTP request // (see URL above for details on the packets) packetBuffer[0] = 0b11100011; // LI, Version, Mode packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[2] = 6; // Polling Interval packetBuffer[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; // all NTP fields have been given values, now // you can send a packet requesting a timestamp: Udp.beginPacket(address, 123); //NTP requests are to port 123 Udp.write(packetBuffer,NTP_PACKET_SIZE); Udp.endPacket(); }
E’ divertente perché stati facendo esattamente l’esperienza che feci io qualche decina di anni fa quando mi arrivò una scheda con a bordo un Intel 8080 e un po’ di i/o analogico e digitale, la differenza è che allora si lavorava in assembler e per fare quello che hai fatto tu ci volevano 20 pagine di codice fitto fitto, il terminale era una vecchissima telescrivente comperata al mercatino di via Pre’.
Fu molto divertente e molto educativo
roberto
sai leggere di queste automazioni intelligenti mi ha fatto ricordare di un aggeggio che mi ero ripromesso di installare nel mio nuovo appartamento…
http://www.nest.com/
bello! ma carissimo 🙂
Se proprio vogliamo buttare carne al fuoco direi che dovrebbe vedere se su Google Calendar (o altro servizio di calendario/appuntamenti che usi) è presente un evento prima della normale ora della sveglia, così da anticiparne l’accensione 🙂
La ricerca (“google calendar API” +Arduino) ha trovato circa 17.300 risultati 🙂 ma io preferirei collegarlo alla sveglia del mio Android
Qualcosa come:
delay(ITERATION);
elapsed += ITERATION;
if (elapsed % 60 * 60 * 24 == 0) {
// chiedi l’ora
elapsed = 0;
}
ti lascia fare operazioni anche fra una richiesta e l’altra. Molto poco estensibile, magari c’è qualche libreria.
Grazie Giorgio, non sapevo dell’operatore +=