esp8266接入阿里云物联网平台MQTT客户端直连
esp8266接入阿里云物联网平台(MQTT客户端直连)
这里不介绍怎么进行详细开发,只讲如何快速实现接入物联网平台,具体操作可以先看文档
我们这次的实验用的是8266的Node-MCU开发板,通过8266接入阿里云平台,然后使用MQTT.fx模拟远程控制的客户端(手机、电脑),远程控制8266板载的LED亮灭。
1、创建设备(默认你们已经注册好账号了)
2、添加设备
我创建了如图所示的设备
3、激活设备(重点)
你们新创建的设备一定和我上图的LED2一样是未激活状态,因为你们的设备还没有接入到阿里云平台。现在就操作一下把MQTT.fx接入到平台上。
先下载MQTT.fx客户端
安装完成后打开软件
ProfileName
MQTT(设备名字)
Broker Address
格式:
{YourProductKey}.iot-as-mqtt.{region}.aliyuncs.com
其中,{
YourProductKey
}这个我就不用说了,强调了很多遍了。{
region
}需替换为您物联网平台服务所在地域的代码。可以参考
我的区是华东2上海 cn-shanghai
Client ID
MQTT_Device|securemode=3,signmethod=hmacsha1|
,表示
TCP直连
(不加密)
②
MQTT_Device|securemode=2,signmethod=hmacsha1|
,表示
TLS直连
(加密)
1){clientId}为设备的ID信息。可取任意值,我这里等同于DeviceName,长度在64字符以内。建议使用设备的MAC地址或SN码。
2)securemode为安全模式,TCP直连模式设置为securemode=3,TLS直连为securemode=2。
3)signmethod为算法类型,支持hmacmd5和hmacsha1(基本上用这个)。
输入Client ID信息后,请勿单击Generate
User Credentials
设置用户名和密码
User Name固定格式:
{YourDeviceName}&{YourPrductKey}
Password:这个就得用工具生成了,工具下载
下载解压后打开里面的html网页,按照图片输入自己的信息就可以了
其实也不需要工具也可以产生password,阿里云在点击设备的时候会有一个MQTT连接参数,里面有我们需要的password和client_id,但是复制的client_id需要考虑securemode。
securemode
直连模式的我们不需要考虑这个,配置完后保存即可
4、MQTT(发布和订阅)
MQTT协议不熟悉的以后有机会再讲吧,目前其他博主介绍的更详细。8266也用类似的方法接入阿里云平台。
//esp8266代码
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <PubSubClient.h>
#include <WiFiClientSecure.h>
const char* WIFI_SSID = "Redmi K50 Ultra"; // WiFi账号密码
const char* WIFI_PASSWORD = "20000906"; // WiFi密码
/******************产品/设备配置(每个人需要根据自己的产品设备信息去动态更换)**********************/
#define PRODUCT_KEY "xxxxxxx" //产品key 从产品详情获取
#define DEVICE_NAME "xxxx" //设备deviceName 从设备详情获取
// 服务端相关
#define MQTT_SERVER PRODUCT_KEY ".iot-as-mqtt.cn-shanghai.aliyuncs.com" //阿里云MQTT服务地址
#define MQTT_PORT 1883 //MQTT服务端口
// 校验三元组
#define MQTT_CLIENT_ID DEVICE_NAME "|securemode=3,signmethod=hmacsha1|" //mqtt clientid
#define MQTT_USERNAME DEVICE_NAME "&" PRODUCT_KEY //mqtt username
#define MQTT_PASSWORD "4E48894AB34F7B0FCB83EA0C19F8FB46EC592CD9" //mqtt password 通过生成工具获得
// 相关主题 自定义一个主题
#define TOPIC1 "/" PRODUCT_KEY "/" DEVICE_NAME "/user/setled"
/*************************************************************************************************/
void mqtt_callback (char* topic, byte* payload, unsigned int length);
void doWiFiTick();
void connect_wifi();
void connectToMqtt();
const __FlashStringHelper* connectErrorToString(int8_t code);
WiFiClient client;
PubSubClient mqttclient(MQTT_SERVER, MQTT_PORT, &mqtt_callback, client);
void setup() {
// put your setup code here, to run once:
delay(2000);
Serial.begin(115200);
doWiFiTick();
pinMode(LED_BUILTIN, OUTPUT);
Serial.println("");
connectToMqtt();
}
void loop() {
if (WiFi.status() == WL_CONNECTED) {
mqttclient.loop();
}
}
/**
* 功能:连接到WiFi热点
*/
void connect_wifi() {
WiFi.disconnect();
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.print(F("\nWiFi connected to "));
Serial.println(WIFI_SSID);
Serial.print(F("IP address: "));
Serial.println(WiFi.localIP());
}
/**
* 功能:连接到Mqtt
*/
void connectToMqtt() {
if (mqttclient.connected()) {
return;
}
Serial.print(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
Serial.println(connectErrorToString(mqttclient.state()));
Serial.println(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();
}
Serial.println(F("Success!"));
// 订阅主题
mqttclient.subscribe(TOPIC1);
}
/**
* 功能:连接路由心跳函数
*/
void doWiFiTick() {
static bool taskStarted = false;
static bool startSTAFlag = false;
static uint32_t lastWiFiCheckTick = 0;
if (!startSTAFlag) {
startSTAFlag = true;
Serial.print("connect to ap:");
Serial.println(WIFI_SSID);
WiFi.disconnect();
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.printf("Heap size:%d\r\n", ESP.getFreeHeap());
}
//未连接1s重连
if ( WiFi.status() != WL_CONNECTED ) {
if (millis() - lastWiFiCheckTick > 1000) {
lastWiFiCheckTick = millis();
Serial.print(".");
}
}
//连接成功建立
else {
if (taskStarted == false) {
taskStarted = true;
Serial.print("\r\nGet IP Address: ");
Serial.println(WiFi.localIP());
}
}
}
/**
* 功能:MQTT回调
* 参数:
* 1. topic 主题
* 2. payload 载体
* 3. length 载体长度
*/
void mqtt_callback (char* topic, byte* payload, unsigned int length) {
byte *end = payload + length;
for (byte *p = payload; p < end; ++p) {
Serial.print(*((const char *)p));
}
Serial.println("");
parseMqttResponse((char *)payload);
}
/**
* 解析mqtt数据
*/
void parseMqttResponse(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 deviceName = root["dn"];
int status = root["s"];
if(strcmp(DEVICE_NAME,deviceName.c_str())== 0){
if (status == 1) {
digitalWrite(LED_BUILTIN, LOW);
} else {
digitalWrite(LED_BUILTIN, HIGH);
}
}
}
/**
* 功能:打印错误
* 参数:
* 1. code 错误码
*/
const __FlashStringHelper* connectErrorToString(int8_t code) {
switch (code) {
case 1: return F("The Server does not support the level of the MQTT protocol requested");
case 2: return F("The Client identifier is correct UTF-8 but not allowed by the Server");
case 3: return F("The MQTT service is unavailable");
case 4: return F("The data in the user name or password is malformed");
case 5: return F("Not authorized to connect");
case 6: return F("Exceeded reconnect rate limit. Please try again later.");
case 7: return F("You have been banned from connecting. Please contact the MQTT server administrator for more details.");
case -1: return F("Connection failed");
case -2: return F("Failed to subscribe");
case -3: return F("Connection Lost");
case -4: return F("Connection Timeout");
default: return F("Unknown error");
}
}
这样8266也连接上了阿里云平台,我们通过8266订阅主题,然后MQTT.fx发布信息从而控制8266的LED亮灭。
如果烧录进去后一直都是“The Client identifier is correct UTF-8 but not allowed by the Server”报错可以改一下 PubSubClient.h头文件内容
// MQTT_VERSION : Pick the version
//#define MQTT_VERSION MQTT_VERSION_3_1
#ifndef MQTT_VERSION
#define MQTT_VERSION MQTT_VERSION_3_1_1
#endif
// MQTT_MAX_PACKET_SIZE : Maximum packet size
#ifndef MQTT_MAX_PACKET_SIZE
#define MQTT_MAX_PACKET_SIZE 1024
#endif
// MQTT_KEEPALIVE : keepAlive interval in Seconds
#ifndef MQTT_KEEPALIVE
#define MQTT_KEEPALIVE 300
#endif
// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds
#ifndef MQTT_SOCKET_TIMEOUT
#define MQTT_SOCKET_TIMEOUT 60
#endif
现在就是往阿里云的mqtt服务器添加topic,让esp8266可以订阅这个topic,mqtt.fx客户端可以对这个topic发布控制信息,esp8266解析这个订阅信息从而控制灯的亮灭。
5、结束–连接阿里云平台
当把上面的程序下载到我们自己的esp8266的时候,如果已经通过MQTT连接阿里云成功后,可以在网页中验证一下,往你的设备发布一下消息,看串口有没有打印出来,或者LED灯能不能控制亮灭。
如果正常控制,说明协议通道已经搭建好了。但是当我们使用mqttfx客户端模拟去控制esp8266时,我们向主题发送控制信息,esp8266却没有任何反应。因为两个人发布和订阅的主题虽然都是setled,但是前面的device_name确是不一致的,这样订阅的主题不对当然获取不到有用数据。我们需要使用新的功能
消息转发的云产品流转。
自己去设置一下数据来源这些,主要就是你另一个设备向主题发布的数据转发到esp8266订阅主题的设备上去就行了。这样一个设备远程控制另一个设备就完成了。这能写这么多了,又不明白的评论区讨论一下。