手机远程访问mqtt服务器,玩转MQTT实现远程数据采集和控制
本帖最后由 yaojin919000 于 2021-1-4 15:15 编辑本文简单介绍利用STM32和esp8266等元器件,利用ONENET平台,实现手机端、电脑端和大屏三种办法对现场温湿度光照度和开关信息的采集显示,并在手机端和电脑端对现场的LED灯以及蜂鸣器进行控制。实现思路:根据ONENET平台的协议要求,先选择多协议接入建立一个产品,记住产品ID,在这个产品下再创建两个设备,记住设备的
本帖最后由 yaojin919000 于 2021-1-4 15:15 编辑
本文简单介绍利用STM32和esp8266等元器件,利用ONENET平台,实现手机端、电脑端和大屏三种办法对现场温湿度光照度和开关信息的采集显示,并在手机端和电脑端对现场的LED灯以及蜂鸣器进行控制。
实现思路:根据ONENET平台的协议要求,先选择多协议接入建立一个产品,记住产品ID,在这个产品下再创建两个设备,记住设备的ID和鉴权信息,这些信息在编程的过程中需要使用。为了体现使用平台的灵活性,我创建了2个不同硬件的设备,一个是使用STM32+8266ESP-01S的硬件组成,一个是采用NODEMCU模块的硬件组成,两个设备都可以独立运行使用,各自单独组成一个独立的控制系统。两个设备通过ONENET平台每5秒钟发布一次数据,并且随时等待平台对自己的控制命令并完成执行。
硬件部分介绍:设备一采用nodemcu设备硬件简单,直接某宝购买(十几元)用杜邦线外配几个LED灯。自己配上5V电源和手机充电线(见图一)完活。设备二稍微复杂一点,选用STM32F103C8T6最小系统板,参照萝卜兄弟设计一个PCB线路板,把蜂鸣器、BHT11、BHT1750、0.96OLED、通讯模块8266ESP01S还有TCP1211,再配上两个按钮和LED指示灯(参图二),线路板选择嘉立创线上编辑,直接5片一元下单,一周内顺丰邮到家,全部硬件成本约50-60元。
软件部分介绍:针对两个不同设备,分别开发两套独立的软件。主要的功能都是完成数据采集,打包,上传,对平台下发的数据进行解析并执行相关的操作。下面将详细讲解一下:使用STM32+8266ESP-01S的软件讲:这部分软件采用c语言编写,参照ONENET平台上张继瑞老师和正点原子的例程,分成几个部分:
初始化部分:/硬件初始化void Hardware_Init(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
Usart1_Init(115200); //串口1初始化为115200
Usart2_Init(115200); //串口2,驱动ESP8266用
EXTIX_Init(); //外部中断初始化
LED_Init(); //LED初始化
ADCx_Init(); //ADC DMA初始化
DHT11_GPIO_Config(); //DHT11温湿度传感器初始化
BH1750_Init(); //光照
KEY_Init();
BEEP = 0;//鸣叫提示接入成功
delay_ms(250);
BEEP = 1;
数据采集部分:
/*光照度传感器获取数据*/
value_light = LIght_Intensity();
/* 温湿度传感器获取数据*/
/*调用Read_DHT11读取温湿度,若成功则输出该信息*/
if( Read_DHT11(&DHT11_Data)==SUCCESS)
{
sprintf(str, "温度:%d.%d ℃ ",DHT11_Data.temp_int,DHT11_Data.temp_deci);
sprintf(str, "湿度:%d.%d %c ",DHT11_Data.humi_int,DHT11_Data.humi_deci,'%');
}
else
{
printf("Read DHT11 ERROR!\r\n");//读取数据失败,串口打印:Read DHT11 ERROR.
}
Led_Status = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4);//读取LED0的状态
Led_Status1 = GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13);//读取LED1的状态
上传部分:
memset(buf, 0, sizeof(buf));
body_len = OneNet_FillBuf(buf); //获取当前需要发送的数据流的总长度
printf("send data:%s\n",buf);
if(body_len)
{
if(MQTT_PacketSaveData(DEVID, body_len, NULL, 5, &mqttPacket) == 0) //封包
{
for(; i < body_len; i++)
mqttPacket._data[mqttPacket._len++] = buf; ESP8266_SendData(mqttPacket._data, mqttPacket._len); //上传数据到平台
MQTT_DeleteBuffer(&mqttPacket); //删包
}
else
printf("WARN: EDP_NewBuffer Failed\r\n");
}
下发指令解析:
void OneNet_RevPro(unsigned char *cmd)
{
MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0}; //协议包
char *req_payload = NULL;
char *cmdid_topic = NULL;
unsigned short req_len = 0;
unsigned char type = 0;
short result = 0;
char *dataPtr = NULL;
char numBuf[10];
int num = 0;
type = MQTT_UnPacketRecv(cmd);
switch(type)
{
case MQTT_PKT_CMD: //命令下发
result = MQTT_UnPacketCmd(cmd, &cmdid_topic, &req_payload, &req_len); //解出topic和消息体
if(result == 0)
{
printf("cmdid: %s, req: %s, req_len: %d\r\n", cmdid_topic, req_payload, req_len);
if(MQTT_PacketCmdResp(cmdid_topic, req_payload, &mqttPacket) == 0) //命令回复组包
{
printf("Tips: Send CmdResp\r\n");
ESP8266_SendData(mqttPacket._data, mqttPacket._len); //回复命令
MQTT_DeleteBuffer(&mqttPacket); //删包
}
}
break;
case MQTT_PKT_PUBACK: //发送Publish消息,平台回复的Ack
if(MQTT_UnPacketPublishAck(cmd) == 0)
break;
default:
result = -1;
break;
}
ESP8266_Clear(); //清空缓存
if(result == -1)
return;
dataPtr = strchr(req_payload, ':'); //搜索':'
if(dataPtr != NULL && result != -1) //如果找到了
{
dataPtr++;
while(*dataPtr >= '0' && *dataPtr <= '9') //判断是否是下发的命令控制数据
{
numBuf[num++] = *dataPtr++;
}
numBuf[num] = 0;
num = atoi((const char *)numBuf); //转为数值形式
if(strstr((char *)req_payload, "LED0:0")) //搜索"LED0:0"字符串
{
GPIO_SetBits(GPIOA, GPIO_Pin_4); //共阳极,拉高PA8电平,熄灭LED0
printf("LED0=0");
}
else if(strstr((char *)req_payload, "LED0:1"))
{
GPIO_ResetBits(GPIOA, GPIO_Pin_4); //点亮LED0
printf("LED0=1");
}
else if(strstr((char *)req_payload, "LED1:0")) //搜索"LED1:0"字符串
{
GPIO_SetBits(GPIOC, GPIO_Pin_13); //共阳极,拉高PC13电平,熄灭LED1
printf("LED1=0");
}
else if(strstr((char *)req_payload, "LED1:1"))
{
GPIO_ResetBits(GPIOC, GPIO_Pin_13); //点亮LED1
printf("LED1=1");
}
else if(strstr((char *)req_payload, "BEEP:0"))
{
GPIO_SetBits(GPIOA, GPIO_Pin_0); //关闭蜂鸣器
alarmFlag=0;
alarm_is_free=0;
printf("BEEP=0");
}
else if(strstr((char *)req_payload, "BEEP:1"))
{
GPIO_ResetBits(GPIOA, GPIO_Pin_0); //打开蜂鸣器
alarmFlag=1;
alarm_is_free=1;
printf("BEEP=1");
网络连接以及检测:
MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0}; //协议包
unsigned char *dataPtr;
_Bool status = 1;
printf("OneNet_DevLink\r\nPROID: %s, AUIF: %s, DEVID:%s\r\n", PROID, AUTH_INFO, DEVID);
if(MQTT_PacketConnect(PROID, AUTH_INFO, DEVID, 512, 0, MQTT_QOS_LEVEL0, NULL, NULL, 0, &mqttPacket) == 0)
{
ESP8266_SendData(mqttPacket._data, mqttPacket._len); //上传平台
dataPtr = ESP8266_GetIPD(250); //等待平台响应
if(dataPtr != NULL)
{
if(MQTT_UnPacketRecv(dataPtr) == MQTT_PKT_CONNACK)
{
switch(MQTT_UnPacketConnectAck(dataPtr))
{
case 0:printf("Tips: 连接成功\r\n");status = 0;break;
case 1:printf("WARN: 连接失败:协议错误\r\n");break;
case 2:printf("WARN: 连接失败:非法的clientid\r\n");break;
case 3:printf("WARN: 连接失败:服务器失败\r\n");break;
case 4:printf("WARN: 连接失败:用户名或密码错误\r\n");break;
case 5:printf("WARN: 连接失败:非法链接(比如token非法)\r\n");break;
default:printf("ERR: 连接失败:未知错误\r\n");break;
}
}
}
MQTT_DeleteBuffer(&mqttPacket); //删包
}
else
printf("WARN: MQTT_PacketConnect Failed\r\n");
return status;
使用NodeMCU的软件讲解:这部分软件比较简单,采用lua语言配合nodemcu固件,设计两个定时器,初始化D1、D2、D5管脚作为LED驱动,A0管脚作为模拟量输入端口。一个一秒的定时器作为连接本地WIFI的定时,另一个是5秒定时器作为上传平台的数据之用。软件首先初始化各个管脚,然后连接WIFI网络,登录ONENET平台并进入透传模式并订阅相应的主题,然后进入5秒循环,循环内先采集LED管脚的电平、模拟量A0和模拟温湿度数据,按照平台要求的数据格式发布到平台,然后,检查平台返回的数据看是否需要有下发的指令要去执行。详见下面部分程序代码:--[[
GPIO0--3
GPIO1--10
GPIO2--4
GPIO3--9
GPIO4--2
GPIO5--1
GPIO9--11
GPIO10--12
GPIO12--6
GPIO13--7
GPIO14--5
GPIO15--8
GPIO16--0
]]
print("Set up wifi..SmartConfig....") --MESSAGE HINT
--yixiashizidongpeiwangdaima--
wifi.setmode(wifi.STATION) --SET THE WiFi_MODE TO STATION
cfg = {} --CREATE NEW TABLE
cfg.ssid = "203" --SET WiFi NAME
cfg.pwd = "987654321" --SET WiFi PASSWORD
wifi.sta.config(cfg) --CONFIG WiFi
wifi.sta.connect() --CONNECT WiFi
--Timer Init
time1 = tmr.create() --create timer1 connect to OneNET
time2 = tmr.create() --create timer1 publice data to OneNET
---------------------
--Dht11Pin7 = 2 --DHT11_BIN
1
LED0=1
LED1=5
LED2=2
---------------------
--Variable Init
Four = 0
DeviceID = "649760557"
AuthInfo = "12345"
ProductID = "385059"
BrokerHost = "183.230.40.39"
Port = 6002
---------------------
gpio.mode(LED0,gpio.OUTPUT)
gpio.write(LED0,gpio.LOW)
gpio.mode(LED1,gpio.OUTPUT)
gpio.write(LED1,gpio.LOW)
gpio.mode(LED2,gpio.OUTPUT)
gpio.write(LED2,gpio.HIGH)
-------------------------
if adc.force_init_mode(adc.INIT_ADC)
then
node.restart()
return -- don't bother continuing, the restart is scheduled
end
---------------------
function Reconnect()
if wifi.sta.getip() == nil then
print("disconnect,waiting for ip...")
wifi.setmode(wifi.STATION)
wifi.startsmart(1, function (wifi_ssid, wifi_password)
config={}
config.ssid= wifi_ssid
config.pwd= wifi_password
config.save=true
wifi.sta.config(config)
wifi.sta.autoconnect(1)
end)
wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, function(T)
print(wifi.sta.getip())
wifi.setmode(wifi.STATION)
print("success")
end)
else
time1:stop()
print("connect success!")
print("ip is "..wifi.sta.getip())
clientD = mqtt.Client(DeviceID, 120, ProductID, AuthInfo, 0)
clientD:connect(BrokerHost, Port, 0, function(client) --connect device
print("Connect to success!")
end)
time2:alarm(500, tmr.ALARM_AUTO, Up_AC_Message)
end
end
function Up_AC_Message()
Four = Four + 1
if(Four%5 == 0)then
Four = 0
--status,temp,humi,temp_dec,humi_dec = dht.read11(Dht11Pin7)
--print("temp is:"..temp, "humi is:"..humi)
--HumiVar = humi
--TempVar = temp
if(gpio.read(LED2)==1)then
gpio.write(LED2,gpio.LOW)
else
gpio.write(LED2,gpio.HIGH)
end
data = {}
data.Temp = 22.3
data.Humi =52.8
data.LED0=gpio.read(LED0) --LED0 green
data.LED1=gpio.read(LED1) --LED1 red
data.MAC=wifi.sta.getmac() --mac
data.Voltage=3000/1024*(adc.read(0))
ok,data_message = pcall(sjson.encode, data)
header = string.char(3, 0, string.len(data_message))..data_message
clientD:publish("$dp",header,0,0,function(client)
print("
UBLISH WEATHER SUCCESS!")
end)
clientD:subscribe("$dp",0,function(client)
print("SUBSCRIBE SUCCESS!")
end)
clientD
n("message",function(client,topic,message)
print(message)
if message=="LED0:0" then gpio.write(LED0,gpio.LOW)end
if message=="LED0:1" then gpio.write(LED0,gpio.HIGH)end
if message=="LED1:0" then gpio.write(LED1,gpio.LOW)end
if message=="LED1:1" then gpio.write(LED1,gpio.HIGH)end
end)
end
if(wifi.sta.getip() == nil) then
time2:stop()
time1:start()
end
end
time1:alarm(1000, tmr.ALARM_AUTO, Reconnect) --do Reconnect()
顺便说一下,制作nodemcu固件需要选择GPIO,TMR,WIFI,ADC,DHT,MQTT,SJSON,I2C几个模块,生成制作固件方法参见我另外一篇文章的相关资料。刚才要把几个上位机的控制图片传上来,但是提示帖子的容量有限度,所以,只能另外再写关于上位机创建产品增加设备和应用管理以及View2.0大屏显示的内容。明天再写,今天就先到这里。

写的不好,请大家多多批评指正!!
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)