将电报数据发布到本地Thingsboard服务器可与mqtt.js一起使用,但不能与ESP arduino示例一起使用

时间:2019-02-13 03:25:47

标签: arduino mqtt iot esp32 thingsboard

我为正在处理的IoT项目设置了运行ThingsBoard代理的VM,并遇到了一些奇怪的问题。我正在使用连接了几个传感器(温度,湿度,压力等)的ESP32,并想使用MQTT将这些值简单地推送到ThingsBoard代理。我基于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 2016年6月8日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,时钟分频:1   负载:0x3fff0018,len:4   加载:0x3fff001c,len:928   ho 0尾巴12房间4   加载:0x40078000,len:9280   加载:0x40080400,len:5848   条目0x40080698

     

连接到WiFiNetwork   ....   WiFi已连接   IP地址:   192.168.0.15   尝试进行MQTT连接...失败,rc = -1,请在5秒后重试   尝试进行MQTT连接...失败,rc = -1在5秒内重试

从查看PubSubClient library documentation来看,状态代码-1表示“客户端已完全断开连接”,这实际上没有任何意义...

因此,假设我的ThingsBoard服务器可能有问题,我使用了ThingsBoard Getting Started Guide中的MQTT.js客户端示例文件,并修改了.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

telemetry-data.json

{"airTemperature":21, "humidity":55.0, "pressure": 101.6}

当我执行.bat文件时,数据将毫无问题地发布到我的服务器上!

奇怪的是,这个MQTT.js文件似乎不需要像我的Arduino代码那样指定的端口8080。显然问题出在Arduino代码,而不是服务器本身,但是我绝对感到困惑……有什么想法吗?

编辑:使用不正确的MQQT端口号纠正问题后,服务器即可正确连接。然后经过一些测试,我注意到一旦包含所有变量,有效负载字符串就根本不会在仪表板上更新。原来,字符串太长而无法正确传输,因此我更新了代码,将字符串分成两次传输,最终修复了所有问题。

1 个答案:

答案 0 :(得分:2)

您说您正在VM中运行ThingsBoard。

除非另有明确配置,否则只有与该虚拟机在同一台计算机上运行的软件才能访问该虚拟机。这就是.bat文件起作用的原因。

VM通常在它们自己运行的计算机内部以及网络上的那台计算机上建立专用虚拟网络。

您需要查看VM软件的文档,以了解如何使Windows计算机所连接的网络上的其他计算机可以访问VM。

也可能是您使用了错误的端口号。 MQTT通常使用1883,而不是您的ESP32代码所定义的8080。在深入研究VM的配置之前,我将首先进行验证。

相关问题