Я установил виртуальную машину, на которой работает брокер ThingsBoard, для проекта IoT, над которым я работаю, и столкнулся с некоторыми странными проблемами.Я использую ESP32 с несколькими подключенными датчиками (температура, влажность, давление и т. Д.) И хочу просто передать эти значения брокеру ThingsBoard с помощью MQTT.Я создал тестовую программу на основе примера кода, предоставленного ThingsBoard, но у меня проблемы с подключением к серверу.Вот мой код ниже:
#include <WiFi.h>
#include <Wire.h>
#include <OneWire.h>
#include <PubSubClient.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <DallasTemperature.h>
// Constants
#define ONE_WIRE_PIN 14 // One-Wire pin for water temperature sensor
#define TURBIDITY_PIN 36 // Analog pin for turbidity sensor
#define SEALEVELPRESSURE_HPA (1013.25)
// WiFi Login Info
#define ssid "WiFiNetwork"
#define password "password"
// MQTT Broker IP address:
#define mqtt_server "192.168.0.10"
#define mqtt_server_port 1883
// MQTT Client Info
#define MQTT_CLIENT_NAME "ESP32"
#define ACCESS_TOKEN "ESP32_DEMO_TOKEN"
// Sensor Variables
float airTemperature = 0;
float waterTemperature = 0;
float humidity = 0;
float pressure = 0;
float altitude = 0;
float turbidity = 0;
// Control Variables
long lastMsg = 0; // keeps track of timestamp since the last message was sent
// Objects
Adafruit_BME280 BME280; // I2C
OneWire oneWire_in(ONE_WIRE_PIN);
DallasTemperature temperature_sensor(&oneWire_in);
WiFiClient espClient;
PubSubClient client(espClient);
void setup() {
int status = 0;
Serial.begin(115200);
// Initialize BME280
status = BME280.begin();
if (!status) {
while(true) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
delay(5000);
}
}
// Initialize the One-Wire Temperature Sensor
temperature_sensor.begin();
// Initialize the WiFi and MQTT connections
setup_wifi();
client.setServer(mqtt_server, mqtt_server_port);
client.setCallback(mqtt_callback);
}
void loop() {
// Update/refresh the Wifi/MQTT connection
updateWirelessConnection();
// Read and transmit the sensor values every 5 seconds
long now = millis();
if (now - lastMsg > 5000) {
lastMsg = now;
// Read all the sensor values
collectMeasurements();
// Publish updated sensor values
publishMeasurements();
// Print all sensor values
printMeasurements();
}
}
void updateWirelessConnection()
{
if (!client.connected()) {
reconnect();
}
client.loop();
}
void printMeasurements()
{
Serial.print("Air Temperature: ");
Serial.print(airTemperature);
Serial.println( " *C");
Serial.print("Air Pressure: ");
Serial.print(pressure);
Serial.println( " hPa");
Serial.print("Humidity: ");
Serial.print(humidity);
Serial.println( " %RH");
Serial.print("Altitude: ");
Serial.print(altitude);
Serial.println( " m");
Serial.print("Water Temperature: ");
Serial.print(waterTemperature);
Serial.println( " *C");
Serial.print("Water Turbidity: ");
Serial.print(turbidity);
Serial.println( " NTUs");
Serial.println();
}
void collectMeasurements()
{
// Read the measurements from the BME280 sensor
airTemperature = BME280.readTemperature();
pressure = BME280.readPressure() / 100.0F;
altitude = BME280.readAltitude(SEALEVELPRESSURE_HPA);
humidity = BME280.readHumidity();
// Read the water temperature sensor
temperature_sensor.requestTemperatures();
waterTemperature = temperature_sensor.getTempCByIndex(0);
// Read the turbidity sensor
turbidity = calculateTurbidityValue(analogRead(TURBIDITY_PIN), waterTemperature);
}
// Calculates the temperature-compensated Turbidity value based on the raw ADC voltage and water temperature in celsius
float calculateTurbidityValue(int adcValue, float waterTemp)
{
// Convert ADC value to original voltage reading
float voltage = adcValue * (5.0 / 4096.0);
// Correct the voltage value for temperature
// TODO: TBD later
// Convert the voltage to NTUs
float NTUs = -1120.4 * pow(voltage, 2.0) + 5742.3 * voltage - 4352.9;
if (NTUs < 0) {
return 0;
} else {
return NTUs;
}
}
// Publishes all measurements to the MQTT broker
void publishMeasurements()
{
// Create Payload string
// Paylod String format: {"key1":"value1", "key2":"value2"}
String payload1 = "{";
payload1 += "\"airTemperature\":"; payload1 += airTemperature; payload1 += ",";
payload1 += "\"pressure\":"; payload1 += pressure; payload1 += ",";
payload1 += "\"humidity\":"; payload1 += humidity;
payload1 += "}";
String payload2 = "{";
payload2 += "\"altitude\":"; payload2 += altitude; payload2 += ",";
payload2 += "\"waterTemperature\":"; payload2 += waterTemperature; payload2 += ",";
payload2 += "\"turbidity\":"; payload2 += turbidity;
payload2 += "}";
transmitPayload(payload1);
transmitPayload(payload2);
}
void transmitPayload(String payload)
{
// Convert Payload string to c-string and transmit
char attributes[500];
payload.toCharArray(attributes, 500);
client.publish("v1/devices/me/telemetry", attributes);
}
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void mqtt_callback(char* topic, byte* message, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(". Message: ");
String messageTemp;
for (int i = 0; i < length; i++) {
Serial.print((char)message[i]);
messageTemp += (char)message[i];
}
Serial.println();
// Feel free to add more if statements to control more GPIOs with MQTT
// If a message is received on the topic esp32/output, you check if the message is either "on" or "off".
// Changes the output state according to the message
/*if (String(topic) == "esp32/output") {
Serial.print("Changing output to ");
if(messageTemp == "on"){
Serial.println("on");
digitalWrite(ledPin, HIGH);
}
else if(messageTemp == "off"){
Serial.println("off");
digitalWrite(ledPin, LOW);
}
}*/
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected())
{
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(MQTT_CLIENT_NAME, ACCESS_TOKEN, NULL)) {
Serial.println("connected");
// Subscribe
//client.subscribe("esp32/output");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
Для тех, кто заинтересован, код, который на самом деле считывает значения датчика и выводит их на печать, работает нормально, проблема заключается в коде, который подключается к серверу ThingsBoard.Когда я запускаю этот код, вот что я вижу в последовательном терминале:
ets 8 июня 2016 00:22: 57
rst: 0x1 (POWERON_RESET), загрузка: 0x13(SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP: 0xEE clk_drv: 0x00, q_drv: 0x00, d_drv: 0x00, cs0_drv: 0x00, hd_drv: 0x00, wp_drv: режим 0x00: DIO, часы DIV: 1 нагрузка: 0x3fff0018, длина: 4 нагрузка:0x3fff001c, len: 928 ho 0 tail 12 room 4 load: 0x40078000, len: 9280 load: 0x40080400, len: 5848 entry 0x40080698
Подключение к WiFiNetwork .... IP-адрес, подключенный по WiFi: 192.168.0.15 Попытка MQTTсоединение ... не удалось, rc = -1, повторите попытку через 5 секунд. Попытка подключения MQTT ... не удалось, rc = -1, повторите попытку через 5 секунд
Из просмотра библиотеки PubSubClientдокументация , код состояния -1 означает «клиент отключен чисто», что на самом деле не имеет смысла ...
Итак, если предположить, что с моим сервером ThingsBoard что-то не так, яиспользовал примеры файлов клиента MQTT.js из графического интерфейса ThingsBoard Getting Startedde и изменил файлы .bat и .json так, чтобы они соответствовали моим данным:
mqtt-js.bat
@echo off
REM Set ThingsBoard host to "demo.thingsboard.io" or "localhost"
set THINGSBOARD_HOST=192.168.0.10
REM Replace YOUR_ACCESS_TOKEN with one from Device details panel.
set ACCESS_TOKEN=ESP32_DEMO_TOKEN
REM Read serial number and firmware version attributes
set /p ATTRIBUTES=<attributes-data.json
REM Read timeseries data as an object without timestamp (server-side timestamp will be used)
set /p TELEMETRY=<telemetry-data.json
REM publish attributes and telemetry data via mqtt client
node publish.js
телеметрия-data.json
{"airTemperature":21, "humidity":55.0, "pressure": 101.6}
Когда я запускаю файл .bat, данные публикуются на моем сервере без проблем!
Странно то, что этот файл MQTT.js делаетПохоже, что порт 8080 указан не так, как мой код Arduino.Понятно, что проблема заключается в коде Arduino, а не в самом сервере, но я совершенно тупик ... Есть идеи?
РЕДАКТИРОВАТЬ: После исправления проблемы с неправильным MQQTномер порта сервер смог правильно подключиться.Затем после некоторого тестирования я заметил, что строка полезной нагрузки вообще не обновлялась на приборной панели, как только все переменные были включены.Оказалось, что строка была слишком длинной для правильной передачи, поэтому я обновил код, чтобы разделить строку на две передачи, что в конечном итоге все исправило.