Yun Christmas Lights

Luminițele mele de Crăciun rulează Linux! E un lucru cu care putem uimi chiar și cel mai versat invitat. Mai mult decât atât, putem să le comandăm direct de pe telefonul mobil prin WiFi. Acest lucru este posibil și destul de ușor de implementat utilizând o placă de dezvoltare Arduino Yun. Această placă de dezvoltare rulează distribuția Linux OpenWRT și combină conectivitatea de rețea a procesorului Atheros AR9331 cu posibilitatea de comandă în timp real a microcontrolerului ATmega32U4. Pentru lumini vom utiliza 25 de LED-uri RGB WS2801. Aceste LED-uri se comandă simplu prin intermediul a doar două fire (unul de clock și unul de date). Conectarea dintre placa de dezvoltare și LED-uri este următoarea:

2

Pinul D6 al plăcii de dezvoltare se va conecta la firul verde al șirului de LED-uri (firul de clock) iar pinul D5 la firul galben (firul de date). Alimentarea se va face cu ajutorul unei surse de tensiune de 5V minimum 2A, alimentarea va fi comună pentru placa de dezvoltare și pentru LED-uri. Nu alimentați montajul prin portul USB al plăcii de dezvoltare deoarece un port USB nu poate oferi un curent mai mare de 500mA. Pentru mai multe informații legate de utilizarea șirului de LED-uri puteți consulta și materialul „12mm LED Pixels”.

O alternativă mai ieftină pentru sistem este utilizarea plăcii Arduino Industrial 101 – placă mai ieftină și de dimensiuni mai mici. Identică din punct de vedere hardware cu placa Arduino Yun, placa Arduino Industrial 101 expune un număr mai mic de pini ai microcontrolerului ATmega32U4 și nu are interfață ethernet – ambele dezavantaje nu afectează cu nimic montajul propus în proiectul de față. Interfațarea cu șirul de LED-uri în cazul plăcii Arduino Industrial 101 este următoarea:

3

Atât programul cât și configurația conexiunii WiFi sunt identice în cazul ambelor plăci (Arduino Yun și Arduino Industrial 101).

Utilizarea plăcilor de dezvoltare presupune configurarea inițială a conexiunii WiFi (completarea informațiilor de acces WiFi). Utilizarea conexiunii ethernet nu presupune nici o configurație inițială (valabil doar pentru placa Arduino Yun) – interfața ethernet este configurată implicit să obțină o adresă în mod dinamic prin DHCP. Pentru configurarea inițială se recomandă parcurgere materialului „Getting Started with the Arduino Yún LininoOS”.

Pentru interfața de comandă mobilă vom utiliza serviciul cloud Blynk. Acest serviciu ne va facilita implementarea aplicației de comandă pe dispozitive mobile Android sau iOS. Necesită înregistrarea unui cont gratuit și instalarea aplicației specifice pe dispozitivul mobil. Se poate vedea și materialul „Cum să realizăm un sistem IoT fără să scriem nici o linie de cod?”.

4

Programul pentru placa de dezvoltare a fost dezvoltat și testat utilizând Arduino IDE 1.8.3 având instalate bibliotecile Adafruit WS2801 1.0.0, Blynk 0.4.10 și Time 1.5.0.

#include <Adafruit_WS2801.h>

#include <BlynkSimpleYun.h>

#include <TimeLib.h>

#include <WidgetRTC.h>

WidgetRTC rtc;

int dataPin = 5;

int clockPin = 6;

Adafruit_WS2801 strip = Adafruit_WS2801(25, dataPin,clockPin);

În cadrul programului trebuie personalizat codul de autentificare în cadrul serviciului Blynk. Acest cod se obține în momentul în care se creează aplicație mobilă de comandă.

char auth[] = “…”;

Sistemul va avea 4 stări posibile (starea va fi stocată în variabila mode): starea 0 – LED-urile vor fi stinse, starea 1 – toate LED-urile vor fi aprinse și vor avea aceiași culoare dată de aplicația de comandă, starea 2 – stare implicită, toate LED-uri vor fi aprinse dar vor avea culori diferite, starea 3 – un singur LED va fi aprins și se va plimba de la un cap la altul al șirului de LED-uri. În modul automat (variabila automat este implicit true) se va închide automat la ora 23:00 și va reporni la ora 10:00 a doua zi, modul automat va putea fi dezactivat din interfața de comandă mobilă.

