Internet of Things (IoT)

Fra HTX-Arduino
Skift til: navigering, søgning
Video med forklaring til kapitlet

Det nye indenfor elektronikverdenen, er Internet of Things - eller bare IoT. Konceptet er, at ALT skal på nettet / forbindes til Internettet. På den måde kan man have sensorer der måler temperatur, lysintensitet, CO2 indhold i luften, jordfugtighedsniveauet i potteplanten eller hvad man nu lige kan finde på. Måledata kan enten sendes via netværket til en server, hvor de samles i f.eks. en database, eller de kan tilgås direkte via en webserver ude ved f.eks. potteplanten. Mulighederne er mange…

Kodeeksempler

Til dette kapitel er der nogle kodeeksempler man kan anvende. De er samlet i en ZIP-fil.

Arduino til IoT

For at få sit Arduinoboard koblet til Internettet, er der behov for et netværksinterface; Det kan enten være med kabel (Ethernet) eller trådløs (WiFi). Man kan købe et Ethernet Shield til sit Arduino Uno board (se figur 1), som passer ned i de sorte connectorer langs kanten af Arduino Uno boardet. Det kunne være et W5100 modul. Dette beskrives i afsnittet #Eksempel til W5100 Ethernet Shield.

W5100 Ethernet Shield til Arduino UNO
Figur 1 W5100 Ethernet Shield til Arduino UNO.

Man kan også købe et WiFi Shield til sit Arduino UNO board. Det kan være et med et ESP8266-12F modul på. Dette beskrives i afsnittet #Eksempel til ESP8266-12F WiFi Shield.

Der er også mulighed for helt at undgå selve Arduino UNO boardet, for så i stedet for at programmere ESP8266 modulet, og bruge det “stand-alone”. Mere om det i afsnit #Eksempel til ESP8266 “Stand-alone”.

Eksempel til W5100 Ethernet Shield

Der findes allerede eksempler i Arduino IDE med programkode til at bruge et Ethernet Shield med W5100 controlleren på. Disse eksempler findes under: Fil - Eksempler - Ethernet. En beskrivelse af eksemplerne findes på Arduino’s egen side: https://www.arduino.cc/en/Reference/Ethernet.

Som eksempel kan nævnes WebServer[1]. Her kan man sætte et antal analoge sensorer på Arduinoboardets analoge input (A0 til A5), og via IP-adressen som Ethernet Shield’et får tildelt fra routeren, tilgå en web side og se værdierne af de analoge input.

For at få eksemplet til at køre med Ethernet Shield’et, skal man i programkoden skrive den MAC-adresse ind, som Ethernet Shield’et har. Det vil sige, at øverst i koden ændres de 6 bytes til det der nu står på det Ethernet Shield man har købt. Standard står den til 0xDEADBEEFFEED

 
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};

på samme måde skal IP adressen ændres til den adresse, som Ethernet Shield’et har fået tildelt af den router som den er koblet til. Standard står den til: 192.168.1.177:

 
IPAddress ip(192, 168, 1, 177);

Eksempel til ESP8266-12F WiFi Shield

Når man benytter et ESP8266-12E WiFi Shield sammen med Arduino UNO boardet, sendes kommandoer fra Arduino’en til ESP8266 modulet. Denne kommunikation foregår via de såkaldte AT kommandoer, via en seriel port (UART).

Arduino UNO boardet har kun én UART port, og det er den port som kommunikationen med computeren (via USB kablet) foregår gennem. Derfor benyttes ofte en såkaldt software UART til kommunikationen mellem Arduino UNO boardet og ESP8266 modulet, hvilket betyder, at to almindelige digitale porte på Arduino Uno boardet, via programkoden, agerer UART. I programeksemplerne skal man derfor vælge, hvilke to digitale porte man ønsker at bruge til software UART’en.

For at kunne kommunikere med ESP8266 WiFi Shield’et, skal man have hentet et WiFi library til Arduino IDE; Der er ikke som standard et brugbart library med i Arduino IDE. Der er flere muligheder, men det kunne være WiFiESP[2], der hentes fra: https://github.com/bportaluri/WiFiEsp. Her vælges “Clone or download”, og efterfølgende “Download ZIP” (se figur 2).

