Client ESP32 MQTT pentru Home assistant Mosquitto broker
În ultimele 3 zile m-am jucat cu applicația open source Home Assistant cu care am încercat să public niște informații către un MQTT broker. Am instalat această aplicație pe o placă tinkerboard(mai veche), urmând procedura pas cu pas din tutorialul de instalare și configurarea home assistant. Zis și făcut...
Zbang ... merge brici ;)
Din câte am citit Home Assistant este cea mai des folosită aplicație pentru automatizări casnice de hobby, dar și profesionale. Se pot face niște automatizări foarte faine doar din câteva clickuri și configurări. Home assistant a fost portat pe mai toate tipurile de hardware de pe piață și comunitatea a integrat foarte multe tipuri de senzori, sisteme de monitorizare și control și aplicații.
După ce am terminat de configurat Home assistant am instalat Mosquitto broker add-on din meniul de configurare -> Add-ons.
Am cautat MQTT broker și l-am instalat .
Mosquitto broker l-am pornit folosind butonul start din panelul de configurarea al add-on-ului:
După pornire arată așa:
Pentru a asculta diverse informatii primite de broker se poate folosi sectiunea Configuration/Devices & services /Mosquitto broker / Configure
MQTT este un protocol de rețea, de Publish–subscribe, care transportă mesaje între dispozitive. Protocolul rulează de obicei prin TCP/IP, cu toate acestea, orice protocol de rețea (Wifi) care oferă conexiuni ordonate, fără pierderi, bidirecționale poate suporta MQTT. Este conceput pentru conexiuni cu locații la distanță unde există constrângeri de resurse sau lățimea de bandă a rețelei este limitată. Protocolul este un standard OASIS deschis și o recomandare ISO (ISO/IEC 20922).
Componente:
- Placa dezvoltare ESP-WROOM-32 ESP-32S
- Kit Raspberry PI 4 model B 4 GB Combo card 32 GB, carcasa aluminiu
- Modul senzor de presiune atmosferica BMP280
- 10 x Fire Dupont mama-mama 10cm
Schema electronica/sistem:
Am folosit un proiect mai vechi în care citesc temperatura, presiunea și umiditatea de la un senzor BMP280, și căruia i-am adaptat software-ul astfel încât să poată publica informații pe MQTT.
În aplicația de pe ESP32 am folosit pachetul de biblioteca PubSubClient adaptat pentru ESP32. Mai jos în source code se poate observa in functia de Setup conectarea la MQTT broker, iar apoi in funcția PrintValues am publicat cele trei topicuri temperatura, presiunea și umiditatea.
Cod de test:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*
Florin Simedru
Complete project details at https://automatic-house.blogspot.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_ST7735.h>
#include <Adafruit_GFX.h>
#include <WiFi.h>
extern "C" {
#include "freertos/FreeRTOS.h"
#include "freertos/timers.h"
}
#include <PubSubClient.h>
#define WIFI_SSID "WIFI"
#define WIFI_PASSWORD "PASSWORD"
#define MQTT_HOST "MQTT_HOST"
#define MQTT_PORT 1883
// MQTT Broker
const char *mqtt_broker = "192.168.xxx.xxx";
const char *topic = "esp32/test";
const char *temperature = "esp32/temperature";
const char *humidity = "esp32/hum";
const char *pressure = "esp32/pres";
const char *mqtt_username = "mqtt_username";
const char *mqtt_password = "mqtt_password";
const int mqtt_port = 1883;
IPAddress ip(192, 168, x, x);
WiFiClient espClient;
PubSubClient client(espClient);
#define MQTT_PUB_TEMP "esp/temperature"
#define MQTT_PUB_HUM "esp/humidity"
#define MQTT_PUB_PRES "esp/pressure"
// These pins will also work for the 1.8" TFT shield
#define TFT_MOSI 23 // SDA Pin on ESP32
#define TFT_SCLK 18 // SCL Pin on ESP32
#define TFT_CS 5 // Chip select control pin
#define TFT_DC 2 // Data Command control pin
#define TFT_RST 4 // Reset pin (could connect to RST pin)
#define RELAY_PIN 15
#define PIR_PIN 13
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 160 // OLED display height, in pixels
/* TFT ST7735 configuration */
Adafruit_ST7735 display = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
#define SEALEVELPRESSURE_HPA (1013.25)
void printValues();
void PrintInfoServer();
void callback(char *topic, byte *payload, unsigned int length);
void reconnect();
Adafruit_BME280 bme; // I2C
unsigned long delayTime;
unsigned long previousMillis = 0;
const long interval = 1000;
TimerHandle_t mqttReconnectTimer;
TimerHandle_t wifiReconnectTimer;
String client_str;
String client_mqtt_topic;
void setup() {
unsigned status;
Serial.begin(115200);
client_str = "";
while(!Serial); // time to get serial running
Serial.println(F("BME280 test"));
// connecting to a WiFi network
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi..");
}
Serial.println("Connected to the WiFi network");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
//connecting to a mqtt broker
client.setServer(ip, mqtt_port);
client.setCallback(callback);
while (!client.connected()) {
String client_id = "esp32-client-";
client_id += String(WiFi.macAddress());
client_str += "The client"+ client_id+"connects to the public mqtt broker; ";
if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
client_str += "Public emqx mqtt broker connected; ";
} else {
client_str +="failed with state; ";
client_str += client.state();
Serial.println(client_str);
delay(1000);
}
}
Serial.println(client_str);
// publish and subscribe
client.publish(topic, "Hi Sir, I'm ESP32");
client.subscribe(topic);
client.publish(temperature, "Temperature");
client.subscribe(temperature);
client.publish(humidity, "Humidity");
client.subscribe(humidity);
client.publish(pressure, "Pressure");
client.subscribe(pressure);
// default settings
status = bme.begin();
// You can also pass in a Wire library object like &Wire2
status = bme.begin(0x76);
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
Serial.print("SensorID was: 0x"); Serial.println(bme.sensorID(),16);
Serial.print(" ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
Serial.print(" ID of 0x56-0x58 represents a BMP 280,\n");
Serial.print(" ID of 0x60 represents a BME 280.\n");
Serial.print(" ID of 0x61 represents a BME 680.\n");
while (1) delay(10);
}
Serial.println("-- Default Test --");
delayTime = 1000;
// Use this initializer if you're using a 1.8" TFT
display.initR(INITR_GREENTAB); // Init ST7735 display 128x160 pixel
delay(100);
display.fillScreen(ST77XX_RED);
delay(100);
display.fillScreen(ST77XX_GREEN);
delay(100);
display.fillScreen(ST77XX_BLUE);
delay(100);
display.fillScreen(ST77XX_BLACK);
display.setTextSize(1);
display.setTextColor(ST77XX_WHITE);
display.setCursor(0, 0);
display.setRotation(3);
display.fillScreen(ST77XX_BLACK);
display.setTextSize(1);
display.setCursor(10, 10);
display.print(" ST7735 TFT display initiated!");
Serial.println();
pinMode(PIR_PIN, INPUT);
}
void loop() {
int pir_val = digitalRead(PIR_PIN); // read input value
Serial.print("PIR = " );
Serial.print(pir_val);
Serial.println("");
printValues();
delay(delayTime);
PrintInfoServer();
if (!client.connected()) {
reconnect();
}
client.loop();
}
void printValues() {
client.publish(temperature,String(bme.readTemperature()).c_str());
client.publish(humidity, String(bme.readHumidity()).c_str());
client.publish(pressure, String(bme.readPressure() / 100.0F).c_str());
Serial.print("Temperature = ");
Serial.print(bme.readTemperature());
Serial.println(" °C");
Serial.print("Pressure = ");
Serial.print(bme.readPressure() / 100.0F);
Serial.println(" hPa");
Serial.print("Approx. Altitude = ");
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
Serial.println(" m");
Serial.print("Humidity = ");
Serial.print(bme.readHumidity());
Serial.println(" %");
Serial.println();
}
void PrintInfoServer() {
unsigned long currentMillis = millis();
if((currentMillis - previousMillis) >= interval) {
previousMillis = millis();
#if (DHT_DEBUG==1)
Serial.println("Temperature: " + temperature + " *C - Humidity: " + humidity + " % - Pressure: " + pressure + " hPa");
#endif
display.fillScreen(ST77XX_BLACK);
// display temperature
display.setTextSize(1);
display.setTextColor(ST77XX_WHITE);
display.setCursor(10,10);
display.print("Temperature: ");
display.print(bme.readTemperature());
display.print(" ");
display.setTextSize(1);
display.write(248);
display.setTextSize(1);
display.print(" C");
// display humidity
display.setTextSize(1);
display.setCursor(10, 20);
display.print("Humidity: ");
display.print(bme.readHumidity());
display.print(" %");
// display altitude
display.setTextSize(1);
display.setCursor(10, 30);
display.print("Altitude:");
display.print( bme.readAltitude(SEALEVELPRESSURE_HPA));
display.print(" m");
// display pressure
display.setTextSize(1);
display.setTextColor(ST77XX_WHITE);
display.setCursor(10,40);
display.print("Pressure: ");
display.print(bme.readPressure() / 100.0F);
display.print(" hPa");
// display MQTT data
display.setTextSize(1);
display.setTextColor(ST77XX_GREEN);
display.setCursor(10,50);
display.print("MQTT: ");
display.print(client_mqtt_topic);
display.print(": ");
display.print(client_str);
display.setTextSize(1);
display.setTextColor(ST77XX_GREEN);
display.setCursor(10,50);
}
}
void callback(char *topic, byte *payload, unsigned int length) {
Serial.print("Message arrived in topic: ");
Serial.println(topic);
client_mqtt_topic = String(topic);
Serial.print("Message:");
client_str = "";
for (int i = 0; i < length; i++) {
client_str += String((char) payload[i]);
}
Serial.println(client_str);
Serial.println();
Serial.println("-----------------------");
}
void reconnect() {
String client_id = "esp32-client-";
// Loop until we're reconnected
while (!client.connected()) {
client_id += String(WiFi.macAddress());
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
Serial.println("connected");
// Subscribe
client.subscribe("esp32/output");
client.subscribe(topic);
client.subscribe(temperature);
client.subscribe(humidity);
client.subscribe(pressure);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Florin Simedru | |
Complete project details at https://automatic-house.blogspot.com | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files. | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
*/ | |
#include <Wire.h> | |
#include <Adafruit_Sensor.h> | |
#include <Adafruit_BME280.h> | |
#include <Adafruit_ST7735.h> | |
#include <Adafruit_GFX.h> | |
#include <WiFi.h> | |
extern "C" { | |
#include "freertos/FreeRTOS.h" | |
#include "freertos/timers.h" | |
} | |
#include <PubSubClient.h> | |
#define WIFI_SSID "WIFI" | |
#define WIFI_PASSWORD "PASSWORD" | |
#define MQTT_HOST "MQTT_HOST" | |
#define MQTT_PORT 1883 | |
// MQTT Broker | |
const char *mqtt_broker = "192.168.xxx.xxx"; | |
const char *topic = "esp32/test"; | |
const char *temperature = "esp32/temperature"; | |
const char *humidity = "esp32/hum"; | |
const char *pressure = "esp32/pres"; | |
const char *mqtt_username = "mqtt_username"; | |
const char *mqtt_password = "mqtt_password"; | |
const int mqtt_port = 1883; | |
IPAddress ip(192, 168, x, x); | |
WiFiClient espClient; | |
PubSubClient client(espClient); | |
#define MQTT_PUB_TEMP "esp/temperature" | |
#define MQTT_PUB_HUM "esp/humidity" | |
#define MQTT_PUB_PRES "esp/pressure" | |
// These pins will also work for the 1.8" TFT shield | |
#define TFT_MOSI 23 // SDA Pin on ESP32 | |
#define TFT_SCLK 18 // SCL Pin on ESP32 | |
#define TFT_CS 5 // Chip select control pin | |
#define TFT_DC 2 // Data Command control pin | |
#define TFT_RST 4 // Reset pin (could connect to RST pin) | |
#define RELAY_PIN 15 | |
#define PIR_PIN 13 | |
#define SCREEN_WIDTH 128 // OLED display width, in pixels | |
#define SCREEN_HEIGHT 160 // OLED display height, in pixels | |
/* TFT ST7735 configuration */ | |
Adafruit_ST7735 display = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); | |
#define SEALEVELPRESSURE_HPA (1013.25) | |
void printValues(); | |
void PrintInfoServer(); | |
void callback(char *topic, byte *payload, unsigned int length); | |
void reconnect(); | |
Adafruit_BME280 bme; // I2C | |
unsigned long delayTime; | |
unsigned long previousMillis = 0; | |
const long interval = 1000; | |
TimerHandle_t mqttReconnectTimer; | |
TimerHandle_t wifiReconnectTimer; | |
String client_str; | |
String client_mqtt_topic; | |
void setup() { | |
unsigned status; | |
Serial.begin(115200); | |
client_str = ""; | |
while(!Serial); // time to get serial running | |
Serial.println(F("BME280 test")); | |
// connecting to a WiFi network | |
WiFi.begin(WIFI_SSID, WIFI_PASSWORD); | |
while (WiFi.status() != WL_CONNECTED) { | |
delay(500); | |
Serial.println("Connecting to WiFi.."); | |
} | |
Serial.println("Connected to the WiFi network"); | |
Serial.println("IP address: "); | |
Serial.println(WiFi.localIP()); | |
//connecting to a mqtt broker | |
client.setServer(ip, mqtt_port); | |
client.setCallback(callback); | |
while (!client.connected()) { | |
String client_id = "esp32-client-"; | |
client_id += String(WiFi.macAddress()); | |
client_str += "The client"+ client_id+"connects to the public mqtt broker; "; | |
if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) { | |
client_str += "Public emqx mqtt broker connected; "; | |
} else { | |
client_str +="failed with state; "; | |
client_str += client.state(); | |
Serial.println(client_str); | |
delay(1000); | |
} | |
} | |
Serial.println(client_str); | |
// publish and subscribe | |
client.publish(topic, "Hi Sir, I'm ESP32"); | |
client.subscribe(topic); | |
client.publish(temperature, "Temperature"); | |
client.subscribe(temperature); | |
client.publish(humidity, "Humidity"); | |
client.subscribe(humidity); | |
client.publish(pressure, "Pressure"); | |
client.subscribe(pressure); | |
// default settings | |
status = bme.begin(); | |
// You can also pass in a Wire library object like &Wire2 | |
status = bme.begin(0x76); | |
if (!status) { | |
Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!"); | |
Serial.print("SensorID was: 0x"); Serial.println(bme.sensorID(),16); | |
Serial.print(" ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n"); | |
Serial.print(" ID of 0x56-0x58 represents a BMP 280,\n"); | |
Serial.print(" ID of 0x60 represents a BME 280.\n"); | |
Serial.print(" ID of 0x61 represents a BME 680.\n"); | |
while (1) delay(10); | |
} | |
Serial.println("-- Default Test --"); | |
delayTime = 1000; | |
// Use this initializer if you're using a 1.8" TFT | |
display.initR(INITR_GREENTAB); // Init ST7735 display 128x160 pixel | |
delay(100); | |
display.fillScreen(ST77XX_RED); | |
delay(100); | |
display.fillScreen(ST77XX_GREEN); | |
delay(100); | |
display.fillScreen(ST77XX_BLUE); | |
delay(100); | |
display.fillScreen(ST77XX_BLACK); | |
display.setTextSize(1); | |
display.setTextColor(ST77XX_WHITE); | |
display.setCursor(0, 0); | |
display.setRotation(3); | |
display.fillScreen(ST77XX_BLACK); | |
display.setTextSize(1); | |
display.setCursor(10, 10); | |
display.print(" ST7735 TFT display initiated!"); | |
Serial.println(); | |
pinMode(PIR_PIN, INPUT); | |
} | |
void loop() { | |
int pir_val = digitalRead(PIR_PIN); // read input value | |
Serial.print("PIR = " ); | |
Serial.print(pir_val); | |
Serial.println(""); | |
printValues(); | |
delay(delayTime); | |
PrintInfoServer(); | |
if (!client.connected()) { | |
reconnect(); | |
} | |
client.loop(); | |
} | |
void printValues() { | |
client.publish(temperature,String(bme.readTemperature()).c_str()); | |
client.publish(humidity, String(bme.readHumidity()).c_str()); | |
client.publish(pressure, String(bme.readPressure() / 100.0F).c_str()); | |
Serial.print("Temperature = "); | |
Serial.print(bme.readTemperature()); | |
Serial.println(" °C"); | |
Serial.print("Pressure = "); | |
Serial.print(bme.readPressure() / 100.0F); | |
Serial.println(" hPa"); | |
Serial.print("Approx. Altitude = "); | |
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA)); | |
Serial.println(" m"); | |
Serial.print("Humidity = "); | |
Serial.print(bme.readHumidity()); | |
Serial.println(" %"); | |
Serial.println(); | |
} | |
void PrintInfoServer() { | |
unsigned long currentMillis = millis(); | |
if((currentMillis - previousMillis) >= interval) { | |
previousMillis = millis(); | |
#if (DHT_DEBUG==1) | |
Serial.println("Temperature: " + temperature + " *C - Humidity: " + humidity + " % - Pressure: " + pressure + " hPa"); | |
#endif | |
display.fillScreen(ST77XX_BLACK); | |
// display temperature | |
display.setTextSize(1); | |
display.setTextColor(ST77XX_WHITE); | |
display.setCursor(10,10); | |
display.print("Temperature: "); | |
display.print(bme.readTemperature()); | |
display.print(" "); | |
display.setTextSize(1); | |
display.write(248); | |
display.setTextSize(1); | |
display.print(" C"); | |
// display humidity | |
display.setTextSize(1); | |
display.setCursor(10, 20); | |
display.print("Humidity: "); | |
display.print(bme.readHumidity()); | |
display.print(" %"); | |
// display altitude | |
display.setTextSize(1); | |
display.setCursor(10, 30); | |
display.print("Altitude:"); | |
display.print( bme.readAltitude(SEALEVELPRESSURE_HPA)); | |
display.print(" m"); | |
// display pressure | |
display.setTextSize(1); | |
display.setTextColor(ST77XX_WHITE); | |
display.setCursor(10,40); | |
display.print("Pressure: "); | |
display.print(bme.readPressure() / 100.0F); | |
display.print(" hPa"); | |
// display MQTT data | |
display.setTextSize(1); | |
display.setTextColor(ST77XX_GREEN); | |
display.setCursor(10,50); | |
display.print("MQTT: "); | |
display.print(client_mqtt_topic); | |
display.print(": "); | |
display.print(client_str); | |
display.setTextSize(1); | |
display.setTextColor(ST77XX_GREEN); | |
display.setCursor(10,50); | |
} | |
} | |
void callback(char *topic, byte *payload, unsigned int length) { | |
Serial.print("Message arrived in topic: "); | |
Serial.println(topic); | |
client_mqtt_topic = String(topic); | |
Serial.print("Message:"); | |
client_str = ""; | |
for (int i = 0; i < length; i++) { | |
client_str += String((char) payload[i]); | |
} | |
Serial.println(client_str); | |
Serial.println(); | |
Serial.println("-----------------------"); | |
} | |
void reconnect() { | |
String client_id = "esp32-client-"; | |
// Loop until we're reconnected | |
while (!client.connected()) { | |
client_id += String(WiFi.macAddress()); | |
Serial.print("Attempting MQTT connection..."); | |
// Attempt to connect | |
if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) { | |
Serial.println("connected"); | |
// Subscribe | |
client.subscribe("esp32/output"); | |
client.subscribe(topic); | |
client.subscribe(temperature); | |
client.subscribe(humidity); | |
client.subscribe(pressure); | |
} else { | |
Serial.print("failed, rc="); | |
Serial.print(client.state()); | |
Serial.println(" try again in 5 seconds"); | |
// Wait 5 seconds before retrying | |
delay(5000); | |
} | |
} | |
} |
Documentatie proiect:
- https://docs.openmqttgateway.com/
- https://a2t.ro/casa-inteligenta/hub-inteligent-sonoff-rf-bridge.html?gclid=CjwKCAiAhreNBhAYEiwAFGGKPI-SuXKK0AeTn8JVA9So-Ap9beAQ-Vddr_QQ3AaSH4L-e0utIzcwjhoCgssQAvD_BwE
- https://webled.ro/adaptor-usb-dongle-zigbee-cc2531-sonoff?utm_source=Google%20Shopping&utm_campaign=WebLed&utm_medium=cpc&utm_term=18525&gclid=CjwKCAiAhreNBhAYEiwAFGGKPOQxPdcuo8UiLQu4RrX6Hon-oBc6l-Irjbk1a8oNyJ5pY4brgGvTKhoCp8MQAvD_BwE
- https://www.zigbee2mqtt.io/
- https://www.optimusdigital.ro/ro/programatoare/952-adaptor-pentru-depanare-microncontrollere-cc.html?search_query=cc2531&results=1
- https://www.home-assistant.io/installation/tinkerboard/
- https://randomnerdtutorials.com/page/2/?s=MQTT