基于STM32设计的物流追踪系统(GPS+BC20+华为云IOT)

Posted DS小龙哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于STM32设计的物流追踪系统(GPS+BC20+华为云IOT)相关的知识,希望对你有一定的参考价值。

1. 前言

随着人们生活节奏的加快,促使物流行业突飞猛进的快速的发展,物流行业的快速发展也导致物流过程出现了一系列的问题。近年来贵重物品在物流中的比例越来越多,同时贵重物流在物流过程中的丢失也越来越多,贵重物品丢失后无法查询在哪个环节丢失的问题引起了物流行业的高度重视。不仅贵重物品需要全程监控,危险品的运输也急需全程的监控,确保在危险品出现事故时可以第一时间解决。

利用GPS技术能够动态采集物流过程中物品的变化信息和地理位置信息,在该系统中加入GPRS模块,利用当前成熟的移动通信技术,在没有有线网络的情况下,也能做到与管理平台数据库之间的通信,既能满足监管平台对物品实时信息的需求,当物品出现丢失时或出现异常替换时,实时报告给监管平台,对物流环节中物品进行全程追踪。有效解决了目前贵重物品和危险品物流过程中信息不能实时采集和物品丢失、掉包的问题。

物流追踪系统结构介绍:基于对贵重物品物流环节的考察,提出了以STM32F103系列的MCU为核心的物流追踪系统,采用移远BC20模块作为上网和GPS定位设备,利用GPS技术实时采集物流过程中的物品的具体信息如地理位置信息和物品变动信息,实时上传到物联网数据平台,这里物联网平台采用的是华为云IOT,并且设计了专用的android手机APP和windows桌面管理软件,可以实时获取所有电子标签的地理位置,调用百度地图接口,显示地理位置。这样能够时,用户,监管平台能实时了解到标签的位置。

整个产品实现流程是:

设备端实时采集GPS数据,并登录华为云物联网服务器,保持与服务器连接;手机APP或者电脑管理软件,可以查看当前在线的设备列表,可以选择某个设备主动获取信息,当设备收到APP发来的数据获取请求后,就将GPS数据传递出去,手机APP收到数据后就解析GPS经纬度,调用百度地图显示当前设备所处的位置。

运行效果

2. 创建产品

(1)找到物联网设备的页面,选择设备接入

官网地址: https://www.huaweicloud.com/s/JeeJqeiBlOe9kSU

(2)选择免费试用

(3)创建产品

(4)设置产品的一些信息,完成注册

(5)产品创建成功后,提示了产品ID,点击查看详情,可以看到创建的产品

(6)查看产品信息。到此,产品创建完成

3. 自定义数据模型

(1)在产品的页面,下面有一个自定义产品模型的选项,这个选项可以定义设备上传的数据模型,也就是数据的类型。

(2)添加属性。

增加经度、纬度两个属性。

4. 创建设备

一个产品目录下可以创建很多个设备,作为电子标签设备,设备端一般支持自动创建设备,这样设备在终端添加进来的时候,就自动在平台产品下完成注册,方便设备的动态添加和删除。如果有固定的设备,不需要动态添加和删除,也可以在网页上手动创建设备。

下面介绍,在网页上手动创建设备的步骤。

(1)选择设备页面,点击右上角的设备创建,填入设备的信息,点击确定

(2)注册成功会提示设备的很多信息,需要保存起来

(3)弹出的下载框里就是设备的ID等信息


    "device_id": "6210e8acde9933029be8facf_dev1",
    "secret": "12345678"

(4)设备创建成功,在设备页面上可以看到设备还未激活,需要设备终端登录一次就可以成功激活

5. 生成MQTT登录信息

设备终端登录服务器需要账号、密码等信息,有了这些身份验证才能正常的登录到服务器。

注意:一个账号不能在多台设备终端使用,每个设备终端应该是自己唯一的账号密匙,这样上传到服务器的数据才不会错乱。

华为云提供的MQTT账户信息生成在线小工具: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/

这里填入的信息,就是在创建设备时提示下载保存的密匙信息,照着填入,点击生成即可得到MQTT的密匙。

ClientId  6210e8acde9933029be8facf_dev1_0_0_2022021913
Username  6210e8acde9933029be8facf_dev1
Password  6cea55404b463e666cd7a6060daba745bbaa17fe7078dfef45f8151cdf19673d

6. 设备与服务器数据交互的流程

当前设备登录华为云物联网服务器的协议是采用MQTT,MQTT协议里的数据交互方法就是:主题的订阅与发布。

