2021年12月8日 星期三

ESP32 MQTT – Publish BMP280 Sensor Readings & send message to Line Bot

ESP32 MQTT – Publish BMP280 Sensor Readings & send message to Line Bot


 源自於https://randomnerdtutorials.com/esp32-mqtt-publish-bme280-arduino/

















安裝PubSubClient Library

Installing the PubSubClient Library

The PubSubClient library provides a client for doing simple publish/subscribe messaging with a server that supports MQTT (basically allows your ESP32 to talk with Node-RED).

  1. Click here to download the PubSubClient library. You should have a .zip folder in your Downloads folder
  2. Unzip the .zip folder and you should get pubsubclient-master folder
  3. Rename your folder from pubsubclient-master to pubsubclient
  4. Move the pubsubclient folder to your Arduino IDE installation libraries folder
  5. Then, re-open your Arduino IDE

The library comes with a number of example sketches. See File >Examples > PubSubClient within the Arduino IDE software.

Important: PubSubClient is not fully compatible with the ESP32, but the example provided in this tutorial is working very reliably during our tests.

Arduino程式

#include <WiFi.h>
extern "C" {
  #include "freertos/FreeRTOS.h"
  #include "freertos/timers.h"
}
#include <AsyncMqttClient.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BMP280.h"

//#define WIFI_SSID "REPLACE_WITH_YOUR_SSID"
//#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD"
//#define WIFI_SSID "PTS-2F"
//#define WIFI_PASSWORD "PTS6662594"

#define WIFI_SSID "TOTOLINK_A3002MU"
#define WIFI_PASSWORD "24063173"

// Raspberry Pi Mosquitto MQTT Broker
#define MQTT_HOST "broker.mqtt-dashboard.com"
// For a cloud MQTT broker, type the domain name
//#define MQTT_HOST "example.com"

#define MQTT_PORT 1883

// Temperature MQTT Topics
#define MQTT_PUB_TEMP "alex9ufo/esp32/bmp280/temperature"
#define MQTT_PUB_ALTI "alex9ufo/esp32/bmp280/altitude"
#define MQTT_PUB_PRES "alex9ufo/esp32/bmp280/pressure"

#define BMP280_I2C_ADDRESS  0x76
Adafruit_BMP280 bmp280; // I2C


// Variables to hold sensor readings
float temperature;
float altitude;
float pressure;

AsyncMqttClient mqttClient;
TimerHandle_t mqttReconnectTimer;
TimerHandle_t wifiReconnectTimer;

unsigned long previousMillis = 0;   // Stores last time temperature was published
const long interval = 10000;        // Interval at which to publish sensor readings

void getBMP280Readings(){
  temperature = bmp280.readTemperature();  // get temperature
  pressure =  bmp280.readPressure()/100.0;     // get pressure
  altitude =  bmp280.readAltitude(1013.25); // get altitude (this should be adjusted to your local forecast)
}

void connectToWifi() {
  Serial.println("Connecting to Wi-Fi...");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}

void connectToMqtt() {
  Serial.println("Connecting to MQTT...");
  mqttClient.connect();
}

void WiFiEvent(WiFiEvent_t event) {
  Serial.printf("[WiFi-event] event: %d\n", event);
  switch(event) {
    case SYSTEM_EVENT_STA_GOT_IP:
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
      connectToMqtt();
      break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
      Serial.println("WiFi lost connection");
      xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
      xTimerStart(wifiReconnectTimer, 0);
      break;
  }
}

void onMqttConnect(bool sessionPresent) {
  Serial.println("Connected to MQTT.");
  Serial.print("Session present: ");
  Serial.println(sessionPresent);
}

void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
  Serial.println("Disconnected from MQTT.");
  if (WiFi.isConnected()) {
    xTimerStart(mqttReconnectTimer, 0);
  }
}

/*void onMqttSubscribe(uint16_t packetId, uint8_t qos) {
  Serial.println("Subscribe acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
  Serial.print("  qos: ");
  Serial.println(qos);
}
void onMqttUnsubscribe(uint16_t packetId) {
  Serial.println("Unsubscribe acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
}*/

