Arduino IoT – Ethernet Shield testailua

Johdanto

Tämä on ensimmäinen IoT-harjoitus, jonka tein alunperin opiskelijoita varten. Harjoituksessa rakennetaan laite, jolla voidaan ohjata mm. LED-valoja ja tuuletinta sekä tarkkaillaan tilan valaistusta ja lämpötilaa. Laitteeseen voidaan ottaa yhteys WiFi-verkon kautta tietokoneella tai mobiililaitteella. Käytännössä Arduino toimii web-serverinä.

Esimerkkikoodi

Tätä koodia ei kannata käyttää ”oikeassa” sovelluksessa, mutta sillä pääset nopeasti testaamaan ethernet shieldin toimintaa ja tekemään jotain konkreettisia ohjauksia. Esimerkissä ei ole huomioitu tietoturvaa millään tavalla, eikä toteutus ole muutenkaan sieltä optimaalisimmasta päästä. ”This is just for fun”

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

#define lampoanturi A5
#define ldrvastus A2

int tuuletinPin = 6;
int ledPin = 7;
int valaistusPin = 5;

int lampo = 0;
int valoisuus = 0;
int porrastus = 40;

int viive = 1000;

int ledtila=0;
int  headerSent=0;
int jaahdytysPaalla = 0;
int valaistustila = 0;
int valaistuskirkkaus = 200;

int incoming;

// Arduino Ethernet MAC-osoite (Samassa verkossa olevilla laitteilla oltava uniikki MAC-osoite eli muista vaihtaa tarvittaessa!!)
// Googlesta löytyy myös MAC-generaattori
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
// Kiinteä IP-osoite (MUISTA VAIHTAA OIKEALLE IP-ALUEELLE JA TARKISTA, ETTÄ OSOITE EI OLE DHCP:LLÄ JAOSSA!)
IPAddress ip(192,168,1,123);
// Arduino web-serverin portti
EthernetServer server(80);