WiFiESP library’et hentes ved at klikke på “Clone or download” og efterfølgende på “Download ZIP”
Figur 2 WiFiESP library’et hentes ved at klikke på “Clone or download” og efterfølgende på “Download ZIP”.

Zip-filen åbnes, og biblioteket “WiFiEsp-master” kopieres til mappen: c:\dokumenter\arduino\libraries\ Herefter ændres mappens navn fra WiFiEsp-master til WiFiEsp. På figur 3 ses WiFiEsp mappen i Stifinder.

WiFiEsp mappen i Stifinder
Figur 3 WiFiEsp mappen i Stifinder.

Når man herefter lukker og genåbner sin Arduino IDE, kan man under: Fil - Eksempler - WiFiEsp finde eksempler der kan køre med ESP8266 WiFi Shield’et.

Hvis man for eksempel vælger eksemplet WebServer[3], er der et par ændringer man skal huske at foretage. Det er de to linjer i starten af programkoden, hvor routerens SSID samt password skal ændres til det ens egen router har:

 
char ssid[] = "Twim";            // your network SSID (name)
char pass[] = "12345678";        // your network password

Det vil sige, at hvis ens router har navnet Twim, og passwordet 12345678, så behøver man ikke ændre noget - ellers ændrer man det til hvad man nu har af navn og password på routeren, som WiFi modulet skal koble sig på.

Programkoden kompileres, og uploades til Arduino UNO boardet, og man starter Serial Monitor i Arduino IDE (øverste højre hjørne af Arduino IDE) se figur 4.

Serial Monitor i Arduino IDE startes op
Figur 4 Serial Monitor i Arduino IDE startes op.

Datakommunikationshastigheden skal i Serial Monitor her sættes til 115.200 Baud.

Herefter vil man kunne følge WiFi modulets forsøg på at koble sig på routeren. Når dette lykkes, skrives den IP adresse som WiFi modulet har fået tildelt af routeren. Man kan derefter taste den IP adresse ind i sin webbrowser, og man vil herefter kunne se en web side der er indeholdt i programkoden der kører på Arduino UNO boardet. I Serial Monitor’en vil man kunne se, at der er tilsluttet en client til webserveren, og at denne har fået tilsendt websiden.

Eksempel til ESP8266 “Stand-alone”

Man kan vælge at arbejde udelukkende med ESP8266 WiFi modulet - helt uafhængig af Arduino UNO boardet. En fordel er, at elektronikken fylder mindre, end hvis Arduino UNO boardet skulle have været med.

ESP8266 modulet er mere end bare en WiFi chip; den indeholder også en mikroprocessor og flash hukommelse, hvor man kan lægge sit eget program over i, og få det afviklet på mikroprocessoren.

Man kan få flere forskellige udgaver af ESP8266 modulet. En populær udgave er 12F, der både har en række digitale input/output porte (ligesom på Arduino UNO boardet), foruden et analog input.

Databladet for ESP8266 modulet kan findes her: https://espressif.com/sites/default/files/documentation/0a-esp8266ex_datasheet_en.pdf

Selve ESP8266-12F modulet er et lille print, med selve ESP8266 chippen indkapslet i en metalkappe. Denne ses på figur 5. Modulet kører med en spænding på 3,3V. Oftest vil man købe et udviklingsboard hvor ESP8266-12F modulet er monteret på, sammen med strømforsyning og connectorer til input/output portene.

ESP8266-12F modul
Figur 5 ESP8266-12F modul.

Der findes flere forskellige udviklingsboards, hvor ESP8266-12F modulet sidder på, og som kan bruges som “stand-alone”. Det kunne for eksempel være WeMos D1 mini (se figur 6).

WeMos D1 mini board med ESP8266 modul
Figur 6 WeMos D1 mini board med ESP8266 modul.

Man kan bruge Arduino IDE til at programmere ESP8266 modulet fra. For at ”opgradere” Arduino IDE til at kunne kommunikere med ESP8266, skal man tilføje følgende link under: Fil - Egenskaber - Additional boards managers URLs:

http://arduino.esp8266.com/stable/package_esp8266com_index.json

Figur 7 viser linket indsat i Egenskaber.

Tilføj ESP8266 som board der kan kommunikeres med fra Arduino IDE
Figur 7 Tilføj ESP8266 som board der kan kommunikeres med fra Arduino IDE.

