MQQT прекращает публикацию данных случайным образом с esp32. Client.publi sh через некоторое время возвращает false - PullRequest
0 голосов
/ 10 марта 2020

Я использую ESP32 для публикации sh данных. Код работает почти все время, но иногда он перестает публиковать данные. Вот код, который я использую. Ниже вы видите ту часть, где я сталкиваюсь с этой проблемой. Было бы здорово, если у кого-то есть решение.

#include "BLEDevice.h"
#include <ArduinoJson.h>
#include <WiFi.h>
#include <WiFiManager.h>
#include <HTTPClient.h>
#include <PubSubClient.h>
#include <WiFiClient.h>
#include <ESPmDNS.h>
#include <OneWire.h>
#include <DallasTemperature.h>
void connectWifi();
String gethttp();
void disconnectWifi();
void connectMqtt();
void hibernate();
void delayedHibernate(void *parameter);
void disconnectMqtt();
void publish_mqtt(String mqtt_topic);
void decode_json (String payload);
void handle_flora(String devname, String macaddress);
void handshake();
void check_wifi_mqtt();
BLEClient* getFloraClient(BLEAddress floraAddress);
BLERemoteService* getFloraService(BLEClient* floraClient);
bool forceFloraServiceDataMode(BLERemoteService* floraService);
bool readFloraDataCharacteristic(BLERemoteService* floraService, float *temperature, float *moisture, float *light, float *conductivity);
bool readFloraBatteryCharacteristic(BLERemoteService* floraService, float *battery);
bool processFloraService(BLERemoteService* floraService, char* deviceMacAddress, float *temperature, float *moisture, float *light, float *conductivity, float *battery);
bool processFloraDevice(BLEAddress floraAddress, char* deviceMacAddress, float *temperature, float *moisture, float *light, float *conductivity, float *battery);
#define RETRY 3 //Number of times a process gets repeated upon failure
static BLEUUID serviceUUID("00001204-0000-1000-8000-00805f9b34fb");
static BLEUUID uuid_version_battery("00001a02-0000-1000-8000-00805f9b34fb");
static BLEUUID uuid_sensor_data("00001a01-0000-1000-8000-00805f9b34fb");
static BLEUUID uuid_write_mode("00001a00-0000-1000-8000-00805f9b34fb");
char JSONmessageBuffer[4000];
int flora_counter = 0;
#define ONE_WIRE_BUS 4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DynamicJsonBuffer outputbuff;
JsonObject& out = outputbuff.createObject();
JsonObject& Status = out .createNestedObject("Status");
JsonObject& StatusSNS = out.createNestedObject("StatusSNS");
JsonObject& StatusSTS = out.createNestedObject("StatusSTS");
TaskHandle_t hibernateTaskHandle = NULL;
WiFiClient espClient;
PubSubClient client(espClient);

void setup()
{
  Serial.begin(115200);
  delay(1000);
  connectWifi();
  connectMqtt();
  handshake();
  String pay_load = gethttp();
  if (pay_load != "failed")
  {
    flora_counter = 0;
    decode_json(pay_load);
    Serial.println (JSONmessageBuffer);
  }
  disconnectWifi();
  disconnectMqtt();
}

void loop()
{
  delay(10000);
  ESP.restart();
  delay(5000);
}

void connectWifi()
{
  String hostname = "ESP32_" + WiFi.macAddress();
  WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);
  WiFi.setHostname(hostname.c_str());
  WiFiManager wifiManager;
  if (!wifiManager.autoConnect("Sudoware_ESP", ""))
  {
    Serial.println("failed to connect and hit timeout");
    delay(3000);
    ESP.restart();
    delay(5000);
  }
  Serial.println("Wifi Connected");
  Serial.print("local ip ");
  Serial.println(WiFi.localIP());
}

String gethttp()
{
  Serial.println("gethttp");
  Serial.println(WiFi.localIP());
  HTTPClient http;
  String apihit = "http://192.168.73.1/get_esp_config.php?mac=" + WiFi.macAddress();
  String payload = "";
  http.begin(apihit.c_str());                   //Specify the URL
  int httpCode = http.GET();                    //Make the request
  if (httpCode > 0)
  {
    payload = http.getString();
    Serial.println(httpCode);
    Serial.println(payload);
  }
  else
  {
    payload = "failed";
  }
  http.end(); //Free the resources
  Serial.println("payload: " + payload);
  return payload;
}

