• 1
  • 2
  • 3
  • 4

首页 / 行业

如何使用Cheetah模板为ESP8266构建配置系统

2019-07-26 11:04:00

如何使用Cheetah模板为ESP8266构建配置系统

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样板代码,以便能够将其作为子项目包含。

系统模板配置物联网

  • 1
  • 2
  • 3
  • 4

最新内容

手机

相关内容

  • 1
  • 2
  • 3

猜你喜欢