Internet of Things/Arduino node

Uit Lab
Naar navigatie springen Naar zoeken springen

Arduino als IoT-node: Ethernet

Voor het gebruik van de Arduino als IoT-node gebruiken we een Arduino met een Ethernet-shield. In de schema's hieronder nemen we aan dat het Ethernet-shield geplaatst is op de Arduino.

Breadboard schakeling

Arduino breadboard

NB: door op een tekening te klikken krijg je een grotere versie.

Als je twijfelt over een aansluiting, raadpleeg dan het schema eronder.

Op het breadboard zijn de volgende deelschakelingen geplaatst:

  • een drukknopschakeling met output naar D2
    • deze bestaat uit een drukknop, aan de ene kant verbonden aan 5V, aan de andere kant via een "pull down weerstand" van 10 kOhm aan 0V.
  • een drukknopschakeling met outout naar P3
  • een LDR-schakeling met outut naar A0
    • de LDR is onderdeel van een spanningsdeler, om de variabele weerstand om te zetten in een variabele spanning
  • een LED-schakeling aangestuurd door output D5
    • de LED staat in serie met een weerstand van 220 Ohm, om de stroom door de LED (en door de Arduino-output) te beperken.
  • een LED-schakeling aangestuurd door output D6
  • een temperatuursensor met output naar A1

Schema

Arduino schema

Software: test van de hardware

De hardware en software voor een IoT-node vormen een complexe keten. Voor een goede werking moet elke schakel van de keten goed functioneren. Het is dan handig om de verschillende onderdelen van de keten afzonderlijk te kunnen controleren.

  • testen van de hardware-schakeling
  • testen van de internet-verbinding
  • testen van de MQTT-server
  • testen van de MQTT-server-verbinding

Voor het testen is het nodig om de tekst-uitvoer (Serial.print(...)) van de Arduino zichtbaar te maken via de Seriële Monitor. De Arduino stuurt deze uitvoer via de USB-verbinding naar de host-computer (waarmee je de software voor de Arduino ontwikkelt). De Seriële Monitor start je op via Hulpmiddelen->Seriële Monitor. Het opstarten van de Seriële Monitor resulteert in een reset van de Arduino.

  • de baudrate van de Serial Monitor moet ingesteld worden op 9600 (rechts onderin het Serial Monitor venster). Dit moet overeenkomen met de instelling in het Arduino-programma (Serial.begin(9600);).


Software: test van hardware

Met de onderstaande software kun je de hardware testen:

const int led0 = 5;
const int led1 = 6;
const int button0 = 2;
const int button1 = 3;

void sensor0Publish() {
  // read the sensor value twice, with 1 msec interval to stabilize A/D converter
  int sensor = analogRead(A0);
  delay(1);
  sensor = analogRead(A0);
  Serial.print("sensor 0:");
  Serial.println(sensor);
}

void sensor1Publish() {
  int sensor = analogRead(A1);
  delay(1);
  sensor = analogRead(A1);
  Serial.print("sensor 1:");
  Serial.println(sensor);
}

void setup() {
  pinMode(led0, OUTPUT);
  pinMode(led1, OUTPUT);
  pinMode(button0, INPUT);
  pinMode(button1, INPUT);
  //analogReference(INTERNAL); //1.1V
  Serial.begin(9600);

  digitalWrite(led0, HIGH);
  digitalWrite(led1, LOW);
  delay(1000);
  digitalWrite(led1, HIGH);
  digitalWrite(led0, LOW);
}

void loop() {
  if (digitalRead(button0)) {
    digitalWrite(led0, HIGH);
    digitalWrite(led1, LOW);
    sensor0Publish();
    delay(200); // limit button repetition rate
  }

  if (digitalRead(button1)) {
    digitalWrite(led0, LOW);
    digitalWrite(led1, HIGH);
    sensor1Publish();
    delay(200); // limit button repetition rate
  }  
}

De software test eerst de beide LEDs: deze worden om de beurt in- en uitgeschakeld; LED 1 blijft branden tot deze uitgeschakeld wordt.

Deze software verbindt de schakelaars met de LEDs en met de sensoren:

  • button 0: schakel LED 0 in en LED 1 uit, en geef de waarde van sensor A0 weer via de Serial Monitor.
  • button 1: schakel LED 0 uit en LED 1 in, en geef de waarde van sensor A1 weer via de Serial Monitor.