这个订阅比较好理解,就相当于抖音里的关注一下,你关注某个主播或者好友,当他发布新动态时,你就可以收到他的消息了。所以,对于设备端而言,需要订阅服务器的主题,当服务器有新消息时,设备端就能收到数据。设备端的主题发布就是向服务器发送信息。

(1)华为云物联网服务器的地址信息

端口: 1883
域名: a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com
IP地址: 121.36.42.100

(2)华为云IOT平台MQTT协议订阅主题的格式

格式: $oc/devices/device_id/sys/messages/down
//订阅主题: 平台下发消息给设备
$oc/devices/6210e8acde9933029be8facf_dev1/sys/messages/down

(3)华为云IOT平台MQTT协议上报主题的格式

格式: $oc/devices/device_id/sys/properties/report
//设备上报主题请求
$oc/devices/6210e8acde9933029be8facf_dev1/sys/properties/report
//上报的数据格式如下
"services": ["service_id": "gps","properties":"longitude":12.345,"latitude":33.345]

参数说明:

device_id 设备ID这个字段,在创建设备时生成的。

service_id这个字段填服务ID,这个ID在产品页面下面自定义模型的位置可以看到,这个服务ID就在创建数据模型时设置的。

后面的里longitude和latitude表示上传到服务器的数据属性字段。这个属性的名称是自己在自定义模型页面自己填的。

7. 软件模拟设备登录测试

这里先使用MQTT客户模拟真实设备,登录服务器激活设备,上传数据测试。

当前使用的MQTT客户端软件下载地址:https://download.csdn.net/download/xiaolong1126626497/18784012

(1)填入参数登录,上传数据

(2)登录云端服务器查看设备效果。正常情况下设备已经处于在线状态,并且收到了设备上传的数据。

8. 开发电子标签管理软件

软件采用QT设计的,获取在线设备,获取设备数据,并调用百度地图显示设备的位置。

STM32设备端的完整源码下载: https://download.csdn.net/download/xiaolong1126626497/85688864

Android、windows上位机源码、可执行文件完整资料包下载:https://download.csdn.net/download/xiaolong1126626497/85688883

8.1 创建IAM账户

创建一个IAM账户,方便接下来使用API接口访问华为云服务时,生成token登录密匙。

地址: https://console.huaweicloud.com/iam/?region=cn-north-4#/iam/users

账户创建好之后,代码里就可以编写一个获取Token的函数。

/*
功能: 获取token
*/
void Widget::GetToken()

    //表示获取token
    function_select=3;

    QString requestUrl;
    QNetworkRequest request;

    //设置请求地址
    QUrl url;

    //获取token请求地址
    requestUrl = QString("https://iam.%1.myhuaweicloud.com/v3/auth/tokens")
                 .arg(SERVER_ID);

    //自己创建的TCP服务器,测试用
    //requestUrl="http://10.0.0.6:8080";

    //设置数据提交格式
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json;charset=UTF-8"));

    //构造请求
    url.setUrl(requestUrl);

    request.setUrl(url);

    QString text =QString("\\"auth\\":\\"identity\\":\\"methods\\":[\\"password\\"],\\"password\\":"
    "\\"user\\":\\"domain\\": "
    "\\"name\\":\\"%1\\",\\"name\\": \\"%2\\",\\"password\\": \\"%3\\","
    "\\"scope\\":\\"project\\":\\"name\\":\\"%4\\"")
            .arg(MAIN_USER)
            .arg(IAM_USER)
            .arg(IAM_PASSWORD)
            .arg(SERVER_ID);

    //发送请求
    manager->post(request, text.toUtf8());

8.2 查询设备列表

帮助文档地址: https://support.huaweicloud.com/api-iothub/iot_06_v5_0048.html

官方提供了API接口,可以直接获取产品下面的所有设备详细信息返回。

关于请求参数,返回结果的字段含义,在帮助文档里有详细介绍。

URL格式: /v5/iot/project_id/devices

示例:  

https://iotda.cn-north-4.myhuaweicloud.com/v5/iot/0f2d61e43600f4e22f74c003616710bc/devices?product_id=6210e8acde9933029be8facf&is_cascade_query=false&limit=10&marker=ffffffffffffffffffffffff&offset=0

接口的在线调试地址:https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=IoTDA&api=ListDevices

