版权声明:本文为原创文章,允许转载,转载时请务必标明文章原始出处 。
https://blog.csdn.net/siaszhangjie/article/details/84104382
刚开始使用Arduino和ESP8266及NodeMcu板子,一个坑接着一个坑,一些群或者百度是无法理解和回答简单的白痴问题的,只能自己慢慢摸索,在此慢慢记录填坑过程。
通过百度账号,登录百度云天宫,创建项目,目前物管理是免费的,提供的每月100万条的数据额度,测试学习是够用的。
有时候会有活动,赠送时序数据库,用来学习测试是很好的平台,-.- 广告了一波
注意的是:设备项目只能创建一个,而且不能够删除和编辑!,虽然影响不大,但是起个好听的名字吧
当时为了测试,随便起的一个名字,后来发现不能修改和删除,真闹心 -_- !
完成项目创建后,跟着说明开始创建物模型和物影子,这个都比较简单,略过,最终建好之后是这个样子:
图一
图二
这里说明一下,数据类型能够使用数字的尽量不用字符串
图三
完成以上后,在任意MQTT测试工具中根据<物详情>给的连接配置进行连接测试
图四
很多测试工具但都需要配置环境,比较麻烦,推荐大家可以使用“通信猫”这个在线工具进行测试,但是目前的问题是,通信猫只能连接8884端口,而且需要勾选TLS,哪位知道原因,请留言
图五
测试通过之后,就可以选择一种ESP8266固件进行连接了;
这里也不多过于介绍,根据自己购买的硬件进行选择,网上很多教程了,可以选择Arduino直接烧录,也可以选择NodeMcu板相应固件,也可以选择Mongoose OS,亦可以百度云天工的SDK自己编译,也可以选择乐鑫官方固件进行烧录等等。
这个东西比较方便,语法也相对容易理解,入门很合适;
MQTT采用PubSubClient库,给Arduino添加上PubSubClient后(通过项目->加载库->管理库 添加),在“文件”->“示例”中会多出如下示例
图六
说这个东西的目的是记录一下,自己爬的一个坑,具体问题如下:
订阅百度云天工物影子的属性变化
$baidu/iot/shadow/smartlamp001/update/documents
代码如下:
#include
#include
const char *ssid = "xxxxxxx"; //wifi账号
const char *password = "xxxxxxx";//wifi密码
const char *mqtt_server = "112.34.115.12"; // 使用的信息中转服务
const char *subTopic = "$baidu/iot/shadow/xxx/update/documents"; // 订阅信息主题
const char *pubTopic = "$baidu/iot/shadow/xxx/update";
const char *client_id = "xxxxxx"; // 标识当前设备的客户端编号
const char *mqtt_username = "xxxxxxxx";
const char *mqtt_password = "xxxxxxx";
WiFiClient espClient; // 定义wifiClient实例
PubSubClient mqttclient(espClient); // 定义PubSubClient的实例
long lastMsg = 0; // 记录上一次发送信息的时长
void callback(char *topic, byte *payload, unsigned int length)
{
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
Serial.println();
Serial.println(String(length));
for (int i = 0; i < length; i++)
{
Serial.print((char)payload[i]);
}
Serial.println();
}
void setup()
{
pinMode(0, OUTPUT); // 定义板载LED灯为输出方式
Serial.begin(115200);
setup_wifi(); //执行Wifi初始化,下文有具体描述
mqttclient.setServer(mqtt_server, 1883); //设定MQTT服务器与使用的端口,1883是默认的MQTT端口
mqttclient.setCallback(callback); //设定回调方式,当ESP8266收到订阅消息时会调用此方法
delay(1500);
}
void setup_wifi()
{
delay(10);
// 板子通电后要启动,稍微等待一下让板子点亮
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void reconnect()
{
while (!mqttclient.connected())
{
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (mqttclient.connect(client_id, mqtt_username, mqtt_password))
{
Serial.println("connected");
if (mqttclient.subscribe(subTopic, 1))
{
Serial.println("subscribe success");
}
else
{
Serial.println("subscribe fail");
}
}
else
{
Serial.print("failed, rc=");
Serial.print(mqttclient.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void loop()
{
if (!mqttclient.connected())
{
reconnect();
}
mqttclient.loop();
digitalWrite(0, HIGH);
delay(1000);
digitalWrite(0, LOW);
delay(1000);
// long now = millis();
// if (now - lastMsg > 2000) {
// lastMsg = now;
// client.subscribe(TOPIC);
// }
}
上面的代码很简单,就是连接wifi,连接MQTT服务器,然后订阅一下属性值变化Topic,当收到信息时,执行callback函数;
mqttclient.setCallback(callback);
void callback(char *topic, byte *payload, unsigned int length)
{
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
Serial.println();
Serial.println(String(length));
for (int i = 0; i < length; i++)
{
Serial.print((char)payload[i]);
}
Serial.println();
}
通过MQTT测试工具发布物影子属性变化,死活callback没有反应,通过物影子中“模型数据的编辑”也会自动发布物影子属性变化的Topic,可以用来测试,但问题是还是没有反应,提示订阅成功,但就是收不到订阅的数据,callback中输出length,一直为0 ,经过一天的试来试去,放弃------
睡了一个好觉后,接着找问题,猜测是不是PubSubClient这个库的问题,查看了一下这个库的源码,看到一个可疑的字段:
uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
uint16_t len = 0;
if(!readByte(buffer, &len)) return 0;
bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH;
uint32_t multiplier = 1;
uint16_t length = 0;
uint8_t digit = 0;
uint16_t skip = 0;
uint8_t start = 0;
do {
if (len == 5) {
// Invalid remaining length encoding - kill the connection
_state = MQTT_DISCONNECTED;
_client->stop();
return 0;
}
if(!readByte(&digit)) return 0;
buffer[len++] = digit;
length += (digit & 127) * multiplier;
multiplier *= 128;
} while ((digit & 128) != 0);
*lengthLength = len-1;
if (isPublish) {
// Read in topic length to calculate bytes to skip over for Stream writing
if(!readByte(buffer, &len)) return 0;
if(!readByte(buffer, &len)) return 0;
skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2];
start = 2;
if (buffer[0]&MQTTQOS1) {
// skip message id
skip += 2;
}
}
for (uint16_t i = start;istream) {
if (isPublish && len-*lengthLength-2>skip) {
this->stream->write(digit);
}
}
if (len < MQTT_MAX_PACKET_SIZE) {
buffer[len] = digit;
}
len++;
}
if (!this->stream && len > MQTT_MAX_PACKET_SIZE) {
len = 0; // This will cause the packet to be ignored.
}
return len;
}
MQTT_MAX_PACKET_SIZE
转到这个字段的定义:
#define MQTT_MAX_PACKET_SIZE 128
只能接收128字节,超过则返回len=0
if (!this->stream && len > MQTT_MAX_PACKET_SIZE) {
len = 0; // This will cause the packet to be ignored.
}
而获取到的数据是变化前的数据和变化后的数据,字符比较多,是超过128字节的,问题找到了,修改吧,直接加个0
#define MQTT_MAX_PACKET_SIZE 128
这个支持方式比较灵活,可以使用JavaScript,可以使用C语言,可以直接将Arduino代码拿来直接使用,有别于其他的是:有web UI界面,可以通过web进行编写代码和修改配置,当然,那是老版本,新版本配置项只能通过脚本进行修改:
mos build(执行编译)、mos flash(执行上传)、mos wifi WiFi账号 WiFi密码(wifi配置)、mos update 2.3(将mos tool 更新到指定版本)网上的教程基本上都是2.3,现在已经是2.7了;mos clone https://github.com/mongoose-os-apps/demo-js app1(从官方下载实例并命名为app1)
1、mos clone 下载dome,在app1 文件夹中 修改 fs/init.js 编写自己的业务逻辑
图九
2、用户自定义配置,需要在fs文件夹中添加conf9.json,进行配置的覆盖,刚开始使用Mongoose OS时,这块花了不少时间,添加的是conf0.json,一直出现各种问题,具体为什么是conf9.json自行百度吧。只是一个文件合并和覆盖的过程。
图十
3、mos build 、mos flash
如果使用的是这个ESP8266
图十一
需要连接CH340G,USB转TTL连接到电脑上,具体连线需要查一下,FLASH需要将GIO0接低电平;
如果使用的是NodeMcu板子就直接flash就行了,不用任何操作比较方便新手还是建议使用NodeMcu
图十二
当然,会比ESP8266贵一点点
通过以上配置,ESP8266就可以和天工MQTT服务器连接,并上传温湿度数据,完成了自己的室温监控,加上百度云天工的时序数据库,就可以记录历史数据了;
比较简单,选择新建,选择数据来源:也就是类型:时序数据库或者设备影子或者静态数据,完成数据表创建后,进行仪表盘拖拽和数据绑定