在游乐场、商场、景区等人流量较大的地方,往往存在用户需要临时存放物品的情况,例如行李箱、外套、购物袋等。为了满足用户的储物需求,并提供更加便捷的服务体验,当前设计了一款物联网智能储物柜。
01
智能储物柜功能和架构设计
智能储物柜主控芯片采用STC12C5A60S2+电磁锁,使用4G联网模块E29 Cat-1 与华为云物联网服务器的连接,实现了数据的传输和管理,让用户可以通过微信小程序轻松查看储物柜的可用状态和选择合适的储物柜进行解锁。
用户在解锁储物柜后,会扣除相应的押金(预付金),然后根据使用时间进行计费。用户可以随时存取自己的物品,并且在使用完成后可以通过微信小程序完成订单结算,使整个使用过程更加便捷和透明。
智能储物柜支持的主要功能:
远程查看储物柜状态:用户可以通过微信小程序实时查看储物柜的可用状态,包括储物柜数量、剩余可用储物柜数量等信息。这使得用户在选择储物柜时可以提前了解储物柜的可用性,避免不必要的等待。
指定储物柜解锁:用户可以在微信小程序上选择需要使用的储物柜,并进行解锁操作。当用户选择指定储物柜后,储物柜会自动解锁,方便用户存放物品。
押金扣除和计费:在解锁储物柜时,系统会自动扣除用户的押金(预付金)。智能储物柜根据使用时间进行计费,用户只需根据实际使用时间支付相应费用。
存取物品:一旦用户成功解锁储物柜,他们就可以将物品存放或取出。用户可以随时存取自己的物品,并享受到安全可靠的储物体验。
临时解锁功能:如果用户需要频繁存取物品,储物柜提供了临时解锁功能。用户可以选择设置一段时间内的临时解锁,无需重复进行解锁操作,方便快捷。
订单结算:用户在使用完成后,可以通过微信小程序完成订单结算。系统会根据实际使用时间和费率进行计算,并生成相应的费用清单供用户支付。
02
软硬件选型
智能储物柜所需的硬件主要包括下面几个部分:
主控芯片:采用STC12C5A60S2主控芯片,具有低功耗、高性能和丰富的外设接口,能够满足储物柜的控制需求。
4G联网模块:采用华为云IOT提供的4G联网模块E29 Cat-1,确保储物柜具备稳定的网络连接功能,实现远程数据传输和管理。
电磁锁:储物柜采用电磁锁作为解锁和上锁的装置,能够快速、安全地实现储物柜的开关操作。电磁锁具有较高的稳定性和安全性。
电源系统:储物柜需要一个可靠的电源系统来供电,以确保储物柜的正常运行。
外壳和结构组件:储物柜外壳。
软件包含了以下四个部分:
设备端的程序开发,智能储物柜设备端的程序。
华为云IoT物联网平台设备注册、消息转发。
智能锁的后台云服务器搭建。
小程序、公众号程序开发。
03
华为云 IoT 物联网开发
开通物联网服务:https://www.huaweicloud.com/product/iothub.html
点击总览,查看 IoT 企业实例接入信息。我们当前设备准备采用MQTT协议接入华为云平台,这里可以看到MQTT协议的地址和端口号等信息。
MQTT协议接入端口号有两个,1883是非加密端口,8883是证书加密端口,单片机无法加载证书,所以使用1883端口比较合适。 接下来的ESP8266就采用1883端口连接华为云物联网平台。
点击产品页,再点击创建产品,根据自己产品名字填写。
产品创建完成之后,点击进入产品详情页面,翻到最下面可以看到模型定义。
先点击自定义模型,创建一个服务ID,接着点击新增属性。
属性添加成功后,如下图
产品是属于上层的抽象模型,接下来在产品模型下添加实际的设备。添加的设备最终需要与真实的设备关联在一起,完成数据交互。
设备标识码、密码这些根据自己情况认真填写。
创建之后,得到的设备身份信息如下:
华为云物联网平台 MQTT协议主题订阅与发布相关帮助文档地址:https://support.huaweicloud.com/devg-iothub/iot_02_2200.html
智能储物柜订阅主题
设备想接收平台下发的消息,就需要订阅平台下发消息给设备 的主题,订阅后,平台下发消息给设备,设备就会收到消息。
以当前设备为例,最终订阅主题的格式如下:
$oc/devices/{device_id}/sys/messages/down
最终的格式:
$oc/devices/65113d05a559fd7cd41435f8_lock1/sys/messages/down
对于设备来说,主题发布表示向云平台上传数据,将最新的传感器数据,设备状态上传到云平台。这个操作称为:属性上报。文档地址:https://support.huaweicloud.com/api-iothub/iot_06_v5_3010.html
当前设备发布主题,上报属性的格式总结如下:
发布的主题格式:
$oc/devices/{device_id}/sys/properties/report
最终的格式:
$oc/devices/65113d05a559fd7cd41435f8_lock1/sys/properties/report
发布主题时,需要上传数据,这个数据格式是JSON格式。
上传的JSON数据格式如下:
{
"services": [
{
"service_id": <填服务ID>,
"properties": {
"<填属性名称1>": <填属性值>,
"<填属性名称2>": <填属性值>,
..........
}
}
]
}
根据JSON格式,一次可以上传多个属性字段。这个JSON格式里的,服务ID,属性字段名称,属性值类型,在前面创建产品的时候就已经介绍了,不记得可以翻到前面去查看。
根据这个格式,组合一次上传的属性数据:
{"services": [{"service_id": "lock","properties":{"lock":1}}]}
设备身份认证:MQTT协议登录需要填用户ID,设备ID,设备密码等信息,就像我们平时登录QQ,微信一样要输入账号密码才能登录。MQTT协议登录的这3个参数,一般称为MQTT三元组。
华为云提供了一个在线工具,用来生成MQTT鉴权三元组:https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/ 打开这个工具,填入设备的信息,点击生成,就可以得到MQTT的登录信息了。
在产品页面,添加控制命令。
根据自己设备的情况填写需要发送的控制命令。
在设备页面测试刚才添加的命令。
点击确定之后,在MQTT客户端上就能收到云端下发的控制命令。
这个下发的命令是有反馈。设备端收到之后,可以向服务器反馈状态,这样服务器才能知道刚才的控制命令确实发送成功了。
MQTT回应之后,可以在云端的发送命令界面,看到右上角有弹窗提示,命令下发成功。
04
微信小程序开发
智能存储柜的用户端微信小程序一般有两种需求:获取设备的状态、给设备发送控制指令。
我们设计的软件里,如果想要获取设备的最新状态信息,就采用设备影子接口。帮助文档:https://support.huaweicloud.com/api-iothub/iot_06_v5_0079.html
设备影子接口返回的数据如下:
{
"device_id": "65113d05a559fd7cd41435f8_lock1",
"shadow": [
{
"service_id": "lock",
"desired": {
"properties": null,
"event_time": null
},
"reported": {
"properties": {
"lock": 1
},
"event_time": "20230925T081357Z"
},
"version": 0
}
]
}
控制命令发送采用CreateCommand 接口,文档:https://support.huaweicloud.com/api-iothub/iot_06_v5_0038.html
设备端可以收到下发的命令
05
硬件端代码开发
MQTT连接主要代码:
// 引入必要的库
#include <reg51.h>
#include <string.h>
// 定义串口通信相关的寄存器地址
#define UART_BAUD_RATE_H 0xFD // 波特率高位
#define UART_BAUD_RATE_L 0xFE // 波特率低位
#define UART_CONTROL_REG 0x98 // 控制寄存器地址
// 定义MQTT服务器信息
#define MQTT_SERVER "mqtt.example.com" // MQTT服务器地址
#define MQTT_PORT "1883" // MQTT端口号
// 定义设备ID和认证信息
#define DEVICE_ID "your_device_id" // 设备ID
#define USERNAME "your_username" // 用户名
#define PASSWORD "your_password" // 密码
// 定义订阅和发布的主题
#define SUBSCRIBE_TOPIC "your_subscribe_topic" // 订阅主题
#define PUBLISH_TOPIC "your_publish_topic" // 发布主题
// 定义MQTT协议相关指令
#define CONNECT_CMD "AT+CMQTTCONN="" MQTT_SERVER "","" MQTT_PORT "","" DEVICE_ID "","" USERNAME "","" PASSWORD ""\r\n" // 连接指令
#define SUBSCRIBE_CMD "AT+CMQTTSUB="" SUBSCRIBE_TOPIC "",1\r\n" // 订阅指令
#define PUBLISH_CMD "AT+CMQTTPUB="" PUBLISH_TOPIC "",0,0,0,"your_message"\r\n" // 发布指令
// 定义串口发送函数
void UART_SendString(char *str) {
while (*str) {
SBUF = *str;
while (!TI);
TI = 0;
str++;
}
}
// 主函数
void main() {
// 配置串口通信波特率为9600bps
PCON = 0x00;
TMOD = 0x20;
TH1 = UART_BAUD_RATE_H;
TL1 = UART_BAUD_RATE_L;
TR1 = 1;
SCON = UART_CONTROL_REG;
// 连接MQTT服务器
UART_SendString(CONNECT_CMD);
// 等待连接成功的回复
// 编写等待回复的代码
// 订阅主题
UART_SendString(SUBSCRIBE_CMD);
// 等待订阅成功的回复
// 编写等待回复的代码
// 设备登录成功,进入循环
while (1) {
// 定时上报数据,可以根据需求设置时间间隔
// 这里使用延时函数模拟时间间隔
delay(5000);
// 上报数据到指定主题
UART_SendString(PUBLISH_CMD);
// 等待上报完成的回复
// 编写等待回复的代码
}
}
锁控制代码:
// 引入必要的库
#include <reg51.h>
#include <string.h>
// 定义串口通信相关的寄存器地址
#define UART_BAUD_RATE_H 0xFD // 波特率高位
#define UART_BAUD_RATE_L 0xFE // 波特率低位
#define UART_CONTROL_REG 0x98 // 控制寄存器地址
// 定义MQTT服务器信息
#define MQTT_SERVER "mqtt.example.com" // MQTT服务器地址
#define MQTT_PORT "1883" // MQTT端口号
// 定义设备ID和认证信息
#define DEVICE_ID "your_device_id" // 设备ID
#define USERNAME "your_username" // 用户名
#define PASSWORD "your_password" // 密码
// 定义订阅主题
#define SUBSCRIBE_TOPIC "your_subscribe_topic" // 订阅主题
// 定义电磁锁的IO口连接图纸
#define LOCK_1 P2_0 // 电磁锁1的控制IO口
#define LOCK_2 P2_1 // 电磁锁2的控制IO口
#define LOCK_3 P2_2 // 电磁锁3的控制IO口
#define LOCK_4 P2_3 // 电磁锁4的控制IO口
#define LOCK_5 P2_4 // 电磁锁5的控制IO口
#define LOCK_6 P2_5 // 电磁锁6的控制IO口
#define LOCK_7 P2_6 // 电磁锁7的控制IO口
#define LOCK_8 P2_7 // 电磁锁8的控制IO口
#define LOCK_9 P3_0 // 电磁锁9的控制IO口
#define LOCK_10 P3_1 // 电磁锁10的控制IO口
#define LOCK_11 P3_2 // 电磁锁11的控制IO口
#define LOCK_12 P3_3 // 电磁锁12的控制IO口
// 定义MQTT协议相关指令
#define CONNECT_CMD "AT+CMQTTCONN="" MQTT_SERVER "","" MQTT_PORT "","" DEVICE_ID "","" USERNAME "","" PASSWORD ""\r\n" // 连接指令
#define SUBSCRIBE_CMD "AT+CMQTTSUB="" SUBSCRIBE_TOPIC "",1\r\n" // 订阅指令
// 定义串口发送函数
void UART_SendString(char *str) {
while (*str) {
SBUF = *str;
while (!TI);
TI = 0;
str++;
}
}
// 电磁锁控制函数
void controlLock(int lockNumber, int lockState) {
switch (lockNumber) {
case 3:
// 控制电磁锁3
if (lockState == 1) {
// 打开电磁锁
LOCK_3 = 1;
} else {
// 关闭电磁锁
LOCK_3 = 0;
}
break;
case 4:
// 控制电磁锁4
if (lockState == 1) {
// 打开电磁锁
LOCK_4 = 1;
} else {
// 关闭电磁锁
LOCK_4 = 0;
}
break;
case 5:
// 控制电磁锁5
if (lockState == 1) {
// 打开电磁锁
LOCK_5 = 1;
} else {
// 关闭电磁锁
LOCK_5 = 0;
}
break;
case 6:
// 控制电磁锁6
if (lockState == 1) {
// 打开电磁锁
LOCK_6 = 1;
} else {
// 关闭电磁锁
LOCK_6 = 0;
}
break;
case 7:
// 控制电磁锁7
if (lockState == 1) {
// 打开电磁锁
LOCK_7 = 1;
} else {
// 关闭电磁锁
LOCK_7 = 0;
}
break;
case 8:
// 控制电磁锁8
if (lockState == 1) {
// 打开电磁锁
LOCK_8 = 1;
} else {
// 关闭电磁锁
LOCK_8 = 0;
}
break;
case 9:
// 控制电磁锁9
if (lockState == 1) {
// 打开电磁锁
LOCK_9 = 1;
} else {
// 关闭电磁锁
LOCK_9 = 0;
}
break;
case 10:
// 控制电磁锁10
if (lockState == 1) {
// 打开电磁锁
LOCK_10 = 1;
} else {
// 关闭电磁锁
LOCK_10 = 0;
}
break;
case 11:
// 控制电磁锁11
if (lockState == 1) {
// 打开电磁锁
LOCK_11 = 1;
} else {
// 关闭电磁锁
LOCK_11 = 0;
}
break;
case 12:
// 控制电磁锁12
if (lockState == 1) {
// 打开电磁锁
LOCK_12 = 1;
} else {
// 关闭电磁锁
LOCK_12 = 0;
}
break;
default:
// 锁编号无效
break;
}
}
// 主函数
void main() {
// 配置串口通信波特率为9600bps
PCON = 0x00;
TMOD = 0x20;
TH1 = UART_BAUD_RATE_H;
TL1 = UART_BAUD_RATE_L;
TR1 = 1;
SCON = UART_CONTROL_REG;
// 连接MQTT服务器
UART_SendString(CONNECT_CMD);
// 等待连接成功的回复
// 编写等待回复的代码
// 订阅主题
UART_SendString(SUBSCRIBE_CMD);
// 等待订阅成功的回复
// 编写等待回复的代码
// 设备登录成功,进入循环
while (1) {
// 接收到MQTT消息后,解析并控制对应的电磁锁
// 编写接收和解析MQTT消息的代码
// 设备接收到的消息格式为 "LOCK_X_ON" 或 "LOCK_X_OFF",其中 X 为电磁锁编号
// 解析消息,并提取电磁锁编号和状态
int lockNumber; // 电磁锁编号
int lockState; // 电磁锁状态,0表示关闭,1表示打开
if (strncmp(receivedMessage, "LOCK_", 5) == 0) {
lockNumber = receivedMessage[5] - '0'; // 提取锁编号
if (strstr(receivedMessage, "ON") != NULL) {
lockState = 1; // 提取锁状态,ON表示打开
} else if (strstr(receivedMessage, "OFF") != NULL) {
lockState = 0; // 提取锁状态,OFF表示关闭
}
// 控制对应的电磁锁
controlLock(lockNumber, lockState);
}
}
}
至此,我们完成了智能寄存柜的端到端完整开发过程。
往期推荐