返回的结果:


 "devices": [
  
   "app_id": "1af45e3938bb4482bc0be0a5cb3089e3",
   "app_name": "DefaultApp_620esbs1",
   "device_id": "6210e8acde9933029be8facf_dev2",
   "node_id": "dev2",
   "gateway_id": "6210e8acde9933029be8facf_dev2",
   "device_name": "dev2",
   "node_type": "GATEWAY",
   "description": null,
   "fw_version": null,
   "sw_version": null,
   "device_sdk_version": null,
   "product_id": "6210e8acde9933029be8facf",
   "product_name": "GPS",
   "status": "INACTIVE",
   "tags": []
  ,
  
   "app_id": "1af45e3938bb4482bc0be0a5cb3089e3",
   "app_name": "DefaultApp_620esbs1",
   "device_id": "6210e8acde9933029be8facf_dev1",
   "node_id": "dev1",
   "gateway_id": "6210e8acde9933029be8facf_dev1",
   "device_name": "dev1",
   "node_type": "GATEWAY",
   "description": null,
   "fw_version": null,
   "sw_version": null,
   "device_sdk_version": null,
   "product_id": "6210e8acde9933029be8facf",
   "product_name": "GPS",
   "status": "OFFLINE",
   "tags": []
  
 ],
 "page": 
  "count": 2,
  "marker": "6210efa980c60c11be19ead1"
 

上面的返回结果里通过JSON数组保存了设备信息,每一个设备就是一个独立的对象,上面的数据里返回了两个设备的信息,说明产品的目录下创建了两个设备。

应用层编写代码完成设备列表获取:

//查询所有设备
void Widget::Get_AllDevice()

    //查询设备列表
    function_select=1;

    QString requestUrl;
    QNetworkRequest request;

    //设置请求地址
    QUrl url;

    //设备列表请求地址
    requestUrl = QString("https://iotda.%1.myhuaweicloud.com/v5/iot/%2/devices?product_id=%3&is_cascade_query=false&limit=10&marker=ffffffffffffffffffffffff&offset=0")
                 .arg(SERVER_ID)
            .arg(PROJECT_ID)
            .arg(Product_id);

    //设置数据提交格式
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));

    //设置token
    request.setRawHeader("X-Auth-Token",Token);

    //构造请求
    url.setUrl(requestUrl);

    request.setUrl(url);

    //发送请求
    manager->get(request);

服务器返回的结果解析:

//查询设备列表
    if(function_select==1)
    
        //清空原来的设备列表
        ui->comboBox->clear();
        device_id_lis.clear();

        //解析数据
        QJsonParseError json_error;
        QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
        if(json_error.error == QJsonParseError::NoError)
        
            QJsonObject obj = document.object();

            //判断是否是对象,然后开始解析数据
            if(document.isObject())
            
                QJsonObject obj = document.object();
                if(obj.contains("devices"))
                
                    QJsonArray array=obj.take("devices").toArray();
                    for(int i=0;i<array.size();i++)
                    
                        QJsonObject obj1=array.at(i).toObject();

                        //得到设备ID
                        if(obj1.contains("device_id"))
                        
                            QString device_id=obj1.take("device_id").toString();
                            device_id_lis.append(device_id);
                            ui->comboBox->addItem(device_id);

                            qDebug()<<"device_id:"<<device_id;
                        
                    
                
            
         
        return;
    

8.3 查询设备属性

(1)应用端查询设备属性的请求

帮助文档地址: https://support.huaweicloud.com/api-iothub/iot_06_v5_0034.html

(2)在线调试地址

接口的在线调试地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=IoTDA&api=ListProperties

(3)设备端响应的数据格式

帮助文档: https://support.huaweicloud.com/api-iothub/iot_06_v5_3011.html

(4)使用总结

上位机APP向设备端请求查询设备属性时,设备端会收到如下的消息:

$oc/devices/6210e8acde9933029be8facf_dev1/sys/properties/get/request_id=5f359b5c-542f-460e-9f51-85e82150ff4a"service_id":"gps"

设备端需要解析这个字符串,得到里面的request_id=5f359b5c-542f-460e-9f51-85e82150ff4a 值。在向服务器回应时,要带上这个请求ID。

设备端响应的主题格式: $oc/devices/device_id/sys/properties/get/response/request_id=request_id

示    例:
$oc/devices/6210e8acde9933029be8facf_dev1/sys/properties/get/response/request_id=6c36c85e-68e1-4d01-a2a3-b89f09bd0427

设备端响应的数据格式:
"services": ["service_id": "gps","properties":"longitude":12.345,"latitude":33.345]


应用端上位机收到设备端的响应数据:
"\\"response\\":\\"services\\":[\\"service_id\\":\\"gps\\",\\"properties\\":\\"longitude\\":12.345,\\"latitude\\":33.345]"

(5)应用端获取设备属性

   //查询设备属性