void onMqttPublish(uint16_t packetId) {
  Serial.print("Publish acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
}

void setup() {
  Serial.begin(115200);
  Serial.println();
  delay(3000);
  if (!bmp280.begin(BMP280_I2C_ADDRESS)) 
  {
    Serial.println(F("Could not find a valid BMP280 sensor, check wiring!"));
    while (1);
  }
  
  mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
  wifiReconnectTimer = xTimerCreate("wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToWifi));

  WiFi.onEvent(WiFiEvent);

  mqttClient.onConnect(onMqttConnect);
  mqttClient.onDisconnect(onMqttDisconnect);
  //mqttClient.onSubscribe(onMqttSubscribe);
  //mqttClient.onUnsubscribe(onMqttUnsubscribe);
  mqttClient.onPublish(onMqttPublish);
  mqttClient.setServer(MQTT_HOST, MQTT_PORT);
  // If your broker requires authentication (username and password), set them below
  //mqttClient.setCredentials("REPlACE_WITH_YOUR_USER", "REPLACE_WITH_YOUR_PASSWORD");
  connectToWifi();
}

void loop() {
  unsigned long currentMillis = millis();
  // Every X number of seconds (interval = 10 seconds) 
  // it publishes a new MQTT message
  if (currentMillis - previousMillis >= interval) {
    // Save the last time a new reading was published
    previousMillis = currentMillis;
    
    getBMP280Readings();
    Serial.println();
    Serial.print("Temperature CELSIUS 攝氏溫度= ");
    Serial.printf("Temperature = %.2f ºC \n", temperature);
    
    Serial.print("Approx Altitude 大概海拔高度= ");
    Serial.printf("Altitude = %.2f % \n", altitude);
    
    Serial.print("Pressure 大氣壓力百帕(hPa)= ");
    Serial.printf("Pressure = %.2f hPa \n", pressure);
    
    // Publish an MQTT message on topic esp/bme680/temperature
    uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB_TEMP, 1, true, String(temperature).c_str());
    Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP, packetIdPub1);
    Serial.printf("Message: %.2f \n", temperature);

    // Publish an MQTT message on topic esp/bmp280/altitude
    uint16_t packetIdPub2 = mqttClient.publish(MQTT_PUB_ALTI, 1, true, String(altitude).c_str());
    Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_ALTI, packetIdPub2);
    Serial.printf("Message: %.2f \n", altitude);
    
    // Publish an MQTT message on topic esp/bmp280/pressure
    uint16_t packetIdPub3 = mqttClient.publish(MQTT_PUB_PRES, 1, true, String(pressure).c_str());
    Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_PRES, packetIdPub3);
    Serial.printf("Message: %.2f \n", pressure);
    
  }
}

Node-Red程式