Herefter kan man installere “ESP8266 boards”. Det gøres ved at vælge: Værktøjer - Board - Boards Manager… og i søgefeltet øverst skrive “esp8266”. Herefter fremkommer esp8266-pakken som skal installeres (se figur 8). Pakken installeres herefter.

Under Værktøjer - Board - Bords Manager… søges efter ESP8266 og denne vælges og installeres
Figur 8 Under Værktøjer - Board - Bords Manager… søges efter ESP8266 og denne vælges og installeres.

Nu kan man vælge ESP8266 som udviklingsboard i stedet for Arduino Uno boardet. Det gøres under: Værktøjer - Boards. Se figur 9 hvor der vælges et WeMos D1 mini board med ESP8266 modul.

Vælg det board du har med ESP8266 modulet på
Figur 9 Vælg det board du har med ESP8266 modulet på.

For at kunne programmere WeMos D1 mini, skal man hente en USB driver til den CH340 USB kreds der sidder på WeMos boardet. Det er samme driver som skal bruges til at koble sig på kinesiske kopiudgaver af Arduino UNO. Man kan hente driveren fra følgende adresse: https://wiki.wemos.cc/downloads

Som programeksempel kan man anvende WebServer[4] eksemplet herfra: http://www.arduinesp.com/wifiwebserver, hvor man via webserveren kan tænde og slukke for portben 2 på ESP8266 modulet.

Det gengives nedenfor i en lettere modificeret version, der øger stabiliteten. Bemærk, at man skal huske at ændre SSID og password til at passe til den router man ønsker at forbinde sig til:

#include <ESP8266WiFi.h>
 
const char* ssid = "SSID";
const char* password = "PASSWORD";   
 
int ledPin = 2; // GPIO2
 
WiFiServer server(80);
 
void setup() {
  Serial.begin(9600);
  delay(10);
 
  WiFi.mode(WIFI_STA);
 
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
 
// Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
 
  // Start the server
  server.begin();
  Serial.println("Server started");
 
  // Print the IP address
  Serial.print("Use this URL to connect: ");
  Serial.print("http://");
  Serial.print(WiFi.localIP());
  Serial.println("/");
}
 
void loop() {
  // Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
 
  // Wait until the client sends some data
  Serial.println("new client");
 
 
  while(client.connected() && !client.available())
  {
    delay(1);
  }
 
  // Read the first line of the request
  String request = client.readStringUntil('\r');
  Serial.println(request);
  client.flush();
 
  // Match the request
  int value = LOW;
  if (request.indexOf("/LED=ON") != -1) {
    digitalWrite(ledPin, LOW);      // Onboard LED is active low
    value = HIGH;
  }
  if (request.indexOf("/LED=OFF") != -1) {
    digitalWrite(ledPin, HIGH);     
    value = LOW;
  }
 
  // Return the response
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println(""); // do not forget this one
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
 
  client.print("Led pin is now: ");
 
  if(value == HIGH) {
    client.print("On");
  } else {
    client.print("Off");
  }
  client.println("<br><br>");
  client.println("Click <a href=\"/LED=ON\">here</a> turn the LED on pin 2 ON<br>");
  client.println("Click <a href=\"/LED=OFF\">here</a> turn the LED on pin 2 OFF<br>");
  client.println("</html>");
 
  delay(1);
  Serial.println("Client disconnected");
  Serial.println("");
}

Eksempel: Projekt sensor logning i database Svaert.png

Dette eksempel beskriver et system, hvor en sensor læses af et ESP8266 modul, og data sendes til en server, hvorpå det gemmes i en SQL database. Data kan udtrækkes fra databasen via en hjemmeside lavet i php, således clienter på netværket kan se data. Figur 10 viser en oversigt over systemet.

Eksempel, hvor sensor læses af ESP8266 og sendes til database, hvor det kan tilgås af client via en web browser
Figur 10 Eksempel, hvor sensor læses af ESP8266 og sendes til database, hvor det kan tilgås af client via en web browser.

Til projektet skal der bruges et ESP8266 modul (f.eks. en WeMos D1 mini) og en DS18B20 temperatursensor (evt. som et shield til WeMos D1 mini). Dette ses på figur 11.

På serveren skal der være en Webserver der kan håndtere php, samt en SQL database. Det ligger dog udenfor rammerne af denne beskrivelse, at redegøre for korrekt opsætning af webserver og SQL database. Her henvises til relevante guides på nettet, der passer til den aktuelle opsætning man ønsker at lave.

