如何使用Preferences.h在ESP8266中持久化MQTT配置?
问题
我正在为电池驱动的ESP8266编写代码,实现传感器数据读取并发布到MQTT总线,希望移除硬编码的凭据。WiFiManager.h库默认支持通过ConfigPortal网页界面修改WiFi凭据,我想在此基础上添加可修改并持久化保存的MQTT自定义字段。
我的实现思路伪代码如下:
#include <Preferences.h> // Declare vars char mqtt_server[40]; char mqtt_port[6]; char mqtt_user[20]; char mqtt_pass[20]; // Read data from persistant memory or else return default mqtt_server = preferences.getChar("mqtt_server", "default mqtt server"); mqtt_port = preferences.getChar("mqtt_port", "default mqtt port"); mqtt_user = preferences.getChar("mqtt_user", "default mqtt user"); mqtt_pass = preferences.getChar("mqtt_pass", "default mqtt pass"); // Connect to mqtt broker using the vars as just defined // Pushing a button starts a ConfigPortal webinterface to change these vars // Write new data to persistant memory // get the new data from the webform (called "Mqtt_server. preferences.begin("mqtt_config", false); preferences.putChar("mqtt_server", new_mqtt_server); preferences.putChar("mqtt_port", new_mqtt_port); preferences.putChar("mqtt_user", new_mqtt_user); preferences.putChar("mqtt_pass", new_mqtt_pass); preferences.end();
目前我遇到两个问题:
- 如何将完整数据写入
mqtt_server变量?当前仅能获取第一个字符; - 为何
getChar仅允许整数作为默认返回值,而无法设置默认文本?
解决方案
问题1:仅获取第一个字符的修复
你误用了Preferences库的API:getChar()和putChar()是专门用来操作单个字符(char类型,本质是8位整数)的,完全不适合处理字符串。要读写字符串,必须使用getString()和putString()方法。
正确的持久化读写代码示例:
#include <Preferences.h> Preferences preferences; // 声明字符串缓冲区 char mqtt_server[40]; char mqtt_port[6]; char mqtt_user[20]; char mqtt_pass[20]; void setup() { // 初始化Preferences,命名空间为"mqtt_config",只读模式 preferences.begin("mqtt_config", false); // 从持久化存储读取字符串,参数依次为:键名、存储缓冲区、缓冲区大小、默认值 preferences.getString("mqtt_server", mqtt_server, sizeof(mqtt_server), "default.mqtt.server"); preferences.getString("mqtt_port", mqtt_port, sizeof(mqtt_port), "1883"); preferences.getString("mqtt_user", mqtt_user, sizeof(mqtt_user), ""); preferences.getString("mqtt_pass", mqtt_pass, sizeof(mqtt_pass), ""); preferences.end(); // 此处可使用读取到的参数连接MQTT broker } // 保存新的MQTT配置到持久化存储 void saveMqttConfig(const char* newServer, const char* newPort, const char* newUser, const char* newPass) { preferences.begin("mqtt_config", true); // 切换为写入模式 preferences.putString("mqtt_server", newServer); preferences.putString("mqtt_port", newPort); preferences.putString("mqtt_user", newUser); preferences.putString("mqtt_pass", newPass); preferences.end(); }
问题2:getChar不支持文本默认值的原因
getChar()的设计目标就是读取单个字符数据,它的返回值是char类型(本质是整数),因此只能接受整数作为默认值,从根本上就不具备处理字符串的能力。处理字符串必须用getString(),这个方法支持传入字符串默认值,还能指定缓冲区大小避免溢出。
补充:结合WiFiManager添加MQTT配置项
要在WiFiManager的ConfigPortal中显示MQTT配置输入框,需要用WiFiManagerParameter定义字段,示例代码片段:
#include <WiFiManager.h> WiFiManager wm; // 定义MQTT配置参数,关联到之前的缓冲区 WiFiManagerParameter mqtt_server_param("mqtt_server", "MQTT Server", mqtt_server, 40); WiFiManagerParameter mqtt_port_param("mqtt_port", "MQTT Port", mqtt_port, 6); WiFiManagerParameter mqtt_user_param("mqtt_user", "MQTT User", mqtt_user, 20); WiFiManagerParameter mqtt_pass_param("mqtt_pass", "MQTT Password", mqtt_pass, 20); void setup() { // 先读取已保存的MQTT配置(前面的代码) // 将参数添加到WiFiManager wm.addParameter(&mqtt_server_param); wm.addParameter(&mqtt_port_param); wm.addParameter(&mqtt_user_param); wm.addParameter(&mqtt_pass_param); // 触发按钮时启动配置门户(示例) // if(buttonPressed()) { // if(wm.startConfigPortal("ESP8266-Config")) { // // 获取新配置并保存 // strncpy(mqtt_server, mqtt_server_param.getValue(), sizeof(mqtt_server)); // strncpy(mqtt_port, mqtt_port_param.getValue(), sizeof(mqtt_port)); // strncpy(mqtt_user, mqtt_user_param.getValue(), sizeof(mqtt_user)); // strncpy(mqtt_pass, mqtt_pass_param.getValue(), sizeof(mqtt_pass)); // saveMqttConfig(mqtt_server, mqtt_port, mqtt_user, mqtt_pass); // } // } }
内容的提问来源于stack exchange,提问作者Szjoin
相关产品推荐
相关产品推荐

