授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力。希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石。。。
共同学习成长QQ群
622368884
,不喜勿加,里面有一大群志同道合的探路人
快速导航
单片机菜鸟的博客快速索引(快速找到你要的)
重点说一下,麻烦三连点赞,你的点赞是博主创作的前进动力
。
从本篇开始,博主将陆续更新多篇关于小程序对接物联网平台以及ESP8266的文章,敬请期待。
这里就开始我们的第一个小程序,群主叫它“IOT菜鸟
”。
对于阿里云物联网(要求至少要会创建产品、创建设备、创建AccessKey,这些都是非常简单的,跟着博主思路去创建即可
)不了解的同学,可以先去查看官方文档或者阅读博主发布过的文章:
因为涉及到小程序的使用,博主会把学习者区分为:
由于目前尚未审核通过,需要的读者可以私信博哥获取体验者权限或者点赞留言邮箱,博哥私发小程序源码,一键导入小程序开发者工具即可。
Android
、IOS App
的双端困扰,学习成本
和难度比App开发低,非常适合IOT学习者
;展示如何和物联网平台对接
功能,初学者可以在学习demo之后发挥自己的创造力去创造更多好玩的小程序,麻雀虽小五脏俱全,博哥只是抛砖引玉;第一个版本的IOT菜鸟小程序非常简单,就只有三个界面:
阿里云物联网配置也非常简单,请按照下面的图示进行创建即可。
首先,在阿里云物联网上直接创建一个产品,博主这里暂且命名为“LED小程序”
智能城市/智能楼宇/灯光设备
”创建完产品后,点击查看产品,点击功能定义,新增一个物模型:
第一步就完成了。
这一步我们我们会获取到:ProductKey
为了方便测试,博主这里创建了多个设备,读者按照自己的需求去创建:
填写备注名称的时候请在最后面加上以下标识(目的是为了显示不一样的灯图片
)中的一个:
举个例子,比如你想在小程序显示名称为“大厅灯
”,那么,你可以填写为“大厅灯_led2
” 。
记住,备注名称一定要写。
这一步我们会得到:DeviceName
、DeviceSecret
,web配置ESP8266的时候需要用到。
在个人头像里面有一个AccessKey管理,点击创建一个即可。
这一步,会得到:AccessKeyId
和 AccessKeySecret
接下来,我们就可以配置小程序了,非常简单,请按照图示填入参数配置:
确定保存成功之后,会自动返回上一个页面。以下是博主的正常显示界面。
控制界面,会显示4类设备,只有在线设备可以正常控制,并且支持下拉刷新。
ESP8266的代码,博主基于 ESP8266开发之旅 阿里云物联网平台篇⑥ LED智能灯控制系统 全面讲解,上手一个小项目(MQTT客户端直连 + Web配网 + WebSocket局域网通信)
做了些许改动。
/**
* 功能: LED智能灯控制系统 设备端1
* 作者: 单片机菜鸟哥
* 时间: 2020-05-02
* 通信方式:MQTT客户端直连 + Web配网,通过小程序控制
*/
#include
#include
#include
#include
#include
//for LED status
#include
#include
#include // https://github.com/tzapu/WiFiManager
#include "utils_hmac.h"
#include
#define DEBUG //是否开启debug功能
#ifdef DEBUG
#define DebugBegin(b) Serial.begin(b)
#define DebugPrintln(message) Serial.println(message)
#define DebugPrint(message) Serial.print(message)
#else
#define DebugBegin(b)
#define DebugPrintln(message)
#define DebugPrint(message)
#endif
const char yellowWifi[] PROGMEM = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4wEJAi4oIVrQDgAADLpJREFUeNrtmntwXNV9xz/n3rsPaVdvrSxvjEEYXMu2AnYVmxo6OCG4U7vgKaS4neCaOonbMbhkAhkwLdS4JRmcqZOSMJNpoUAS2inuZBJ7poUyQyApxNYMmNgIV7IiySroga3XarWve+85/ePc1a4eu5ZdO5sM+ml2dnXPvXt+v+/5nu/5nfNb0XsQxcfYjFI7UGpbAKDUDpTaFgAotQOltgUASu1AqW0BgFI7UGpbAKDUDpTaPvYAWL+qjpQC5b0LAWJme37bHO2/sQBIpQPzWxD0gSHAdsGVMxwxwTL09ZSt7zE8MH4jAVBKB1/u18EPjsObp+EXfdA/CmNJHWD23poQRKth7ZWwaglEKiDtQDJzeYG4LAC4EgIWlPnhxP/Cj96Btm4YGNNtpqGDyh5ECO8ZqeBffg5LauFTV8Mdvw3NUZhMa0aYl0GxxKU+EHElVJbpYJ95A15th3hKM8Fn6pFUBXrMtmUcSNpQVQa//0n44s2aIROpSw/CJQXAlVBdDj85Bd/4T/hwRINhGjktmJdTQjPElRBLwrIG+OpmuOEaGE9cWhAuGICsWs8MRgE15fDiz+Fbr2gny3zgyAv59tlmGZDI6M+P3AZb18Lo5GxNuNjVY94aoAApNY2D/umjIJVW+GffgIOvQDigR/D/Gzzo7yjz6/e//bG+dtc6PUWMvGhdqa85F6gV82KAVGAKCAfh7ASc6of/GYCRuG43hO781fe8/435032WQ0JgGDoCKXMIZgG1DPjsKr2yZPOGSKVgZVSwvFFSU66YSGmfjXnQ4bwAZEc348D334SXT0L/GLgu0x4UaIAEXLSomKZJJuMy6VE8EJgJjg46nspbQQQ4DigXmpfCHetMPtfqYhja5/OBUHQKZIMfGIO/+SEc74OQX7/mWpddWTx4IQSqADUMw2BszCUSCXLXXVtYt24dixcvRszRUZbiSikMw2B8fJx33/0F33vx39h/aJxjvzR5bKtLdbnOJYqBUJABSumOkjbc+wJ0DEJd2EAiPBFUSClnUTbrVNbxfBpLqTBNY9q1bPCxmORP/vg27v/y/SxeulQ74LqFPTeMnKOWBYbB6EA/j/31I/zg0M/47PUm39immSBVYXEsyACpoMIP33wFTg1ApEIQi0tsW7cHAhAMGqTTklRKO1pWBn6/QSIhyXjKHQyCaWqahkIWsZhDeXneaJomY2Muu3dv5+HHH4d0WqutbiwYfyaRQAiBZVlMxmKEQiFqamr59tPfZWLi8/zo5Xf5wVKT3Z9xGSuydM7JAKUg4IOes7DrnwEhsG1FS0sz0WgUgJ6eHtrbu1m2LEpzczMA7e3tdHcPsm7dapqamhBC8P7773PmzBmefPJJWlpaOHToEN/5zj8SCAiEECQSkrVrV/LSSy8hpWR4eJjjx49PsWouc12X9evXY5ome/fu5b333mPbtm3s2rULy+fjdGcHd975R6Acnv2i4BPViowz97SdkwFS6VT2tfchloK6CoPxcZfW1lYe/vrXQSneOHKErVt3s2/fdv50z18C8MJT/8Ce+w9w9913c9vdOwCDh/7iCwgh+L27dgJpdu2q4fnnnyeVyuD3m9i2ZMeOHYhAADOToa+vj507v0IgkFP5aSMmIJGA1177d5LJJM+9+DoBAbHYP3HPPfdg2zbXtnySTbd+hme/91+0f2iwLOKSsvVKNmsmzUkLLwvrPacFREqF3w9vvfUW6aGPYGKCqqoqQiE0IyZiMD5Gc3MzFSGoq6uD2Cj2uQG6u7s5efI03/67h2l79T/46oMPMjGRwbIMHMchHIZly5ah0mkwDAzDIByGigqLUEjg8zHrFQxCIpFgbWsrX9v3JbZsWcOBAwcoD4W0yErJpk2bMC3oGFBFhXlOBgj05mN0MpvGSgIBTfue3h5WXHcdNTU1NDT4aWho0KyRkkWLFhGJ+AiHwxAM8kF3N50dndTWltPb28vg4CCJZBKfT4uo40BtbSX19fW4rotl5dxJJBxWrLia/fv3Y9v2tNVAKcXy5csZGxmhqamJaDRKWVkZruPoqeM4XHVVE+EQ9I9KXFl4N1l0GVR5HyxLi1V3dzcrrr+euro6brzxRqLRKK5t47ouixYtYsOGDUQiERCCzs5OBoccbrrpGv7+6achUEFH23+zZcsdWJbOGCzLwrKsWcuj40BVVRVrNm4GUuR0XEAmAbbNiXfe4d57HyEeh5tvvoYfHzlCJpMBpRCGwDQMlJIXzoCCgCg4ceIEm++8E4Dl1y6nvr6eU6dOoZRiZUsLq1atotyT+WPHjiGlFq3J4WFC4TRjY2PTRmOuvEApTfWPPvqIQ888heM4er4aBul0mpaWFtbccAOmaVJXZxEMOlRXV89KP7PkL5YLzX8voBQ+H7z99tuQTGJZFrdvvR2CQbq6unBdl5Wtraxfv15TOZ2mu7ubLKtN0wTTLKru+QAEgwZ9fR/ywAP7cs5aMDwCjz26kzUbb8F1Xe+lQc63+W6KzgtAFlOlFIEAdHV10dPTQ1NTE42NjWBZtLW1aS0wDFavXk0gEGDggw/o6Ojw1LwwCUWByamUwjSZljNYliCZVPh8Ps6XcM83HS+uAXkZlGaAychIhq6uLppW/BZOPA6OQ39/PwP9/eA4OI5DsKKCzs5OhoZiU4JXuA81q90wIJ1WNDcv44knniCTySCEzhscx9HAJ+KaVYWA9f4UqujGrCAAQuR2XPkmpU54bt28Wae0qRRnz57Ftm1kIqGvCcGxo0dxHPIU3wHXnZYGKwV+v3+aCOrsDjIZqKyspGX9ep0d5jnmptPgOAghME0T03Smg+EB5UqJ3yy+FyiYCPktfTA5tYR4+b9lQVtbGwSDVEajxAcHGRoaIp3WAld75ZVgmHSePo1pasBM0yRcWwtllVRUVHgJjsBxoKGhgcrKSpLJ5JTjw8Ng2zA6OoqMx0mn07OWwTK/H9d1GR11mJiAWCw21YYQJJMJkim4ukFgGh4L5psJZm31EjhyfDpdg0E4ffo0jz/4IOXl5QwMDDA+rg8G9u/fTzQaxbZt2tvbCQQ0eENDQzz60EP4fD6GhoawLA1AJgMbN26EYBCVSCAzGa644goOHvwrpJREIhGklLOorpTCzWRobGzkwIFHsW2bxsZGXMfRDAsGef31N7AzsCJqIJVbUBTn3gugE6BEGnY+A+cmwJc3HaSEeDy3EQuFdEDxuE5uhIBwOLdhm3l/RYWB40jKy4McPnyYaDSq12/AsizMcFg/6DhkJifndFyz0cLUnYPjEB8dJVxTQ39vD5tvu4Nq3yTPfkngM1XBHWHhTNCB+jB8fgN87TDU+cD1qjuGATU1uVFxXRelFJWVuWvZrTGAaQpqaoxpzp87BwcO3McnrrqK+Ojo1Cin02ncRMKbyqKo0OXf6/P5CDc0cPZML3vuu5cPBibZu9OgqkwSSxbeDRacAqahj6E/9ynoGoJ/PQp1Yb2hkGr2upsFotBoZdsMwyCZlOzd+wX+7MtfgVSCcH39RVY+1NR6lxwd4Yfff4FvfuspTnaM8MDtJp9uds97lF70SCyrGz4TnvuZPhJLZvRW2W8yi1MCDU7BzoTAcRSRSC3bt2+fAi17UjTzoGTW84BSEpm3Yriuy+DAIEfb3uH4yQ+J1MB9m0y2rXNJO7kYLgoAPXrenA7CSa/Kc7wXhmKzg3WlLoDI82QhSoEn2kULJdPB04EkMzltyZplQFMj/O4qkz+4TrJisWIiqSM/H6/mXRdwJZQHwGfAyCT0DXsFTqFFrtwPr5yEF97U9YFs/aCQFZvbMy1bRoslYfctsOHaXM1QKc3QJbWSqjKF7eg6wnyPxue9FzAN3WnCOyhdvWT2CXBzVK8Wz/0UQgFd8XULsNotdt43o9+UrQ8399wKO27SZ/9TI+j5kHZ01UiIC6sLXNBu0BC6R1flqjVT5k2VPbfC0jo4+LIesYogUyyZrwlytYXxBNSGYd8fwqbVMJ4s8MwFBj713KUujkqvONo5CN/9Cfy0Q18v8+u5CrkfS8wMOrsQOG6OxreshD//NFxZT9Hl7GLtkgMAOTEEOPpLOHxcl8cnkrmRMvJGLFsadySgoDoEv3MN3L4GWpu8stcFzOuSAwC5s/hQQI9215Aup717BvpGdJYZ8wCpLNOANUXguiu0llzdoL9j0tsHzafM9WsFQD4QoIUzYGn9sB0tbCmvxlDm121+SwOS9kTvcgaetcv+G6FsAGlb0zi7nlsmVHq9S6nreGnbS7XF5Q/8VwZA1oSYfi6vFDgeO7ICeLl/EFVSAOYEpZSde/ax/6HkAgCldqDUtgBAqR0otS0AUGoHSm0LAJTagVLbAgCldqDU9n+vbbJY13ln1QAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxOS0wMS0wOVQwMjo0Njo0MCswODowMELuAxIAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTktMDEtMDlUMDI6NDY6NDArMDg6MDAzs7uuAAAAQ3RFWHRzb2Z0d2FyZQAvdXNyL2xvY2FsL2ltYWdlbWFnaWNrL3NoYXJlL2RvYy9JbWFnZU1hZ2ljay03Ly9pbmRleC5odG1svbV5CgAAABh0RVh0VGh1bWI6OkRvY3VtZW50OjpQYWdlcwAxp/+7LwAAABh0RVh0VGh1bWI6OkltYWdlOjpIZWlnaHQANTEyj41TgQAAABd0RVh0VGh1bWI6OkltYWdlOjpXaWR0aAA1MTIcfAPcAAAAGXRFWHRUaHVtYjo6TWltZXR5cGUAaW1hZ2UvcG5nP7JWTgAAABd0RVh0VGh1bWI6Ok1UaW1lADE1NDY5NzMyMDBYBo4+AAAAEnRFWHRUaHVtYjo6U2l6ZQAzMjE5MUJVXU35AAAAYnRFWHRUaHVtYjo6VVJJAGZpbGU6Ly8vaG9tZS93d3dyb290L25ld3NpdGUvd3d3LmVhc3lpY29uLm5ldC9jZG4taW1nLmVhc3lpY29uLmNuL2ZpbGVzLzExMi8xMTIzMjIxLnBuZ7vHiF8AAAAASUVORK5CYII=";
/******************产品/设备配置(每个人需要根据自己的产品设备信息去动态更换)**********************/
#define REGION_ID "cn-shanghai" //地域 填写自己的
#define PRODUCT_KEY "a1bXlwV5MSn" //产品key 从产品详情获取
// 服务端相关
#define MQTT_SERVER PRODUCT_KEY ".iot-as-mqtt." REGION_ID ".aliyuncs.com" //阿里云MQTT服务地址
#define MQTT_PORT 1883 //MQTT服务端口
#define HTTPS_SERVER "iot-auth." REGION_ID ".aliyuncs.com" //认证地址
#define HTTPS_PORT 443
// 相关主题
#define TOPIC_SET_PROPERTY "/sys/" PRODUCT_KEY "/{dName}/thing/service/property/set"
/*************************************************************************************************/
static char MQTT_CLIENT_ID[50]; // Mqtt ClientID
static char MQTT_USERNAME[40]; // Mqtt UserName
static char MQTT_PASSWORD[50]; // Mqtt Psw
static char MQTT_TOPIC_STATUS[100];
#define CONFIG_NUMBER 0xAA
#define NOCONFIG_NUMBER 0x00
void initWifiManager();
void saveConfigCallback();
void configModeCallback (WiFiManager *myWiFiManager);
void doWiFiTick();
void connectToMqtt();
bool connectHTTPS();
bool loadROOTcert();
void deviceAuthen();
void sendHTTPSrequest();
void readHTTPSreponse();
void mqtt_callback (char* topic, byte* payload, unsigned int length);
void parseMqttResponse(char* payload);
String charToString(char *src,int len);
void onButtonClick();
// 结构体 存储到eeprom
struct device_config{
char deviceName[40]; //设备deviceName 从设备详情获取
char deviceSecret[40]; //对应的设备秘钥
char ssid[20];
char psw[20];
uint8_t magic;
} config;
// https
WiFiClientSecure client_s;
// mqtt
PubSubClient mqttclient(MQTT_SERVER, MQTT_PORT, &mqtt_callback, client_s);
//flag for saving data
bool shouldSaveConfig = false;
int state = 0;
//for LED status
Ticker ticker;
#define buttonPin D4
OneButton button(buttonPin, true);
void setup() {
// put your setup code here, to run once:
delay(2000);
DebugBegin(115200);
pinMode(LED_BUILTIN, OUTPUT);
button.attachDoubleClick(onButtonClick);
digitalWrite(LED_BUILTIN, state);
WiFi.disconnect();
loadConfig();
initWifiManager();
client_s.setInsecure();
}
void loop() {
// put your main code here, to run repeatedly:
ESP.wdtFeed();
button.tick();
doWiFiTick();
if (WiFi.status() == WL_CONNECTED) {
connectToMqtt();
mqttclient.loop();
}
}
/**
* 功能描述:初始化wifimanager
*/
void initWifiManager(){
/*** 步骤一:创建 wifimanager对象 **/
WiFiManager wifiManager;
/*************************************/
/*** 步骤二:进行一系列配置,参考配置类方法 **/
// 打印调试内容
#ifdef DEBUG
wifiManager.setDebugOutput(true);
#endif
// 设置个人图标 大叔黄
wifiManager.setHeadImgBase64(FPSTR(yellowWifi));
wifiManager.setButtonBackground("#E08E00");
// 设置最小信号强度
wifiManager.setMinimumSignalQuality(40);
// 设置固定AP信息
IPAddress _ip = IPAddress(192, 168, 4, 1);
IPAddress _gw = IPAddress(192, 168, 4, 1);
IPAddress _sn = IPAddress(255, 255, 255, 0);
wifiManager.setAPStaticIPConfig(_ip, _gw, _sn);
// 设置进入AP模式的回调
wifiManager.setAPCallback(configModeCallback);
wifiManager.setConnectTimeout(5);
// 设置点击保存的回调
wifiManager.setSaveConfigCallback(saveConfigCallback);
// 设置 如果配置错误的ssid或者密码 退出配置模式
wifiManager.setBreakAfterConfig(true);
// 添加额外的参数 设备名字 设备秘钥
WiFiManagerParameter custom_device_name("dn", "DeviceName", config.deviceName, 40);
WiFiManagerParameter custom_device_secret("ds", "DeviceSecret", config.deviceSecret, 40);
if (config.magic == CONFIG_NUMBER){
wifiManager.setSSID(config.ssid);
wifiManager.setPassword(config.psw);
}
wifiManager.addParameter(&custom_device_name);
wifiManager.addParameter(&custom_device_secret);
/*************************************/
/*** 步骤三:尝试连接网络,失败去到配置页面 **/
String mac = WiFi.macAddress();
mac.replace(":","");
String ssid = String("ESP") + "-" + mac;
if (!wifiManager.autoConnect(ssid.c_str(),"12345678")) {
DebugPrintln("failed to connect and hit timeout");
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(1000);
}
/*************************************/
// 保存自定义信息
if (shouldSaveConfig) {
// 读取配置页面配置好的信息
strcpy(config.deviceName, custom_device_name.getValue());
strcpy(config.deviceSecret, custom_device_secret.getValue());
strcpy(config.ssid, wifiManager.getSSID().c_str());
strcpy(config.psw, wifiManager.getPassword().c_str());
saveConfig();
#ifdef DEBUG
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
json["ssid"] = config.ssid;
json["psw"] = config.psw;
json["device_name"] = config.deviceName;
json["device_secret"] = config.deviceSecret;
json.printTo(Serial);
DebugPrintln("");
#endif
}
String topicSetProperty = TOPIC_SET_PROPERTY;
// deviceName placeholder替换
topicSetProperty.replace("{dName}",config.deviceName);
strcpy(TOPIC_SET_PROPERTY, topicSetProperty.c_str());
DebugPrint(F("topicSetProperty:"));
DebugPrintln(topicSetProperty);
DebugPrintln(F("local ip"));
DebugPrintln(WiFi.localIP());
// 我们在loop里面去做检测
WiFi.disconnect();
ticker.detach();
}
/**
* 功能描述:配置进入AP模式通知回调
*/
void configModeCallback (WiFiManager *myWiFiManager) {
DebugPrintln(F("Entered config mode"));
DebugPrintln(WiFi.softAPIP());
// if you used auto generated SSID, print it
DebugPrintln(myWiFiManager->getConfigPortalSSID());
// entered config mode, make led toggle faster
ticker.attach(0.2, tick);
}
/**
* 功能描述:设置点击保存的回调
*/
void saveConfigCallback () {
DebugPrintln(F("Should save config"));
shouldSaveConfig = true;
}
/**
* 功能描述:设置LED灯闪烁,提示用户进入配置模式
*/
void tick(){
//toggle state
int state = digitalRead(BUILTIN_LED); // get the current state of GPIO1 pin
digitalWrite(BUILTIN_LED, !state); // set pin to the opposite state
}
/**
* 功能:连接路由心跳函数
*/
void doWiFiTick() {
static bool taskStarted = false;
static bool startSTAFlag = false;
static uint32_t lastWiFiCheckTick = 0;
if (!startSTAFlag) {
startSTAFlag = true;
DebugPrint("connect to ap:");
DebugPrintln(config.ssid);
WiFi.disconnect();
WiFi.mode(WIFI_STA);
WiFi.begin(config.ssid, config.psw);
}
//未连接1s重连
if ( WiFi.status() != WL_CONNECTED ) {
if (millis() - lastWiFiCheckTick > 1000) {
lastWiFiCheckTick = millis();
DebugPrint(".");
}
}
//连接成功建立
else {
if (taskStarted == false) {
taskStarted = true;
DebugPrint("\r\nGet IP Address: ");
DebugPrintln(WiFi.localIP());
deviceAuthen();
}
}
}
/**
* 生成 HmacSha1
* @param sign HmacSha1字符串
*/
static ICACHE_FLASH_ATTR char* parseHmacSha1(char *sign) {//
String chipidStr = String(ESP.getChipId(), HEX);//"ef63aa";
String clientIDStr = String(PRODUCT_KEY) + "." + chipidStr;
char *hmac_source;//[120];
strcpy(MQTT_CLIENT_ID, clientIDStr.c_str());
String str = "clientId" + clientIDStr + "deviceName" + config.deviceName + "productKey" + PRODUCT_KEY;
uint8_t str_len = str.length() + 1;
hmac_source = (char*)malloc(str_len * sizeof(char));
memcpy(hmac_source, str.c_str(), str_len);
DebugPrint(F("hmac_source: "));
DebugPrintln(hmac_source);
utils_hmac_sha1(hmac_source, strlen(hmac_source), sign, config.deviceSecret, strlen(config.deviceSecret));
DebugPrint(F("signature: "));
DebugPrintln(sign);
free(hmac_source);
return sign;
}
/***
* 发送验证请求
*/
void ICACHE_FLASH_ATTR sendHTTPSrequest() {
DebugPrintln(F("sendHTTPSrequest"));
char signature[40];
parseHmacSha1(signature);
String signatureStr = charToString(signature,40);
DebugPrint(F("signatureStr: "));
DebugPrintln(signatureStr);
String str = String("productKey=") + PRODUCT_KEY + "&deviceName=" + config.deviceName + "&signmethod=hmacsha1&sign=" + signatureStr +
"&version=default&clientId=" + MQTT_CLIENT_ID + "&resources=mqtt";
String str1 = (String("POST ") + "/auth/devicename HTTP/1.1\r\nHost: " + HTTPS_SERVER + "\r\n" +
"Accept: text/xml,text/javascript,text/html,application/json\r\nContent-Type: application/x-www-form-urlencoded\r\n" +
"Content-Length: " + str.length() + "\r\n\r\n");
client_s.print(str1);
DebugPrint(str1);
client_s.print(str);
DebugPrintln(str);
DebugPrint(F("request sent!"));
delay(100);
}
/**
* 处理认证请求
*/
void ICACHE_FLASH_ATTR readHTTPSreponse() {
DebugPrintln(F("readHTTPSreponse"));
while (client_s.connected()) {
String line = client_s.readStringUntil('\n');
if (line == "\r") {
DebugPrintln(F("=========="));
break;
}
}
String resstring = client_s.readStringUntil('\n');
DebugPrint(F("receiving: "));
DebugPrintln(resstring);
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(resstring);
// Test if parsing succeeds.
if (!root.success()) {
DebugPrintln("parse failed");
return;
} else {
#ifdef DEBUG
// 格式化打印json
root.prettyPrintTo(Serial);
#endif
DebugPrintln(F("parse success"));
}
strcpy(MQTT_USERNAME, root["data"]["iotId"]);
strcpy(MQTT_PASSWORD, root["data"]["iotToken"]);
DebugPrint(F("MQTT_CLIENT_ID: "));
DebugPrintln(MQTT_CLIENT_ID);
DebugPrint(F("MQTT_USERNAME: "));
DebugPrintln(MQTT_USERNAME);
DebugPrint(F("MQTT_PASSWORD: "));
DebugPrintln(MQTT_PASSWORD);
DebugPrintln(F("=========="));
client_s.stop();
}
/*
* 设备认证
*/
void deviceAuthen() {
while (loadROOTcert()) {
while (connectHTTPS()) {
sendHTTPSrequest();
readHTTPSreponse();
return;
}
ESP.wdtFeed();
}
}
/*
* 连接到远程服务器并且获取状态
*/
bool ICACHE_FLASH_ATTR connectHTTPS() {
DebugPrint(F("connecting to "));
DebugPrintln(HTTPS_SERVER);
if (!client_s.connect(HTTPS_SERVER, HTTPS_PORT)) {
DebugPrintln(F("connection failed"));
return false;
}else {
DebugPrintln(F("connection succeed"));
return true;
}
}
/*
* 设置根证书并且返回状态
*/
bool ICACHE_FLASH_ATTR loadROOTcert() {
return true;
}
void connectToMqtt() {
if (mqttclient.connected()) {
return;
}
DebugPrint(F("Connecting to MQTT... "));
int8_t ret;
uint8_t retries = 3;
while (!mqttclient.connect(MQTT_CLIENT_ID, MQTT_USERNAME,MQTT_PASSWORD)) { // connect will return true for connected
DebugPrintln(F("Retrying MQTT connection in 5 seconds..."));
mqttclient.disconnect();
delay(5000); // wait 5 seconds
retries--;
if (retries == 0) {
// basically die and wait for WDT to reset me
while (1);
}
yield();
}
DebugPrint(F("Connect MQTT Success!"));
// 订阅主题
mqttclient.subscribe(TOPIC_SET_PROPERTY);
}
/**
* 解析mqtt数据
*/
void parseMqttResponse(char* payload){
DebugPrintln(F("parseMqttResponse"));
StaticJsonBuffer<300> jsonBuffer;
// StaticJsonBuffer 在栈区分配内存 它也可以被 DynamicJsonBuffer(内存在堆区分配) 代替
// DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(payload);
// Test if parsing succeeds.
if (!root.success()) {
DebugPrintln(F("parse failed"));
return ;
} else {
#ifdef DEBUG
// 格式化打印json
root.prettyPrintTo(Serial);
#endif
DebugPrintln(F("parse success"));
}
if (root.containsKey("params")){
JsonObject ¶ms = root["params"];
if (params.containsKey("status")) {
state = !state;
digitalWrite(LED_BUILTIN, state);
}
}
}
/*
* 保存参数到EEPROM
*/
void saveConfig(){
DebugPrintln(F("-----Save config To EEPROM!-----"));
EEPROM.begin(300);
config.magic = CONFIG_NUMBER;
uint8_t *p = (uint8_t*)(&config);
for (int i = 0; i < sizeof(config); i++){
EEPROM.write(i, *(p + i));
}
EEPROM.commit();
DebugPrintln(F("--------- Save End ----------"));
}
/*
* 从EEPROM加载参数
*/
void loadConfig(){
DebugPrintln(F("-----Read config From EEPROM!-----"));
EEPROM.begin(300);
uint8_t *p = (uint8_t*)(&config);
for (int i = 0; i < sizeof(config); i++){
*(p + i) = EEPROM.read(i);
}
EEPROM.commit();
if (config.magic == CONFIG_NUMBER){
DebugPrint(F("deviceName:"));
DebugPrintln(config.deviceName);
DebugPrint(F("deviceSecret:"));
DebugPrintln(config.deviceSecret);
DebugPrint(F("ssid:"));
DebugPrintln(config.ssid);
DebugPrint(F("psw:"));
DebugPrintln(config.psw);
} else{
DebugPrintln(F("Has No config"));
config.magic == NOCONFIG_NUMBER;
memset(config.deviceName, 0, 40);
memset(config.deviceSecret, 0, 40);
memset(config.ssid, 0, 40);
memset(config.psw, 0, 40);
}
DebugPrintln(F("------------- Read End --------------"));
}
/**
* 数组转字符串
*/
String charToString(char *src,int len){
String str = "";
for (byte i = 0 ; i < len; i++) {
str += src[i];
}
return str;
}
// 重置
void onButtonClick() {
DebugPrintln(F("Button click."));
config.magic = NOCONFIG_NUMBER;
memset(config.deviceName, 0, 40);
memset(config.deviceSecret, 0, 40);
memset(config.ssid, 0, 40);
memset(config.psw, 0, 40);
saveConfig();
ESP.reset();
delay(1000);
} // click1
/**
* 功能:MQTT回调
* 参数:
* 1. topic 主题
* 2. payload 载体
* 3. length 载体长度
*/
void mqtt_callback (char* topic, byte* payload, unsigned int length) {
parseMqttResponse((char *)payload);
}
注意点:
#define REGION_ID "xxxx" //地域 填写自己
#define PRODUCT_KEY "xxxx" //产品key 从产品详情获取
完整代码:
把以上代码烧录进ESP8266之后,请自行进行web配网,之后就可以愉快地玩耍了。
需要小程序源码的,麻烦点赞评价留下自己的邮箱地址。创作不易,请点赞支持。