void Widget::Get_device_properties()

    //表示获取token
    function_select=0;

    QString requestUrl;
    QNetworkRequest request;

    //设置请求地址
    QUrl url;

    if(device_id_lis.size()<=0)
    
        //显示错误代码
        QMessageBox::information(this,"提示","未选择设备,请先获取设备列表\\n选择设备后重试.",QMessageBox::Ok,QMessageBox::Ok);
        return;
    

    //获取token请求地址
    requestUrl = QString("https://iotda.%1.myhuaweicloud.com/v5/iot/%2/devices/%3/properties?service_id=%4")
                 .arg(SERVER_ID)
            .arg(PROJECT_ID)
            .arg(device_id_lis.at(ui->comboBox->currentIndex()))
            .arg(service_id);

    //自己创建的TCP服务器,测试用
    //requestUrl="http://10.0.0.6:8080";

    //设置数据提交格式
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));

    //设置token
    request.setRawHeader("X-Auth-Token",Token);

    //构造请求
    url.setUrl(requestUrl);

    request.setUrl(url);

    //发送请求
    manager->get(request);

(6)应用端解析数据

    //查询设备属性
    if(function_select==0)
    
        //解析数据
        QJsonParseError json_error;
        QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
        if(json_error.error == QJsonParseError::NoError)
        
            //判断是否是对象,然后开始解析数据
            if(document.isObject())
            
                QJsonObject obj = document.object();
                if(obj.contains("response"))
                
                    QJsonObject obj1=obj.take("response").toObject();
                    if(obj1.contains("services"))
                    
                         QJsonArray array=obj1.take("services").toArray();

                         QDateTime current_date_time =QDateTime::currentDateTime();
                         QString current_date =current_date_time.toString("yyyy/MM/dd hh:mm:ss.zzz");
                         QString display_time="更新时间:"+current_date+"\\n";
                         for(int i=0;i<array.size();i++)
                         
                             QJsonObject obj2=array.at(i).toObject();
                             if(obj2.contains("properties"))
                             
                                 QJsonObject obj3=obj2.take("properties").toObject();


                                 if(obj3.contains("longitude"))
                                 
                                     //经度
                                     longitude_jin=obj3.take("longitude").toDouble();
                                     qDebug()<<"longitude_jin:"<<longitude_jin;
                                 

                                 if(obj3.contains("latitude"))
                                 
                                     //纬度
                                     latitude=obj3.take("latitude").toDouble();
                                     qDebug()<<"latitude:"<<latitude;
                                 

                                 display_time+=QString("GPS经度:%1\\n").arg(longitude_jin);
                                 display_time+=QString("GPS纬度:%1\\n").arg(latitude);
                                 ui->label_gps_info->setText(display_time);
                             
                         
                    
                
            
         
        return;
    

9. 开发电子标签设备端(软件模拟)

下面采用QT加MQTT协议开发一款真实设备模拟软件,与电子标签上位机管理软件完成数据交互。

下面图片左边是模拟设备端,右边是电子标签管理的上位机。可以快速模拟应用层与设备端的交互。

软件与服务器的交互都是通过华为云提供的HTTP接口实现的,具体的交互方法和格式,在第8小节已经讲过了,软件里只是使用具体的代码来实现。

工程代码:

10. STM32+BC20开发设备端(真实设备)

STM32设备端的完整源码下载: https://download.csdn.net/download/xiaolong1126626497/85688864

Android、windows上位机源码、可执行文件完整资料包下载:https://download.csdn.net/download/xiaolong1126626497/85688883

本小节介绍STM32+BC20连接华为云物联网平台,实现与上位机之间进行数据交互,完成真实的产品开发。

10.1 BC20模块

BC20是一款高性能、低功耗、多频段、支持 GNSS 定位功能的 NB-IoT 无线通信模块。BC20 在设计上兼容移远通信 GSM/GPRS/GNSS 系列的 MC20 模块,方便客户快速、灵活的进行产品设计和升级。BC20 提供丰富的外部接口和协议栈,同时支持中国移动 OneNET 物联网云平台,为客户的应用提供极大的便利。

BC2

以上是关于基于STM32设计的物流追踪系统(GPS+BC20+华为云IOT)的主要内容,如果未能解决你的问题,请参考以下文章

基于STM32单片机的的智能水杯系统设计-毕业设计资料

基于STM32设计物联网在线智能称重系统(OneNet)_2022

基于STM32设计物联网在线智能称重系统(OneNet)_2022

基于STM32设计的遥控小车(手机APP+GPS+温湿度+ESP8266)

基于STM32设计的遥控小车(手机APP+GPS+温湿度+ESP8266)

基于STM32设计智能称重系统(华为云IOT)