void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(tuuletinPin, OUTPUT);
  pinMode(valaistusPin, OUTPUT);

  // Muodostetaan verkkoyhteys ja käynnistetään serveri
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop()
{   
  headerSent=0;     
  // Seuraillaan yhdistääkö joku serveriin
  EthernetClient client = server.available();
  if (client) {
    // HTTP-pyyntö päättyy tyhjään riviin
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
                // Jos osoitteessa ei ole muuta niin ei käydä läpi käskyjä vaan tulostetaan pelkkä HTML-sivu
                if (incoming && c==' ')
                {
                    incoming=0;
                }
                // Jos osoitteessa on komentoja niin käydään läpi käskyt
                if (c=='$')
                {
                    incoming=1;
                }
                // Tsekataan url ja tehdään sen perusteella juttuja (ip/$1, ip/$2 jne jne...)
                if (incoming==1)
                {
                  headerSent=1;
                  client.println("HTTP/1.1 200 OK");
                  client.println("Content-Type: text/html");
                  client.println();
                    // Laitetaan tuulettimen ohjaus päälle ja sytytetään merkkivalo
                    if(c=='1')
                    {
                       digitalWrite(ledPin, HIGH);
                       ledtila = 1;
                       headerSent=1;
                       jaahdytysPaalla = 1;
                        client.println("<meta http-equiv='refresh' content='0;URL=/'>\n");
                    }
                    // Tuulettimen ohjaus pois
                    if(c=='2')
                    {
                       digitalWrite(ledPin, LOW);
                       ledtila = 0;
                       jaahdytysPaalla = 0;
                        client.println("<meta http-equiv='refresh' content='0;URL=/'>\n");
                    }
                    // Valaistus päälle
                    if(c=='3')
                    {
                       valaistustila = 1;
                        client.println("<meta http-equiv='refresh' content='0;URL=/'>\n");
                    }
                    // Valaistus pois
                    if(c=='4')
                    {
                       valaistustila = 0;
                        client.println("<meta http-equiv='refresh' content='0;URL=/'>\n");
                    }
                    // Kirkkautta lisää
                    if(c=='5')
                    {
                      // Tarkistetaan, että säädettävä arvo pysyy halutulla alueella (PWM alue 0-255)
                      if(valaistuskirkkaus<=250 && (valaistuskirkkaus+porrastus)<=250) {
                        valaistuskirkkaus += porrastus;
                      }
                        client.println("<meta http-equiv='refresh' content='0;URL=/'>\n");
                    }
                    // Kirkkautta vähemmän
                    if(c=='6')
                    {
                      // Tarkistetaan, että säädettävä arvo pysyy halutulla alueella (PWM alue 0-255)
                      // Ei kuitenkaan haluta sammuttaa valoa kokonaan vaan pidetään 10 miniminä
                      if(valaistuskirkkaus>=10 && (valaistuskirkkaus-porrastus)>=10) {
                        valaistuskirkkaus -= porrastus;
                      }
                        client.println("<meta http-equiv='refresh' content='0;URL=/'>\n");
                    }
                }
        // Käskyt käyty läpi eli tulostetaan varsinainen HTML-sivu
        if (c == '\n' && currentLineIsBlank) {
          // TULOSTETAAN HTML SIVU
            // Luetaan valoanturin arvo
            valoisuus = analogRead(ldrvastus);
            // Luetaan lämpötila
            lampo = analogRead(lampoanturi);
              float voltage = lampo * 5;
                 voltage /= 1024.0; 
                 float temperatureC = (voltage - 0.5) * 100 ; 
                 
          // Jos http-header lähetetty jo ylempänä niin ei lähetetä uudelleen, koska se ilmestyisi tekstinä www-sivulle
          // Muuten lähetetään header data niin saadaan renderöity www-sivu selaimeen
          if(headerSent == 0) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html");
            client.println();
          }
            // Tulostetaan HTML-runko
            client.println("<html>\n<head>\n<meta charset='UTF-8'>\n");
            client.println("<meta name='viewport' content='width=device-width, initial-sclae=1.0'>\n");
            client.println("<meta http-equiv='refresh' content='5'>\n");
            client.println("<title>Arduino Ethernet IoT testi</title>\n");
            client.println("<style>");
            client.println("body { background-color:#143366; color : #FFF; font-size:24px; font-family: Calibri, Arial, Verdana; text-align:center; margin : 10px; } \n");
            client.println(".painike { display:block; margin:0 auto; min-width:80px; max-width : 70%; background-color:#e28000; border-radius:10px; padding:10px; color:#FFF; font-weight:bold; color:#FFF; text-decoration:none; margin-bottom:20px; }");
            client.println(".painike:hover { border:2px solid white; }");
            client.println(".puolikas { display:block; margin:0 auto; width:50%; text-align:center; }");
            client.println(".mini { display:inline-block; margin:10px; font-size:32px; }");
            client.println("</style>");
            client.println("</head>\n<body>\n");
            client.println("<h1>Huone X</h1>\n");
            client.println("<b>Tilan valaistus:</b> ");
              // Tsekataan onko valot päällä (LDR-vastuksen arvot luettu valojen ollessa päällä ja ilman valoa)
              if(valoisuus>=980) {
                client.println("päällä <br>\n");
              }
              else {
                client.println("pois <br>\n");
              }
            // Jos haluat tarkistaa LDR-vastuksen arvot niin poista kommentti alemmasta rivistä
            //client.println(valoisuus);
            // Tulostetaan lämpötila
            client.println("<b>Lämpötila:</b> ");
            client.println(temperatureC);
            client.println(" C <br><br>");
            // Tulostellaan jäähdytyksen painike
            if(ledtila == 1) {
              client.println("<a class='painike' href='/$2'>Sammuta jäähdytys</a><br>");
            }
            else {
              client.println("<a class='painike' href='/$1'>Käynnistä jäähdytys</a><br>");
            }
            // Tulostetaan valaistuksen painike
            if(valaistustila == 1) {
              client.println("<a class='painike' href='/$4'>LED-valaistus pois</a><br>");
              client.println("<span class='puolikas'>");
              client.println("<b>Kirkkaus:</b><br>");
              client.println("<a class='painike mini' href='/$5'>+</a>");
              client.println("<a class='painike mini' href='/$6'>-</a>");
              client.println("</span>");
            }
            else {
              client.println("<a class='painike' href='/$3'>LED-valaistus päälle</a><br>");
            }
            client.println("</body>\n</html>");

          break;
        }
        if (c == '\n') {
          // Osoite loppuu
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          // Osoitteessa on merkkejä
          currentLineIsBlank = false;
        }
      }
    }
    // Odotellaan hetki www-serveriä...
    delay(1);
    // Suljetaan yhteys
    client.stop();
  }
  
  // Tuulettimen ohjaus
  if(jaahdytysPaalla == 1) {
    analogWrite(tuuletinPin,255);
  }
  else {
    digitalWrite(tuuletinPin,LOW);
  }
  // Valaistuksen ohjaus
  if(valaistustila == 1) {
    analogWrite(valaistusPin,valaistuskirkkaus);
  }
  else {
    digitalWrite(valaistusPin,LOW);
  }
}

Lopputulos

Mikäli kaikki meni niin kuin strömsössä niin lopputulema pitäisi olla jotakuinkin tämmöinen:

https://www.instagram.com/p/Bqs2ndBDdAS/