WeMos D1 mini med DS18B20 temperatur shield
Figur 11 WeMos D1 mini med DS18B20 temperatur shield.

Koden til ESP8266 modulet

Koden der skal køre på ESP8266 modulet, har til formål at læse data fra en sensor med jævne mellemrum. Når data er læst, sendes det til en SQL-database via et html kald med parametre, til en php-fil på en Webserver.

Koden er inspireret af projektet her: http://www.instructables.com/id/Arduino-motion-detector-PIR-that-writes-to-SQL-via/

/* TemperaturSensor
 * Version 1.0
 * Based on: https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266HTTPClient/examples/BasicHttpClient/BasicHttpClient.ino
 *  and    : https://create.arduino.cc/projecthub/everth-villamil-ruiz/temperature-sensor-ds18b20-3decfc
 *
 * Modifications by HNL June 2017, February 2018
 *
 *
 * Change log
 * ============
 * Version 1.0  
 *   - Initiel version based on the WebServer example: https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266HTTPClient/examples/BasicHttpClient/BasicHttpClient.ino
 *   - DS18B20 temperature sensor example: https://create.arduino.cc/projecthub/everth-villamil-ruiz/temperature-sensor-ds18b20-3decfc
 *   - Blink LED on ESP8266 module when successfully sent data to database server.
 *   
 *   
 * Description
 * ============
 * The DS18B20 transmits data via OneWire data bus.
 *
 * Each 5 minute the ESP8266 measures the temperature, connects to the WiFi network and add temperature value to the database.
 *
 */

// *************************************************
//                    Prototypes
// *************************************************
void blinkLED(int iopin, int msbetweentoggle, int numberofblink, boolean activeHigh);


// *************************************************
//                 Include headers
// *************************************************
#include <OneWire.h>             // Download from: https://github.com/PaulStoffregen/OneWire
#include <DallasTemperature.h> // Download from: https://github.com/milesburton/Arduino-Temperature-Control-Library
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WiFiMulti.h>

// *************************************************
//            Definitions
// *************************************************
#define VERSION "1.0"
#define DEVICEID 3

// *************************************************
//            Constant definitions
// *************************************************
const int LEDPIN       = 2;   // GPIO 2
const int ONE_WIRE_BUS = D2;  // WeMos D1 port D2

const String serverAddress = "http://192.168.18.100";      // IP address for the webserver
const String databaseLink = "iot/tempsensor/add_data.php"; // directory for the php-file



// *************************************************
//          Global variabels definitions
// *************************************************
long lastTime;
long currentTime;
long interval;

int httpCode;
long chipID;
String stringToSend;
float tempValue;

// *************************************************
//              Instantiate objects
// *************************************************
HTTPClient http;
ESP8266WiFiMulti wifiMulti;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);


void setup()
{
  wifiMulti.addAP("SSID1", "PASSWORD1"); // SSID and Password for router to connect to
  wifiMulti.addAP("SSID2", "PASSWORD2"); // SSID and Password for router to connect to 

  Serial.begin(9600);
  delay(10);

  WiFi.softAPdisconnect(true);      // Be sure that the ESP8266 is in standard mode (NOT AP mode)
  WiFi.mode(WIFI_STA);              //

  pinMode(LEDPIN, OUTPUT);
  blinkLED(LEDPIN, 100, 5, LOW);     // Blink onboard LED 5 times for startup

  chipID = ESP.getChipId();

  interval = 5*60*1000;              // interval = 5 minutes
  lastTime = 0-interval;             // start to send data at startup
      
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to WiFi");
    
  while (wifiMulti.run() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
 
  Serial.println("");
  Serial.print("WiFi connected to network: ");
  Serial.println(WiFi.SSID());
  Serial.print("RSSI: ");
  Serial.print(WiFi.RSSI());
  Serial.println("dBm");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());  

  sensors.begin();
}

