Select Page

Välkommen till del 3 av artikelserien “Så kommer du igång med IoT”. I denna del skall jag fokusera på hur man kopplar ihop flera noder över internet. Missade du del 1 där jag gick igenom lämplig hårdvara och del 2 hur man programmerar den hårdvaran så ta gärna lite tid och läs dem.

När man har flera saker som skall kommunicera på olika sätt med varandra och speciellt när man vill ändra om ofta är det väldigt tidsödande och jobbigt att göra detta i varje enhet. Därför vill man ha en enda plats där man beskriver hur de olika enheterna kopplas ihop. Och gärna att man kan göra vissa inställningar där med. Men det finns även nackdelar med en sådan lösning. Det blir en enskild punkt som kan rasera hela systemet. Det kan därmed bli en sårbar lösning att göra så här. Men för att labba och lära sig är det mycket lättare att ha ett enda ställe än att ha hela uppsättningen helt utspridd över alla noder. Det är dock en mycket robustare lösning om delar av systemet kan fortsätta fungera även om en eller flera noder rasar eller den centrala delen försvinner. Med andra ord, det är helst inställningar som skall skickas istället för värden. Och det är en bra princip att enheterna skall i möjligaste mån kunna operera vidare utan nya sensorvärden.

Som jag beskrev i del 1 är en Raspberry Zero W en billig lösning för att få till en server och Node-RED är en lämplig mjukvara. Node-RED blir som en kopplingscentral. Det är relativt enkelt att skicka in information och även få ut något från Node-RED. Man kan även skriva små bitar av kod som påverkar informationen i en koppling. Så i den här delen kommer vi beskriva det hela genom att skapa en tjänst som kopplar ihop avståndsmätaren med ett servo och styr det.

Jag kommer dela upp detta i tre delar, först hur man får upp Raspberry och Node-RED på den. Sedan går jag igenom den kod som behövs för att noderna skall prata med Node-RED, en del för avståndsmätaren och en del för servot. Och till sist avslutar jag med att i Node-RED koppla ihop mätaren med servot.

Sätta upp Raspberry med Node-RED

Börja med denna guide som förklarar hur man installerar Raspbian (operativsystemet) på ett minneskort. Jag föredrar lösningen med BalenaEtcher samt Raspbian distributionen. Dels för jag är van vid Unix och det går lätt att installera Node-RED. Man hittar Raspbian på nedladdningssidan. Välj den version som heter Lite. Lägg den på ett minneskort med hjälp av BalenaEtcher.

Sedan måste man konfigurera Raspberryn för så kallad headless uppsättning. Det betyder att man sätter upp den utan skärm och tangentbord inkopplat på Raspberryn. Följ instruktionerna på sidan.

Jag brukar spara en kopia av wpa_supplicant.conf-filen på datorn så att det går snabbt att ändra nät om jag flyttar Raspberryn till en ny plats. Glöm inte heller att skapa en tom fil som heter ssh så ssh aktiveras på Raspberryn. När det är gjort kan man boota upp den. OBS både Windows och Mac har som standard att dölja så kallade filändelser och råkar tex dessa två filer ha kvar filändelsen .txt så kommer inget att fungera. Så var noga med att så inte är fallet.

Nu är det dags att logga in på Raspberryn. Det är inte alltid lätt att inse vilket IP-nummer som Raspberryn har fått. Det finns ju ingen skärm att titta på. Fing är en utmärkt mobil app för att skanna av ett trådlöst nät och hitta saker på det. Ladda ned appen till en telefon och hitta vilket IP-nummer Raspberryn fått. När IP-numret är hittat är det dags att koppla in sig på den. Kör man Mac, så starta Terminalen som finns under Verktyg. Kör men en dator med Windows så ladda ned Putty. På Mac skriver man sedan i terminalen ssh pi@192.168.1.23. I Putty får man ange IP-numret och sedan när användarnamn efterfrågas, ange pi. När man loggat in får man upp en text liknande:

The authenticity of host '192.168.10.156 (192.168.10.156)' can't be established. ECDSA key fingerprint is SHA256:SaY0xJ0CZIescP+VExAi9M+9N2icIRakVg1j4ndlHms. Are you sure you want to continue connecting (yes/no)?

Svara yes på frågan.

Warning: Permanently added '192.168.10.156' (ECDSA) to the list of known hosts. pi@192.168.10.156's password:

Ange raspberry som lösenord.

Linux raspberrypi 4.19.75+ #1270 Tue Sep 24 18:38:54 BST 2019 armv6l 

The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. 

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law.

SSH is enabled and the default password for the 'pi' user has not been changed. This is a security risk - please login as the 'pi' user and type 'passwd' to set a new password.

På Node-REDs hemsida finns en guide för att installera Node-RED på Raspberry Pi. Följ den och svara Ja på frågan om du vill installera Raspberry specifika noder.

Jag brukar sätta upp så Node-RED startar efter omstart så den alltid är igång. För att göra det ge även följande kommando: sudo systemctl enable nodered.service och efter det starta om Raspberryn med kommandot sudo reboot.

