ESP8266的上訴
過(guò)去,我做過(guò)幾個(gè)基于Arduino的項(xiàng)目,通常是網(wǎng)絡(luò)連接,主要是在各種物聯(lián)網(wǎng)中。自從幾年前引入ESP8266模塊以來(lái),我更頻繁地使用這些電路板有四個(gè)主要原因:
集成Wi-Fi
緊湊尺寸
經(jīng)濟(jì)實(shí)惠
以Arduino為中心的開(kāi)發(fā)環(huán)境
我使用ESP8266實(shí)現(xiàn)的所有應(yīng)用程序的通用是需要一些配置,包括Wi-Fi連接數(shù)據(jù),應(yīng)用程序的管理員憑據(jù),在大多數(shù)情況下是MQTT代理的地址和用于接收命令的一些MQTT主題,以及發(fā)布狀態(tài)或測(cè)量數(shù)據(jù)。
對(duì)通用配置系統(tǒng)的需求
對(duì)于我的前幾個(gè)項(xiàng)目,所有這些配置都是硬編碼的,因?yàn)闃?gòu)建只需要在我自己的房子里工作。但很快我不得不重新配置Wi-Fi連接,因?yàn)槌鲇诎踩紤],我決定將所有IoT設(shè)備移到一個(gè)單獨(dú)的子網(wǎng)中。
必須移動(dòng)每個(gè)設(shè)備,并且必須更改固件并將其下載到設(shè)備。然后我建造了多個(gè)小型溫度計(jì),ESP-01和DS18B20安裝在一個(gè)盒子上,用于兩個(gè)LR20電池,我放在房子的每個(gè)房間。顯然,來(lái)自不同設(shè)備的測(cè)量需要是可區(qū)分的。因此,它們要么使用設(shè)備所在的房間來(lái)注釋測(cè)量值,要么使用包含有關(guān)位置信息的不同MQTT主題。
對(duì)于硬編碼配置,我不得不反復(fù)修改每個(gè)設(shè)備的固件。這種持續(xù)的修改是當(dāng)我對(duì)硬編碼方法不滿意并尋求引入動(dòng)態(tài)配置系統(tǒng)的方法時(shí)。
我的第一種方法是硬編碼配置結(jié)構(gòu),一個(gè)帶有表單反映的小網(wǎng)頁(yè)這個(gè)配置結(jié)構(gòu)和一些代碼用于解析通過(guò)表單傳遞的數(shù)據(jù),將其放入結(jié)構(gòu)并將其存儲(chǔ)在ESP8266的EEPROM中。
但是,這種方法對(duì)我嘗試的下一個(gè)設(shè)備不起作用修改。該設(shè)備包含D1 Mini模塊和兩個(gè)紅/綠LED。它放在我的前門,顯示房子里的所有窗戶是否都關(guān)閉(紅燈:一些窗戶打開(kāi),綠燈:所有窗戶都關(guān)閉),這也需要一些配置 - 事實(shí)上不同的配置。因此,配置不再是硬編碼,而是具有結(jié)構(gòu)的系統(tǒng)。再次,另一個(gè)問(wèn)題。
獵豹模板
在我的“日常工作”中那時(shí)候,我正在研究一種基于模型的軟件開(kāi)發(fā)方法,其中代碼是從模型中的信息生成的,我記得幾年前我用過(guò)的Python包:獵豹模板。使用此模板引擎,您可以編寫(xiě)要獲取的文本,并將Python變量作為占位符放在每個(gè)位置,需要一些動(dòng)態(tài)文本:
tConfigBlock configBlock;
const uint32_t MAGIC = $magic;
const char* CONFIG_SSID = “$confWifiSsid”;
extern ESP8266WebServer webServer;
在這個(gè)小片段中,我有C變量(或?qū)嶋H上) ,在C代碼常量中)對(duì)于魔術(shù)值(或多或少是配置結(jié)構(gòu)的信息版本)和Wi-Fi網(wǎng)絡(luò)的SSID,ESP8266應(yīng)在AP模式下打開(kāi)以進(jìn)行初始配置。
必須處理此代碼段的模板引擎會(huì)將占位符$ magic和$ confWifiSsid替換為Python變量的內(nèi)容。
除了使用簡(jiǎn)單替換占位符之外,您可以做的不僅僅是獵豹:
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.)
有條件和循環(huán)。您可以迭代容器的項(xiàng)目,也可以根據(jù)條件插入文本。
這些是我在基于ESP8266/Arduino的應(yīng)用程序的通用配置系統(tǒng)中使用的Cheetah的主要功能:變量替換,循環(huán)和條件。
項(xiàng)目的輸入文件
讓我們看一下項(xiàng)目特定的輸入文件,它描述了實(shí)際項(xiàng)目的配置結(jié)構(gòu):
configItems = [
{“l(fā)abel”:“_”, “key”:“magic”, “type”:“I”, “default”: “”},
{“l(fā)abel”:“Config Username”, “key”:“confUser”, “type”:“C”, “l(fā)ength”:16, “default”:“admin”},
{“l(fā)abel”:“Config Password”, “key”:“confPasswd”, “type”:“C”, “l(fā)ength”:16, “default”:“geheim123”},
{“l(fā)abel”:“Wifi SSID”, “key”:“wifiSsid”, “type”:“C”, “l(fā)ength”:32, “default”:“test”},
{“l(fā)abel”:“Wifi Key”, “key”:“wifiKey”, “type”:“C”, “l(fā)ength”:64, “default”:“geheim”},
{“l(fā)abel”:“MQTT Broker”, “key”:“mqttBroker”, “type”:“C”, “l(fā)ength”:32, “default”:“broker.hottis.de”},
{“l(fā)abel”:“MQTT Username”, “key”:“mqttUser”, “type”:“C”, “l(fā)ength”:32, “default”:“RgbLed1”},
{“l(fā)abel”:“MQTT Password”, “key”:“mqttPass”, “type”:“C”, “l(fā)ength”:32, “default”:“geheim123”},
{“l(fā)abel”:“MQTT ClientId”, “key”:“mqttClientId”, “type”:“C”, “l(fā)ength”:32, “default”:“RgbLed1”},
{“l(fā)abel”:“MQTT Port”, “key”:“mqttPort”, “type”:“I”, “default”:8883},
{“l(fā)abel”:“MQTT Topic Color Command”, “key”:“mqttTopicColorCommand”, “type”:“C”, “l(fā)ength”:64, “default”:“IoT/RgbLed1/ColorCommand”},
{“l(fā)abel”:“MQTT Topic Command”, “key”:“mqttTopicCommand”, “type”:“C”, “l(fā)ength”:64, “default”:“IoT/RgbLed1/Command”},
{“l(fā)abel”:“MQTT DebugTopic”, “key”:“mqttDebugTopic”, “type”:“C”, “l(fā)ength”:64, “default”:“IoT/RgbLed1/Debug”},
{“l(fā)abel”:“DebugMode”, “key”:“debugMode”, “type”:“I”, “default”:0}
]
magic = 0xC0DE0006
appName = “ESP8266 based RgbLedLight”
這是另一個(gè)控制RGB LED的小型設(shè)備的輸入。
關(guān)于魔術(shù)的一個(gè)詞:每當(dāng)配置存儲(chǔ)在EEPROM中的幻數(shù)和生成到代碼中的幻數(shù)不同,固件 - 特別是配置的結(jié)構(gòu) - 已更新,存儲(chǔ)的配置無(wú)效。
在這種情況下,應(yīng)用程序不會(huì)以“生產(chǎn)模式”啟動(dòng),而是以“配置模式”啟動(dòng)。在配置模式下,它會(huì)在AP模式下打開(kāi)自己的Wi-Fi,因?yàn)閃i-Fi客戶端參數(shù)可能無(wú)效并且僅為配置網(wǎng)頁(yè)提供服務(wù)。
您現(xiàn)在可以將移動(dòng)智能手機(jī)連接到此單獨(dú)的Wi-Fi,訪問(wèn)配置網(wǎng)頁(yè)并執(zhí)行應(yīng)用程序的初始配置。稍后,一旦Wi-Fi客戶端參數(shù)正確并且應(yīng)用程序可以連接到您的家庭Wi-Fi,您仍然可以通過(guò)家庭Wi-Fi訪問(wèn)配置網(wǎng)頁(yè)以及應(yīng)用程序從本地DHCP服務(wù)器接收的地址。
以下是處理上述輸入文件( ConfigDataStructure )并創(chuàng)建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包含帶有配置數(shù)據(jù)的struct的typedef,configuration.c包含配置結(jié)構(gòu)的實(shí)例化,生成的帶有表單的網(wǎng)頁(yè),以及處理從表格傳送的輸入信息用于將其存儲(chǔ)在EEPROM中。
應(yīng)用程序代碼
在應(yīng)用程序代碼中,配置struct variable configBlock可用于訪問(wèn)配置。
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上提供了該系統(tǒng)的所有代碼,包括配置示例,模板和代碼生成器。我在Gitlab頁(yè)面上的幾個(gè)項(xiàng)目中使用了這段代碼。
此應(yīng)用程序的后續(xù)步驟
這方法一直讓我高興。但是,我正在努力重構(gòu)整個(gè)應(yīng)用程序結(jié)構(gòu),以提取所有ESP8266和MQTT樣板代碼,以便能夠?qū)⑵渥鳛樽禹?xiàng)目包含。
-
ESP8266
+關(guān)注
關(guān)注
51文章
965瀏覽量
47057
發(fā)布評(píng)論請(qǐng)先 登錄
評(píng)論