void loop()
{
  sensors.requestTemperatures();
  tempValue = sensors.getTempCByIndex(0);

  currentTime = millis();
 
  if (currentTime - lastTime > interval)
  {
    stringToSend = serverAddress;
    stringToSend += "/";
    stringToSend += databaseLink;
    stringToSend += "?";
    stringToSend += "cliID=";
    stringToSend += String(chipID);
    stringToSend += "&";
    stringToSend += "devID=";
    stringToSend += "DEVICEID";
    stringToSend += "&";
    stringToSend += "value=";
    stringToSend += String(tempValue);
    stringToSend += "&";
    stringToSend += "version=";
    stringToSend += VERSION;
    stringToSend += "&";
    stringToSend += "ssid=";
    stringToSend += String(WiFi.SSID());
    stringToSend += "&";
    stringToSend += "rssi=";
    stringToSend += String(WiFi.RSSI());

    http.setTimeout(2000);                                 // Use 2 seconds timeout for HTTP connection
    http.begin(stringToSend);                              // Start HTTP connection and send HTTP header

    httpCode = http.GET();                                 // Get response from HTTP request
    
    if(httpCode > 0)                                       // httpCode will be negative on error
    {      
      Serial.printf("[HTTP] GET... code: %d\n", httpCode); // Response from server is not an error

      blinkLED(LEDPIN, 500, 1, LOW);
      
      if(httpCode == HTTP_CODE_OK)                          // Response from server is HTTP CODE 200
      {
           String payload = http.getString();
           Serial.println(payload);
      }
      http.end();
    }      
    else
    {
      Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());

      http.end();
    }
    lastTime = currentTime;
  }  
}


void blinkLED(int iopin, int msbetweentoggle, int numberofblink, boolean activeHigh)
{
  for (int i=0; i<numberofblink; i++)
  {
    digitalWrite(iopin, activeHigh);
    delay(msbetweentoggle);
    digitalWrite(iopin, !activeHigh);

    if (numberofblink > 1)
    {
      delay(msbetweentoggle);
    }
  }
}

Opsætning af SQL-database

Der skal oprettes en SQL-database, der kan bruges til at gemme de data der sendes fra ESP8266 modulet. Når man har en SQL-database, oprettes en tabel, hvori data kan tilføjes.

Tabellen der anvendes i dette eksempel, oprettes ved at skrive følgende SQL kommando:

CREATE TABLE `IoTsensorDatabase` (
 `entryID` int(11) NOT NULL AUTO_INCREMENT,
 `clientID` int(11) NOT NULL,
 `timedate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 `deviceID` int(11) NOT NULL,
 `value` int(11) NOT NULL,
 `version` text NOT NULL,
 `ssid` text NOT NULL,
 `rssi` int(11) NOT NULL,
 PRIMARY KEY (`entryID`),
 UNIQUE KEY `entryID` (`entryID`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

Det giver en tabelstruktur som ses på figur 12.

Tabellayout over tabellen til at gemme data fra ESP8266 modulet
Figur 12 Tabellayout over tabellen til at gemme data fra ESP8266 modulet.

De otte kolonner bruges til følgende:

entryID Et fortløbende nummer (heltal), som automatisk oprettes for hver nyt entry i databasen.
clientID Et ID nummer (heltal) som den enkelte ESP8266 modul kan identificeres med. Her sendes ESP8266 modulets serienummer.
timedate Tid og dato for hvornår entry’et oprettes i databasen. Oprettes automatisk i databasen.
deviceID En talværdi der kan anvendes til at identificere hvilken sensor der er koblet på ESP8266 modulet.
value Data / værdien der er målt af sensoren på ESP8266 modulet.
version Version af det program man har liggende på ESP8266 modulet.
ssid SSID fra routeren som ESP8266 modulet er tilkoblet til.
rssi Signalstyrken som ESP8266 modulet modtager fra Routeren.

Kode til Webserveren

Her er tre php-filer som skal ligge på Webserveren, og som håndtere udskrift af data fra SQL-databasen til clientens webbrowser, samt tilføjning af data til SQL-databasen fra EPS8266 modulet.

De tre php-filer har følgende funktioner:

dbconnect.php Indeholder koden til at forbinde sig til SQL-databasen. Her står brugernavn og password til databasen.
data_review.php Indeholder koden til at udtrække data fra SQL-databasen. data_review.php anvender dbconnect.php filen.
add_data.php Indeholder koden til at tilføje data til SQL-databasen. Kaldes fra EPS8266 modulet med parametre og data.

Når man ønsker at se data der er gemt i SQL-databasen, tilgår man data_review.php via en Web browser (der selvfølgelig er på samme netværk som som Webserveren). Herefter vises alle data i tabelform.

Referencer