Software

De meet recente versie van de software is te vinden op GitHub: https://github.com/eelcodijkstra/iot2016/blob/master/arduinonode.ino

De software moet op de volgende punten aangepast worden aan de eigen situatie:

  • het MAC-adres van de Ethernet-shield moet juist ingevuld worden; deze gegevens staan meestal op het Ethernet shield;
  • het adres van de MQTT-broker moet aangepast worden aan de eigen broker; dit bestaat uit:
    • de domeinnaam (hier: mqttbroker.com) of het IP-adres, en
    • het poortnummer (hier: 1883).
/*
 * test a combination of JSON, MQTT over Arduino-Ethernet
 * simple sensor: button
 * simple actuator: LED
 */

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

// i/o pin map
const int led0 = 5;
const int button0 = 2;
const int button1 = 3;
// analog sensor on A0

// Ethernet: define MAC address of Ethernet shield
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x4D, 0x61};
EthernetClient ethClient;

// PubSub (MQTT)
const char* mqttServer = "mqttbroker.com";
// alternative: IPAddress mqttServer(172, 16, 0, 2);
const int mqttPort = 1883;

PubSubClient client(ethClient);

String nodeID;
String sensorTopic;
String actuatorTopic;

long sensor1Timer = 0;
long sensor1Period = 50000; // in millisecs

// JSON

void sensor0Publish() {
  StaticJsonBuffer<200> jsonBuffer;
  JsonObject& root = jsonBuffer.createObject();
  String msg;
  root["id"] = nodeID;
  root["button0"] = digitalRead(button0);
  root["button1"] = digitalRead(button1);
  root["localtime"] = millis();
  root.printTo(msg);
  Serial.println(msg);
  client.publish(sensorTopic.c_str(), msg.c_str());
}

void sensor1Publish() {
  StaticJsonBuffer<200> jsonBuffer;
  JsonObject& root = jsonBuffer.createObject();
  String msg;
  root["id"] = nodeID;
  root["sensor0"] = analogRead(A0);
  delay(1);
  root["sensor1"] = analogRead(A1);
  root["localtime"] = millis();
  root.printTo(msg);
  Serial.println(msg);
  client.publish(sensorTopic.c_str(), msg.c_str());
}

void networkSetup() {
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for (;;)
      ;
  }
  // print your local IP address:
  Serial.print("My IP address: ");
  Serial.println(Ethernet.localIP());
}

void mqttCallback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  if (strcmp(topic, actuatorTopic.c_str())==0) {
    Serial.println("actuator message received");
    StaticJsonBuffer<200> jsonBuffer;
    JsonObject& root = jsonBuffer.parseObject((char*) payload);
    if (root.success()) {
      if (root.containsKey("led0")) {
        digitalWrite(led0, root["led0"]);
      }
    }
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    String clientID = "IoTClient-" + nodeID;
    if (client.connect(clientID.c_str())) {
      Serial.println("connected");

      client.subscribe(actuatorTopic.c_str());
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  pinMode(led0, OUTPUT);
  pinMode(button0, INPUT);
  //analogReference(INTERNAL); //1.1V
  Serial.begin(9600);

  networkSetup();
  nodeID = String(mac[4] * 256 + mac[5], HEX);
  // MQTT init:
  sensorTopic = "node/" + nodeID + "/sensors";
  actuatorTopic = "node/" + nodeID + "/actuators";
  client.setServer(mqttServer, mqttPort);
  client.setCallback(mqttCallback);
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  if (digitalRead(button0)) {
    sensor0Publish();
    delay(200); // limit button repetition rate
  }

  if (millis() >= sensor1Timer) {
    sensor1Publish();
    sensor1Timer = sensor1Timer + sensor1Period;
  }
}

Testen

Hiervoor gebruik je de Serial Monitor: daarop zie je de verschillende stappen.

  • verkrijgen van het IP-adres door het Ethernet-shield, bijvoorbeeld:
    • My IP address: 192.68.1.123
  • maken van verbinding met MQTT-verbinding:
    • Attempting MQTT connection...connected
  • bij het indrukken van button 0 wordt het uitgaande MQTT-bericht afgedrukt, bijvoorbeeld: