ESP8266的上訴
過去,我做過幾個基于Arduino的項目,通常是網絡連接,主要是在各種物聯網中。自從幾年前引入ESP8266模塊以來,我更頻繁地使用這些電路板有四個主要原因:
集成Wi-Fi
緊湊尺寸
經濟實惠
以Arduino為中心的開發環境
我使用ESP8266實現的所有應用程序的通用是需要一些配置,包括Wi-Fi連接數據,應用程序的管理員憑據,在大多數情況下是MQTT代理的地址和用于接收命令的一些MQTT主題,以及發布狀態或測量數據。
對通用配置系統的需求
對于我的前幾個項目,所有這些配置都是硬編碼的,因為構建只需要在我自己的房子里工作。但很快我不得不重新配置Wi-Fi連接,因為出于安全考慮,我決定將所有IoT設備移到一個單獨的子網中。
必須移動每個設備,并且必須更改固件并將其下載到設備。然后我建造了多個小型溫度計,ESP-01和DS18B20安裝在一個盒子上,用于兩個LR20電池,我放在房子的每個房間。顯然,來自不同設備的測量需要是可區分的。因此,它們要么使用設備所在的房間來注釋測量值,要么使用包含有關位置信息的不同MQTT主題。
對于硬編碼配置,我不得不反復修改每個設備的固件。這種持續的修改是當我對硬編碼方法不滿意并尋求引入動態配置系統的方法時。
我的第一種方法是硬編碼配置結構,一個帶有表單反映的小網頁這個配置結構和一些代碼用于解析通過表單傳遞的數據,將其放入結構并將其存儲在ESP8266的EEPROM中。
但是,這種方法對我嘗試的下一個設備不起作用修改。該設備包含D1 Mini模塊和兩個紅/綠LED。它放在我的前門,顯示房子里的所有窗戶是否都關閉(紅燈:一些窗戶打開,綠燈:所有窗戶都關閉),這也需要一些配置 - 事實上不同的配置。因此,配置不再是硬編碼,而是具有結構的系統。再次,另一個問題。
獵豹模板
在我的“日常工作”中那時候,我正在研究一種基于模型的軟件開發方法,其中代碼是從模型中的信息生成的,我記得幾年前我用過的Python包:獵豹模板。使用此模板引擎,您可以編寫要獲取的文本,并將Python變量作為占位符放在每個位置,需要一些動態文本:
tConfigBlock configBlock;
const uint32_t MAGIC = $magic;
const char* CONFIG_SSID = “$confWifiSsid”;
extern ESP8266WebServer webServer;
在這個小片段中,我有C變量(或實際上) ,在C代碼常量中)對于魔術值(或多或少是配置結構的信息版本)和Wi-Fi網絡的SSID,ESP8266應在AP模式下打開以進行初始配置。
必須處理此代碼段的模板引擎會將占位符$ magic和$ confWifiSsid替換為Python變量的內容。
除了使用簡單替換占位符之外,您可以做的不僅僅是獵豹:
typedef struct {
#for $configItem in $configItems
#if $configItem.type == ‘C’
char ${configItem.key}[$configItem.length];
#else if $configItem.type == ‘I’
uint32_t $configItem.key;
#end if
#end for
} tConfigBlock;
extern const uint32_t MAGIC;
extern tConfigBlock configBlock;
extern const char* CONFIG_SSID;
void configServeIndex();
void configServeGetConfiguration();
void showConfiguration();
//(This is the complete template for the configuration.h file.)
有條件和循環。您可以迭代容器的項目,也可以根據條件插入文本。
這些是我在基于ESP8266/Arduino的應用程序的通用配置系統中使用的Cheetah的主要功能:變量替換,循環和條件。
項目的輸入文件
讓我們看一下項目特定的輸入文件,它描述了實際項目的配置結構:
configItems = [
{“label”:“_”, “key”:“magic”, “type”:“I”, “default”: “”},
{“label”:“Config Username”, “key”:“confUser”, “type”:“C”, “length”:16, “default”:“admin”},
{“label”:“Config Password”, “key”:“confPasswd”, “type”:“C”, “length”:16, “default”:“geheim123”},
{“label”:“Wifi SSID”, “key”:“wifiSsid”, “type”:“C”, “length”:32, “default”:“test”},
{“label”:“Wifi Key”, “key”:“wifiKey”, “type”:“C”, “length”:64, “default”:“geheim”},
{“label”:“MQTT Broker”, “key”:“mqttBroker”, “type”:“C”, “length”:32, “default”:“broker.hottis.de”},
{“label”:“MQTT Username”, “key”:“mqttUser”, “type”:“C”, “length”:32, “default”:“RgbLed1”},
{“label”:“MQTT Password”, “key”:“mqttPass”, “type”:“C”, “length”:32, “default”:“geheim123”},
{“label”:“MQTT ClientId”, “key”:“mqttClientId”, “type”:“C”, “length”:32, “default”:“RgbLed1”},
{“label”:“MQTT Port”, “key”:“mqttPort”, “type”:“I”, “default”:8883},
{“label”:“MQTT Topic Color Command”, “key”:“mqttTopicColorCommand”, “type”:“C”, “length”:64, “default”:“IoT/RgbLed1/ColorCommand”},
{“label”:“MQTT Topic Command”, “key”:“mqttTopicCommand”, “type”:“C”, “length”:64, “default”:“IoT/RgbLed1/Command”},
{“label”:“MQTT DebugTopic”, “key”:“mqttDebugTopic”, “type”:“C”, “length”:64, “default”:“IoT/RgbLed1/Debug”},
{“label”:“DebugMode”, “key”:“debugMode”, “type”:“I”, “default”:0}
]
magic = 0xC0DE0006
appName = “ESP8266 based RgbLedLight”
這是另一個控制RGB LED的小型設備的輸入。
關于魔術的一個詞:每當配置存儲在EEPROM中的幻數和生成到代碼中的幻數不同,固件 - 特別是配置的結構 - 已更新,存儲的配置無效。
在這種情況下,應用程序不會以“生產模式”啟動,而是以“配置模式”啟動。在配置模式下,它會在AP模式下打開自己的Wi-Fi,因為Wi-Fi客戶端參數可能無效并且僅為配置網頁提供服務。
您現在可以將移動智能手機連接到此單獨的Wi-Fi,訪問配置網頁并執行應用程序的初始配置。稍后,一旦Wi-Fi客戶端參數正確并且應用程序可以連接到您的家庭Wi-Fi,您仍然可以通過家庭Wi-Fi訪問配置網頁以及應用程序從本地DHCP服務器接收的地址。
以下是處理上述輸入文件( ConfigDataStructure )并創建C文件 configuration.h 和 configuration.c 《的Python代碼。 i》。
from Cheetah.Template import Template
from ConfigDataStructure import configItems, magic, appName
confWifiSsid = “espconfig”
params = {
“magic”:magic,
“appName”:appName,
“confWifiSsid”:confWifiSsid,
“configItems”:configItems
}
h_file = Template(file=“configuration_h.tmpl”, searchList=[params])
open(‘configuration.h’,‘w’).write(str(h_file))
c_file = Template(file=“configuration_c.tmpl”, searchList=[params])
open(‘configuration.cpp’,‘w’).write(str(c_file))
configuration.h包含帶有配置數據的struct的typedef,configuration.c包含配置結構的實例化,生成的帶有表單的網頁,以及處理從表格傳送的輸入信息用于將其存儲在EEPROM中。
應用程序代碼
在應用程序代碼中,配置struct variable configBlock可用于訪問配置。
static void mqttReconnect() {
uint32_t currentMillis = millis();
static uint32_t lastMillis = 0;
// Loop until we‘re reconnected
if (!mqttClient.connected() && (currentMillis 》 (lastMillis + RECONNECT_DELAY))) {
lastMillis = currentMillis;
#ifdef DEBUG
Serial.print(“Attempting MQTT connection.。.”);
#endif
// Attempt to connect
//char clientId[128];
//snprintf(clientId, 127, “esp%s”, WiFi.macAddress().c_str());
if (mqttClient.connect(configBlock.mqttClientId, configBlock.mqttUser, configBlock.mqttPass)) {
#ifdef DEBUG
Serial.println(“connected”);
#endif
mqttClient.setCallback(callback);
// Once connected, publish an announcement.。.
mqttClient.publish(configBlock.mqttDebugTopic, “hello world”);
mqttClient.publish(configBlock.mqttDebugTopic, WiFi.localIP().toString().c_str());
subscribeApplication();
} else {
#ifdef DEBUG
Serial.print(“failed, rc=”);
Serial.print(mqttClient.state());
Serial.println(“ try again in 5 seconds”);
#endif
}
}
}
void mqttSetup() {
mqttClient.setServer(configBlock.mqttBroker, configBlock.mqttPort);
}
void mqttLoop() {
if (!mqttClient.connected()) {
mqttReconnect();
} else {
mqttClient.loop();
}
}
Gitlab上提供了該系統的所有代碼,包括配置示例,模板和代碼生成器。我在Gitlab頁面上的幾個項目中使用了這段代碼。
此應用程序的后續步驟
這方法一直讓我高興。但是,我正在努力重構整個應用程序結構,以提取所有ESP8266和MQTT樣板代碼,以便能夠將其作為子項目包含。
-
ESP8266
+關注
關注
50文章
962瀏覽量
45374
發布評論請先 登錄
相關推薦
評論