Välkommen till del 3 av artikelserien “Så kommer du igång med IoT”. I denna del ska jag fokusera på hur du kopplar ihop flera noder över internet. Missade du del 1 där jag gick igenom lämplig hårdvara och del 2 hur du programmerar hårdvaran, så ta gärna lite tid och läs dem först!
När du har flera saker som på olika sätt ska kommunicera med varandra – och speciellt när du vill ändra om ofta – är det väldigt tidsödande och jobbigt att göra detta i varje enhet. Därför bör du ha en enda plats där du beskriver hur de olika enheterna kopplas ihop och där du kan göra vissa inställningar direkt. Men det finns även nackdelar med en sådan lösning. Det kan bli en sårbar lösning att göra så här – du har en enskild punkt som kan rasera hela systemet. Men för att labba och lära sig är det mycket lättare att ha ett enda ställe än att ha uppsättningen utspridd över alla noder. En utspridd lösning är dock robustare eftersom delar av systemet kan fortsätta fungera även om en eller flera noder rasar eller den centrala delen försvinner. En metod du kan nyttja för att få fördelen av bägge är att försöka undvika skicka värden från den centrala platsen och istället skicka ut beskrivningar av inställningar. Det är en bra princip att enheterna i möjligaste mån ska kunna operera vidare utan nya sensorvärden.
För att få till en server är, som jag beskrev i del 1, Raspberry Zero W en billig lösning och Node-RED 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. Du kan även skriva små bitar av kod som påverkar informationen i en koppling. Så i den här delen kommer jag 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 du får upp Raspberry och Node-RED. Sedan går jag igenom den kod som behövs för att noderna ska 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 du 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 dels för att det går lätt att installera Node-RED. Du 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 du konfigurera Raspberryn för så kallad headless uppsättning. Det betyder att du 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 du boota upp den. Observera att både Windows och Mac har som standard att dölja filändelser och råkar till exempel någon av filerna (wpa_supplicant.cong eller ssh) 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 din Raspberry har fått. När IP-numret är hittat är det dags att koppla in sig på den. Kör du Mac så starta Terminalen som finns under Verktyg. Kör du en dator med Windows så ladda ned Putty. På Mac skriver du sedan i terminalen
<code>ssh pi@192.168.1.23
I Putty får du ange IP-numret och sedan, när användarnamn efterfrågas, ange pi. När du loggat in får du upp en text liknande:
<em>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)?</em>
Svara yes på frågan.
<em>Warning: Permanently added '192.168.10.156' (ECDSA) to the list of known hosts.<br>pi@192.168.10.156's password:</em>
Ange raspberry som lösenord.
<em>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.</em>
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å att den alltid är igång. För att göra det ge även följande kommando:
<code>sudo systemctl enable nodered.service<span style="background-color: initial; font-family: inherit; font-size: inherit;"> </span>
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 – du ska 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 (topics). Node-RED har redan stöd för MQTT men du behöver en så kallad MQTT Broker körandes för det ska fungera. Brokern blir som en växel och styr vart olika meddelanden ska 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
<code>sudo apt-get update
Installera sedan både Mosquitto brokern och dess klient med kommandot:
<code>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. Du vill att brokern också startar automatiskt när Raspberryn startas om, så ge kommandot
<code>sudo systemctl enable mosquitto
och verifiera sedan att den startat med kommandot
<code>sudo systemctl status mosquitto
Nu är det dags att testa brokern. Ge kommandot
<code>mosquitto_sub -h localhost -t "test/message"<span style="background-color: initial; font-family: inherit; font-size: inherit;"> </span>
för att börja prenumerera på meddelanden på ämnet test/message. För att skicka ett meddelande i detta ämne behöver du en ny terminal som ssh:as till Raspberryn igen. När du loggat in så ger du kommandot
<code>mosquitto_pub -h localhost -t "test/message" -m "Hello, world"<span style="background-color: initial; font-family: inherit; font-size: inherit;"> </span>
som kommer skicka Hello, world på ämnet. Samma text ska dyka upp i terminalen där du 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 bredvid 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; det ska 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 du 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 webbexemplet i del 2 återanvänder jag hur du 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 ska 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 du inte ändra så mycket i koden ovan. Delarna som mäter avstånd behövs inte längre och du får lägga till styrningen av servot samt ändra om så att koden prenumererar på meddelanden i ett rätt ämne. Jag har valt att kalla ämnet servo/position. I del 2 skrev jag en kod för att styra servot så där kan vi ta bitar från nu 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å du kan använda den för att skicka meddelanden.
Dubbelklicka på Inject-noden, ändra att den ska skicka ett nummer och skriv in till exempel 45.
Deploya flödet och testa att klicka på knappen åt vänster på Inject-noden. Det ska leda till att noden skickade 45 och i monitorn ska du 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 du 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 noden som styr servot vill ta emot värden mellan 0 och 180. Så du 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 du kan nyttja. Dra in den noden och ställ in den så att den skalar om och begränsar. För in anger du spannet 2 till 400 och ut 0 till 180. Kryssa sedan i att den ska 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 som en sträng, och längst ned i inställningarna för Range-noden står att den BARA fungerar för siffror. Så det behövs en nod till. I en Function-nod kan du skriva in valfri kod och därmed lätt lägga in kod som gör om strängen till en siffra. Dessa noder kodas i Javascript och den kod du vill ha är:
return { payload: parseInt(msg.payload) };
Mellan noder i Node-RED skickas meddelanden och i funktionsnoden når du dessa via msg
-variabeln. De har en payload
-del som innehåller resultatet från föregående nod. Så med parseInt()
omvandlar du msg.payload
till en siffra. Ut ur noden måste du skicka ett objekt som ska bli meddelandet ut, och värdet lägger du i payload
. Så denna nod kopplar du 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 servot flyttar på sig när avståndet framför sensorn ändras. 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 med de olika bitarna av kod, kan du nu rätt enkelt få in alla de sensorer och aktuatorer 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@yelloworb.com om du har några frågor! Eller berätta om något spännande du skapat med den här kunskapen.
Samtliga delar i serien
» Så kommer du igång med IoT: Del 1 (Publicerades 10 december 2019)
» Så kommer du igång med IoT: Del 2 – Programmering (Publicerades 20 december 2019)
» Så kommer du igång med IoT: Del 3 – Koppla över Internet (Publicerades 14 januari 2020)