深度睡眠后 ESP32 未收到 MQTT 消息

时间:2021-05-10 07:53:39

标签: mqtt esp32 sleep-mode

我有一个电池供电的 ESP32 板(=客户端)并使用深度睡眠模式来节省电量。我想在董事会(客户端)睡着时接收 Nodered 发送给代理的 mqtt 消息。我使用 async-mqtt-client/AsyncMQttClient.h(见 github)。

重新启动 ESP32 后,ESP32 板可以正确接收消息。但是当董事会从第一次睡眠中醒来时,消息不会到达。我将 mqttClient.setCleanSession(false) 添加到我的初始化代码中以允许“断开的会话”。这没有帮助。

我每次都开始订阅主题(第一次启动后或醒来后)。当我只在没有会话的情况下订阅主题时(在 if (sessionPresent == 0) 之后)问题仍然存在。

有没有人有关于如何继续前进的建议???

[编辑] 我在这里添加了我的代码。它正在开发中,因此充满了来自不同来源的片段:

Arduino IDE

/* Code by FV for WIFI Lora 32(V2) board, derived from File / Examples / Heltec ESP32 Dev-Boards / ESP32 / ADC_Read_Voltage / Battery_power 
 * The original example gives a correct battery voltage readout on the display and a raw value in the Serial output .
 * The aim is to modify the code to send MQTT readouts to a web-service 
 * This requires establishing a Wifi connection (station mode) and introduction of an MQTT client
 * 
*/
 
/*
* V1.0
* WiFi and MQTT operational 
* Battery voltage readout sometimes gives high values 
*   - are the used pins in the combined sketches compatible?
*   - does introduction of WiFi interfere with the battery measurement?
*   - is the combination of the two loop delay methods sloppy?
*   - is it lack of conversion time for the ADC?
*   
* V1.1 added some extra code with settings to do ADC conversion properly  
*
* V1.2 adding deep sleep to save battery power in idle time
*   - https://randomnerdtutorials.com/esp32-timer-wake-up-deep-sleep/
*   - https://raw.githubusercontent.com/RuiSantosdotme/ESP32-Course/master/code/DeepSleep/TimerWakeUp/TimerWakeUp.ino
*   - need to move the includes to the top of the code, to prevent an error when compiling RTC_DATA_ATTR int wakeupCount = 0;
*   - BUG: after waking up, connecting to the WiFi network does not work.
*          connection is OK after pressing the RST button. 
* V1.3 created more reliable WiFi reconnect using WiFi events         
*   - BUG: delivery of data stops, reason unknown. Battery voltage at the moment of "crash" was high enough.
*   - introduce tools for debugging:
*         * introduce logging, while not connected to serial port
*         * introduce ESP side logging (Use different levels. Set level in Preferences)  
*         * introduce logging on cloud server (a.o. battery voltage, timestamp, deviceId)
*   - SOLVED: not all info printed to Serial, solved by moving display initialization 
*   - added timers for optimization / rationalization of delays      
*   - BUG: awakeDuration should be the longest duration of all, It isn't.
*   - introduce reporting of timers in wireless / battery mode (MQTT)
* V1.4 solve V1.3 issues   
*   - must be able to use MQTT client in any scope
*   - Optimization of delays and uptime:
*     - successDuration takes most of the awake time. Room for improvement in speed of making connection with WiFi 
* V1.5 SWITCH TO  Async MQTT Client Library,  https://randomnerdtutorials.com/esp32-mqtt-publish-bme280-arduino/
*   - see demo sketch: ESP-mqtt-publish
*   - added deviceId, a string representing the board's MAC adress in reverse order
*   - added MQTT topics containing the unique deviceId
*     * prevent using String variables. See
*   - a logging flag is present, which persists over reboots by storing it into flash memory
*     * further logging methods to be implemented
*   -   
*   
*   

*/


 
/* 
 * HelTec Automation(TM) Electricity detection example.
 *
 * Function summary:
 *
 * - Vext connected to 3.3V via a MOS-FET, the gate pin connected to GPIO21;  //BUT WHERE IS THE CODE THAT DOES THAT?
 *
 * - Battery power detection is achieved by detecting the voltage of GPIO13;  //SHOULD BE GPIO37    what is the meaning of GPIO36 in this sketch?
 *
 * - OLED display and PE4259(RF switch) use Vext as power supply;
 *
 * - WIFI Kit series V1 don't have Vext control function;
 *
 * HelTec AutoMation, Chengdu, China.
 * 成都惠利特自动化科技有限公司
 * https://heltec.org
 * support@heltec.cn
 *
 * this project also release in GitHub:
 * https://github.com/Heltec-Aaron-Lee/WiFi_Kit_series
 * 
*/