[{"id":"b30645bac3aa1085","type":"mqtt in","z":"51a158a3aefe25e1","name":"","topic":"alex9ufo/esp32/bmp280/temperature","qos":"1","datatype":"auto","broker":"2db287b.addf978","nl":false,"rap":false,"x":340,"y":100,"wires":[["20912703a013bcb1","bfa3c15020ae16c1","118415c187405aee"]]},{"id":"20912703a013bcb1","type":"ui_gauge","z":"51a158a3aefe25e1","name":"","group":"8ea9cc0540356bef","order":2,"width":0,"height":0,"gtype":"gage","title":"攝氏溫度","label":"ºC","format":"{{value}}ºC ","min":0,"max":"60","colors":["#00b500","#f7df09","#ca3838"],"seg1":"","seg2":"","className":"","x":600,"y":100,"wires":[]},{"id":"546055255ca8ac0a","type":"mqtt in","z":"51a158a3aefe25e1","name":"","topic":"alex9ufo/esp32/bmp280/pressure","qos":"1","datatype":"auto","broker":"2db287b.addf978","nl":false,"rap":false,"x":330,"y":160,"wires":[["b631824e122f37dd"]]},{"id":"b631824e122f37dd","type":"ui_gauge","z":"51a158a3aefe25e1","name":"","group":"8ea9cc0540356bef","order":2,"width":0,"height":0,"gtype":"gage","title":"大氣壓力百帕(hPa)","label":"%","format":"{{value}} hPa","min":"30","max":"2000","colors":["#53a4e6","#1d78a9","#4e38c9"],"seg1":"","seg2":"","className":"","x":630,"y":160,"wires":[]},{"id":"db175d90cc7c5fc4","type":"mqtt in","z":"51a158a3aefe25e1","name":"","topic":"alex9ufo/esp32/bmp280/altitude","qos":"1","datatype":"auto","broker":"2db287b.addf978","nl":false,"rap":false,"x":330,"y":220,"wires":[["9e2d12a6e22edd52"]]},{"id":"9e2d12a6e22edd52","type":"ui_gauge","z":"51a158a3aefe25e1","name":"","group":"8ea9cc0540356bef","order":3,"width":0,"height":0,"gtype":"gage","title":"大概海拔高度","label":"units","format":"{{value}} 米","min":"-500","max":"1000","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","className":"","x":620,"y":220,"wires":[]},{"id":"edaaedcc778611a5","type":"comment","z":"51a158a3aefe25e1","name":"[BMP280 大氣壓強度(高度計)感測模組 ]","info":"[BMP280 大氣壓強度(高度計)感測模組 ]","x":350,"y":40,"wires":[]},{"id":"bfa3c15020ae16c1","type":"function","z":"51a158a3aefe25e1","name":"傳送信息","func":"//CHANNEL_ACCESS_TOKEN = 'Messaging API Token';\nCHANNEL_ACCESS_TOKEN = 'UwdpPeFsI2wuLNy+2pMf+KKl64ATWBaqmJCHs8u3yHWl28YfeN2B3Ghklw2zeJ7FS8oD8J4DOoB5ex1bVwEU8XDyFQ1REpYqOxpKmOJ9ZRn4fiEeki9QTtiUtJ0fV9aW4w+ixGoOIvKh+/QWXba5dmQdB04t89/1O/w1cDnyilFU=';\nUSER_ID = 'U1bc09946a1ebc28d0fba29ec62d84a4d8'; //'使用者ID(不是Line ID)';\nmessage = {\n    type:'text',\n    text:'目前BMP280溫度:'+msg.payload\n};\nheaders = {\n    'Content-Type': 'application/json; charset=UTF-8',\n    'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN,\n};\npayload = {\n    'to':  USER_ID,\n    'messages': [message]\n};\nmsg.headers = headers;\nmsg.payload = payload;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":580,"y":300,"wires":[["69d9661826a23fcb","e299f6edcc14cd03"]]},{"id":"69d9661826a23fcb","type":"http request","z":"51a158a3aefe25e1","name":"Messaging API 傳送","method":"POST","ret":"txt","paytoqs":false,"url":"https://api.line.me/v2/bot/message/push","tls":"","persist":false,"proxy":"","authType":"","x":800,"y":300,"wires":[["4b32a6f0620bd078"]]},{"id":"4b32a6f0620bd078","type":"debug","z":"51a158a3aefe25e1","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":990,"y":300,"wires":[]},{"id":"702760b3f5dd3be6","type":"comment","z":"51a158a3aefe25e1","name":"developers.line.biz","info":"https://developers.line.biz/zh-hant/\n\n\nNews - LINE Developershttps://developers.line.biz › zh-hant\nThe LINE Developers site is a portal site for developers. It contains documents and tools that will help you use our various developer products.\n‎產品 · ‎LINE Login · ‎Messaging API · ‎文件\n\nhttps://developers.line.biz/console/channel/1656701433/basics\n\nhttps://developers.line.biz/console/channel/1656701433/messaging-api","x":590,"y":360,"wires":[]},{"id":"118415c187405aee","type":"debug","z":"51a158a3aefe25e1","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":620,"y":60,"wires":[]},{"id":"e299f6edcc14cd03","type":"debug","z":"51a158a3aefe25e1","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":820,"y":240,"wires":[]},{"id":"2db287b.addf978","type":"mqtt-broker","name":"","broker":"broker.mqtt-dashboard.com","port":"1883","clientid":"","usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"/vm/mqtt/birth","birthQos":"0","birthPayload":"birth","birthMsg":{},"closeTopic":"","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"sessionExpiry":""},{"id":"8ea9cc0540356bef","type":"ui_group","name":"BMP280","tab":"53b8c8f9.cfbe48","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"53b8c8f9.cfbe48","type":"ui_tab","name":"Home","icon":"dashboard","order":2,"disabled":false,"hidden":false}]

沒有留言:

張貼留言

WOKWI LED + MQTT Node-Red SQLite

WOKWI LED + MQTT Node-Red SQLite const char *mqtt_broker = "broker.mqtt-dashboard.com" ; const char *topic1 = "alex9ufo/e...