Testa att Node-RED fungerar genom att med en webbläsare gå till http://{raspberry-ip-adress}:1880. Byt ut till ditt ip-nummer och man skall då få upp Node-REDs gränssnitt.

Kommunikationsprotokollet MQTT

MQTT är ett kommunikationsprotokoll skapat för sakernas internet. MQTT bygger på principen att klienter publicerar eller prenumererar på meddelanden som postas eller läses från olika ämnen(topic). Node-RED har redan stöd för MQTT men man behöver en så kallad MQTT Broker körandes för det skall fungera. Brokern blir som en växel och styr vart olika meddelanden skall skickas. Som tur är passar det utmärkt att köra en sådan på en Raspberry Pi Zero W.

För att försäkra att det blir senaste versionerna av saker och ting som installeras börja med kommandot sudo apt-get update. Installera sedan både Mosquitto brokern och dess klient med kommandot: sudo apt install mosquitto mosquitto-clients

Klienten behövs inte för att köra brokern men den behövs för att testa brokern. Man vill att brokern också startar automatiskt när Raspberryn startas om så ge kommandot sudo systemctl enable mosquitto och med kommandot sudo systemctl status mosquitto verifiera att den startat.

Nu är det dags att testa brokern. Ge kommandot mosquitto_sub -h localhost -t "test/message" för att börja prenumerera på meddelanden på ämnet test/message. För att skicka ett meddelande i detta ämne behöver man en ny terminal och ssh:a till Raspberryn igen. När man loggat in så ger man kommandot
mosquitto_pub -h localhost -t "test/message" -m "Hello, world" som kommer skicka Hello, world på ämnet. Samma text skall dyka upp i terminalen där vi prenumererar på ämnet.

Nu är det dags att testa med Node-RED. Gå med en webbläsare till Node-RED (se ovan för address) och leta upp MQTT in noden. Dra in den i arbetsytan.

Konfigurera MQTT noden att koppla mot brokern och prenumerera på test/message. Klicka på noden och följande syns.

Klicka på pennan jämte Add new mqtt-broker och följande öppnas.

Fyll i localhost i server och klicka på Add. Och fyll sedan i text/message som Topic.

För att se meddelandena som kommer in är det lämpligt att koppla en debug nod till MQTT noden. Leta upp den i listan och dra in på ytan och dra sedan en koppling mellan noderna.

Klicka på Deploy uppe i högra hörnet. Och sedan på den lilla skalbaggen för att få upp debug fliken. Testa igen att skicka Hello, world till ämnet och det skall då dyka upp i Node-RED.

Skicka MQTT från avståndsmätaren

För att skicka och ta emot MQTT meddelanden på ESP noderna är PubSubClient lämplig. Så börja med att lägga till det i Arduino utvecklingsmiljön, version 2.7.0 när detta skrevs. I del 2 beskrev jag hur man lägger till bibliotek.

I del 2 skapade jag ett litet program för att mäta avstånd med avståndsmätaren. Bitar av den koden kan återanvändas men programmet behöver också ansluta till nätet samt skicka MQTT meddelanden. Kodbiten som mäter avståndet gör jag om till en funktion. Från webb exemplet i del 2 återanvänder jag hur man ansluter till Wifi-nätet. Och sedan tillkommer kod för att ansluta till brokern och skicka avståndet med jämna mellan rum till den.

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

#define ssid "networkname"
#define password "secretpassword"
#define mqtt_server "MQTT_BROKER_IP"

WiFiClient wifi;
PubSubClient client(wifi);

const int trigPin = D3;
const int echoPin = D1;

void setup() {
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  Serial.begin(115200);

  WiFi.begin(ssid, password);

  Serial.println("Trying to connect WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println("-");
  }

  Serial.print("Connected! ESP can be connected to by using IP number: ");
  Serial.println(WiFi.localIP());

  client.setServer(mqtt_server, 1883);
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Connection to broker - ");
    if (client.connect("ESP8266DistanceClient")) {
      Serial.println("connected");
    } else {
      Serial.print("failed, state=");
      Serial.print(client.state());
      Serial.println(" - try again in 5 seconds");
      delay(5000);
    }
  }
}

int measure() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  long duration = pulseIn(echoPin, HIGH);
  int distance = duration*0.034/2;
  Serial.print("Avstånd: ");
  Serial.println(distance);
  return distance;
}

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

  long now = millis();
  if (now - last > 2000) {
    last = now;
    int distance = measure();
    client.publish("sensor/distance", String(distance).c_str(), true);   
  }
}

Kopiera in koden till en skiss i Arduino utvecklingsmiljön. Kom ihåg att ändra networkname och secretpassword för nätverket och sedan MQTT_BROKER_IP till det IP-nummer Raspberryn har.

Koppla upp elektroniken och ladda över koden. Starta monitorn för att se att koden ansluter till nätet och brokern. Gå sedan till Node-RED och ändra om så att det flöde som skapades innan istället lyssnar till sensor/distance och deploya flödet. Nu skall det komma in avstånd och skrivas ut i debug fliken.