byte mode = 2;

byte lastmode = 255;

int lastcolor = -1;

byte r,g,b;

boolean automat = true;

Secțiunea setup va inițializa conexiunea cu serviciul cloud Blynk, comunicația cu LED-urile WS2801 și va configura biblioteca Time să comunice la un interval de o oră (3600 de secunde) cu obiectul RTC (definit în interfața mobilă de comandă) pentru sincronizarea ceasului.

void setup() {

  Blynk.begin(auth);

  setSyncInterval(60*60);

  strip.begin();

  strip.show();

  r = 0; g = 0; b = 0;

}

Procedurile BLYNK_ tratează evenimentele specifice serviciului cloud preluând comenzile din interfața de comandă mobilă.

BLYNK_CONNECTED() {

rtc.begin();

}

BLYNK_WRITE(V7) {

b = param.asInt();

}

BLYNK_WRITE(V6) {

g = param.asInt();

}

BLYNK_WRITE(V5) {

r = param.asInt();

}

BLYNK_WRITE(V2) {

mode = param.asInt();

}

BLYNK_WRITE(V1) {

automat = param.asInt();

}

În cadrul secțiunii loop se implementează comanda efectivă către șirul de LED-uri WS2801 în conformitate cu informațiile primite din interfața mobilă.

void loop() {

Blynk.run();

if (automat) { if ((hour()>22) || (hour()<10)) mode = 0;

else if (mode==0) mode=2; }

if ((lastmode!=mode) || (lastcolor!=Color(r,g,b))) {

switch (mode) {

case 0:

for (int i = 0; i < strip.numPixels(); i++)

strip.setPixelColor(i, 0);

strip.show();

break;

case 1:

for (int i = 0; i < strip.numPixels(); i++)

strip.setPixelColor(i, Color(r,g,b));

strip.show();

break;

case 2:

for (int i = 0; i < strip.numPixels(); i++)

strip.setPixelColor(i, Wheel(((i * 256 /

strip.numPixels()) + Color(r,g,b)) & 255));

strip.show();

break;

case 3:

for (int i = 0; i < strip.numPixels(); i++) {

if(i>0) strip.setPixelColor(i-1, 0);

strip.setPixelColor(i, Color(r,g,b));

strip.show();

Blynk.run();

delay(200);

}

strip.setPixelColor(strip.numPixels()-1, 0);

strip.show();

break;

}

lastmode = mode;

lastcolor = Color(r,g,b);

}

}

Funcțiile Wheel și Color sunt utilizate pentru a calcula comanda de culoare către șirul de LED-uri WS2801.

uint32_t Wheel(byte WheelPos) {

if (WheelPos < 85) {

return Color(WheelPos * 3, 255 – WheelPos * 3, 0);

} else if (WheelPos < 170) {

WheelPos -= 85;

return Color(255 – WheelPos * 3, 0, WheelPos * 3);

} else {

WheelPos -= 170;

return Color(0, WheelPos * 3, 255 – WheelPos * 3);

}

}

uint32_t Color(byte r, byte g, byte b)

{

uint32_t c;

c = r;

c <<= 8;

c |= g;

c <<= 8;

c |= b;

return c;

}

Aplicația mobilă va conține 4 controale (cost total 900 de credite din cele 2000 oferite gratuit):

5

  • Un control Slider pentru stabilirea modului de funcționare (cost 200 de credite);
  • Un control ZeRGBa pentru stabilirea culorii LED-urilor în modurile de funcționare 1 și 3 (cost 400 de credite);
  • Un control Button pentru activarea / dezactivare funcționării automate a sistemului (cost 200 de credite);
  • Un control Real Time Clock (RTC) pentru sincronizarea timpului (cost 100 de credite).

Controlul Slider va fi conectat la pinul virtual V2 și va lua valori între 0 și 3 (cele patru moduri de funcționare ale sistemului).

6

Controlul zeRGBa va fi conectat la pinii virtuali V5, V6 și V7 ce vor trimite către sistem comanda RGB de culoare.

7

Controlul Button se va configura ca fiind de tip Switch și se va conecta la pinul virtual V1.

8

