曾无好事来相访,赖尔高文一起予。这篇文章主要讲述玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制相关的知识,希望能为你提供帮助。
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力。希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石。。。
QQ技术互动交流群:ESP8266& 32 物联网开发 群号622368884,不喜勿喷一、你如果想学基于Arduino的ESP8266开发技术一、基础篇
二、网络篇
- ESP8266开发之旅 基础篇① 走进ESP8266的世界
- ESP8266开发之旅 基础篇② 如何安装ESP8266的Arduino开发环境
- ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明
- ESP8266开发之旅 基础篇④ ESP8266与EEPROM
- ESP8266开发之旅 基础篇⑤ ESP8266 SPI通信和I2C通信
- ESP8266开发之旅 基础篇⑥ Ticker——ESP8266定时库
三、应用篇
- ESP8266开发之旅 网络篇① 认识一下Arduino Core For ESP8266
- ESP8266开发之旅 网络篇② ESP8266 工作模式与ESP8266WiFi库
- ESP8266开发之旅 网络篇③ Soft-AP——ESP8266WiFiAP库的使用
- ESP8266开发之旅 网络篇④ Station——ESP8266WiFiSTA库的使用
- ESP8266开发之旅 网络篇⑤ Scan WiFi——ESP8266WiFiScan库的使用
- ESP8266开发之旅 网络篇⑥ ESP8266WiFiGeneric——基础库
- ESP8266开发之旅 网络篇⑦ TCP Server & TCP Client
- ESP8266开发之旅 网络篇⑧ SmartConfig——一键配网
- ESP8266开发之旅 网络篇⑨ HttpClient——ESP8266HTTPClient库的使用
- ESP8266开发之旅 网络篇⑩ UDP服务
- ESP8266开发之旅 网络篇? WebServer——ESP8266WebServer库的使用
- ESP8266开发之旅 网络篇? 域名服务——ESP8266mDNS库
- ESP8266开发之旅 网络篇? SPIFFS——ESP8266 Flash文件系统
- ESP8266开发之旅 网络篇? web配网
- ESP8266开发之旅 网络篇? 真正的域名服务——DNSServer
- ESP8266开发之旅 网络篇? 无线更新——OTA固件更新
四、高级篇
- ESP8266开发之旅 应用篇① 局域网应用 ——炫酷RGB彩灯
- ESP8266开发之旅 应用篇② OLED显示天气屏
- ESP8266开发之旅 应用篇③ 简易版WiFi小车
1.理论基础????参考博主线上博文:
- ESP8266开发之旅 进阶篇① 代码优化 —— ESP8266内存管理
- ESP8266开发之旅 进阶篇② 闲聊Arduino IDE For ESP8266配置
- ESP8266开发之旅 进阶篇③ 闲聊 ESP8266 Flash
- ESP8266开发之旅 进阶篇④ 常见问题 —— 解决困扰
- ESP8266开发之旅 进阶篇⑤ 代码规范 —— 像写文章一样优美
- ESP8266开发之旅 进阶篇⑥ ESP-specific APIs说明
- 玩转PubSubClient MQTT库
- 玩转OneNET物联网平台之简介
- 玩转OneNET物联网平台之MQTT服务①
- 玩转OneNET物联网平台之MQTT服务②
- 玩转OneNET物联网平台之MQTT服务③
- 人为手动控制,对于开发者来说极度不友好;
- 如果设备数量很多,岂不是要手动操作非常多次;
- 为了区分唯一性,我们采用ESP-Mac地址的组合形式
- 同时为了操作方便,博主花了个周末的时间做了一个对应的app,理论上不限制ESP8266接入点的数量
- 博主极度建议大家从第一篇看起,有个大概了解,因为本系列教程都是有相联系的
文章图片
2.远程控制LED,实现设备自注册 2.1 实验材料
- ESP8266 NodeMcu
- android手机
- OneNet平台
2.2.1 创建 ESP8266智能灯系统 产品(MQTT协议)
文章图片
注意点:
- 务必选择MQTT协议
文章图片
注意点:
- 需要记录产品ID,其用来区分产品唯一标识符,这个ID待会需要填入App
- Master-APIkey,网络请求鉴权信息,接口调用需要带入,这个ID待会需要填入App
- 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 0xAAint 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("
Start 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);
WiFi.disconnect();
delay(100);
WiFi.begin(ssid, password);
while (WiFi.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(内存在堆区分配) 代替
// DynamicJsonBufferjsonBuffer;
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(内存在堆区分配) 代替
// DynamicJsonBufferjsonBuffer;
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"
;
//wifi账号
const char* password = "
xxxxxxx"
;
//wifi秘密//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请求;
文章图片
文章图片
文章图片
【玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制】????同时,也可以在OneNet平台看到设备情况,如下:
文章图片
????接下来就可以通过App进行远程控制led了。
3.配套android App 3.1 下载App
- 博主把App放在了个人交流群上以及Github
- App源码暂不开源,博主也上传到了个人交流群
文章图片
- 手机App作为一个特殊的设备,需要自行注册一个新的设备,然后填入deviceId,至于如何注册设备,请参考 之前的博文。
文章图片
- 主页面可以看到当前所有的设备列表(也就是你自注册的所有智能灯),并且标明了设备状态,然后我们就可以远程控制开关灯。
文章图片
文章图片
文章图片
4.总结需要注意几点:
- 创建自己的OneNet产品,不要用博哥创建的,不然很容易发生MQTT重连的现象
- 理论上设备接入数是无限制的,基本上能满足普通需求。
推荐阅读
- CSAPP_AttackLab实验报告
- Python Pandas如何读取文件(详细实现————)
- 如何将列添加到DataFrame列(添加新列详细解释————)
- Pandas DataFrame.sum()使用介绍
- Pandas DataFrame.shift()用法示例
- Pandas DataFrame.fillna()例子
- Pandas DataFrame.where()例子
- Pandas DataFrame.transpose()使用示例
- Pandas DataFrame.to_excel()用法详解