Ta emot MQTT på servot

För att istället ta emot meddelanden och styra servot med dem behöver jag inte ändra så mycket i koden ovan. Delarna som mäter avstånd behövs inte längre och jag får lägga till styrningen av servot samt ändra om så att koden prenumererar på meddelanden i ett rätt ämne. Har valt att kalla ämnet servo/position. I del 2 skrev jag kod för att styra servot så där kan jag ta bitar också.

#include <Servo.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

#define ssid "networkname"
#define password "secretpassword"
#define mqtt_server "MQTT_BROKER_IP"

WiFiClient wifi;
PubSubClient client(wifi);
Servo servo;

void setup() {
  servo.attach(D2);
  Serial.begin(115200);

  WiFi.begin(ssid, password);

  Serial.println("Trying to connect WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println("-");
  }

  Serial.print("Connected! ESP can be connected to by using IP number: ");
  Serial.println(WiFi.localIP());

  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Connection to broker - ");
    if (client.connect("ESP8266ServoClient")) {
      Serial.println("connected");
    } else {
      Serial.print("failed, state=");
      Serial.print(client.state());
      Serial.println(" - try again in 5 seconds");
      delay(5000);
    }
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  String message = "";
  for (int i = 0; i < length; i++) {
    message += (char)payload[i];
  }

  int pos = message.toInt();
  Serial.print(topic);
  Serial.print(" ");
  Serial.println(pos);
  servo.write(pos);
}

void loop() {
  if (!client.connected()) {
    reconnect();
    client.subscribe("servo/position");  
  }
 
  client.loop(); 
  delay(250);
}

Kopiera över koden till Arduino utvecklingsmiljön och kom ihåg att igen ändra networkname och secretpassword för nätverket och sedan MQTT_BROKER_IP till det IP-nummer Raspberryn har.

Koppla sedan upp elektroniken för servot och ladda över koden till ESPn. Starta monitorn för att se att koden ansluter till nätet och brokern. Gå tillbaka till Node-RED och lägg till en MQTT out nod och ändra om så att den skickar meddelanden på ämnet(topic) servo/position.

Dra in en Inject nod på arbetsytan så man kan använda den för att skicka meddelanden.

Dubbelklicka på Inject noden och ändra till att den skall skicka ett nummer och skriv in tex 45.

Deploya flödet och testa att klicka på knappen åt vänster på Inject noden. Det skall leda till att noden skickade 45 och i monitorn skall man se att ESP tog emot 45, samt att servot vred sig.

Koppla ihop avståndsmätaren med servot

Dags att koppla ihop dessa två uppkopplade enheter och det gör jag i Node-RED. I flödet finns redan en nod som tar emot meddelanden från avståndsmätare. Värden som varierar mellan 2-3 cm upp till 430-450 cm. Och sedan noden som styr servot och vill ta emot värden mellan 0 och 180. Så jag behöver på något sätt omvandla de ingående värdena till lämpliga utgående värden. Just för dessa fall finns en nod som heter Range som jag kan nyttja. Dra in den noden och ställ in den så att den skalar om och begränsar. För in anger vi spannet 2 till 400 och ut 0 till 180. Sedan kryssa i att den skall avrunda till närmaste heltal.

Nu tror man att det bara skulle vara att koppla ihop MQTT mottagaren med denna nod och sedan den utgående. Men de inkommande värden kommer nämligen som en sträng och längst ned i inställningarna för Range noden står att den fungerar BARA för siffror. Så det behövs en nod till. I en Function nod kan man skriva in valfri kod och därmed kan jag lätt lägga in kod som gör om strängen till en siffra. Dessa noder kodar man i Javascript så den kod jag vill ha är:

return { payload: parseInt(msg.payload) };

Mellan noder i Node-RED skickas meddelanden och i funktionsnoden når man dessa via msg variabeln och de har en payload del som innehåller resultatet från föregående nod. Så med parseInt() omvandlar jag msg.payload till en siffra. Och ut ur noden måste man skicka ett objekt som skall bli meddelandet ut och värdet lägger man i payload. Så denna nod kopplar man in före Range noden och Range kommer få in siffror istället för strängar.

Hela flödet ser ut som följande:

Debug noden är utmärkt att koppla in på olika ställen i flödet för att kunna undersöka vad som skickas mellan noder.

Då är det dags att testa att när avståndet framför sensorn ändras så flyttar servot på sig. Om det hela känns lite segt beror det på att koden bara läser av avståndet en gång i sekunden.

Efter denna lilla introduktion samt ihop med de olika bitarna av kod kan man nu rätt enkelt få in alla de sensorer och aktuatorer in i Node-RED. Sedan är det bara fantasin som sätter gränser för vad som kan skapas.

Därmed avslutas denna serie. Hoppas denna lilla inblick i sakernas internet lockat fram mer energi till att utforska området. Kontakta mig på karl-petter.akesson@forefront.se om du har några frågor! Eller berätta om något spännande du skapat med den här kunskapen.