Pentru alte idei și alternative de realizare se pot trece în revistă și următoarele proiecte:

Sistem antifurt pentru cadourile de Crăciun

Securitatea cadourilor de Crăciun este o problemă care ar trebui să preocupe pe toți părinții responsabili. Hoți, persoane răuvoitoare și mai ales personajul malefic Grinch abia așteaptă să distrugă bucuria copiilor din dimineața zilei de Crăciun.

2

Pentru a împiedica acest lucru este absolut necesar ca toate cadourile să fie dotate cu sisteme de siguranță pentru a preveni furtul de sub bradul de Crăciun. În cadrul acestui proiect vă propunem realizarea unui sistem sofisticat care permite declanșarea unei alarme sonore când un cadou este sustras de sub brad.

Sistemul antifurt este bazat pe o placă de dezvoltare Arduino Uno ce are conectate un mini difuzor brick și un senzor magnetic brick. Mini difuzorul este utilizat pentru a genera sunetul de alarmă iar senzorul magnetic pentru a sesiza dacă cadoul a fost mișcat. Pentru a sesiza mișcarea / mutarea cadoului acesta trebuia să aibă integrat un mic magnet. Mișcarea magnetului este sesizată de senzorul magnetic Hall și semnalizată plăcii de dezvoltare ce declanșează alarma sonoră.

3

Mini difuzorul se va conecta la pinul digital 8 al plăcii de dezvoltare și la pinul de GND. Generarea sunetului de alarmă se va face utilizând funcția tone() din mediul Arduino IDE.

Senzorul magnetic brick se conecta la 5V și GND iar ieșirea (OUT) se va conecta la pinul digital 2 al plăcii de dezvoltare. Ieșirea senzorului va fi ”1” (adică 5V) dacă nu detectează un magnet în apropiere sau ”0” (adică 0V) dacă un magnet se află în imediata apropiere.

4

Schema de interconectare între cele trei componente este următoarea:

5

Programul a fost dezvoltat și testat utilizând mediul Arduino IDE 1.8.3.

#define hallPin 2

#define buzzerPin 8

void setup() {

  pinMode(hallPin,INPUT);

  pinMode(buzzerPin, OUTPUT);

}

void loop() {

  boolean alarma;

  alarma = digitalRead(hallPin);

  if (!alarma) tone(buzzerPin,1000);

  else noTone(buzzerPin);

  delay(5000);

}

După încărcarea programului pe placa de dezvoltare și instalarea sistemului antifurt sub cadou, în cazul în care se îndepărtează cadoul de pe sistemul antifurt se va declanșa alarma sonoră ce va zădărnici tentativa de furt.

În cazul în care dorim să micșorăm dimensiunea sistemului antifurt putem înlocui placa de dezvoltare Arduino Uno cu o placă Arduino Pro Mini. În plus putem alimenta sistemul de la o baterie de 9V și pentru a prelungi durata de funcționare vom configura microcontrolerul să funcționeze în regim de consum redus. Noua schemă de interconectare este:

6

Programul a fost realizat și testa utilizând mediul Arduino IDE 1.8.3 și biblioteca LowPower.

#include “LowPower.h”

#define wakeUpPin 2

#define buzzerPin 8

void setup() {

  pinMode(wakeUpPin,INPUT);

  pinMode(buzzerPin, OUTPUT);

}

void wakeUp(){ }

void loop() {

  attachInterrupt(0, wakeUp, HIGH);

  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);

  detachInterrupt(0);

  while (digitalRead(wakeUpPin)==1) {

    tone(buzzerPin,1000);

    delay(1000);

  }

  noTone(buzzerPin);

}

Spre deosebire de programul anterior, sistemul antifurt va funcționa în mod de consum redus. Declanșarea senzorului magnetic (mișcarea cadoului de pe sistemul antifurt) va declanșa o întrerupere ce va trezi microcontrolerul și va porni alarma sonoră. Dacă cadoul este pus la loc alarma va înceta.

Control WiFi pentru luminițele de Crăciun