/*
Simple Deep Sleep with Timer Wake Up
=====================================
ESP32 offers a deep sleep mode for effective power
saving as power is an important factor for IoT
applications. In this mode CPUs, most of the RAM,
and all the digital peripherals which are clocked
from APB_CLK are powered off. The only parts of
the chip which can still be powered on are:
RTC controller, RTC peripherals ,and RTC memories

This code displays the most basic deep sleep with
a timer to wake it up and how to store data in
RTC memory to use it over reboots

This code is under Public Domain License.

Author:
Pranav Cherukupalli <cherukupallip@gmail.com>
*/
/*
   This sketch shows the WiFi event usage - Example from WiFi > WiFiClientEvents
   Complete details at https://RandomNerdTutorials.com/esp32-useful-wi-fi-functions-arduino/
*/

#include "Arduino.h"
#include <Preferences.h>  //not required in Arduino IDE ( NOT TRUE !)
//https://randomnerdtutorials.com/esp32-save-data-permanently-preferences/
//also see info on how to remove a namespace

Preferences preferences;     //create an instance (preferences) of Preferences

#define PREFERENCES_READ_ONLY = false //use preferences in R/W mode
 
#include <Wire.h>
#include "heltec.h"         //study conditional includes/ compilation
//#include "esp_wifi.h"
#include <WiFi.h>
extern "C" {
  #include "freertos/FreeRTOS.h"
  #include "freertos/timers.h"
}
// https://github.com/marvinroger/async-mqtt-client
// https://github.com/marvinroger/async-mqtt-client/blob/master/docs/2.-API-reference.md
// Very important: As a rule of thumb, never use blocking functions in the callbacks (don't use delay() or yield()). 
// Otherwise, you may very probably experience unexpected behaviors.
#include <AsyncMqttClient.h>


#define WIFI_SSID "XXXXXXXXXXXXXX"
#define WIFI_PASSWORD "XXXXXXXXXXXXXXX"
#define MQTT_USER "XXXXXXXXX"
#define MQTT_PASSWORD "XXXXXXXXXXXXXXX"

// Mosquitto MQTT Broker
#define MQTT_HOST IPAddress(192, XXXXXXXXXXX)
// For a cloud MQTT broker, type the domain name
//#define MQTT_HOST "example.com"
#define MQTT_PORT XXXXXXXX


bool enabled_sleepmode = true;
char deviceId[23] = "";
char deviceType[10] = "";
char deviceTopic[50] = "";
 
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 connectToWifi() {
  Serial.println("Connecting to Wi-Fi...");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}

void connectToMqtt() {
  Serial.println("Connecting to MQTT...");
  //mqttClient.setClientId("myESP");
  //mqttClient.setCredentials(MQTT_USER,MQTT_PASSWORD);
  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);
  //test sub

  if (sessionPresent == 0){
  
  uint16_t packetIdSub = mqttClient.subscribe("test/lol", 2);
  Serial.print("Subscribing at QoS 2, packetId: ");
  Serial.println(packetIdSub);
  }
  
  mqttClient.publish("test/lol", 0, true, "test 1");
  Serial.println("Publishing at QoS 0");
  uint16_t packetIdPub1 = mqttClient.publish("test/lol", 1, true, "test 2");
  Serial.print("Publishing at QoS 1, packetId: ");
  Serial.println(packetIdPub1);
  
  
  uint16_t packetIdPub2 = mqttClient.publish("test/lol", 2, true, "test 3");
  Serial.print("Publishing at QoS 2, packetId: ");
  Serial.println(packetIdPub2);
     if (sessionPresent == 0){   //if no active previous session, subscribe. This assumes that subscription is not necessary when sessionPresent != 0

  uint16_t packetIdSub2a = mqttClient.subscribe("test/lol2", 2);
  Serial.print("Subscribing at QoS 2, packetId: ");
  Serial.println(packetIdSub2a);


  uint16_t packetIdSub1a = mqttClient.subscribe("test/lol1", 1);
  Serial.print("Subscribing at QoS 1, packetId: ");
  Serial.println(packetIdSub1a);
  uint16_t packetIdSub0a = mqttClient.subscribe("test/lol0", 0);
  Serial.print("Subscribing at QoS 0, packetId: ");
  Serial.println(packetIdSub0a);
   }
  
}

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 onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
  Serial.println("Publish received.");
  Serial.print("  topic: ");
  Serial.println(topic);
  Serial.print("  qos: ");
  Serial.println(properties.qos);
  Serial.print("  dup: ");
  Serial.println(properties.dup);
  Serial.print("  retain: ");
  Serial.println(properties.retain);
  Serial.print("  len: ");
  Serial.println(len);
  Serial.print("  index: ");
  Serial.println(index);
  Serial.print("  total: ");
  Serial.println(total); 

 //need to convert payload to properly readably info
  String messageTemp;
