授人以鱼不如授人以渔, 目的不是为了教会你具体项目开发, 而是学会学习的能力. 希望大家分享给你周边需要的朋友或者同学, 说不定大神成长之路有博哥的奠基石...
QQ 技术互动交流群: ESP8266&32 物联网开发 群号 622368884, 不喜勿喷
一, 你如果想学基于 Arduino 的 ESP8266 开发技术
一, 基础篇
ESP8266 开发之旅 基础篇1 走进 ESP8266 的世界
ESP8266 开发之旅 基础篇2 如何安装 ESP8266 的 Arduino 开发环境
ESP8266 开发之旅 基础篇3 ESP8266 与 Arduino 的开发说明
ESP8266 开发之旅 基础篇4 ESP8266 与 EEPROM
ESP8266 开发之旅 基础篇5 ESP8266 SPI 通信和 I2C 通信
ESP8266 开发之旅 基础篇6 Ticker--ESP8266 定时库
二, 网络篇
ESP8266 开发之旅 网络篇1 认识一下 Arduino Core For ESP8266
ESP8266 开发之旅 网络篇2 ESP8266 工作模式与 ESP8266WiFi 库
ESP8266 开发之旅 网络篇3 Soft-AP--ESP8266WiFiAP 库的使用
ESP8266 开发之旅 网络篇4 Station--ESP8266WiFiSTA 库的使用
ESP8266 开发之旅 网络篇5 Scan Wi-Fi--ESP8266WiFiScan 库的使用
ESP8266 开发之旅 网络篇6 ESP8266WiFiGeneric-- 基础库
ESP8266 开发之旅 网络篇7 TCP Server & TCP Client
ESP8266 开发之旅 网络篇8 SmartConfig-- 一键配网
ESP8266 开发之旅 网络篇9 HttpClient--ESP8266HTTPClient 库的使用
ESP8266 开发之旅 网络篇10 UDP 服务
ESP8266 开发之旅 网络篇 webServer--ESP8266WebServer 库的使用
ESP8266 开发之旅 网络篇 域名服务 --ESP8266mDNS 库
ESP8266 开发之旅 网络篇 SPIFFS--ESP8266 Flash 文件系统
ESP8266 开发之旅 网络篇 Web 配网
ESP8266 开发之旅 网络篇 真正的域名服务 --DNSServer
ESP8266 开发之旅 网络篇 无线更新 --OTA 固件更新
三, 应用篇
ESP8266 开发之旅 应用篇1 局域网应用 -- 炫酷 RGB 彩灯
ESP8266 开发之旅 应用篇2 OLED 显示天气屏
ESP8266 开发之旅 应用篇3 简易版 Wi-Fi 小车
四, 高级篇
ESP8266 开发之旅 进阶篇1 代码优化 -- ESP8266 内存管理
ESP8266 开发之旅 进阶篇2 闲聊 Arduino IDE For ESP8266 配置
ESP8266 开发之旅 进阶篇3 闲聊 ESP8266 Flash
ESP8266 开发之旅 进阶篇4 常见问题 -- 解决困扰
ESP8266 开发之旅 进阶篇5 代码规范 -- 像写文章一样优美
ESP8266 开发之旅 进阶篇6 ESP-specific APIs 说明
1. 理论基础
参考博主线上博文:
玩转 PubSubClient MQTT 库
玩转 OneNET 物联网平台之简介
玩转 OneNET 物联网平台之 MQTT 服务1
玩转 OneNET 物联网平台之 MQTT 服务2
玩转 OneNET 物联网平台之 MQTT 服务3
在前面的博文中, 博主主要通过手动方式去创建设备. 这种方式的缺点明显:
人为手动控制, 对于开发者来说极度不友好;
如果设备数量很多, 岂不是要手动操作非常多次;
那么, 如何实现设备自注册呢? 所谓自注册就是设备连入网络后自动往 OneNet 云平台注册设备信息并获取设备 Id.
为了区分唯一性, 我们采用 ESP-Mac 地址的组合形式
同时为了操作方便, 博主花了个周末的时间做了一个对应的 App, 理论上不限制 ESP8266 接入点的数量
本篇博文的目的就在于教会大家如何和 App 通信, 完成 MQTT 协议下的 App 远程控制 LED 灯, 并且 LED 灯的数量可以随意接入, 用户可以在 App 端修改设备名字以便方便操作.
博主极度建议大家从第一篇看起, 有个大概了解, 因为本系列教程都是有相联系的
先上个概念图:
2. 远程控制 LED, 实现设备自注册
2.1 实验材料
ESP8266 NodeMcu
Android 手机
OneNet 平台
2.2 实验步骤
2.2.1 创建 ESP8266 智能灯系统 产品 (MQTT 协议)
注意点:
务必选择 MQTT 协议
创建完毕后, 我们点击查看具体的产品信息:
注意点:
需要记录产品 ID, 其用来区分产品唯一标识符, 这个 ID 待会需要填入 App
Master-APIkey, 网络请求鉴权信息, 接口调用需要带入, 这个 ID 待会需要填入 App
2.2.2 NodeMcu 烧录代码 -- MQTT 设备端
为了明确区分代码功能, 博哥命名工程名为 P_OneNet_Exam05:
P_OneNet_Exam05.ino 文件:
- /**
- * 功能: ESP8266 Mqtt 客户端自注冊功能, 通过配套 App 控制 Led 消息, 理论上可以接入无数个 esp8266
- * 作者: 单片机菜鸟
- * 时间: 2019-10-27
- * 描述:
- * 1. 初始化工作: 初始化网络配置, Mqtt 客户端自注冊, 连接鉴权, 订阅主题
- * 2. 订阅消息: 获取发送过来的消息 (JSON 格式), 解析消息, 实现控制亮灭灯
- */
- #include <ESP8266WiFi.h>
- #include <PubSubClient.h>
- #include <ESP8266HTTPClient.h>
- #include <ArduinoJson.h>
- #include <EEPROM.h>
- #include <Ticker.h>
- #include "H_project.h"
- #define MAGIC_NUMBER 0xAA
- int state;
- WiFiClient espClient;
- // 声明方法
- void initSystem();
- void initOneNetMqtt();
- void callback(char* topic, byte* payload, unsigned int length);
- void saveConfig();
- void loadConfig();
- bool parseRegisterResponse();
- void parseOneNetMqttResponse(char* payload);
- /**
- * 初始化
- */
- void setup() {
- initSystem();
- initOneNetMqtt();
- }
- void loop() {
- ESP.wdtFeed();
- state = connectToOneNetMqtt();
- if(state == ONENET_RECONNECT){
- // 重连成功 需要重新注册
- mqttClient.subscribe(TOPIC,1);
- mqttClient.loop();
- }else if(state == ONENET_CONNECTED){
- mqttClient.loop();
- }
- delay(2000);
- }
- void initSystem(){
- int cnt = 0;
- Serial.begin (115200);
- Serial.println("\r\n\r\nStart ESP8266 MQTT");
- Serial.print("Firmware Version:");
- Serial.println(VER);
- Serial.print("SDK Version:");
- Serial.println(ESP.getSdkVersion());
- wifi_station_set_auto_connect(0);// 关闭自动连接
- ESP.wdtEnable(5000);
- Wi-Fi.disconnect();
- delay(100);
- Wi-Fi.begin(ssid, password);
- while (Wi-Fi.status() != WL_CONNECTED) {
- delay(500);
- cnt++;
- Serial.print(".");
- if(cnt>=40){
- cnt = 0;
- // 重启系统
- delayRestart(1);
- }
- }
- pinMode(LED_BUILTIN, OUTPUT);
- loadConfig();
- // 还没有注册
- if(strcmp(config.deviceid,DEFAULT_ID) == 0){
- int tryAgain = 0;
- while(!registerDeviceToOneNet()){
- Serial.print(".");
- delay(500);
- tryAgain++;
- if(tryAgain == 5){
- // 尝试 5 次
- tryAgain = 0;
- // 重启系统
- delayRestart(1);
- }
- }
- if(!parseRegisterResponse()){
- // 重启系统
- delayRestart(1);
- while(1);
- }
- }
- }
- void initOneNetMqtt(){
- mqttClient.setServer(mqttServer,mqttPort);
- mqttClient.setClient(espClient);
- mqttClient.setCallback(callback);
- initOneNet(PRODUCT_ID,API_KEY,config.deviceid);
- }
- void callback(char* topic, byte* payload, unsigned int length) {
- Serial.print("Message arrived [");
- Serial.print(topic);
- Serial.print("]");
- for (int i = 0; i <length; i++) {
- Serial.print((char)payload[i]);
- }
- Serial.println();
- parseOneNetMqttResponse((char *)payload);
- }
- /*
- * 保存参数到 EEPROM
- */
- void saveConfig()
- {
- Serial.println("Save OneNet config!");
- Serial.print("deviceId:");
- Serial.println(config.deviceid);
- EEPROM.begin(150);
- uint8_t *p = (uint8_t*)(&config);
- for (int i = 0; i < sizeof(config); i++)
- {
- EEPROM.write(i, *(p + i));
- }
- EEPROM.commit();
- }
- /*
- * 从 EEPROM 加载参数
- */
- void loadConfig()
- {
- EEPROM.begin(150);
- uint8_t *p = (uint8_t*)(&config);
- for (int i = 0; i < sizeof(config); i++)
- {
- *(p + i) = EEPROM.read(i);
- }
- EEPROM.commit();
- if (config.magic != MAGIC_NUMBER)
- {
- strcpy(config.deviceid, DEFAULT_ID);
- config.magic = MAGIC_NUMBER;
- saveConfig();
- Serial.println("Restore config!");
- }
- Serial.println("-----Read config-----");
- Serial.print("deviceId:");
- Serial.println(config.deviceid);
- Serial.println("-------------------");
- }
- /**
- * 解析 mqtt 数据
- */
- void parseOneNetMqttResponse(char* payload){
- Serial.println("start parseOneNetMqttResponse");
- StaticJsonBuffer<100> jsonBuffer;
- // StaticJsonBuffer 在栈区分配内存 它也可以被 DynamicJsonBuffer(内存在堆区分配) 代替
- // DynamicJsonBuffer jsonBuffer;
- JsonObject& root = jsonBuffer.parseObject(payload);
- // Test if parsing succeeds.
- if (!root.success()) {
- Serial.println("parseObject() failed");
- return ;
- }
- String deviceId = root["Did"];
- int status = root["sta"];
- if(strcmp(config.deviceid,deviceId.c_str()) == 0){
- if (status == 1) {
- digitalWrite(LED_BUILTIN, LOW);
- } else {
- digitalWrite(LED_BUILTIN, HIGH);
- }
- }
- }
- /**
- * 解析注册返回结果
- */
- bool parseRegisterResponse(){
- Serial.println("start parseRegisterResponse");
- StaticJsonBuffer<200> jsonBuffer;
- // StaticJsonBuffer 在栈区分配内存 它也可以被 DynamicJsonBuffer(内存在堆区分配) 代替
- // DynamicJsonBuffer jsonBuffer;
- JsonObject& root = jsonBuffer.parseObject(response);
- // Test if parsing succeeds.
- if (!root.success()) {
- Serial.println("parseObject() failed");
- return false;
- }
- int errno = root["errno"];
- if(errno !=0){
- Serial.println("register failed!");
- return false;
- }else{
- Serial.println("register sucess!");
- strcpy(config.deviceid, root["data"]["device_id"]);
- saveConfig();
- return true;
- }
- }
H_project.h 代码:
- #ifndef _MAIN_H__
- #define _MAIN_H__
- extern "C" {
- #include "user_interface.h"
- #include "smartconfig.h"
- }
- struct onenet_config
- {
- char deviceid[15];
- uint8_t magic;
- };
- /************** ESP8266 相关操作 **************************/
- void delayRestart(float t);
- void delayNs(uint8_t m);
- /*********************************************************/
- /*************** OneNet MQTT 相关操作 ****************************/
- void initOneNet(uint8_t *productId,uint8_t *apiKey,uint8_t *deviceId);
- int connectToOneNetMqtt();
- /*********************************************************/
- /**************** OneNet Http 相关操作 ***************************/
- HTTPClient http;
- String response;
- const char* host = "api.heclouds.com";
- bool registerDeviceToOneNet();
- /****************************************************************/
- #define ONENET_DISCONNECTED 1 // 已经断开
- #define ONENET_CONNECTED 2 // 已经连接上
- #define ONENET_RECONNECT 3 // 重连成功
- // 常量
- #define VER "MQTT_LED_V1.0"
- const char* ssid = "xxxxxxxx";//Wi-Fi 账号
- const char* password = "xxxxxxx";//Wi-Fi 秘密
- //OneNet 相关
- PubSubClient mqttClient;
- const char* mqttServer = "183.230.40.39";//mqtt 服务器
- const uint16_t mqttPort = 6002;
- #define PRODUCT_ID "253190" // 此为博哥自己的产品 id 请新建自己的
- #define API_KEY "xxxxxx"
- #define DEFAULT_ID "123456"
- #define TOPIC "esp8266led"
- unsigned long lastWiFiCheckTick = 0;
- bool ledState = 0;
- onenet_config config;
- #endif
全部工程代码, 博哥放在个人 QQ 群里或者 代码下载地址.
注意点:
这里用到了 JSON, 请参考博哥上线博文 玩转 ArduinoJson 库 V5 版本;
我们这里使用到了 ESP8266 HttpClient 来封装 Http 请求;
将工程分别烧进多个 NodeMcu(博哥这里烧录了两个), 然后可以看到串口打印内容, 如下:
同时, 也可以在 OneNet 平台看到设备情况, 如下:
接下来就可以通过 App 进行远程控制 led 了.
3. 配套 Android App
3.1 下载 App
博主把 App 放在了个人交流群上以及 GitHub
App 源码暂不开源, 博主也上传到了个人交流群
3.2 配置 App
手机 App 作为一个特殊的设备, 需要自行注册一个新的设备, 然后填入 deviceId, 至于如何注册设备, 请参考 之前的博文.
3.3 操作 App
主页面可以看到当前所有的设备列表 (也就是你自注册的所有智能灯), 并且标明了设备状态, 然后我们就可以远程控制开关灯.
3.4 实验效果
4. 总结
需要注意几点:
创建自己的 OneNet 产品, 不要用博哥创建的, 不然很容易发生 MQTT 重连的现象
理论上设备接入数是无限制的, 基本上能满足普通需求.
来源: https://www.cnblogs.com/danpianjicainiao/p/11751729.html