Farmecul sărbătorilor de iarnă este dat, printre altele, de instalațiile de lumini. În sute de variante, în zeci de culori, aflate undeva între plăcerea de a decora și obsesie, jucării sau elemente de iluminat, instalațiile de luminițe sunt cu siguranță un element important în cadrul pregătirilor pentru sărbătoarea de Crăciun. Dacă ați experimentat suficiente instalații și simțiți că vreți să treceți la un nivel următor (adică să începeți să le personalizați), în cadrul proiectului de față vă propunem modificarea unei instalații existente prin adăugarea unei comenzi de pornire prin WiFi.

Comanda de pornire se poate realiza simplu prin intermediul unui element de tip releu. Pentru a realiza comanda de la distanță prin intermediul WiFi este necesar să conectăm elementul de tip releu la o placă de dezvoltare ce permite comunicație WiFi. Realizarea unui ansamblu compact, placă de dezvoltare WiFi plus releu de comandă, este însă o sarcină destul de anostă. Din acest motiv vă propunem utilizarea unei platforme integrate: ESP8266-EVB-BAT-BOX.

2

Această platformă este echipată cu un microprocesor WiFi ESP8266 și un releu 220VAC/10A. Platforma se poate alimenta de la alimentator de rețea de 5V sau de la un acumulator LiPo de 3.7V. Platforma se comercializează împreună cu o carcasă de protecție HAMMOND și conține un conector WAGO cu șurub de tip mufă (din două părți) pentru integrarea facilă a releului într-un montaj. Datorită facilităților oferite de această platformă este ideală pentru o aplicație de comandă de tip WiFi.

3

ATENȚIE!!! Chiar dacă releul de pe platforma ESP8266-EVB-BAT-BOX suportă comanda unor circuite conectate la tensiune de rețea (220V), NU este recomandată realizarea de montaje proprii la această tensiune fără supravegherea sau îndrumarea unui specialist. Pericol de electrocutare, moarte, scurtcircuit, incendiu!!! Pentru montaje personale de tip hobby se recomandă comanda unor circuite de luminițe alimentate de la baterii sau cu alimentator de rețea (tensiunea din firele conectate la releu să fie de 3V-12V) eliminând astfel riscul de accidentare.

Conectarea instalației se va face prin secționarea firului de curent (nu cel de masă) și intercalarea releului. Astfel, platforma ESP8266-EVB-BAT-BOX va putea controla alimentarea instalației și vom putea programa când aceasta să se aprindă. Sistemul propus va putea să aprindă instalația la o anumită oră sau în urma unei comenzi directe.

4

Programarea platformei necesită un programator FTDI de 3.3V. Pentru mai multe detalii despre programarea platformei EVB-BAT-BOX este necesară consultarea materialului „HOW TO USE ESP8266 WITH ARDUINO IDE”. Programul a fost dezvoltat și testat utilizând Arduino IDE 1.8.3 având instalată extensia ESP8266 Community 2.3.0.

#include <ESP8266WiFi.h>

#include <ESP8266mDNS.h>

#include <WiFiUdp.h>

#include <ESP8266WebServer.h>

#include <TimeLib.h>

const int timeZone = 2;

WiFiUDP Udp;

const int NTP_PACKET_SIZE = 48;

byte packetBuffer[NTP_PACKET_SIZE];

unsigned int localPort = 2390;   

WiFiServer server(80);

În cadrul programului trebuie personalizate datele de conectare la rețeaua WiFi (variabilele ssid și pass).

char ssid[] = “…”;

char pass[] = “…”;

WiFiClient client;

#define HOSTNAME “ESP8266-“

#define RELAY_PIN 5

int start_hour = 20;

int stop_hour = 23;

boolean automatic = true;

În cadrul secțiunii setup() se va inițializa conexiunea WiFi și se va raporta în consola serială adresa IP a sistemului. Aceasta trebuie folosită pentru a accesa sistemul dintr-un client web (browser) din aceiași rețea locală. Programul va utiliza biblioteca Time și conexiunea de rețea pentru a menține ora exactă (prin sincronizare NTP).

void setup() {

  Serial.begin(115200);

  Serial.println();

  Serial.println();

  pinMode(RELAY_PIN, OUTPUT);

  digitalWrite(RELAY_PIN,LOW);

  String hostname(HOSTNAME);

  hostname += String(ESP.getChipId(), HEX);

  Serial.println(“Hostname:” + hostname);

  WiFi.mode(WIFI_STA);

  WiFi.hostname(hostname);

  WiFi.begin(ssid, pass);

  delay(5000);

  if (WiFi.status() != WL_CONNECTED) {

    delay(10000);

    ESP.restart();

  }

  Serial.print(“IP:”);

  Serial.println(WiFi.localIP());

  server.begin();

  Udp.begin(localPort);

  setSyncProvider(getNtpTime);

}