for (int i = 0; i < len; i++) {
//Serial.print((char)payload[i]);
messageTemp += (char)payload[i];
}

  Serial.print("  payload: ");
  Serial.println(messageTemp);
  
}

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




//#include <ESP8266WiFi.h>
//#include <PubSubClient.h>   //Knoleary MQTT module

//WiFiClient espClient;
//PubSubClient mqtt_client(espClient);
//unsigned long lastMsg = 0;
//#define MSG_BUFFER_SIZE  (50)
//char msg[MSG_BUFFER_SIZE];
//int value = 0;

#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  60        /* Time ESP32 will go to sleep (in seconds) */

RTC_DATA_ATTR int wakeupCount = 0;  //store in ULP, keep value while sleeping

bool loggingMode = false;
unsigned long wakeupTime; //milliseconds
unsigned long sleepTime; //milliseconds
unsigned long connectStart; //milliseconds
unsigned long connectSuccess; //milliseconds


//get unique deviceId, it contains the MAC address in reverse order
//later also get the device type and Rev

void get_deviceId() {
  uint64_t chipid = ESP.getEfuseMac(); // The chip ID is essentially its MAC address(length: 6 bytes).
  snprintf(deviceId, 23, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid);
}

void get_deviceType() {
  snprintf(deviceType, 23, "ESP32", "", "");
}


/*
Method to print the reason by which ESP32 has been awaken from sleep
*/



void wake_up_from_deep_sleep(){
  wakeupTime = millis();
  Serial.begin(115200);
  delay(10); //Take some time to open up the Serial Monitor //was 1000
  //Print the wakeup reason for ESP32
  print_wakeup_reason();

  // Open Preferences with my-app namespace. Each application module, library, etc
  // has to use a namespace name to prevent key name collisions. We will open storage in
  // RW-mode (second parameter has to be false).
  // Note: Namespace name is limited to 15 chars.
  preferences.begin("my-app", false);

  // Remove all preferences under the opened namespace
  //preferences.clear();

  // Or remove the counter key only
  //preferences.remove("counter");

  // Get the counter value, if the key does not exist, return a default value of 0
  // Note: Key name is limited to 15 chars.
  unsigned int counter = preferences.getUInt("counter", 0);

  // Increase counter by 1
  counter++;

  // Print the counter to Serial Monitor
  Serial.printf("Total nr of wakeups: %u\n", counter);

  // Store the counter to the Preferences
  preferences.putUInt("counter", counter);

  loggingMode = preferences.getBool("loggingMode", false);
  //loggingMode = true;
  // Close the Preferences
  preferences.end();

  Serial.println("loggingMode: " + String(loggingMode));
/*
  for(int i=0; i<17; i=i+8) {
    chipId2 |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
  }

*/
  
//  Serial.printf("ESP32 Chip model = %s Rev %d\n", ESP.getChipModel(), ESP.getChipRevision());   //ESP.getChipModel() 

//  Serial.printf("This chip has %d cores\n", ESP.getChipCores());
//  Serial.print("Chip ID: "); Serial.println(chipId2);

get_deviceId();
Serial.println(deviceId);
get_deviceType();
Serial.println(deviceType);
//get device Ver ????

  //Increment boot number and print it every reboot
  ++wakeupCount;
  Serial.println("----- wakeupCount since last reboot: " + String(wakeupCount)+" -----");

  }

