Mit MQTT einen Roboter steuern - [Teil 2] - AZ-Delivery

In het eerste deel van deze blogserie heb je alles geleerd wat er te weten valt over MQTT. Daarnaast werd op een Raspberry Pi een server, de zogenaamde broker, opgezet en werden er berichten naar en ontvangen vanaf de commandoregel.

In dit deel wordt de structuur iets complexer, waarbij de gegevens worden verzonden en ontvangen door verschillende NodeMCU's en een Arduino Uno met Ethernet-shield, de zogenaamde clients.

De achtergrond zal zijn dat u een MQTT-client kunt bedienen op de meest voorkomende microcontrollers die AZ-Delivery verkoopt. In de hardwarevereisten leest u welke onderdelen nodig zijn om de serie compleet te maken. Sommige componenten zijn alleen nodig voor dit bloggedeelte, maar worden in diverse andere blogberichten van AZ-Delivery gebruikt.

hardwarevereiste

Je hebt maar een paar componenten nodig voor deze blogpost, zie tafel 1.

aantal Component
1 Raspberry Pi (vereist)
1 Bijpassende voeding
1 NodeMCU Lua Amica Module V2 ESP8266 ESP-12F(verplicht)
1 ESP32 NodeMCU Module WLAN WiFi Development Board (verplicht)
1 Microcontrollerkaart met USB-kabel (optioneel)
1 Ethernet-schild W5100 (optioneel)
1 Weerstanden bereik (optioneel)
2 Potentiometer (verplicht)
1 LCD-display 4x20 karakters blauw I2C (optioneel)
1 Eenkleurige LED (optioneel)

Tabel 1: Vereiste hardware

Houd er bij de Pi rekening mee dat je naast de bovengenoemde hardware ook een microSD-kaart nodig hebt. Om dit te doen, moet u het Raspberry Pi-besturingssysteem (voorheen bekend als Raspbian) als afbeelding op de kaart installeren.

Softwarevereiste