Secțiunea loop() implementează comunicația HTTP ce ne va permite acționarea releului de la distanță. Interfața de comandă (ce poate fi accesată la adresa IP a sistemului) prezintă ora curentă, modul de funcționare (automat sau manual), ora de pornire și oprire automată precum și comenzile manuale de pornire / oprire. La pornire sistemul este în mod automat și are setate ca oră de pornire ora 20:00 și ca oră de oprire ora 23:00. Prin acționarea semnelor +/- din dreptul celor două ore presetate acestea pot fi modificate.

5

Prin acționarea comenzilor manuale de oprire sau pornire se va comuta în modul manual de comandă în care intervalul de funcționare automată este ignorat și sistemul răspunde doar la comenzile manuale de pornire și oprire. Reactivarea modului de funcționare automat se poate face apelând orice modificare (+/-) a orelor de pornire / oprire automată.

6

void loop() {

  if (automatic)

    if ((hour()>start_hour) && (hour()<stop_hour))

digitalWrite(RELAY_PIN, HIGH);

    else digitalWrite(RELAY_PIN, LOW);

  WiFiClient client = server.available();

  if (!client) return;  

  Serial.println(“new client”);

  while(!client.available()){ delay(1); }

  String request = client.readStringUntil(‘\r’);

  Serial.println(request);

  client.flush();

  if (request.indexOf(“/COMMAND=ON”) != -1) {

    digitalWrite(RELAY_PIN, HIGH); 

    automatic = false;

  }

  else if (request.indexOf(“/COMMAND=OFF”) != -1) {

    digitalWrite(RELAY_PIN, LOW); 

    automatic = false;

  }

  else if (request.indexOf(“/COMMAND=PLUS_START”) != -1) {

    start_hour++;

    if (start_hour>23) start_hour=0;

    automatic = true;

  }

  else if (request.indexOf(“/COMMAND=MIN_START”) != -1) {

    start_hour–;

    if (start_hour<0) start_hour=23;

    automatic = true;

  }

  else if (request.indexOf(“/COMMAND=PLUS_STOP”) != -1) {

    stop_hour++;

    if (stop_hour>23) stop_hour=23;

    automatic = true;

  }

  else if (request.indexOf(“/COMMAND=MIN_STOP”) != -1) {

    stop_hour–;

    if (stop_hour<0) stop_hour=23;

    automatic = true;

  }

  client.println(“HTTP/1.1 200 OK”);

  client.println(“Content-Type: text/html”);

  client.println(“”);

  client.println(“<!DOCTYPE HTML>”);

  client.println(“<html>”);

  client.println(“<h1>WiFi Christmas Lights</h1>”);

  client.println(“<br>”);

  client.print(“Time now: “);

  client.print(hour());

  client.print(“:”);

  client.print(minute());

  client.print(“:”);

  client.println(second());

  client.println(“<br>”);

  if (automatic) client.print(“Mode: Automatic”);

  else client.print(“Mode: Manual”);

  client.println(“<br>”);

  client.println(“Click <a href=\”/COMMAND=ON\”>here</a> to turn ON the Christmas Lights<br>”);

  client.println(“Click <a href=\”/COMMAND=OFF\”>here</a> to turn OFF the Christmas Lights<br>”);

  client.print(“Autostart at <a href=\”/COMMAND=PLUS_START\”>(+)</a>”);

  client.print(start_hour);

  client.println(“<a href=\”/COMMAND=MIN_START\”>(-)</a> hour.”);

  client.println(“<br>”);

  client.print(“Autostop at <a href=\”/COMMAND=PLUS_STOP\”>(+)</a>”);

  client.print(stop_hour);

  client.println(“<a href=\”/COMMAND=MIN_STOP\”>(-)</a> hour.”);

  client.println(“</html>”);

  delay(1);

  Serial.println(“Client disonnected”);

  Serial.println(“”);

}