void put_loggingMode(bool my_value){

   preferences.begin("my-app", false);
   preferences.putBool("loggingMode", my_value);
   // Close the Preferences
   preferences.end();
  }

void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

  void prepare_and_go_for_sleep(){
   
  /*
  First we configure the wake up source
  We set our ESP32 to wake up every 5 seconds
  */
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for " + String(TIME_TO_SLEEP) +
  " Seconds");

  /*
  Next we decide what all peripherals to shut down/keep on
  By default, ESP32 will automatically power down the peripherals
  not needed by the wakeup source, but if you want to be a poweruser
  this is for you. Read in detail at the API docs
  http://esp-idf.readthedocs.io/en/latest/api-reference/system/deep_sleep.html
  Left the line commented as an example of how to configure peripherals.
  The line below turns off all RTC peripherals in deep sleep.
  */
  //esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
  //Serial.println("Configured all RTC Peripherals to be powered down in sleep");

  /*
  Now that we have setup a wake cause and if needed setup the
  peripherals state in deep sleep, we can now start going to
  deep sleep.
  In the case that no wake up sources were provided but deep
  sleep was started, it will sleep forever unless hardware
  reset occurs.
  */

  //esp_wifi_disconnect();
  unsigned long disconnectTime = millis();
  sleepTime = millis();

  
  unsigned long awakeDuration = sleepTime - wakeupTime;  
  Serial.println("awakeDuration " + String(awakeDuration));


   strcpy(deviceTopic,"");
   strcat(deviceTopic,"fleet/");
   strcat(deviceTopic,deviceType);
   strcat(deviceTopic,"/"); 
   strcat(deviceTopic,deviceId);
   strcat(deviceTopic,"/timers/awakeDuration"); 
 
  mqttClient.publish(deviceTopic, 1, true, String(awakeDuration).c_str());
  unsigned long connectDuration = disconnectTime - connectStart; 

  Serial.println("connectDuration " + String(connectDuration));


   strcpy(deviceTopic,"");
   strcat(deviceTopic,"fleet/");
   strcat(deviceTopic,deviceType);
   strcat(deviceTopic,"/"); 
   strcat(deviceTopic,deviceId);
   strcat(deviceTopic,"/timers/connectDuration"); 
   mqttClient.publish(deviceTopic, 1, true, String(connectDuration).c_str());
    
  unsigned long successDuration = connectSuccess - connectStart;

  Serial.println("successDuration " + String(successDuration));
  
   strcpy(deviceTopic,"");
   strcat(deviceTopic,"fleet/");
   strcat(deviceTopic,deviceType);
   strcat(deviceTopic,"/"); 
   strcat(deviceTopic,deviceId);
   strcat(deviceTopic,"/timers/successDuration"); 
   mqttClient.publish(deviceTopic, 1, true, String(successDuration).c_str());
    Serial.println("----- Waiting for going to sleep -----");
     delay(5000); 
  Serial.println("----- Going to sleep now -----");
  Serial.println();
  
  Serial.flush(); 
  esp_deep_sleep_start();
  Serial.println("This will never be printed"); //unreachable code
  }

//battery parameters
#define Fbattery    3700  //The default battery is 3700mv when the battery is fully charged.

float XS = 0.00225;      //The returned reading is multiplied by this XS to get the battery voltage.
uint16_t MUL = 1000;
uint16_t MMUL = 100;

