c++ - 在自定义类中使用 PubSubClient
问题描述
我正在构建一个库,我可以在多个设备上重复使用它,以节省我在代码中一遍又一遍地设置相同的功能。
我在尝试发布消息时遇到问题,希望您能提供帮助!
该代码针对启用了 BLE 和 WiFi 的 ESP32(它是Timo 的 Heart Rate Monitor的一个端口,并且消息有效负载是使用 ArduinoJSON 6.x 创建的(最初使用的是 ArduinoJSON 5.x,但这不是代码的问题)尝试打印纯文本时失败并出现相同的错误)
代码通过 Platformio.org 管理,而不是 Arduino IDE,我的 platformio.ini 文件如下所示:
[env:esp32dev]
platform = espressif32
board = ttgo-t-beam
framework = arduino
lib_extra_dirs =
../common_libraries
build_flags = !../bin/build_flags.sh
board_build.partitions = min_spiffs.csv
lib_deps =
nkolban/ESP32 BLE Arduino@^1.0.1
bblanchon/ArduinoJson@^6.17.2
该build_flags.sh
脚本只是为 WiFi 和 MQTT 客户端设置环境变量,稍后您会看到。
库中的代码如下,我看到的问题是,虽然总是发送课程设置中的“注册消息”,但心率监测器的数据是零星发送的,总是会导致 Guru Meditation .
令人沮丧的是,这只会在类外部的 MQTT 发布上失败,无论客户端在哪里初始化,订阅消息都会通过。
编码
我的图书馆”
/*
* mymqtt32.h
*
*/
#ifndef mymqtt32_h
#define mymqtt32_h
#include "Arduino.h"
#include <WiFi.h>
#include <PubSubClient.h>
class mymqtt32 {
public:
mymqtt32(
char* device_name,
char* device_type,
char* wifi_ssid,
char* wifi_pw,
char* mqtt_server_ip,
int mqtt_server_port
);
void wifi_setup();
PubSubClient mqtt_setup(String client_name);
private:
char* _device_name;
char* _device_type;
char* _wifi_ssid;
char* _wifi_pw;
char* _mqtt_server_ip;
int _mqtt_server_port;
String _getMAC();
WiFiClient _espClient;
PubSubClient _mqtt_client;
};
#endif
#include "mymqtt32.h"
#include <ArduinoJson.h>
mymqtt32::MYMQTT(
char* device_name,
char* device_type,
char* wifi_ssid,
char* wifi_pw,
char* mqtt_server_ip,
int mqtt_server_port
) {
_device_name = device_name;
_device_type = device_type;
_wifi_ssid = wifi_ssid;
_wifi_pw = wifi_pw;
_mqtt_server_ip = mqtt_server_ip;
_mqtt_server_port = mqtt_server_port;
}
void mymqtt32::wifi_setup() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(_wifi_ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(_wifi_ssid, _wifi_pw);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.print("My mac address is: ");
Serial.println(_getMAC());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
PubSubClient mymqtt32::mqtt_setup(String client_name) {
_mqtt_client.setClient(_espClient);
_mqtt_client.setServer(_mqtt_server_ip,
_mqtt_server_port);
String _client_name = client_name;
String _dev_type_str = _device_type;
while (!_mqtt_client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (
_mqtt_client.connect(_client_name.c_str())
) {
Serial.println("connected");
const size_t capacity = JSON_OBJECT_SIZE(3);
DynamicJsonDocument systemDescription(capacity);
systemDescription["device_name"] = _client_name;
systemDescription["device_type"] = _dev_type_str;
systemDescription["device_mac"] = _getMAC();
char bodyString[500];
serializeJson(systemDescription, bodyString, sizeof(bodyString));
serializeJson(systemDescription, Serial);
Serial.println();
Serial.println(bodyString);
String pub_topic = "/register";
char pub_topic_name[50];
pub_topic.toCharArray(pub_topic_name, 50);
Serial.print("Publishing to: ");
Serial.println(pub_topic_name);
// Once connected, publish an announcement...
_mqtt_client.publish(pub_topic_name, bodyString);
// Now subscribe to the controller topic
String sub_topic = "devices/control/";
sub_topic.concat(_dev_type_str);
sub_topic.concat("/");
sub_topic.concat(_getMAC());
char sub_topic_name[50];
sub_topic.toCharArray(sub_topic_name, 50);
Serial.print("Subscribing to: ");
Serial.println(sub_topic_name);
_mqtt_client.subscribe(sub_topic_name);
} else {
Serial.print("Trying to connect to ");
Serial.print(_mqtt_server_ip);
Serial.print(" on port ");
Serial.println(_mqtt_server_port);
Serial.print("failed, rc=");
Serial.print(_mqtt_client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
return _mqtt_client;
}
String mymqtt32::_getMAC()
{
String macaddr = String(WiFi.macAddress());
macaddr.replace(":", "");
macaddr.toLowerCase();
return String( macaddr );
}
我如何调用代码
#include <MYMQTT32.h>
#define ST(A) #A
#define STR(A) ST(A)
// Setup the WiFi and MQTT Client based on the build flags
MYMQTT mymqtt(STR(DEVICE_NAME), device_type, STR(WIFI_SSID), STR(WIFI_PASS), STR(MQTT_SERVER), 1883);
PubSubClient mqctrl;
...
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
hbat.wifi_setup();
mqctrl = hbat.mqtt_setup(device_type);
mqctrl.setCallback(control);
...
}
void loop() {
...
mqctrl.loop()
}
旨在发布但导致上师冥想的功能
//--------------------------------------------------------------------------------------------
// Send HRM stats to MQTT
//--------------------------------------------------------------------------------------------
void sendHRMData() {
Serial.println("Message received from chest strap, sending to MQTT");
DynamicJsonDocument dataJson(20);
dataJson[F("HRM")] = hrm.HRM;
char buffer[20];
serializeJson(dataJson, buffer);
~ Serial.print("Buffer Content: ");
~ Serial.println(buffer);
mqctrl.publish("/devices/status/heartrate", buffer); // <- JSON BUFFER CAUSES GURU MEDITIATION
~ // mqctrl.publish("/devices/status/heartrate", "test message"); <- STATIC MESSAGE CAUSES THE SAME ISSUE
}
“冥想”
返回的冥想如下:
Guru Meditation Error: Core 0 panic'ed (InstrFetchProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x2f736563 PS : 0x00060031 A0 : 0x8001a060 A1 : 0x3ffbe290
A2 : 0x00000000 A3 : 0x00000000 A4 : 0x00000000 A5 : 0x00000001
A6 : 0x00000000 A7 : 0x3ffb8360 A8 : 0x8008ebac A9 : 0x3ffbc88c
A10 : 0x00000002 A11 : 0x3ffbc230 A12 : 0x800922e0 A13 : 0x3ffbc230
A14 : 0x00000008 A15 : 0x00000000 SAR : 0x0000001d EXCCAUSE: 0x00000014
EXCVADDR: 0x2f736560 LBEG : 0x00000000 LEND : 0x00000000 LCOUNT : 0x00000000
Core 0 was running in ISR context:
EPC1 : 0x2f736563 EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x00000000
Backtrace: 0x2f736563:0x3ffbe290 0x4001a05d:0x3ffbe2b0 0x4008cd3e:0x3ffbe2e0 0x4008a591:0x3ffbe320 0x4008df8d:0x3ffbe340 0x4008e97f:0x3ffbe360 0x40086f41:0x3ffbe380 0x401e7d03:0x3ffbc210 0x400df6ce:0x3ffbc230 0x400922dd:0x3ffbc250 0x40090af9:0x3ffbc270
这解码为
PC: 0x2f736563
EXCVADDR: 0x2f736560
Decoding stack results
0x4008df8d: xRingbufferCreate at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp_ringbuf/ringbuf.c line 704
0x4008e97f: xQueueGenericSendFromISR at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/queue.c line 1207
0x40086f41: spi_flash_mmap_pages at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/spi_flash/flash_mmap.c line 201
0x400df6ce: esp_fill_random at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/hw_random.c line 61
0x400922dd: verify_allocated_region at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/heap/multi_heap_poisoning.c line 109
0x40090af9: vTaskPlaceOnEventListRestricted at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/include/freertos/portable.h line 208
并且根据文件表明我错误地调用了发布命令:
InstrFetchProhibited
This CPU exception indicates that CPU could not load an instruction because the the address of the instruction did not belong to a valid region in instruction RAM or ROM.
Usually this means an attempt to call a function pointer, which does not point to valid code. PC (Program Counter) register can be used as an indicator: it will be zero or will contain garbage value (not 0x4xxxxxxx).
(来自ESP32 致命错误页面)
我确定这是一个明显的问题,这只是我对如何传递 PubSubClient 的误解,但我完全不知道该怎么做!
解决方案
推荐阅读
- azure - 如何从 ADF 将 json 发布到 REST
- mediawiki - MediaWiki 从 1.15 更新到最新版本
- sql - 我可以使用 <-> 在 PostgreSQL 中找到数组之间的距离吗?
- javascript - 试图在控制台中更改变量的值,但它以未定义的形式出现
- r - 是否有 R 函数或代码字符串来识别一行中的两个单元格列何时重复?
- reactjs - React - 状态数组删除数组中的最后一项而不是指定的索引
- c++ - 如何解决程序在负数情况下工作方式相同的问题?
- math - 你将如何为这个问题开发有效的算法
- sql - 如何将列单元添加到@Header 每行有标志允许 1?
- python - 将列表条件填充到另一个关于值的条件