void disconnectWifi()
{
  WiFi.disconnect(true);
  Serial.println("WiFi disonnected");
}

void connectMqtt()
{
  Serial.println("Connecting to MQTT...");
  Serial.print("local ip ");
  Serial.println(WiFi.localIP());
  client.setServer("192.168.73.1", 1883);
  while (!client.connected())
  {
    if (!client.connect("", "", ""))
    {
      Serial.print("MQTT connection failed:" );
      Serial.print(client.state());
      Serial.println(" Retrying..." );
      delay(1000);
    }
  }
  Serial.println("MQTT connected");
  Serial.println("");
}

//void hibernate()
//{
//  esp_sleep_enable_timer_wakeup(SLEEP_DURATION * 1000000ll);
//  Serial.println("Going to sleep now.");
//  delay(100);
//  esp_deep_sleep_start();
//}
//
//void delayedHibernate(void *parameter)
//{
//  delay(EMERGENCY_HIBERNATE * 1000); // delay for five minutes
//  Serial.println("Something got stuck, entering emergency hibernate...");
//  hibernate();
//}

void disconnectMqtt()
{
  client.disconnect();
  Serial.println("MQTT disconnected");
}

**void publish_mqtt(String mqtt_topic)
{
  //Change mqtt topic to character
  out.printTo(JSONmessageBuffer);
  Serial.println(JSONmessageBuffer);
  int count = 0;
  check_wifi_mqtt();
  while (count <= 3 and !client.publish(mqtt_topic.c_str(), JSONmessageBuffer, true))
  {
    count += 1;
    check_wifi_mqtt();
    Serial.println("Error sending message and count is: ");
    Serial.print(count);
    Serial.println("");
  }
  if (count > 3)
  {
    esp_sleep_enable_timer_wakeup(10 * 1000000ll);
    Serial.println("Restarting in 10 seconds");
    delay(100);
    esp_deep_sleep_start();
  }
  Serial.println("Success sending message");
}**
BLEClient* getFloraClient(BLEAddress floraAddress)
{
  BLEClient* floraClient = BLEDevice::createClient();
  if (!floraClient->connect(floraAddress))
  {
    Serial.println("- Connection failed, skipping");
    return nullptr;
  }
  Serial.println("- Connection successful");
  return floraClient;
}
BLERemoteService* getFloraService(BLEClient* floraClient)
{
  BLERemoteService* floraService = nullptr;
  try
  {
    floraService = floraClient->getService(serviceUUID);
  }
  catch (...)
  {
    // something went wrong
  }
  if (floraService == nullptr)
  {
    Serial.println("- Failed to find data service");
  }
  else
  {
    Serial.println("- Found data service");
  }
  return floraService;
}
bool forceFloraServiceDataMode(BLERemoteService* floraService)
{
  BLERemoteCharacteristic* floraCharacteristic;
  // get device mode characteristic, needs to be changed to read data
  Serial.println("- Force device in data mode");
  floraCharacteristic = nullptr;
  try
  {
    floraCharacteristic = floraService->getCharacteristic(uuid_write_mode);
  }
  catch (...)
  {
    // something went wrong
  }
  if (floraCharacteristic == nullptr)
  {
    Serial.println("-- Failed, skipping device");
    return false;
  }
  // write the magic data
  uint8_t buf[2] = {0xA0, 0x1F};
  floraCharacteristic->writeValue(buf, 2, true);
  delay(500);
  return true;
}
bool readFloraDataCharacteristic(BLERemoteService* floraService, float *temperature, float *moisture, float *light, float *conductivity)
{
  BLERemoteCharacteristic* floraCharacteristic = nullptr;
  // get the main device data characteristic
  Serial.println("- Access characteristic from device");
  try
  {
    floraCharacteristic = floraService->getCharacteristic(uuid_sensor_data);
  }
  catch (...)
  {
    // something went wrong
  }
  if (floraCharacteristic == nullptr)
  {
    Serial.println("-- Failed, skipping device");
    return false;
  }
  // read characteristic value
  Serial.println("- Read value from characteristic");
  std::string value;
  try
  {
    value = floraCharacteristic->readValue();
  }
  catch (...)
  {
    // something went wrong
    Serial.println("-- Failed, skipping device");
    return false;
  }
  const char *val = value.c_str();
  Serial.print("Hex: ");
  for (int i = 0; i < 16; i++)
  {
    Serial.print((int)val[i], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");
  int16_t* temp_raw = (int16_t*)val;
  *temperature = (*temp_raw) / ((float)10.0);
  Serial.print("-- Temperature: ");
  Serial.println(*temperature);
  *moisture = (float)val[7];
  Serial.print("-- Moisture: ");
  Serial.println(*moisture);
  *light = (float)val[3] + (float)val[4] * 256;
  Serial.print("-- Light: ");
  Serial.println(*light);
  *conductivity = (float)val[8] + (float)val[9] * 256;
  Serial.print("-- Conductivity: ");
  Serial.println(*conductivity);
  return true;
}
bool readFloraBatteryCharacteristic(BLERemoteService* floraService, float *battery)
{
  BLERemoteCharacteristic* floraCharacteristic = nullptr;
  // get the device battery characteristic
  Serial.println("- Access battery characteristic from device");
  try
  {
    floraCharacteristic = floraService->getCharacteristic(uuid_version_battery);
  }
  catch (...)
  {
    // something went wrong
  }
  if (floraCharacteristic == nullptr)
  {
    Serial.println("-- Failed, skipping battery level");
    return false;
  }
  // read characteristic value
  Serial.println("- Read value from characteristic");
  std::string value;
  try
  {
    value = floraCharacteristic->readValue();
  }
  catch (...)
  {
    // something went wrong
    Serial.println("-- Failed, skipping battery level");
    return false;
  }
  const char *val2 = value.c_str();
  *battery = (float)val2[0];
  Serial.print("-- Battery: ");
  Serial.println(*battery);
  return true;
}
bool processFloraService(BLERemoteService* floraService, char* deviceMacAddress, float *temperature, float *moisture, float *light, float *conductivity, float *battery)
{
  // set device in data mode
  if (!forceFloraServiceDataMode(floraService))
  {
    return false;
  }
  bool dataSuccess = readFloraDataCharacteristic(floraService, temperature, moisture, light, conductivity);
  bool batterySuccess = readFloraBatteryCharacteristic(floraService, battery);
  return dataSuccess && batterySuccess;
}
bool processFloraDevice(BLEAddress floraAddress, char* deviceMacAddress, float *temperature, float *moisture, float *light, float *conductivity, float *battery)
{
  Serial.print(" Processing Flora device at ");
  Serial.print(floraAddress.toString().c_str());
  Serial.print(" Flora counter: ");
  Serial.print(flora_counter);
  // connect to flora ble server
  BLEClient* floraClient = getFloraClient(floraAddress);
  if (floraClient == nullptr)
  {
    return false;
  }
  // connect data service
  BLERemoteService* floraService = getFloraService(floraClient);
  if (floraService == nullptr)
  {
    floraClient->disconnect();
    return false;
  }
  // process devices data
  bool success = processFloraService(floraService, deviceMacAddress, temperature, moisture, light, conductivity, battery);
  // disconnect from device
  floraClient->disconnect();
  return success;
}

void handle_flora (String devname, String deviceMacAddress)
{
  float temperature, moisture, light, conductivity, battery;
  Serial.println("Initialize BLE client...");
  BLEDevice::init("");
  BLEDevice::setPower(ESP_PWR_LVL_P7);
  // process devices
  BLEAddress floraAddress(deviceMacAddress.c_str());
  if (processFloraDevice(floraAddress, const_cast<char*>(deviceMacAddress.c_str()), &temperature, &moisture, &light, &conductivity, &battery))
  {
    JsonObject& StatusSNS_FLORA = StatusSNS.createNestedObject(devname);
    StatusSNS_FLORA["Temperature"] = temperature;
    StatusSNS_FLORA["Moisture"] = moisture;
    StatusSNS_FLORA["Light"] = light;
    StatusSNS_FLORA["Conductivity"] = conductivity;
    StatusSNS_FLORA["Battery"] = battery;
  }
  delay(1000);
}

void handle_dallas_ufire(String devname)
{
  sensors.begin();
  sensors.requestTemperatures();
  float tempC = sensors.getTempCByIndex(0);
  JsonObject& StatusSNS_dallas_ufire = StatusSNS.createNestedObject(devname);
  StatusSNS_dallas_ufire["Temperature"] = tempC;
}

void handshake()
{
  String topic_hand = "" + WiFi.macAddress();
  Serial.println("");
  Serial.println(topic_hand);
  char* boolval = "true";
  if (client.publish(topic_hand.c_str(), boolval, true))
  {
    Serial.println("Handshake Successfull");
  }
}

void check_wifi_mqtt()
{
  Serial.println("Wifi status: " );
  int status_wifi = WiFi.status();
  Serial.println(status_wifi);
  if (status_wifi != 3)
  {
    connectWifi();
  }
  bool mqtt_status = client.connected();
  if (mqtt_status != 0)
  {
    if (!client.connect("", "", ""))
    {
      Serial.print("MQTT connection failed:" );
      Serial.print(client.state());
      Serial.println(" Retrying..." );
      delay(1000);
    }
  }
}

void decode_json (String payload)
{
  DynamicJsonBuffer jsonBuffer;
  Serial.println("Parsing JSON Object");
  //payload = "{\"topic\":\"flora1x\",\"enabled\":\"1\",\"settings\":[{\"name\":\"asd\",\"type\":\"flora\",\"others\":\"c4:7c:8d:63:ce:02\"},{\"name\":\"asd\",\"type\":\"temperature\",\"others\":\"\"}]}";
  JsonObject& doc = jsonBuffer.parseObject(payload);
  doc.printTo(Serial);
  if (!doc.success())
  {
    Serial.println("parseObject() failed");
  }
  else
  {
    Serial.println("ParseObject() successfull");
  }
  if (doc["enabled"])
  {
    Status["FriendlyName"] = "h2o";
    Status["Topic"] = doc["topic"];
    Status["Power"] = 0;
    StatusSNS["Time"] = "2019-11-07T02:06:13";
    StatusSTS["Time"] = "2018.02.15 01:00:50";
    StatusSTS["Uptime"] = "1 02:33:26";
    StatusSTS["Vcc"] = 3.504;
    StatusSTS["POWER"] = "OFF";
    String MQTT_TOPIC = doc["topic"];
    Serial.println (MQTT_TOPIC);
    JsonArray& dev_status = doc["settings"];
    for (JsonObject& results : dev_status)
    {
      String sensor_type = results["type"];
      if (sensor_type == "flora")
      {
        flora_counter++;
        String devname = results["name"];
        String deviceMacAddress = results["others"];
        handle_flora(devname, deviceMacAddress);
      }
      else if (sensor_type == "dallas")
      {
        String devname = results["name"];
        handle_dallas_ufire(devname);
      }
    }
    publish_mqtt(MQTT_TOPIC);
  }
}

В этой части кода я сталкиваюсь с проблемой

void publish_mqtt(String mqtt_topic)
{
  //Change mqtt topic to character
  out.printTo(JSONmessageBuffer);
  Serial.println(JSONmessageBuffer);
  int count = 0;
  check_wifi_mqtt();
  while (count <= 3 and !client.publish(mqtt_topic.c_str(), JSONmessageBuffer, true))
  {
    count += 1;
    check_wifi_mqtt();
    Serial.println("Error sending message and count is: ");
    Serial.print(count);
    Serial.println("");
  }
  if (count > 3)
  {
    esp_sleep_enable_timer_wakeup(10 * 1000000ll);
    Serial.println("Restarting in 10 seconds");
    delay(100);
    esp_deep_sleep_start();
  }
  Serial.println("Success sending message");
}

Хотелось бы услышать ответ от кого-то, кто мог бы есть решение для этого. Хотя код будет работать только для следующей итерации, но мне любопытно выяснить причину проблемы root.

...