De software die nodig is voor dit project is beheersbaar:

  • Arduino IDE (https://www.arduino.cc/en/Main/Software), kunt u het beste de huidige versie hier downloaden
  • De bibliotheek PubSubClient met alle afhankelijkheden
  • De bibliotheek LiquidCrystal_I2C met alle afhankelijkheden

Hoe u bibliotheken kunt installeren via het bibliotheekbeheer staat onder https://www.az-delivery.de/blogs/azdelivery-blog-fur-arduino-und-raspberry-pi/arduino-ide-programmieren-fuer-einsteiger-teil-1 Sectie Bibliotheekbeheer, in meer detail beschreven.

Basisvereiste

Een Raspberry Pi met een geïnstalleerde MQTT-broker is vereist om dit en de volgende blogberichten te laten werken. Hoe dit precies werkt en welke commando's je moet invoeren, lees je in deel 1 van deze blogserie. Controleer ook of de makelaar ook is gestart bij het opstarten van de Raspberry Pi. Geef hiervoor het commando uit Code 1 in de terminal.

sudo service mosquitto status

Code 1: Vraag in de terminal of mosquitto is gestart

De uitvoer moet een actief (hardlopen) toon zien afbeelding 1zijn er geen verdere commando's nodig.

Figuur 1: Status mosquitto-makelaar in de terminal

Als de output verschilt, controleer dan nogmaals of mosquitto correct is geïnstalleerd en de service ook correct is geïntegreerd in de autostart. De exacte instructies zijn te vinden in deel 1.

Eenvoudig MQTT-abonnement met NodeMCU Lua Amica-module V2 ESP8266

Een opmerking op dit punt: de NodeMCU Lua Amica-module V2 ESP8266 wordt gebruikt voor het hier beschreven voorbeeld.

Zie in het eerste voorbeeld Code 2moet de NodeMCU een verbinding tot stand brengen met de MQTT-broker en alle gegevens ontvangen. Dit geeft je ook direct inzicht in hoe de algemene communicatie met de PubSubClient-bibliotheek werkt. Elke functie is in detail beschreven, zodat u de broncode beter kunt begrijpen.

Om ervoor te zorgen dat de broncode met u werkt, moet u uw WLAN-ID en wachtwoord in de broncode wijzigen.


//-----------------------------------------------------
// Voorbeeld 1 NodeMCU met MQTT
// Auteur: Joern Weise
// Licentie: GNU GPl 3.0
// Gemaakt: 20 oktober 2020
// Update: 25 oktober 2020
//-----------------------------------------------------
# include // Lib voor wifi
# include // Lib voor MQTT Pub en Sub
//
#ifndef STASSID
#define STASSID "................"
#define STAPSK "................"
#endif

#define GEAVANCEERD 1
const char * MQTT_BROKER = "raspberrypi"; // Naam van de mqtt-makelaar
const char * SUBTOPIC = "/ #";
String clientID = "NodeMCU_1"; // Klantnaam voor MQTT-makelaar
WiFiClient espClient;
PubSubClient mqttClient (espClient);

leegte setup ()
{
Serial.begin (115200); // Start seriële monitor baudrate 115200
vertraging (50);
writeAdvanceDiag ("SerialMonitor ingeschakeld", true);
setupWifi ();
writeAdvanceDiag ("Set MQTT-Server", true);
mqttClient.setServer (MQTT_BROKER, 1883);
writeAdvanceDiag ("Set Callback-functie", true);
mqttClient.setCallback (terugbellen);
writeAdvanceDiag ("Finish setup () - Function", true);
}

/*
* =================================================================
* Functie: setupWifi
* Retourneert: ongeldig
* Beschrijving: stel wifi in om verbinding te maken met het netwerk
* =================================================================
*/
leegte setup Wifi ()
{
Serial.println ("Verbinding met:" + String (STASSID));
WiFi.mode (WIFI_STA);
WiFi.begin (STASSID, STAPSK);
while (WiFi.status ()! = WL_CONNECTED)
  {
vertraging (500);
Serial.print (".");
  }
Serial.println ("");
Serial.println ("WiFi verbonden");
Serial.println ("IP-adres:");
Serial.println (WiFi.localIP ());
}

leegte lus () {
// plaats je hoofdcode hier, om herhaaldelijk uit te voeren:
if (! mqttClient.connected ())
reconnectMQTT ();

mqttClient.loop ();
}

/*
* =================================================================
* Functie: terugbellen
* Retourneert: ongeldig
* Beschrijving: wordt automatisch gebeld als een onderwerp is geabonneerd
* heeft een nieuw bericht
* topic: Geeft het onderwerp terug, waar een nieuw bericht vandaan komt
* payload: het bericht van het onderwerp
* lengte: lengte van het bericht, belangrijk om inhoud te krijgen
* =================================================================
*/
void callback (char * topic, byte * payload, unsigned int length)
{
String stMessage = "";
writeAdvanceDiag ("Bericht is aangekomen van topic:" + String (topic), true);
writeAdvanceDiag ("Berichtlengte:" + String (lengte), true);
voor (int i = 0; i stMessage + = String ((char) payload [i]);
writeAdvanceDiag ("Bericht is:" + stMessage, true);
}

/*
* =================================================================
* Functie: reconnectMQTT
* Retourneert: ongeldig
* Beschrijving: als er geen verbinding is met MQTT, is deze functie
* gebeld. Bovendien wordt het gewenste onderwerp geregistreerd.
* =================================================================
*/
leegte reconnectMQTT ()
{
while (! mqttClient.connected ())
  {
writeAdvanceDiag ("Login bij MQTT-Broker", true);
if (mqttClient.connect (clientID.c_str ()))
    {
Serial.println ("Verbonden met MQTT-Broker" + String (MQTT_BROKER));
writeAdvanceDiag ("Abonneer op onderwerp '" + String (SUBTOPIC) + "'", true);
mqttClient.subscribe (SUBTOPIC, 1); // Abonneer op onderwerp "SUBTOPIC"
    }
anders
    {
writeAdvanceDiag ("Mislukt met rc =" + String (mqttClient.state ()), true);
Serial.println ("Volgende MQTT-Connect in 3 sec");
vertraging (3000);
    }
  }
}

/*
* =================================================================
* Functie: writeAdvanceDiag
* Retourneert: ongeldig
* Beschrijving: schrijft vooraf bericht naar seriële monitor, indien
* GEAVANCEERD> = 1
* msg: bericht voor de seriële monitor
* newLine: Bericht met linebreak (true)
* =================================================================
*/
void writeAdvanceDiag (String msg, bool newLine)
{
if (bool (ADVANCEDIAG)) // Controleer of geavanceerde diag is ingeschakeld
  {
if (newLine)
Serial.println (msg);
anders
Serial.print (msg);
  }
}


Code 2: Voorbeeld NodeMCU MQTT-gegevens ontvangen

Am Anfang vom Code wird een Objekt espClient erzeugt and dem ebenfalls erzeugten Objekt mqttClient übergeben. Damit kann bei einer aktiven WiFi-Verbindung eine General Kommunikation hergestellt.

Starten van NodeMCU, wird zunächst das WiFi, hier in der Funktion setupWifi (), eingerichtet and anschließend in the setup () - Funktion die Verbindung zum MQTT-Broker hergestellt. Mittels „mqttClient.setServer (MQTT_BROKER, 1883);” wird die Adresse en de Port vom MQTT Broker configureert en über „mqttClient.setCallback (callback);“ die Funktion zur Abarbeitung der empfangenen Data bestimmt, dazu weiter unten mehr.

Die loop () - Funktion macht genau zwei Dinge:

1. Prüfung, ob der NodeMCU mit dem MQTT-Broker verbunden ist. Er is geen sprake van een herfst, maar de functie kan opnieuw worden aangeslotenMQTT () aufgerufen.

2. De functie mqttClient.loop () wordt aangeroepen om communicatie met MQTT uit te voeren.

De eerste stap is om u te registreren bij de MQTT-makelaar met een unieke klantnaam. U kunt dit vrij definiëren met behulp van de globale variabele “clientID”. Als de registratie is gelukt, wordt in de volgende stap op het gewenste onderwerp geabonneerd. Dit gebeurt met

"MqttClient.subscribe (SUBTOPIC, 1)"

waar in dit voorbeeld SUBTOPIC zich abonneert op het onderwerp "/ #" (alle onderwerpen) en "1" staat voor een QoS groter dan 0. De NodeMCU wordt dus voorzien van berichten van de broker zodra er wijzigingen in een topic zijn.

In het geval van een fout probeert de NodeMCU elke 3 seconden opnieuw verbinding te maken met de broker.

Dit brengt ons op het punt waarop de NodeMCU gegevens van de broker ontvangt als de NodeMCU is aangesloten. Als er nieuwe berichten zijn, worden deze geëvalueerd met de functie callback (). Er worden drie parameters doorgegeven aan de functie callback ():

  1. topic: wat het absolute onderwerppad van het ontvangen bericht weergeeft
  2. payload: het bericht, in byte-indeling
  3. length: de lengte van het bericht

Met deze drie stukjes informatie kun je evalueren waarvoor je het geselecteerde onderwerp nodig hebt. In het onderhavige geval voeren we het onderwerp uit via de seriële monitor. Meteen daarna zetten we het bytebericht om in een string met behulp van de for-lus die wordt getoond in code 3. U heeft een normaal leesbaar bericht.

voor (int i = 0; i stMessage + = String ((char) payload [i]);

Code 3: codefragment om MQTT-bericht naar string te converteren

Dit bericht in stringformaat wordt ook uitgestuurd via de seriële monitor

Je kunt in figuur 2 zien dat deze schets zo soepel werkt.

Figuur 2: Bericht ontvangen van de MQTT-makelaar

Bedenk van tevoren dat onze Duitse umlauten niet werken. Deze worden dan vertegenwoordigd door andere karakters.

Eenvoudig MQTT-abonnement met ESP32 NodeMCU

Merk op dat op dit punt de ESP32 NodeMCU Module WLAN WiFi Development Board wordt gebruikt voor het volgende voorbeeld.

In het voorbeeld van Code 4 moet de ESP32 NodeMCU gegevens naar de MQTT-broker sturen. Omdat het heel eenvoudig is, beginnen we met het elke twee seconden verzenden van de runtime van de ESP32 NodeMCU Module WLAN WiFi Development Board naar de broker.

Ook in dit voorbeeld staan ​​er veel opmerkingen in de code om het voor u gemakkelijker te maken. Om ervoor te zorgen dat de broncode met u werkt, moet u uw WLAN-ID en wachtwoord in de broncode wijzigen.


//-----------------------------------------------------
// Voorbeeld 2 ESP-NodeMCU met MQTT
// Auteur: Joern Weise
// Licentie: GNU GPl 3.0
// Gemaakt: 20 oktober 2020
// Update: 25 oktober 2020
//-----------------------------------------------------
# include
# include // Lib voor MQTT Pub en Sub
//
#ifndef STASSID
#define STASSID "……………" // Voer de Wfi-naam in
#define STAPSK "……………" // Voer wachtwoord in
#endif

#define GEAVANCEERD 1
const char * MQTT_BROKER = "raspberrypi"; // Naam van de mqtt-makelaar
const char * PubTopic = "/ Client / ESP32"; // Onderwerp waar te publiceren
String clientID = "ESP-DevKit_1"; // Klantnaam voor MQTT-makelaar
WiFiClient espClient;
PubSubClient mqttClient (espClient);

niet-ondertekende lange lLastMsg = 0;
int iTimeDelay = 2000; // Stel de vertraging voor het volgende bericht in op 2 seconden
# definiëren MSG_BUFFER_SIZE (50)
char msg [MSG_BUFFER_SIZE];

leegte setup ()
{
Serial.begin (115200); // Start seriële monitor baudrate 115200
vertraging (50);
writeAdvanceDiag ("SerialMonitor ingeschakeld", true);
setupWifi ();
writeAdvanceDiag ("Set MQTT-Server", true);
mqttClient.setServer (MQTT_BROKER, 1883);
writeAdvanceDiag ("Finish setup () - Function", true);
}

/*
* =================================================================
* Functie: setupWifi
* Retourneert: ongeldig
* Beschrijving: stel wifi in om verbinding te maken met het netwerk
* =================================================================
*/
leegte setup Wifi ()
{
Serial.println ("Verbinding met:" + String (STASSID));
WiFi.mode (WIFI_STA);
WiFi.begin (STASSID, STAPSK);
while (WiFi.status ()! = WL_CONNECTED)
  {
vertraging (500);
Serial.print (".");
  }
Serial.println ("");
Serial.println ("WiFi verbonden");
Serial.println ("IP-adres:");
Serial.println (WiFi.localIP ());
}

leegte lus () {
// plaats je hoofdcode hier, om herhaaldelijk uit te voeren:
if (! mqttClient.connected ())
reconnectMQTT ();

mqttClient.loop ();

if (millis () - lLastMsg> iTimeDelay)
  {
lLastMsg = millis ();
snprintf (msg, MSG_BUFFER_SIZE, "% 1d", millis ()); // Converteer bericht naar char
mqttClient.publish (PubTopic, msg, true); // Stuur naar makelaar
  }
}

/*
* =================================================================
* Functie: reconnectMQTT
* Retourneert: ongeldig
* Beschrijving: als er geen verbinding is met MQTT, is deze functie
* gebeld. Bovendien wordt het gewenste onderwerp geregistreerd.
* =================================================================
*/
leegte reconnectMQTT ()
{
while (! mqttClient.connected ())
  {
writeAdvanceDiag ("Login bij MQTT-Broker", true);
if (mqttClient.connect (clientID.c_str ()))
    {
Serial.println ("Verbonden met MQTT-Broker" + String (MQTT_BROKER));
    }
anders
    {
writeAdvanceDiag ("Mislukt met rc =" + String (mqttClient.state ()), true);
Serial.println ("Volgende MQTT-Connect in 3 sec");
vertraging (3000);
    }
  }
}

/*
* =================================================================
* Functie: writeAdvanceDiag
* Retourneert: ongeldig
* Beschrijving: schrijft vooraf bericht naar seriële monitor, indien
* GEAVANCEERD> = 1
* msg: bericht voor de seriële monitor
* newLine: Bericht met linebreak (true)
* =================================================================
*/
void writeAdvanceDiag (String msg, bool newLine)
{
if (bool (ADVANCEDIAG)) // Controleer of geavanceerde diag is ingeschakeld
  {
if (newLine)
Serial.println (msg);
anders
Serial.print (msg);
  }
}

Code 4: ESP32 MQTT-Daten empfangen lassen

Wie schon im ersten Beispiel wird ein Objekt espClient erzeugt and dem ebenfalls erzeugten Objekt mqttClient übergeben. Beim Start vom ESP32 NodeMCU Module WLAN WiFi Development Board wird das WiFi über die Funktion setupWiFi () aufgebaut. Direkt im Anschluss der setup () - Funktion wird der MQTT-Broker mittels „mqttClient.setServer (MQTT_BROKER, 1883);” vorkonfiguriert. Eine callback () - Funktion braucht is an dieser Stelle nicht, da keine data empfangen and verarbeitet were müssen.

Die loop () - Funktion ist daher fast identisch zum ersten Beispiel, mit der Ausnahme von der Zeile die Code 5 zeigt.


if (millis () - lLastMsg> iTimeDelay)
{
lLastMsg = millis ();
snprintf (msg, MSG_BUFFER_SIZE, "% 1d", millis ()); // Converteer bericht naar char
mqttClient.publish (PubTopic, msg, true); // Stuur naar makelaar
}

Code 5: Codefragment voor het verzenden van de actieve tijd

Deze pagina is verzonden naar alle 2 weken die actief zijn Laufzeit an das Topic "/ Client / ESP32". Het dieses Beispiel funktioniert, zeigt Abbildung 3. In diesem Fall zeigt MQTT.fx die Nachrichten vom MQTT Broker an.

Afbeelding 3: MQTTfx gesendete gegevens vom ESP32 NodeMCU

MQTT-Beispiel mit mehreren Clients




In de letzten Beispielen, auch im ersten Blogbeitrag, sind wir immer of einem Broker and einem Client ausgegangen. Die realität bei solchen MQTT-Projekten sieht aber oft anders aus. In der Praxis gibt es meist Clients, die Daten von Sensoren liefern, Clients, welche die gepushten Daten empfangen und weiterverarbeiten, and zu guter Letzt Clients, die ausführen.


Voor de eerste keer dat de klant in de buurt is, moet een NodeMCU Lua Amica Module V2 een potentiometerwert maken en een nieuwe aanwinst voor een makelaar.

Een ESP32 NodeMCU-module WLAN WiFi Development Board is geabonneerd op de data en de kaart van 0-1024 op 0-255, gepubliceerd door de BME / BMP280-sensoren van de temperatuur en de luchtdruk.

Deze gegevens zijn geabonneerd op een Arduino-eenheid met Ethernet-Shield, LED en I2C-LCD-Display en visuele gegevens. Die LED geeft een signaal van de Potentiometer en de Display van de temperatuur en de temperatuur van de sensoren.


We beginnen met de NodeMCU Lua Amica module V2 en de potentiometer. Bedraad beide zoals weergegeven in figuur 4. Dit onderdeel is eenvoudig omdat er maar drie draden hoeven te worden aangesloten.

 

Figuur 4: Bedrading van de NodeMCU Lua Amica module V2 met potentiometer

De code voor de NodeMCU Lua Amica-module V2 wordt slank gehouden en omvat in wezen de initialisatie van het WLAN en de verbinding met MQTT, evenals de datatransmissie van de analoge potentiometerwaarden, zie Code 6. Zodat de broncode ook op u moet uw WLAN Change ID en wachtwoord in de broncode gebruiken.

//-----------------------------------------------------
// Voorbeeld 3 NodeMCU met Poti-overdracht naar mqtt-broker
// Auteur: Joern Weise
// Licentie: GNU GPl 3.0
// Gemaakt: 20 oktober 2020
// Update: 25 oktober 2020
//-----------------------------------------------------
# include // Lib voor wifi
# include // Lib voor MQTT Pub en Sub

#ifndef STASSID
#define STASSID "ENTER-WIFI_HERE" // Voer Wfi-naam in
#define STAPSK "ENTER-PASS-HERE" // Voer Wifi-Passkey in
#endif
#define GEAVANCEERD 1
# definiëren MSG_BUFFER_SIZE (50)
#define UPDATETIME 200
# definiëren MINVALUECHANGE 1

const char * MQTT_BROKER = "raspberrypi"; // Naam van de mqtt-makelaar
String clientID = "NodeMCU_1"; // Klantnaam voor MQTT-makelaar
const char * PubTopicPoti = "/ Client / ESP32 / Poti / Value"; // Onderwerp waar te publiceren
const int iAnalogPin = A0; // Stel analoge pin in
int iSensorValue = 0;
int iLastValue = 0;

// Maak objecten voor mqtt
WiFiClient espClient;
PubSubClient mqttClient (espClient);
unsigned int iLastTime = 0;
char msg [MSG_BUFFER_SIZE];
leegte setup ()
{
Serial.begin (115200); // Start seriële monitor baudrate 115200
vertraging (50);
writeAdvanceDiag ("SerialMonitor ingeschakeld", true);
setupWifi ();
writeAdvanceDiag ("Set MQTT-Server", true);
mqttClient.setServer (MQTT_BROKER, 1883);
writeAdvanceDiag ("Set Callback-functie", true);
writeAdvanceDiag ("Finish setup () - Function", true);
}

/*
=================================================================
Functie: setupWifi
Retourneert: ongeldig
Beschrijving: wifi instellen om verbinding te maken met het netwerk
=================================================================
*/
leegte setup Wifi ()
{
Serial.println ("Verbinding met:" + String (STASSID));
WiFi.mode (WIFI_STA);
WiFi.begin (STASSID, STAPSK);
while (WiFi.status ()! = WL_CONNECTED)
  {
vertraging (500);
Serial.print (".");
  }
Serial.println ("");
Serial.println ("WiFi verbonden");
Serial.println ("IP-adres:");
Serial.println (WiFi.localIP ());
}

leegte lus () {
// plaats je hoofdcode hier, om herhaaldelijk uit te voeren:
if (! mqttClient.connected ())
reconnectMQTT ();

mqttClient.loop ();

if (millis () - iLastTime> UPDATETIME)
  {
iSensorValue = analogRead (iAnalogPin); // Lees analoge waarde
if (iSensorValue! = iLastValue)
    {
if (abs (iSensorValue - iLastValue)> MINVALUECHANGE) // Controleer of de verandering hoog genoeg is
      {
Serial.println ("Sensorvalue:" + String (iSensorValue));
snprintf (msg, MSG_BUFFER_SIZE, "% d", iSensorValue); // Converteer bericht naar char
mqttClient.publish (PubTopicPoti, msg); // Stuur naar makelaar
iLastValue = iSensorValue;
      }
    }
iLastTime = millis ();
  }
}

/*
=================================================================
Functie: reconnectMQTT
Retourneert: ongeldig
Beschrijving: als er geen verbinding is met MQTT, is deze functie
gebeld. Bovendien wordt het gewenste onderwerp geregistreerd.
=================================================================
*/
leegte reconnectMQTT ()
{
while (! mqttClient.connected ())
  {
writeAdvanceDiag ("Inloggen bij MQTT-makelaar", true);
if (mqttClient.connect (clientID.c_str ()))
    {
Serial.println ("Verbonden met MQTT Broker" + String (MQTT_BROKER));
    }
anders
    {
writeAdvanceDiag ("Mislukt met rc =" + String (mqttClient.state ()), true);
Serial.println ("Volgende MQTT-Connect in 3 sec");
vertraging (3000);
    }
  }
}

/*
=================================================================
Functie: writeAdvanceDiag
Retourneert: ongeldig
Beschrijving: schrijft vooraf bericht naar seriële monitor, if
GEAVANCEERD> = 1
msg: bericht voor de seriële monitor
newLine: Bericht met linebreak (true)
=================================================================
*/
void writeAdvanceDiag (String msg, bool newLine)
{
if (bool (ADVANCEDIAG)) // Controleer of geavanceerde diag is ingeschakeld
  {
if (newLine)
Serial.println (msg);
anders
Serial.print (msg);
  }
}

code 6: NodeMCU Lua Amica module V2

Om u te helpen de broncode sneller te begrijpen, zijn er veel opmerkingen en opmerkingen over de functies gemaakt.

De volgende microcontroller die hier moet worden ingesteld en zijn functie krijgt, is de ESP32 NodeMCU Module WLAN WiFi Development Board. Omdat het twee I2C-interfaces heeft, ontvangt het twee BME / BMP280-sensoren en neemt het de mapping van de analoge potentiometerwaarden over. Nogmaals, de bedrading is eenvoudig, zie afbeelding 5.

Afbeelding 5: Bedrading ESP32 NodeMCU-module WLAN WiFi-ontwikkelbord

De code voor deze taken, zie Code 7, is iets uitgebreider. Eerst worden de WLAN-verbinding, de MQTT-verbinding en de sensoren geïnitialiseerd. In de callback-functie wordt de nieuw ontvangen analoge potentiometerwaarde toegewezen aan een waarde tussen 0 en 255 en teruggestuurd naar de makelaar. Indien één of beide BME / BMP280 nieuwe meetgegevens heeft die afwijken van de voorgaande waarden, worden deze ook naar de broker gestuurd.

Om ervoor te zorgen dat de broncode met u werkt, moet u uw WLAN-ID en wachtwoord in de broncode wijzigen.

//-----------------------------------------------------
// Voorbeeld 3 ESP-NodeMCU met twee BME-overdrachten naar
// mqtt broker en mapping analoge input
// Auteur: Joern Weise
// Licentie: GNU GPl 3.0
// Gemaakt: 20 oktober 2020
// Update: 25 oktober 2020
//-----------------------------------------------------
# include
# include
# include
# include // Lib voor MQTT Pub en Sub

// Definieer WiFi-instellingen
#ifndef STASSID
#define STASSID "ENTER-WIFI-HIER" // Voer Wfi-naam in
#define STAPSK "ENTER-PASS-HERE" // Voer wachtwoord in
#endif

#define GEAVANCEERD 1

# definiëren I2C_SDA1 21
# definiëren I2C_SCL1 22
# definiëren I2C_SDA2 17
# definiëren I2C_SCL2 16
#define NEXTUPDATE 2000

// Objecten voor I2C en BME
TwoWire I2Cone = TwoWire (0);
TwoWire I2Ctwo = TwoWire (1);
Adafruit_BME280 bmeOne;
Adafruit_BME280 bmeTwo;
unsigned long lastTime = 0;

const char * MQTT_BROKER = "raspberrypi"; // Naam van de mqtt-makelaar
const char * PubTopicTempOne = "/ Client / ESP32 / TempOne"; // Onderwerp eerste temp
const char * PubTopicTempTwo = "/ Client / ESP32 / TempTwo"; // Onderwerp tweede temp
const char * PubTopicPresOne = "/ Client / ESP32 / PressOne"; // Onderwerp eerste druk
const char * PubTopicPresTwo = "/ Client / ESP32 / PressTwo"; // Onderwerp tweede druk
const char * PubTopicPotiMap = "/ Client / ESP32 / PotiMapValue"; // Onderwerp tweede druk
const char * SUBTOPIC = "/ Client / ESP32 / Poti / Value"; // Onderwerp abonneer poti-waarde
String clientID = "ESP-DevKit_1"; // Klantnaam voor MQTT-makelaar

int iLastTempOne, iLastTempTwo, iLastPressOne, iLastPressTwo;

// Maak objecten voor mqtt
WiFiClient espClient;
PubSubClient mqttClient (espClient);

# definiëren MSG_BUFFER_SIZE (50)
char msg [MSG_BUFFER_SIZE];

ongeldige setup () {
// plaats je setup-code hier, om een ​​keer uit te voeren:
Serial.begin (115200);
Serial.println ("BME280-test");
Serial.println ("Init beide I2C-verbindingen");
I2Cone.begin (I2C_SDA1, I2C_SCL1, 400000);
I2Ctwo.begin (I2C_SDA2, I2C_SCL2, 400000);
Serial.println ("Laat de eerste BME met ons praten");
bool bStatus;
// Init eerste sensor
bStatus = bmeOne.begin (0x76, & I2Cone);
if (! bStatus)
  {
Serial.println ("Kon geen geldige BME280 - 1 sensor vinden, controleer bedrading!");
terwijl (1);
  }
anders
Serial.println ("Geldige BME280 - 1 sensor!");

// Initiële tweede sensor
bStatus = bmeTwo.begin (0x76, & I2Ctwo);
if (! bStatus)
  {
Serial.println ("Kon geen geldige BME280 - 2 sensor vinden, controleer bedrading!");
terwijl (1);
  }
anders
Serial.println ("Geldige BME280 - 2 sensor!");
writeAdvanceDiag ("Init Wifi", true);
setupWifi ();
writeAdvanceDiag ("Init Wifi - DONE", true);
writeAdvanceDiag ("Set MQTT-Server", true);
mqttClient.setServer (MQTT_BROKER, 1883);
writeAdvanceDiag ("Set Callback-functie", true);
mqttClient.setCallback (terugbellen);
writeAdvanceDiag ("Finish setup () - Function", true);
  }

leegte lus () {
// plaats je hoofdcode hier, om herhaaldelijk uit te voeren:
int iTempOne, iTempTwo, iPressOne, iPressTwo;
if (! mqttClient.connected ())
reconnectMQTT ();

mqttClient.loop ();
// Controleer na "NEXTUPDATE" of de waarden zijn gewijzigd
if (millis () - lastTime> NEXTUPDATE)
    {
iTempOne = int (bmeOne.readTemperature ()); // Krijg tijdelijke een
iTempTwo = int (bmeTwo.readTemperature ()); // Krijg temp twee
iPressOne = int (bmeOne.readPressure () / 100.0F); // Haal er één
iPressTwo = int (bmeTwo.readPressure () / 100.0F); // haal druk op twee
if (iTempOne! = iLastTempOne) // Controleer de tijdelijke wijziging en verzend
    {
snprintf (msg, MSG_BUFFER_SIZE, "% 1d", iTempOne); // Converteer bericht naar char
mqttClient.publish (PubTopicTempOne, msg, true); // Stuur naar makelaar
writeAdvanceDiag ("Send Temp one:" + String (iTempOne), true);
iLastTempOne = iTempOne;
  }
if (iTempTwo! = iLastTempTwo) // Controleer temp twee gewijzigd en verzend
    {
snprintf (msg, MSG_BUFFER_SIZE, "% 1d", iTempTwo); // Converteer bericht naar char
mqttClient.publish (PubTopicTempTwo, msg, true); // Stuur naar makelaar
writeAdvanceDiag ("Send Temp two:" + String (iTempTwo), true);
iLastTempTwo = iTempTwo;
    }
if (iPressOne! = iLastPressOne) // Controleer de druk één gewijzigd en verzend
    {
snprintf (msg, MSG_BUFFER_SIZE, "% 1d", iPressOne); // Converteer bericht naar char
mqttClient.publish (PubTopicPresOne, msg, true); // Stuur naar makelaar
writeAdvanceDiag ("Send Press one:" + String (iPressOne), true);
iLastPressOne = iPressOne;
    }
if (iPressTwo! = iLastPressTwo) // Controleer druk twee gewijzigd en verzend
    {
snprintf (msg, MSG_BUFFER_SIZE, "% 1d", iPressTwo); // Converteer bericht naar char
mqttClient.publish (PubTopicPresTwo, msg, true); // Stuur naar makelaar
writeAdvanceDiag ("Verzenden Druk op twee:" + String (iPressTwo), true);
iLastPressTwo = iPressTwo;
    }
lastTime = millis ();
  }
}

/*
* =================================================================
* Functie: terugbellen
* Retourneert: ongeldig
* Beschrijving: wordt automatisch gebeld als een onderwerp is geabonneerd
* heeft een nieuw bericht
* topic: Geeft het onderwerp terug, waar een nieuw bericht vandaan komt
* payload: het bericht van het onderwerp
* lengte: lengte van het bericht, belangrijk om inhoud te krijgen
* =================================================================
*/
void callback (char * topic, byte * payload, unsigned int length)
{
String stMessage = "";
writeAdvanceDiag ("Bericht is aangekomen van topic:" + String (topic), true);
writeAdvanceDiag ("Berichtlengte:" + String (lengte), true);
voor (int i = 0; i stMessage + = String ((char) payload [i]);
writeAdvanceDiag ("Bericht is:" + stMessage, true);
// Wijs waarde toe en stuur de toegewezen waarde naar mqtt broker
int iValue, iMapValue;
iValue = stMessage.toInt ();
iMapValue = kaart (iValue, 0,1024,0,255);
snprintf (msg, MSG_BUFFER_SIZE, "% 1d", iMapValue); // Converteer bericht naar char
writeAdvanceDiag ("Stuur toegewezen PotiValue:" + String (iMapValue), true);
mqttClient.publish (PubTopicPotiMap, msg, true); // Stuur naar makelaar
}

/*
* =================================================================
* Functie: setupWifi
* Retourneert: ongeldig
* Beschrijving: stel wifi in om verbinding te maken met het netwerk
* =================================================================
*/
leegte setup Wifi ()
{
Serial.println ("Verbinding met:" + String (STASSID));
WiFi.mode (WIFI_STA);
WiFi.begin (STASSID, STAPSK);
while (WiFi.status ()! = WL_CONNECTED)
  {
vertraging (500);
Serial.print (".");
  }
Serial.println ("");
Serial.println ("WiFi verbonden");
Serial.println ("IP-adres:");
Serial.println (WiFi.localIP ());
}

/*
* =================================================================
* Functie: writeAdvanceDiag
* Retourneert: ongeldig
* Beschrijving: schrijft vooraf bericht naar seriële monitor, indien
* GEAVANCEERD> = 1
* msg: bericht voor de seriële monitor
* newLine: Bericht met linebreak (true)
* =================================================================
*/
void writeAdvanceDiag (String msg, bool newLine)
{
if (bool (ADVANCEDIAG)) // Controleer of geavanceerde diag is ingeschakeld
{
if (newLine)
Serial.println (msg);
anders
Serial.print (msg);
  }
}

/*
* =================================================================
* Functie: reconnectMQTT
* Retourneert: ongeldig
* Beschrijving: als er geen verbinding is met MQTT, is deze functie
* gebeld. Bovendien wordt het gewenste onderwerp geregistreerd.
* =================================================================
*/
leegte reconnectMQTT ()
{
while (! mqttClient.connected ())
{
writeAdvanceDiag ("Inloggen bij MQTT-makelaar", true);
if (mqttClient.connect (clientID.c_str ()))
    {
Serial.println ("Verbonden met MQTT Broker" + String (MQTT_BROKER));
writeAdvanceDiag ("Abonneer op onderwerp '" + String (SUBTOPIC) + "'", true);
mqttClient.subscribe (SUBTOPIC, 1); // Abonneer op onderwerp "SUBTOPIC"
    }
anders
    {
writeAdvanceDiag ("Mislukt met rc =" + String (mqttClient.state ()), true);
Serial.println ("Volgende MQTT-Connect in 3 sec");
vertraging (3000);
    }
  }
}

 Code 7: ESP32 NodeMCU-module WLAN WiFi-ontwikkelbord

In de laatste stap moeten de verzamelde gegevens worden gevisualiseerd. Hiervoor worden de Arduino Uno met aangehecht ethernet shield, het 20x04 LCD I2C display en een monochrome LED gebruikt.

U kunt de exacte bedrading in zien Figuur 6 zien. Houd er rekening mee dat het 20x04 LCD I2C-scherm een ​​voeding van 5V vereist.

 

Figuur 6: Arduino Uno Ethernetshield voor uitvoer

Er zijn geen grote verrassingen bij het programmeren van de Arduino Uno. Eerst wordt het netwerk geïnitialiseerd en wordt de verbinding gecontroleerd. In de volgende stap worden de weergave en de verbinding met de MQTT-makelaar tot stand gebracht. De callback () functie is relevant voor het uitvoeren van de data, ontvangt alle data van de broker en toont veranderingen in één of meerdere waarden in het display of via de LED.

//-----------------------------------------------------
// Voorbeeld 3 Arduino Uno Ehternetshiled om te ontvangen
// gegevens van makelaar en tonen op LCD en LED
// Auteur: Joern Weise
// Licentie: GNU GPl 3.0
// Gemaakt: 25 oktober 2020
// Update: 26 oktober 2020
//-----------------------------------------------------
# include
# omvatten
# include // Lib voor MQTT Pub en Sub
# include
# include

#define GEAVANCEERD 1

LiquidCrystal_I2C lcd (0x27,20,4); // stel het LCD-adres in op 0x27 voor een display met 16 tekens en 2 regels
const int iAnalogOut = 6;
byte mac [] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // MAC-adres voor shield
IP-adres ip (192, 168, 178, 177); // Statisch IP-adres voor arduino
IP-adres myDns (192, 168, 178, 1); // IP-adres router
char server [] = "www.google.com"; // Controleer of Arduino online is

String clientID = "Arduino_Uno"; // Klantnaam voor MQTT-makelaar
// Onderwerpen om in te schrijven
const char * MQTT_BROKER = "raspberrypi"; // Naam van de mqtt-makelaar
const char * SubTopicTempOne = "/ Client / ESP32 / TempOne"; // Onderwerp eerste temp
const char * SubTopicTempTwo = "/ Client / ESP32 / TempTwo"; // Onderwerp tweede temp
const char * SubTopicPresOne = "/ Client / ESP32 / PressOne"; // Onderwerp eerste druk
const char * SubTopicPresTwo = "/ Client / ESP32 / PressTwo"; // Onderwerp tweede druk
const char * SubTopicPotiMap = "/ Client / ESP32 / PotiMapValue"; // Onderwerp toegewezen potentiometer

// Objecten voor ethernet-com
EthernetClient-client;
PubSubClient mqttClient (klant);

// Enkele varianten voor update
bool bUpdateDisplay = false;
bool bUpdatePWM = false;
int iLastTempOne, iLastTempTwo, iLastPressOne, iLastPressTwo, iLastPotiMap;

ongeldige setup () {
Serial.begin (115200);
while (! Serial) {
; // wacht tot de seriële poort verbinding maakt. Alleen nodig voor native USB-poort
  }
Serial.println ("Arduino Uno Monitor");
pinMode (iAnalogOut, OUTPUT);
Ethernet.init (10); // De meeste Arduino-schilden gebruiken digitale pin 10
lcd.init (); // Initiële LCD
lcd.backlight (); // achtergrondverlichting aan
lcd.clear (); // Wis oude inhoud
bUpdateDisplay = true;
Ethernet.begin (mac, ip); // Initiële ethernet-afscherming
// Controleer of er Ethernet-hardware aanwezig is
if (Ethernet.hardwareStatus () == EthernetNoHardware) {
Serial.println ("Ethernet-schild is niet gevonden. Sorry, kan niet werken zonder hardware. :(");
while (true) {
vertraging (1); // niets doen, het heeft geen zin om te draaien zonder Ethernet-hardware
    }
  }
// Controleer of er com naar de router is
while (Ethernet.linkStatus () == LinkOFF) {
Serial.println ("Ethernet-kabel is niet aangesloten.");
vertraging (500);
  }

// geef het Ethernet-schild een seconde om te initialiseren:
vertraging (1000);
Serial.println ("verbinden ...");

// Controleer of het systeem kan communiceren
if (client.connect (server, 80)) {
Serial.print ("verbonden met");
Serial.println (client.remoteIP ());
// Maak een HTTP-verzoek:
client.println ("GET / search? q = arduino HTTP / 1.1");
client.println ("Host: www.google.com");
client.println ("Verbinding: sluiten");
client.println ();
} anders {
// als je geen verbinding met de server hebt gekregen:
Serial.println ("verbinding mislukt");
  }
// Init MQTT
writeAdvanceDiag ("Set MQTT-Server", true);
mqttClient.setServer (MQTT_BROKER, 1883);
writeAdvanceDiag ("Set Callback-functie", true);
mqttClient.setCallback (terugbellen);
writeAdvanceDiag ("Finish setup () - Function", true);
}

leegte lus () {
// plaats je hoofdcode hier, om herhaaldelijk uit te voeren:
if (! mqttClient.connected ())
reconnectMQTT ();

mqttClient.loop ();

if (bUpdateDisplay)
  {
UpdateDisplay ();
bUpdateDisplay = false;
  }
if (bUpdatePWM)
  {
analogWrite (iAnalogOut, iLastPotiMap); // Schrijf nieuwe analoge waarde naar LED-Pin
bUpdatePWM = false;
  }
}

/*
* =================================================================
* Functie: writeAdvanceDiag
* Retourneert: ongeldig
* Beschrijving: schrijft vooraf bericht naar seriële monitor, indien
* GEAVANCEERD> = 1
* msg: bericht voor de seriële monitor
* newLine: Bericht met linebreak (true)
* =================================================================
*/
void writeAdvanceDiag (String msg, bool newLine)
{
if (bool (ADVANCEDIAG)) // Controleer of geavanceerde diag is ingeschakeld
  {
if (newLine)
Serial.println (msg);
anders
Serial.print (msg);
  }
}

/*
* =================================================================
* Functie: reconnectMQTT
* Retourneert: ongeldig
* Beschrijving: als er geen verbinding is met MQTT, is deze functie
* gebeld. Bovendien wordt het gewenste onderwerp geregistreerd.
* =================================================================
*/
leegte reconnectMQTT ()
{
while (! mqttClient.connected ())
  {
writeAdvanceDiag ("Login bij MQTT-Broker", true);
if (mqttClient.connect (clientID.c_str ()))
    {
Serial.println ("Verbonden met MQTT-Broker" + String (MQTT_BROKER));
writeAdvanceDiag ("Abonneer op onderwerp '" + String (SubTopicTempOne) + "'", true);
mqttClient.subscribe (SubTopicTempOne, 1); // Abonneer op onderwerp "SubTopicTempOne"
writeAdvanceDiag ("Abonneren op onderwerp '" + String (SubTopicTempTwo) + "'", true);
mqttClient.subscribe (SubTopicTempTwo, 1); // Abonneer op onderwerp "SubTopicTempTwo"
writeAdvanceDiag ("Abonneer op onderwerp '" + String (SubTopicPresOne) + "'", true);
mqttClient.subscribe (SubTopicPresOne, 1); // Abonneer op onderwerp "SubTopicPresOne"
writeAdvanceDiag ("Abonneer op onderwerp '" + String (SubTopicPresTwo) + "'", true);
mqttClient.subscribe (SubTopicPresTwo, 1); // Abonneer op onderwerp "SubTopicPresTwo"
writeAdvanceDiag ("Abonneer op onderwerp '" + String (SubTopicPotiMap) + "'", true);
mqttClient.subscribe (SubTopicPotiMap, 1); // Abonneer op onderwerp "SubTopicPotiMap"
    }
anders
    {
writeAdvanceDiag ("Mislukt met rc =" + String (mqttClient.state ()), true);
Serial.println ("Volgende MQTT-Connect in 3 sec");
vertraging (3000);
    }
  }
}

/*
* =================================================================
* Functie: terugbellen
* Retourneert: ongeldig
* Beschrijving: wordt automatisch gebeld als een onderwerp is geabonneerd
* heeft een nieuw bericht
* topic: Geeft het onderwerp terug, waar een nieuw bericht vandaan komt
* payload: het bericht van het onderwerp
* lengte: lengte van het bericht, belangrijk om inhoud te krijgen
* =================================================================
*/
void callback (char * topic, byte * payload, unsigned int length)
{
String stMessage = "";
voor (int i = 0; i stMessage + = String ((char) payload [i]);

// Controleer of de tijdelijke is gewijzigd
if (String (topic) == "/ Client / ESP32 / TempOne")
  {
if (iLastTempOne! = stMessage.toInt ())
    {
iLastTempOne = stMessage.toInt ();
bUpdateDisplay = true;
    }
  }
// Controleer of temp twee is gewijzigd
if (String (topic) == "/ Client / ESP32 / TempTwo")
  {
if (iLastTempTwo! = stMessage.toInt ())
    {
iLastTempTwo = stMessage.toInt ();
bUpdateDisplay = true;
    }
  }
// Controleer of de druk is veranderd
if (String (topic) == "/ Client / ESP32 / PressOne")
  {
if (iLastPressOne! = stMessage.toInt ())
    {
iLastPressOne = stMessage.toInt ();
bUpdateDisplay = true;
    }
  }
// Controleer of druk twee is veranderd
if (String (topic) == "/ Client / ESP32 / PressTwo")
  {
if (iLastPressTwo! = stMessage.toInt ())
    {
iLastPressTwo = stMessage.toInt ();
bUpdateDisplay = true;
    }
  }
// Controleer of de toegewezen poti-waarde is gewijzigd
if (String (topic) == "/ Client / ESP32 / PotiMapValue")
  {
if (iLastPotiMap! = stMessage.toInt ())
    {
iLastPotiMap = stMessage.toInt ();
bUpdatePWM = waar;
    }
  }
}

/*
* =================================================================
* Functie: UpdateDisplay
* Retourneert: ongeldig
* Beschrijving: Nieuwe waarden weergeven op I2C-Display
* =================================================================
*/
ongeldig UpdateDisplay ()
{
lcd.clear ();
lcd.home ();
lcd.print ("Tijdelijke [C]:");
lcd.print (iLastTempOne);
lcd.setCursor (0,1);
lcd.print ("Tijdelijke twee [C]:");
lcd.print (iLastTempTwo);
lcd.setCursor (0,2);
lcd.print ("Druk op een [hPa]:");
lcd.print (iLastPressOne);
lcd.setCursor (0,3);
lcd.print ("Druk op twee [hPa]:");
lcd.print (iLastPressTwo);
}

Code 8: Arduino Uno naar Anzeige der MQTT-Daten

Dit is alles wat u moet weten en de code op alle MicroControllers kan worden weergegeven, bijvoorbeeld op het LCD-scherm en de andere LED-schermen. Beim Drehen vom Potentiometer wird die Helligkeit of LED geändert and aktuelle Temperatur and Druck beider Sensoren sollten visualisiert were. Wie das aussehen kann, zeigt Abbildung 7.

Abbildung 7: Ausgabe von Sensordaten en LED-Helligkeit

Wollen Sie alle Daten ihres Brokers zien, kan ich Ihnen das Tool MQTT.fx empfehlen. Damit können Sie sowohl Data vom Broker abonneert als auch publishen. Probeer deze uit een andere hardware en de MicroController, die kan worden gebruikt en de gegevens die door de makelaar worden verzonden. Der Arduino Uno kann, über eine Schleife, sterven abwechselnd anzeigen.

Mit Abschluss overlijdt Beitrages haben Sie sowohl die Grundlagen, als auch ein komplexeres praktisches Beispiel erhalten. Dit is een handige manier om de machine te grillen en te gebruiken.

Dit en weitere Projekte vindt u op GitHub onder https://github.com/M3taKn1ght/Blog-Repo

Projekte für anfängerRaspberry pi

3 Reacties

Jörn Weise

Jörn Weise

Hello jm1704,

thank you for the nice compliment. Of course, as bloggers, we are always interested in writing interesting and knowledgeable posts with az-delivery. Of course, the variety must not be missing and the reference to the products. Especially IoT is an interesting topic, but also holds great dangers if the knowledge is missing.
However, it must not be forgotten at this point that the topic is only dealt with on the surface! The broker is not secured and the Pi itself has no significant protection against manipulation. This makes it easy for criminal bodies to do damage when sensitive systems are controlled and regulated.
As my professor in college used to say, “You’ve now learned the basics, do something with it!”

Greetings Weise
-—-IN GERMAN———

Hallo jm1704,

danke für das nette Kompliment. Natürlich sind wir als Blogger immer daran interessiert mit az-delivery interessante und wissenswerte Beiträge zu schreiben. Natürlich darf die Abwechslung nicht fehlen und der Bezug den den Produkten nicht fehlen. Gerade IoT ist ein interessantes Thema, birgt aber auch große Gefahren, wenn das Wissen fehlt.
Man darf an dieser Stelle aber auch nicht vergessen, dass das Thema nur an der Oberfläche behandelt wird! Der Broker ist nicht gesichert und auch der Pi an sich hat keinen nennenswerten Schutz gegen Manipulation. Das macht es für kriminelle Organe einfach, Schaden anzurichten, wenn sensible Systeme kontrolliert und geregelt werden.
Wie mein Professor an der Uni immer sagte, “Sie haben nun die Grundlagen gelernt, machen Sie was drauß!”

Gruß Weise

Dieter Behm

Dieter Behm

Hallo und einen schönen guten Morgen.
Ich habe den ersten Blog glaube ich verstanden und mein Broker läuft auf dem Raspi. Jetzt mein Problem :
Der Node MCU (allerdings V3) lauft , bekommt nur die Verbindung zur FritzBox , gibt im seriellen Monitor keine Ip aus und folgendes erscheint:
-————-

ets Jan 8 2013,rst cause:2, boot mode:(3,6)

load 0×4010f000, len 3584, room 16
tail 0
chksum 0xb0
csum 0xb0
v2843a5ac
~ld
SerialMonitor enabled
Connection to: FRITZ!Box 7590 XQ

CUT HERE FOR EXCEPTION DECODER -——————

Exception (3):
epc1=0×40100718 epc2=0×00000000 epc3=0×00000000 excvaddr=0×4006eb39 depc=0×00000000

>>>stack>>>

Warum verbindet er sich nicht mit dem Broker
Ich hoffe Sie können einem Anfänger aufs Fahrrad helfen
Gruß
Dieter

jm1704

jm1704

Jörn,
Very good article on MQTT with explanatory notes and examples.
By this article you show the know how of AZ-Delivery and its team to use products offered for sale and their integrations.
Thanks

Laat een reactie achter

Alle opmerkingen worden voor publicatie gecontroleerd door een moderator

Aanbevolen blogberichten

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery