上次利用STM32单片机实现连接OneNET并支持Siri语音助手控制的功能,这次利用ESP-01S实现Siri远程控制灯开关和获取温湿度数据。
本段代码支持ESP8266系列的01、01S模块甚至12E、12F系列模块。如果使用的是12系列的话还支持深度睡眠唤醒功能。
OneNET注册和创建产品和设备
安装Arduino开发环境和必要的库
ESP-01S编程和下载
iOS快捷指令编写
点亮和关闭一个灯
查询DHT11温湿度
在中国移动OneNET物联网平台注册并创建多协议接入产品,然后创建一个设备,并记下产品ID、设备ID、Api-Key、鉴权信息等必要信息;
在设备管理页面的“数据流模板”界面创建温度、湿度、LED三个变量的数据流;
在搜索引擎搜索Arduino并进入官网下载安装Arduino开发环境,然后在首选项里添加附加开发板管理器网址:http://arduino.esp8266.com/stable/package_esp8266com_index.json
添加完之后IDE就支持ESP8266系列MCU啦,然后安装库文件,在工具-管理库里面添加必要的库:
//需提前安装的库文件:
//ESP8266WiFi库、ArduinoJSON库(V6)、PubSubClient库、DHT Sensor库
#include
#include
#include "PubSubClient.h"
#include "DHT.h"
安装好库之后,将ESP-01S通过USB转TTL模块连接电脑,然后在Arduino中选择对应端口,并打开串口监视器测试AT指令(官方固件)以验证ESP-01S与电脑通信正常。
然后在下面的代码里修改自己对应的信息,包括WiFi信息、OneNET产品ID、设备ID等信息,然后验证、编译、下载。
完整代码如下:
/*
============================================================================
Name : ESP-01S_OneNET.ino
Author : Kaelvean
Version : 1.1
Copyright : 2021.6 YYY copyright.
Description : 实现ESP-01S利用MQTT连接OneNET,上传LED状态和温湿度数据至OneNET平台
支持用网页、iOS快捷指令或Siri控制IO2引脚的电平高低以实现开关灯或继电器
利用Siri或网页实时监控温湿度值
============================================================================
*/
//需提前安装的库文件:ESP8266WiFi库、ArduinoJSON库(V6)、PubSubClient库、DHT Sensor库
#include
#include
#include "PubSubClient.h"
#include "DHT.h"
//OneNET平台创建的产品和设备相关信息
#define mqtt_devid "**********" //设备ID
#define mqtt_pubid "**********" //产品ID
#define mqtt_password "**********" //鉴权信息
#define mqtt_server "183.230.40.39" //OneNET服务器IP
#define mqtt_sevr_port 6002 //端口填6002
#define WIFI_SSID "********" //WIFI名称
#define WIFI_PASSWD "********" //WiFi密码
#define DHTPIN 0 //DHT11传感器的DATA口接ESP-01S的IO0
#define DHTTYPE DHT11 //默认DHT11,也支持DHT22/21
static WiFiClient espClient;
static PubSubClient client(espClient);
DHT dht(DHTPIN, DHTTYPE);
char Mesg_Buf[256]; //发送信息缓冲区
char Json_Buf[200]; //发送的json格式数据
char Recv_Buf[200]; //接收缓冲
unsigned short sd_json_len = 0; //待发送的json数据长度
unsigned short LED_Light; //LED控制变量,1表示开
unsigned short SleepMode = 0; //睡眠模式控制变量。非零进入睡眠
float Humidity = 0.0; //湿度
float Temperature = 0.0; //温度
void setup()
{
Serial.begin(115200); //初始化串口
while (!Serial) continue;
pinMode(LED_BUILTIN, OUTPUT); //ESP8266模块的LED连在IO2上,LED_Bulitin即IO2
digitalWrite(LED_BUILTIN, HIGH);//拉高熄灭LED
wifiInit(WIFI_SSID, WIFI_PASSWD); //连接WIFI
client.setServer(mqtt_server, mqtt_sevr_port); //连接Onenet服务器
client.connect(mqtt_devid, mqtt_pubid, mqtt_password); //连接到产品&设备
client.setCallback(CMDcallback); //客户端收到信息回调
dht.begin();
}
void loop()
{
client.loop(); //客户端循环检测
//上传间隔6秒,可修改
if (millis() % 6000 == 0) {
get_DHT_value(); //获取温湿度
LED_Light = !digitalRead(LED_BUILTIN);
ESPsendData(); //发送数据
}
}
//回调。topic&cmdid,payload:有效信息 3: length:长度
void CMDcallback(const char *topic, byte *payload, unsigned int length)
{
Serial.println("Topic & cmdid:");
Serial.println(topic); //打印topic和cmdid
Serial.println("payload:"); //打印Payload
for (size_t i = 0; i < length; i++) {
Serial.print((char)payload[i]);
Recv_Buf[i] = (char)payload[i];
}
Serial.println(); //换行
Recv_JsonPro(); //接收到的JSON数据解析
Cmd_Opera(); //根据接收的数据执行相关操作
}
//读取温湿度
void get_DHT_value() {
Humidity = dht.readHumidity();
Temperature = dht.readTemperature();
while (isnan(Humidity) || isnan(Temperature))
return;
}
//接收JSON数据解析
void Recv_JsonPro()
{
//解析json
StaticJsonDocument<64> doc;
DeserializationError error = deserializeJson(doc, Recv_Buf);
if (error) {
Serial.print(F("反序列化JSON失败!"));
Serial.println(error.c_str());
return;
}
//获取键值
LED_Light = doc["LED_Light"];
SleepMode = doc["SleepMode"];
}
//执行服务器下发的命令
void Cmd_Opera()
{
if (LED_Light == 0)digitalWrite(LED_BUILTIN, HIGH);
else digitalWrite(LED_BUILTIN, LOW);
if (SleepMode != 0) {
Serial.println("进入深度睡眠模式");
ESP.deepSleep(0);
}
}
//发送数据生成JSON格式
void Mesg_JsonPro()
{
StaticJsonDocument<200> doc;
doc["Humidity"] = Humidity;
doc["Temperature"] = Temperature;
doc["LED_Light"] = LED_Light;
serializeJson(doc, Json_Buf); //构造序列化json,紧凑型
Serial.println(Json_Buf); //打印序列化json
}
//发送数据至服务器
void ESPsendData() {
ReconnectJudge();//断线检测与重连函数
Mesg_JsonPro(); //构造JSON格式数据
sd_json_len = strlen(Json_Buf);
Mesg_Buf[0] = char(0x03); //数据第一位是0X03
Mesg_Buf[1] = char(sd_json_len >> 8); //数据第二位是要发送的数据长度的高八位
Mesg_Buf[2] = char(sd_json_len & 0xff); //数据第三位是要发送数据的长度的低八位
memcpy(Mesg_Buf + 3, Json_Buf, sd_json_len); //从Mesg_Buf的第四位开始,放入要传的数据Json_Buf
Mesg_Buf[3 + sd_json_len] = 0; //添加一个0作为最后一位
client.publish("$dp", (uint8_t *)Mesg_Buf, 3 + sd_json_len); //发送
}
//Wi-Fi连接函数
void wifiInit(const char *ssid, const char *passphrase) {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, passphrase);
while (WiFi.status() != WL_CONNECTED) {
Serial.println("准备连接Wi-Fi");
delay(3000);
}
Serial.println("Wi-Fi连接成功");
}
//断线检测与重连函数
void ReconnectJudge() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Wi-Fi掉线重连中...");
wifiInit(WIFI_SSID, WIFI_PASSWD);
}
while (!client.connected()) {
Serial.println("MQTT掉线重连中...");
if (client.connect(mqtt_devid, mqtt_pubid, mqtt_password)) {
Serial.println("连接成功");
}
else {
Serial.println("重连失败");
Serial.println(client.state());
Serial.println("将在3s后重试");
delay(3000);
}
}
}
在这篇文章里有详细的介绍如何编写iOS快捷指令来控制设备:
在这里简要介绍一下关键操作:
需要用到HTTP通信协议的POST和GET方法,恰巧快捷指令就能直接发起HTTP请求,所以很简单:
请求方式:POST URL:http://api.heclouds.com/cmds
URL参数:device_id、qos、timeout
HTTP头部:api-key
请求体:用户自定义内容,json、字符串,数字
例如:
POST http://api.heclouds.com/cmds?device_id=123456789 HTTP/1.1
api-key: l2aH**BRtAo=dk==
Host: api.heclouds.com
Content-Length: 15
{“LED_Light”:1}
返回示例:(收到这样的代码代表发送成功)
{ "errno": 0, "error": "succ", "data": { "cmd_uuid": "81572aae-fc34-5deb-8f06-ab45d73cb12b" } }
否则发送失败:(errno非零的时候)
{ "errno": 10, "error": "device not online: 8029377" }
在快捷指令里点击“打开那个蓝色指示灯”,即可打开ESP8266自带的LED灯;
也可直接呼叫Siri并念出快捷指令的名称,即可执行相应操作,如“Hey Siri,获取传感器温度。”,即可获取DHT11读取到的温度信息。
也可将LED灯IO口接到继电器上来控制其他电器开关。