void setup(){

  wake_up_from_deep_sleep();

  //set logging mode 
  loggingMode = true;
  //persist the value in the preferences
  put_loggingMode(loggingMode);


  Heltec.begin(true /*DisplayEnable Enable*/, false /*LoRa Enable*/, false /*Serial Enable*/);
  Heltec.display->init();  
  Heltec.display->flipScreenVertically();
  Heltec.display->setFont(ArialMT_Plain_10);
  Heltec.display->drawString(0, 0, "WAKE UP");
  Heltec.display->display();
  delay(1);
  Heltec.display->clear();

  //setup WiFi and MQTT connections    
  if (wakeupCount == 1) {    

  Serial.println("setting up WiFi");
/* XXXXX
  setup_wifi();
XXXXX */
  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.onMessage(onMqttMessage);
  mqttClient.onPublish(onMqttPublish);
  mqttClient.setServer(MQTT_HOST, MQTT_PORT);

  //find a way to use a unique MQTT clientId, the broker uses the clientId and does not need action by the user 
  //see e.g.: https://www.cloudmqtt.com/blog/mqtt-what-is-client-id.html
  //you can re-use the MQTT clientId as an Id for the cloud service. Look up, if it can be retrieved automatically from messa content
  //otherwise the device may have to send the clientId to the cloud service
  //investigate if chipID or boardId is unique
   
  mqttClient.setClientId(deviceId);  
  
  // If your broker requires authentication (username and password), set them below
  mqttClient.setCredentials(MQTT_USER, MQTT_PASSWORD);
  connectToWifi(); //and MQTT broker
  }
  else {
    Serial.println("alternative WiFi connect");
    /* XXXXX
    setup_wifi();
    XXXXX */
    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);
  mqttClient.setClientId(deviceId);
  
  //messages to the board do not arrive after wake-up
  //have a look at "clean sessions" vs "persistent sessions"
  
  
  mqttClient.setCleanSession(false);  //for interrupted sessions 




  
  // If your broker requires authentication (username and password), set them below
   mqttClient.setCredentials(MQTT_USER, MQTT_PASSWORD);
  connectToWifi(); //and MQTT broker
    }

  Serial.println("Wait for WiFi... ");
  while (WiFi.status() != WL_CONNECTED) { }
  connectSuccess = millis(); 
  Serial.println("WIFI CONNECTED"); 
  while (mqttClient.connected() == false) { }
  Serial.println("MQTT CONNECTED"); 


   strcpy(deviceTopic,"");
   strcat(deviceTopic,"fleet/");
   strcat(deviceTopic,deviceType);
   strcat(deviceTopic,"/deviceId"); 

        
   //report deviceId to cloud service
   uint16_t packetIdPubx = mqttClient.publish(deviceTopic, 2, true, deviceId); 
   Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", deviceTopic, packetIdPubx);

  
    // DO SOMETHING USEFUL in setup
  Serial.println("something useful in setup()");
   //prepare ADC for battery voltage measurement
   //analogSetClockDiv(255); // 1338mS
   analogSetCycles(8);                   // Set number of cycles per sample, default is 8 and provides an optimal result, range is 1 - 255
   analogSetSamples(1);                  // Set number of samples in the range, default is 1, it has an effect on sensitivity has been multiplied
   analogSetClockDiv(1);                 // Set the divider for the ADC clock, default is 1, range is 1 - 255
   analogSetAttenuation(ADC_11db);       // Sets the input attenuation for ALL ADC inputs, default is ADC_11db, range is ADC_0db, ADC_2_5db, ADC_6db, ADC_11db
   analogSetPinAttenuation(36,ADC_11db); // Sets the input attenuation, default is ADC_11db, range is ADC_0db, ADC_2_5db, ADC_6db, ADC_11db
   analogSetPinAttenuation(37,ADC_11db);
                                        // ADC_0db provides no attenuation so IN/OUT = 1 / 1 an input of 3 volts remains at 3 volts before ADC measurement
                                        // ADC_2_5db provides an attenuation so that IN/OUT = 1 / 1.34 an input of 3 volts is reduced to 2.238 volts before ADC measurement
                                        // ADC_6db provides an attenuation so that IN/OUT = 1 / 2 an input of 3 volts is reduced to 1.500 volts before ADC measurement
                                        // ADC_11db provides an attenuation so that IN/OUT = 1 / 3.6 an input of 3 volts is reduced to 0.833 volts before ADC measurement