Funcțiile getNtpTime() și sendNTPpacket() sunt apelate periodic automat de biblioteca Time pentru sincronizarea timpului.

IPAddress timeServerIP;

const char* ntpServerName = “time.nist.gov”;

time_t lastsyncr;

time_t getNtpTime() {

  WiFi.hostByName(ntpServerName, timeServerIP);

  while (Udp.parsePacket() > 0) ;

  sendNTPpacket(timeServerIP);

  uint32_t beginWait = millis();

  while (millis() – beginWait < 2500) {

    int size = Udp.parsePacket();

    if (size >= NTP_PACKET_SIZE) {

      Udp.read(packetBuffer, NTP_PACKET_SIZE); 

      unsigned long secsSince1900;

      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;

     secsSince1900 |= (unsigned long)packetBuffer[41] << 16;

      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;

      secsSince1900 |= (unsigned long)packetBuffer[43];

      lastsyncr = (time_t) (secsSince1900 – 2208988800UL + timeZone * SECS_PER_HOUR);

      return lastsyncr;

    }

  }

 return 0;

}

void sendNTPpacket(IPAddress &address) {

  memset(packetBuffer, 0, NTP_PACKET_SIZE);

  packetBuffer[0] = 0b11100011;  

  packetBuffer[1] = 0;

  packetBuffer[2] = 6;

  packetBuffer[3] = 0xEC; 

  packetBuffer[12]  = 49;

  packetBuffer[13]  = 0x4E;

  packetBuffer[14]  = 49;

  packetBuffer[15]  = 52;

  Udp.beginPacket(address, 123);

  Udp.write(packetBuffer, NTP_PACKET_SIZE);

  Udp.endPacket();

}

Pentru alte variante de realizare puteți consulta și proiectele:

Calendar de Crăciun

Calendarul de Crăciun sau Calendarul de Advent este o modalitate de a face să treacă timpul mai ușor în așteptarea sărbătorii de Crăciun. Acest calendar indică câte zile au trecut și câte zile mai sunt (în luna decembrie bineînțeles) până în dimineața zilei de Crăciun. Pentru copii există variante care oferă zilnic mici surprize (bomboane sau ciocolată) pentru a atenua nerăbdarea așteptării cadourilor de Crăciun dar, în cadrul proiectului de față, propunem construirea unui calendar de Crăciun bazat pe 24 de LED-uri: un calendar de Crăciun cu luminițe.

Pentru a comanda mai ușor cele 24 de LED-uri vom utiliza LED-uri RGB adresabile WS2812. Acestea nu necesită comandă individuală, este suficientă o singură linie de comandă între cele 24 de LED-uri și placa de dezvoltare. Se pot utiliza LED-uri NeoPixel  sau module WS2812 breakout. Pentru mai multe detalii legate de funcționarea LED-urilor WS2812 se recomandă parcurgerea materialului: „Adafruit NeoPixel Überguide”.

2

Pentru comandă vom utiliza placa de dezvoltare WiDo echipată cu un microcontroler ATmega32U4 (prezent și pe placa Arduino Leonardo) și un controler WiFi CC3000. Această combinație este perfectă pentru implementarea sistemului nostru: microcontrolerul ATmega32U4 va asigura comanda LED-urilor la o tensiune de 5V iar controlerul WiFi va fi utilizat pentru a putea ști în ce zi calendaristică ne aflăm (sincronizare de timp de tip NTP).

3

Conexiunile dintre placa de dezvoltare și LED-uri sunt prezentate în schema următoare. Sistemul necesită o alimentare de 5V minim 2A (pentru placa de dezvoltare și cele 24 de LED-uri). Pinul de comandă este pinul D6. Comanda se va transmite serial de la un LED la următorul. LED-urile pot fi aranjate pe un carton pictat cu un brad de crăciun sau orice alt suport doriți (o căsuță de poveste sau o ilustrată de Crăciun).

4

Programul a fost dezvoltat și testat utilizând Arduino IDE 1.8.3 și bibliotecile Adafruit Neopixel 1.1.3 și o versiune modificată a bibliotecii Adafruit CC3000. Placa se va programa în Arduino IDE ca o placă Arduino Leonardo obișnuită.

#include <Adafruit_NeoPixel.h>

#ifdef __AVR__

  #include <avr/power.h>

#endif

#define PIN 6

#define NUMPIXELS 24

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS,PIN, NEO_GRB + NEO_KHZ800);

#include <Adafruit_CC3000.h>

#include <ccspi.h>

#include <SPI.h>

#define WiDo_IRQ   7

#define WiDo_VBAT  5

#define WiDo_CS    10

Adafruit_CC3000 WiDo = Adafruit_CC3000(WiDo_CS, WiDo_IRQ,  WiDo_VBAT,SPI_CLOCK_DIVIDER);

În cadrul programului trebuie personalizate datele de conectare la rețeaua WiFi (WLAN_SSID și WLAN_PASS).

#define WLAN_SSID       “…”          

#define WLAN_PASS       “…”

#define WLAN_SECURITY   WLAN_SEC_WPA2

Adafruit_CC3000_Client client;

#include <TimeLib.h>

Pentru sistemul final, directiva debug se poate comenta pentru a suprima mesajele din consola serială.

#define debug

void setup() {

  #ifdef debug

    SerialUSB.begin(115200);

    while(!SerialUSB) { ; }

    SerialUSB.println(F(“Calendar de Craciun\n”));

    SerialUSB.println(F(“\nInitialising the CC3000 …”));

  #endif

  if (!WiDo.begin())  {

    #ifdef debug

      SerialUSB.println(F(“Unable to initialise the

CC3000! Check your wiring?”));

    #endif

    while(1);   }

 if (!WiDo.connectToAP(WLAN_SSID,WLAN_PASS,WLAN_SECURITY)) {

    #ifdef debug

      SerialUSB.println(F(“Failed to connect to AP!”));

    #endif

    while(1);   }

  #ifdef debug

    SerialUSB.println(F(“Connected to AP!”));

    SerialUSB.println(F(“Request DHCP”));

  #endif

  while (!WiDo.checkDHCP())  {    delay(100);  } 

  while (! displayConnectionDetails()) {

      delay(1000);

    }

  setSyncProvider(getTime);

  pinMode(6,OUTPUT);

  pixels.begin();

  randomSeed(analogRead(0));

  startprogram();

}

bool displayConnectionDetails(void)

{

  uint32_t ipAddress, netmask, gateway, dhcpserv, dnsserv;

  if(!WiDo.getIPAddress(&ipAddress, &netmask, &gateway, &dhcpserv, &dnsserv))  {

    #ifdef debug

      SerialUSB.println(F(“Unable to retrieve the IP Address!\r\n”));

    #endif

    return false;

  }

  else

  {

    #ifdef debug

      SerialUSB.print(F(“\nIP Addr: “));

     WiDo.printIPdotsRev(ipAddress);

      SerialUSB.print(F(“\nNetmask: “));

      WiDo.printIPdotsRev(netmask);

      SerialUSB.print(F(“\nGateway: “));

      WiDo.printIPdotsRev(gateway);

      SerialUSB.print(F(“\nDHCPsrv: “));

      WiDo.printIPdotsRev(dhcpserv);

      SerialUSB.print(F(“\nDNSserv: “));

      WiDo.printIPdotsRev(dnsserv);

      SerialUSB.println();

    #endif

    return true;

  }

}

Procedura startprogram(), apelată o singură dată în secțiunea setup(), aprinde toate LED-urile de trei ori în trei culori diferite: roșu, verde, albastru. Este o procedură de verificare a montajului ce se execută la fiecare pornire a sistemului.

void startprogram() {

  for (int i=0; i<NUMPIXELS; i++) {

    pixels.setPixelColor(i, pixels.Color(255,0,0));

    pixels.show();

    delay(100);

  }

  for (int i=0; i<NUMPIXELS; i++) {

    pixels.setPixelColor(i, pixels.Color(0,0,0));

  }

  pixels.show();

  delay(100);

  for (int i=0; i<NUMPIXELS; i++) {

    pixels.setPixelColor(i, pixels.Color(0,255,0));

    pixels.show();

    delay(100);

  }

  for (int i=0; i<NUMPIXELS; i++) {

    pixels.setPixelColor(i, pixels.Color(0,0,0));

  }

  pixels.show();

  delay(100);

  for (int i=0; i<NUMPIXELS; i++) {

    pixels.setPixelColor(i, pixels.Color(0,0,255));

    pixels.show();

    delay(100);

  }

  for (int i=0; i<NUMPIXELS; i++) {

    pixels.setPixelColor(i, pixels.Color(0,0,0));

  }

  pixels.show();

  delay(100);

}