//   adcAttachPin(VP);                     // Attach a pin to ADC (also clears any other analog mode that could be on), returns TRUE/FALSE result 
//   adcStart(VP);                         // Starts an ADC conversion on attached pin's bus
//   adcBusy(VP);                          // Check if conversion on the pin's ADC bus is currently running, returns TRUE/FALSE result 
//   adcEnd(VP);
   
   adcAttachPin(36);
   adcAttachPin(37);

   //WiFi LoRa 32        -- hardare versrion ≥ 2.3
   //WiFi Kit 32         -- hardare versrion ≥ 2
   //Wireless Stick      -- hardare versrion ≥ 2.3
   //Wireless Stick Lite -- hardare versrion ≥ 2.3
   //Battery voltage read pin changed from GPIO13 to GPI37


   delay(100);

   //measure ????? voltage on pin 36
   adcStart(36);
   while(adcBusy(36));

   //publish ????? voltage

   uint16_t c2  =  analogRead(36)*0.769 + 150;
   adcEnd(36);
   Serial.printf("voltage input on GPIO 36: ");
   Serial.println(analogRead(36));


   strcpy(deviceTopic,"");
   strcat(deviceTopic,"fleet/");
   strcat(deviceTopic,deviceType);
   strcat(deviceTopic,"/"); 
   strcat(deviceTopic,deviceId);
   strcat(deviceTopic,"/Vin"); 
   uint16_t packetIdPub0 = mqttClient.publish(deviceTopic, 1, true, String(c2).c_str()); 

   //uint16_t packetIdPub0 = mqttClient.publish(deviceTopic, 2, true, "HELLO");                             
   Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", deviceTopic, packetIdPub0);
   Serial.printf("Message: %.2f \n", c2);


   strcpy(deviceTopic,"");
   strcat(deviceTopic,"fleet/");
   strcat(deviceTopic,deviceType);
   strcat(deviceTopic,"/"); 
   strcat(deviceTopic,deviceId);
   strcat(deviceTopic,"/topic1"); 
   
   
   uint16_t packetIdPubt = mqttClient.publish(deviceTopic, 1, true, "device specific info"); 
   Serial.printf("Pablishing on topic %s at QoS 1, packetId: %i", deviceTopic, packetIdPubt);
   Serial.printf("Message: %s \n", "device specific info");
   
      Serial.println("-------------");
   //measure battery voltage on pin 37
   adcStart(37);
   while(adcBusy(37));
   uint16_t c  =  analogRead(37)*XS*MUL;
   adcEnd(37);

   //publish battery voltage
   Serial.println(analogRead(37));


   strcpy(deviceTopic,"");
   strcat(deviceTopic,"fleet/");
   strcat(deviceTopic,deviceType);
   strcat(deviceTopic,"/"); 
   strcat(deviceTopic,deviceId);
   strcat(deviceTopic,"/Vbat"); 


   uint16_t packetIdPuba = mqttClient.publish(deviceTopic, 2, true, String(c).c_str()); 
   //uint16_t packetIdPuba = mqttClient.publish(deviceTopic, 1, true, "HELLO");                             
   Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", deviceTopic, packetIdPuba);
   Serial.printf("Message: %.2f \n", c);


   Heltec.display->drawString(0, 0, "Remaining battery still has:");
   Heltec.display->drawString(0, 10, "Vbat =");
   Heltec.display->drawString(35, 10, (String)c);
   Heltec.display->drawString(60, 10, "(mV)");
   
   Heltec.display->drawString(0, 20, "Vin   = ");
   Heltec.display->drawString(33, 20, (String)c2);
   Heltec.display->drawString(60, 20, "(mV)");

   Heltec.display->display();

  delay(100);
  //delay(10000); // long delay for visibility in network device list
  if (enabled_sleepmode) {prepare_and_go_for_sleep();}
}

void loop(){
  //This is not going to be called when going to sleep in setup()
  // DO SOMETHING USEFUL in loop
    Serial.println("something useful in loop()");
    delay(1000);
  //prepare_and_go_for_sleep();
}

3 个答案:

答案 0 :(得分:1)

在深度睡眠时,代理会将客户端标记为离线。

将 Clean Session 标志设置为 false 是一个好的开始,但您还需要确保您已订阅 QOS 1 或 2 而不是 0,以便代理知道在客户端离线时将消息排队。

答案 1 :(得分:0)

当您进入深度睡眠时,您的连接会断开,服务器可能会决定将您的节点标记为离线。

您订阅的主题具有不同的 QoS'。某些订阅使用 QoS 0,这会告诉代理尝试将消息发送到这些主题一次,而无需重试。

如果您指定 QoS 1 或 QoS 2,代理将在检测到您的节点再次处于活动状态时尝试重新发送这些消息。

有一个符合标准的项目,您可以在调试设备时找到它,MQTTnet,您可以用它实现一个非常简单的代理,启用它的日志记录支持,并使用它的参数。它可以提供漂亮而清晰的线索,但您需要 VisualStudio、社区版本运行良好,以及一些 C# 知识。

答案 2 :(得分:0)

我观察到的行为可能是由于客户端的限制造成的。请参阅:this link。对此有何评论?

如果这个限制真的是原因,我就不必再走这条路了。

谢谢