Secțiunea loop() va aștepta realizarea sincronizării de timp după care va verifica o dată la 10 minute data calendaristică. Între 1 decembrie și 24 decembrie va aprinde un număr de LED-uri egal cu data calendaristică. Culoarea va fi de fiecare dată generată aleatoriu. În data de 25 decembrie programul va executa un joc de lumini pe toată perioada zilei (va aprinde toate cele 24 de LED-uri treptat în culori aleatorii). În restul anului LED-urile vor rămâne stinse.

void loop() {

   #ifdef debug

    if(timeStatus()==timeNotSet) SerialUSB.println(“Time Not Set”);

    if(timeStatus()==timeNeedsSync) SerialUSB.println(“Time Needs Sync”);

   #endif

   while(timeStatus()==timeNotSet) delay(1000);

   for (int i=0; i<NUMPIXELS; i++) {

      pixels.setPixelColor(i, pixels.Color(0,0,0));

    }

   pixels.show();

   delay(100);

   if(month()==12) {

    if (day()<25) {

      #ifdef debug

        SerialUSB.print(“Days to Christmas: “); SerialUSB.println(25-day());

      #endif

      for (int i=0; i<NUMPIXELS; i++) {

        pixels.setPixelColor(i, pixels.Color(0,0,0));

      }

      pixels.show();

      delay(100);

      for (int i=0; i<day(); i++) {

        pixels.setPixelColor(i,pixels.Color(random(0,255),random(0,255),random(0,255)));

      }

      pixels.show();

    }

    if (day()==25) {

        for (int i=0; i<NUMPIXELS; i++) {

          pixels.setPixelColor(i,pixels.Color(random(0,255), random(0,255),random(0,255)));

         pixels.show();

         delay(1000);

        }

    }

   }

   delay(600000);

}

Funcția getTime() este folosită de biblioteca Time pentru sincronizarea de timp NTP.

const unsigned long

  connectTimeout  = 15L * 1000L,

  responseTimeout = 15L * 1000L;

unsigned long getTime(void) {

  uint8_t       buf[48];

  unsigned long ip, startTime, t = 0L;

  #ifdef debug

    SerialUSB.print(F(“Locating time server…”));

  #endif

  if(WiDo.getHostByName(“pool.ntp.org”, &ip)) {

    static const char PROGMEM

      timeReqA[] = { 227,  0,  6, 236 },

      timeReqB[] = {  49, 78, 49,  52 };

    #ifdef debug

      SerialUSB.println(F(“\r\nAttempting

                 connection…”));

    #endif

    startTime = millis();

    do {

      client = WiDo.connectUDP(ip, 123);

    } while((!client.connected()) &&

            ((millis() – startTime) < connectTimeout));

    if(client.connected()) {

      #ifdef debug

        SerialUSB.print(F(“connected!\r\nIssuing

                 request…”));

      #endif

      memset(buf, 0, sizeof(buf));

      memcpy_P( buf    , timeReqA, sizeof(timeReqA));

      memcpy_P(&buf[12], timeReqB, sizeof(timeReqB));

      client.write(buf, sizeof(buf));

      #ifdef debug

        SerialUSB.print(F(“\r\nAwaiting response…”));

      #endif

      memset(buf, 0, sizeof(buf));

      startTime = millis();

      while((!client.available()) &&

            ((millis() – startTime) < responseTimeout));

      if(client.available()) {

        client.read(buf, sizeof(buf));

        t = (((unsigned long)buf[40] << 24) |

             ((unsigned long)buf[41] << 16) |

             ((unsigned long)buf[42] <<  8) |

              (unsigned long)buf[43]) – 2208988800UL;

        #ifdef debug

          SerialUSB.print(F(“OK\r\n”));

        #endif

      }

      client.close();

    }

  }

  #ifdef debug

    if(!t) SerialUSB.println(F(“error”));

  #endif

  return t;

}

Pentru idei suplimentarea în realizarea artistică a aranjamentului se pot vedea și următoarele două proiecte: