2022-8-15 10:00:04 [显示全部楼层]
220浏览
查看: 220|回复: 0

[项目] 家庭安全相册(三)-Tinkernode

[复制链接]
本帖最后由 szjuliet 于 2022-9-8 23:04 编辑





家庭安全相册(四)- 手机端(监护人)

开发板简介物联网与NB-IoT简介

物联网(The Internet of things,IoT)顾名思义,就是物与物相连的互联网。这有两层意思:第一,物联网的核心和基础仍然是互联网,是在互联网基础上的延伸和扩展的网络;第二,其用户端延伸和扩展到了任何物品与物品之间,进行信息交换和通信。

窄带物联网(Narrow Band Internet of Things,NB-IoT)是物联网领域一个新兴的技术,主要用于低移动性、小数据量、对时延不敏感的连接服务,其支持低功耗设备在网络中的数据传输,因此也是一种低功耗广域网(Low Power Wide Area Network,LPWAN)通信技术。相对于被逐渐淘汰的2G通信,NB-IoT具有三大优势:


大连接:海量链接的能力,在同一基站的情况下, NB-IoT 可以比现有无线技术提供 50~100 倍的接入数。一个扇区能够支持,10 万个连接,设备成本与功耗有效降低,网络架构得到优化。


广覆盖:在同样的频段下, NB-IoT比现有的网络增益提升了 20 dB,相当于提升了 100 倍的覆盖面积。

低功耗:NB-IoT借助 PSM(Power Saving Mode,节电模式)和 eDRX(Extended Discontinuous Reception,超长非连续接收)可实现更长待机。

特色:TinkerNode NB-IoT物联网开发板具有:NB-IoT全网通、GPS/北斗双星精确定位、全方位电源管理、太阳能供电、WiFi+蓝牙4.0二合一EPS32主控、微型U盘等六大特色功能,全方位覆盖物联网项目中的各类需要。

材料清单:1x ThinkerNode NB-loT 物联网开发版

Tinkernode接口说明

MonAugust-202208159175..png

Tinkernode在本项目的作用

因为Tinkernode搭载了北斗和GPS模块,同时有具有窄带物联网的功能。因此对于无法携带手机进校园的中小学生来说,可以作为可穿戴设备携带(如腕带),走到哪里,通过卫星实时获得的位置信息就可以随时发送出去。

但是经过我的数次尝试,随Tinkernode购买附送的联通NB IoT卡信号不好,打过客服的电话,了解到在深圳自己常呆的地方信号都不太好,“很少有绿色,基本都是灰色的”。因此无法通过sim卡将信息发送出来。所以只能通过Tinkernode的wifi功能连接手机热点将信息发送。后面可以尝试购买其他网络运营商的NB IoT卡来看看网络效果。


因为正值暑假,手头材料有限,只能裸机展示。

步骤1: 接线


接天线

GSM天线插在板子的NB孔上,GPS/BeiDou陶瓷有源天线连接在开发板背面标有GNSS的u.FL天线连接孔上。这两个孔都非常小,一定要对准才能插的上去。
说明:如果不需要用到NBIoT,可以不用接GSM天线。


接电池


Tinkernode有一个3.7V锂电池接口,可以接上3.7V的锂电池,带电状态下是给锂电池充电,此时板子上的CHG灯亮红色,脱机运行时可由接在电池接口上的锂电池供电。


注意事项:


GPS/BeiDou陶瓷有源天线的陶瓷面应该面向天空,尽可能在室外使用,否则无法获取有效的定位信息。
某天晚上在学校测试,当时在空旷的走廊上都没有任何卫星信号,索性抱着手提电脑到操场上绕了一圈,虽然NBIoT仍然没有信号,但是能看到的卫星一下子多了起来。如下图,能够看到20颗卫星,GPS9颗,北斗11颗,一共19颗卫星被用到。需要提醒的是北京在东8区,Tinkernode返回的时间需要加上8小时,实际时间是21点41分多。


步骤2: 编写程序

使用合适的示例程序


本项目只需要实时的经纬度数据,在Tinkernode示例程序中的GNSS(全球导航卫星系统)中有多个示例程序,我们要弄清楚它们代表的是什么意思。


上图中的GGA、GSA、GSV、RMC、VTG、GLL等是常见的GPS数据协议格式,我们只有理解了这些数据格式,才能对数据进行解析并找到我们需要的数据。
比如GGA返回的数据为:


//$GNGGA,023100.000,2240.63547,N,11403.56956,E,1,22,0.7,230.0,M,0.0,M,,*7D


这些数据代表的含义如下,我们可以根据自己的需要来解析相应字段的数据。

代码:
  1. //$GNGGA,023100.000,2240.63547,N,11403.56956,E,1,22,0.7,230.0,M,0.0,M,,*7D
  2. 字段0:$GPGGA,语句ID,表明该语句为Global Positioning System Fix Data(GGA)GPS定位信息
  3. 字段1:UTC 时间,hhmmss.sss,时分秒格式
  4. 字段2:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
  5. 字段3:纬度N(北纬)或S(南纬)
  6. 字段4:经度dddmm.mmmm,度分格式(前导位数不足则补0)
  7. 字段5:经度E(东经)或W(西经)
  8. 字段6:GPS状态,0=未定位,1=非差分定位,2=差分定位,3=无效PPS,6=正在估算
  9. 字段7:正在使用的卫星数量(00 - 12)(前导位数不足则补0)
  10. 字段8:HDOP水平精度因子(0.5 - 99.9)
  11. 字段9:海拔高度(-9999.9 - 99999.9)
  12. 字段10:M
  13. 字段11:地球椭球面相对大地水准面的高度
  14. 字段12:M
  15. 字段13:差分修正的数据龄期
  16. 字段14:差分参考站的ID
  17. 字段15:CRC
  18. 字段16:回车换行
复制代码

GNSS示例程序

本项目中,我们只需要经纬度信息(及时间信息),几乎所有示例程序我们都可以使用,这里我们使用GNSS示例程序,它返回的有时间信息、位置信息和卫星信息。

代码:
  1. /*!
  2. * @file getGNSS.ino
  3. * @brief Print all the GNSS info available in BC20.
  4. *
  5. * @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
  6. * @licence     The MIT License (MIT)
  7. * @author      Wuxiao
  8. * @version  V1.0
  9. * @date  2019-10-29
  10. * @get from https://www.dfrobot.com
  11. */
  12. #include "DFRobot_BC20.h"
  13. DFRobot_BC20 myBC20;

  14. void Display_Location_Information(){

  15.     //UTC time of the anchor point
  16.     Serial.print("Time:\t\t");
  17.     Serial.print(sCLK.Year);
  18.     Serial.print("/");
  19.     Serial.printf("d",sCLK.Month);
  20.     Serial.print("/");
  21.     Serial.printf("d ",sCLK.Day);
  22.     Serial.printf(" d",sCLK.Hour);
  23.     Serial.printf(":d",sCLK.Minute);
  24.     Serial.printf(":d\r\n",sCLK.Second);

  25.     Serial.print("Latitude:\t");
  26.     Serial.print(sGGNS.LatitudeVal,6);
  27.     Serial.print(" deg ");
  28.     Serial.println(sRMC.LatitudeDir);
  29.     Serial.print("Longitude:\t");
  30.     Serial.print(sGGNS.LongitudeVal,6);
  31.     Serial.print(" deg ");
  32.     Serial.println(sRMC.LongitudeDir);
  33.     Serial.print("Altitude:\t");
  34.     Serial.print(sGGNS.Altitude,1);
  35.     Serial.println(" m");
  36.     Serial.print("Speed:\t\t");
  37.     Serial.print(sGGNS.Speed);
  38.     Serial.println(" km/h");
  39.     Serial.print("Heading:\t");
  40.     Serial.print(sGGNS.Heading);
  41.     Serial.println(" deg");
  42.     Serial.print("Status:\t\t");
  43.     Serial.println(sGGNS.FixStatus);
  44.     Serial.print("PDOP:\t\t");
  45.     Serial.println(sGGNS.PDOP);
  46.     Serial.print("HDOP:\t\t");
  47.     Serial.println(sGGNS.HDOP);
  48.     Serial.print("VDOP:\t\t");
  49.     Serial.println(sGGNS.VDOP);
  50.     Serial.println();
  51. }

  52. void Display_Satellite_Information(){
  53.     Serial.print(sSAT.NUM);
  54.     Serial.println(" in view.");
  55.     Serial.print(sSAT.USE);
  56.     Serial.println(" in used.");
  57.     Serial.print("PRN\t");
  58.     Serial.print("Elev(deg)\t");
  59.     Serial.print("Azim(deg)\t");
  60.     Serial.print("SNR(dBHz)\t");
  61.     Serial.print("SYS\t");
  62.     Serial.println("Used");
  63.     for(uint8_t i = 0; i <sSAT.NUM; i++){
  64.         Serial.print(sSAT.data[i].PRN);
  65.         Serial.print("\t");
  66.         Serial.print(sSAT.data[i].Elev);
  67.         Serial.print("\t\t");
  68.         Serial.print(sSAT.data[i].Azim);
  69.         Serial.print("\t\t");
  70.         Serial.print(sSAT.data[i].SNR);
  71.         Serial.print("\t\t");
  72.         Serial.print(sSAT.data[i].SYS);
  73.         Serial.print("\t");
  74.         Serial.println(sSAT.data[i].Status);
  75.     }
  76. }

  77. void setup(){
  78.     Serial.begin(115200);
  79.     Serial.print("Starting the BC20.Please wait. . . ");
  80.     while(!myBC20.powerOn()){
  81.         delay(1000);
  82.         Serial.print(".");
  83.     }
  84.     Serial.println("BC20 started successfully !");
  85.     Serial.println("check OK");
  86.     if(myBC20.getQGNSSC() == OFF){
  87.         Serial.println("open QGNSSC");
  88.         myBC20.setQGNSSC(ON);
  89.     }
  90. }

  91. void loop(){
  92.     delay(5000);
  93.     myBC20.getQGNSSRD();
  94.     Display_Location_Information();
  95.     Display_Satellite_Information();
  96. }
复制代码

改写程序

因为我们使用wifi来进行MQTT连接并发布消息,所以需要添加wifi头文件。

虽然使用Tinkernode发送消息没有20个字符的限制(如下图是在EasyIoT上接收到的Tinkernode发送的消息),但是由于我们在行空板已经进行了数据格式的定义,所以在Tinkernode端我们也需要对经纬度进行编码。即经度、纬度加上100再乘以10的6次方,连同家庭成员ID一起发送。


进行编码后再发送的经纬度消息:


使用相同的经纬度数据,家庭成员ID在1~6中随机产生。


头文件

代码:

  1. #include "DFRobot_BC20.h"
  2. #include <WiFi.h>
  3. #include <PubSubClient.h>
  4. #include "DFRobot_Iot.h"
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
复制代码

配置wifi

代码:

  1. /*配置WIFI名和密码*/
  2. const char * WIFI_SSID     = "";        //填入WiFi SSID
  3. const char * WIFI_PASSWORD = "";        //填入WiFi 密码
复制代码

配置MQTT参数


代码:
  1. *配置设备的认证信息*/
  2. String Iot_id = "";                        //填入Iot_id
  3. String Client_ID  = "";                        //任意数值,用于区分不同设备
  4. String Iot_pwd    = "";                    //填入Iot_pwd

  5. /*配置IoT云平台的IP地址和端口号*/
  6. String EasyIot_SERVER = "182.254.130.180";
  7. uint16_t PORT = 1883;

  8. /*配置要推送(Publish)或订阅(Subscribe)的topic*/
  9. const char * pubTopic = "";                //填入发布消息的Topic
复制代码

定义变量

代码:
  1. /*位置信息变量*/
  2. float Latitude; /* 经度原始值*/
  3. float Longitude; /* 纬度原始值*/
  4. int Latitude_int; /* 经度转换为整数值*/
  5. int Longitude_int; /* 纬度转换为整数值*/

  6. int id; /*家庭成员ID号,1:爸爸, 2: 妈妈, 3:爷爷, 4:奶奶, 5: 大宝, 6: 小宝*/
  7. String str; /*存放待发送的MQTT消息:ID号,转换为整数的经纬度值*/
  8. String str1; /*存放转换为字符串的原始的经度*/
  9. String str2; /*存放转换为字符串的原始的纬度*/
  10. String joint; /*用于合并信息发送*/
复制代码

连接wifi

代码:
  1. /*连接WiFi*/
  2. void connectWiFi() {
  3.   WiFi.disconnect();
  4.   delay(100);
  5.   Serial.print("Connecting to ");
  6.   Serial.println(WIFI_SSID);
  7.   WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  8.   while (WiFi.status() != WL_CONNECTED) {
  9.     delay(500);
  10.     Serial.print(".");
  11.   }
  12.   Serial.println();
  13.   Serial.println("WiFi connected");
  14.   Serial.print("IP Adderss: ");
  15.   Serial.println(WiFi.localIP());
  16. }
复制代码

连接到IoT云服务器

代码:
  1. /*连接到IoT云服务器*/
  2. void ConnectCloud() {
  3.   while (!client.connected()) {
  4.     Serial.print("Attempting MQTT connection...");
  5.     if (client.connect(myEasyIoT._clientId, myEasyIoT._username, myEasyIoT._password)) {
  6.       Serial.println("Connect Server OK");
  7.     } else {
  8.       Serial.print("failed, rc=");
  9.       Serial.print(client.state());
  10.       Serial.println(" Try again in 5 seconds");
  11.       delay(5000);
  12.     }
  13.   }
  14. }
复制代码

对经纬度进行编码

由于需要在空旷的地方才能获得卫星信号并传回经纬度信息,为了方便展示,这里我们使用固定数值来演示。只要程序能够测试通过,等实际使用时效果是完全一样的。

为了能够在20位以内的字符将信息完整的发送出去,我们仍然要对经纬度进行适当的编码。经度、纬度加上100后再乘以10的6次方转换为整数,前面拼接上ID发送到行空板,行空板再进行解码即可获得原始的经纬度数据。


代码:
  1. /*显示位置信息*/
  2. void Display_Location_Information(){

  3.     Serial.print("Latitude:\t");
  4.     Serial.print(sGGNS.LatitudeVal,6);
  5.     Serial.print(" deg ");
  6.     Serial.println(sRMC.LatitudeDir);
  7.     //Latitude = sGGNS.LatitudeVal;
  8.     Latitude = 22.70537;
  9.     Serial.print("Longitude:\t");
  10.     Serial.print(sGGNS.LongitudeVal,6);
  11.     Serial.print(" deg ");
  12.     Serial.println(sRMC.LongitudeDir);
  13.     //Longitude = sGGNS.LongitudeVal;
  14.     Longitude = 114.2185209;
  15.     str1 = String(Longitude,6);
  16.     str2 = String(Latitude,6);
  17.     Longitude_int = (Longitude+100) * pow(10,6); /* 将经度编码,加100后转换为整数*/
  18.     Latitude_int = (Latitude+100) * pow(10,6); /* 将纬度编码,加100后转换为整数*/
  19.     str = (String(rand()%6+1)) + String(Longitude_int) + String(Latitude_int); /* 将随机生成的id号和经度纬度拼接*/
  20. }
复制代码

setup函数


代码:
  1. void setup(){
  2.     Serial.begin(115200);

  3.     /*连接WIFI*/
  4.     connectWiFi();

  5.     /*配置需要连接的IoT云服务器(Easy-IoT)*/
  6.     myEasyIoT.init(EasyIot_SERVER, Iot_id, Client_ID, Iot_pwd);
  7.     client.setServer(myEasyIoT._mqttServer, PORT);

  8.     /*连接到Easy-IoT*/
  9.     ConnectCloud();

  10.     /*启动BC20*/
  11.     Serial.print("Starting the BC20.Please wait. . . ");
  12.     while(!myBC20.powerOn()){
  13.         delay(1000);
  14.         Serial.print(".");
  15.     }
  16.     Serial.println("BC20 started successfully !");
  17.     Serial.println("check OK");
  18.     if(myBC20.getQGNSSC() == OFF){
  19.         Serial.println("open QGNSSC");
  20.         myBC20.setQGNSSC(ON);
  21.     }
  22. }
复制代码

loop函数


代码:
  1. void loop(){
  2.     delay(5000);
  3.     myBC20.getQGNSSRD();
  4.     Display_Location_Information();
  5.     // Display_Satellite_Information();

  6.     /*IoT云服务器断线重连*/
  7.     if (!client.connected()) {
  8.       ConnectCloud();
  9.     }
  10.     client.loop();

  11.     /*每隔一段时间向Easy-IoT发送消息*/
  12.     Serial.println("Sending message to cloud...");
  13.     joint = String("Latitude:") + str1 + String("   Longitude:" )+ String(str2);
  14.     Serial.println(joint); //将经度和纬度合并一起打印
  15.     client.publish(pubTopic, str.c_str()); //将字符串str转换为publish支持的格式:const char*
  16.     Serial.println("Message is sent.");
  17.     delay(10000);
  18. }
  19. ArduinoCopy
复制代码

完整的程序:


代码:
  1. #include "DFRobot_BC20.h"
  2. #include <WiFi.h>
  3. #include <PubSubClient.h>
  4. #include "DFRobot_Iot.h"
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>

  8. /*配置WIFI名和密码*/
  9. const char * WIFI_SSID     = "";        //填入WiFi SSID
  10. const char * WIFI_PASSWORD = "";        //填入WiFi 密码

  11. /*配置设备的认证信息*/
  12. String Iot_id = "S1ZmZq37SX";                        //填入Iot_id
  13. String Client_ID  = "12345";                        //任意数值,用于区分不同设备
  14. String Iot_pwd    = "SkGQ-937Hm";                    //填入Iot_pwd

  15. /*配置IoT云平台的IP地址和端口号*/
  16. String EasyIot_SERVER = "182.254.130.180";
  17. uint16_t PORT = 1883;

  18. /*配置要推送(Publish)或订阅(Subscribe)的topic*/
  19. const char * pubTopic = "";                //填入Topic

  20. /*位置信息变量*/
  21. float Latitude; /* 经度原始值*/
  22. float Longitude; /* 纬度原始值*/
  23. int Latitude_int; /* 经度转换为整数值*/
  24. int Longitude_int; /* 纬度转换为整数值*/
  25. int id; /*家庭成员ID号,1:爸爸, 2: 妈妈, 3:爷爷, 4:奶奶, 5: 大宝, 6: 小宝*/
  26. String str; /*存放待发送的MQTT消息:ID号,转换为整数的经纬度值*/
  27. String str1; /*存放转换为字符串的原始的经度*/
  28. String str2; /*存放转换为字符串的原始的纬度*/
  29. String joint; /*用于合并信息发送*/

  30. DFRobot_Iot myEasyIoT;
  31. WiFiClient espClient;
  32. PubSubClient client(espClient);
  33. DFRobot_BC20 myBC20;

  34. /*连接WiFi*/
  35. void connectWiFi() {
  36.   WiFi.disconnect();
  37.   delay(100);
  38.   Serial.print("Connecting to ");
  39.   Serial.println(WIFI_SSID);
  40.   WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  41.   while (WiFi.status() != WL_CONNECTED) {
  42.     delay(500);
  43.     Serial.print(".");
  44.   }
  45.   Serial.println();
  46.   Serial.println("WiFi connected");
  47.   Serial.print("IP Adderss: ");
  48.   Serial.println(WiFi.localIP());
  49. }

  50. /*连接到IoT云服务器*/
  51. void ConnectCloud() {
  52.   while (!client.connected()) {
  53.     Serial.print("Attempting MQTT connection...");
  54.     if (client.connect(myEasyIoT._clientId, myEasyIoT._username, myEasyIoT._password)) {
  55.       Serial.println("Connect Server OK");
  56.     } else {
  57.       Serial.print("failed, rc=");
  58.       Serial.print(client.state());
  59.       Serial.println(" Try again in 5 seconds");
  60.       delay(5000);
  61.     }
  62.   }
  63. }

  64. /*显示位置信息*/
  65. void Display_Location_Information(){

  66.     //UTC time of the anchor point

  67.     Serial.print("Latitude:\t");
  68.     Serial.print(sGGNS.LatitudeVal,6);
  69.     Serial.print(" deg ");
  70.     Serial.println(sRMC.LatitudeDir);
  71.     //Latitude = sGGNS.LatitudeVal;
  72.     Latitude = 22.70537;
  73.     Serial.print("Longitude:\t");
  74.     Serial.print(sGGNS.LongitudeVal,6);
  75.     Serial.print(" deg ");
  76.     Serial.println(sRMC.LongitudeDir);
  77.     //Longitude = sGGNS.LongitudeVal;
  78.     Longitude = 114.2185209;
  79.     str1 = String(Longitude,6);
  80.     str2 = String(Latitude,6);
  81.     Longitude_int = (Longitude+100) * pow(10,6); /* 将经度加100后转换为整数*/
  82.     Latitude_int = (Latitude+100) * pow(10,6); /* 将纬度加100后转换为整数*/
  83.     str = (String(rand()%6+1)) + String(Longitude_int) + String(Latitude_int); /* 将随机生成的id号和经度纬度拼接*/
  84. }

  85. void setup(){
  86.     Serial.begin(115200);

  87.     /*连接WIFI*/
  88.     connectWiFi();

  89.     /*配置需要连接的IoT云服务器(Easy-IoT)*/
  90.     myEasyIoT.init(EasyIot_SERVER, Iot_id, Client_ID, Iot_pwd);
  91.     client.setServer(myEasyIoT._mqttServer, PORT);

  92.     /*连接到Easy-IoT*/
  93.     ConnectCloud();

  94.     /*启动BC20*/
  95.     Serial.print("Starting the BC20.Please wait. . . ");
  96.     while(!myBC20.powerOn()){
  97.         delay(1000);
  98.         Serial.print(".");
  99.     }
  100.     Serial.println("BC20 started successfully !");
  101.     Serial.println("check OK");
  102.     if(myBC20.getQGNSSC() == OFF){
  103.         Serial.println("open QGNSSC");
  104.         myBC20.setQGNSSC(ON);
  105.     }
  106. }

  107. void loop(){
  108.     delay(5000);
  109.     myBC20.getQGNSSRD();
  110.     Display_Location_Information();
  111.     // Display_Satellite_Information();

  112.     /*IoT云服务器断线重连*/
  113.     if (!client.connected()) {
  114.       ConnectCloud();
  115.     }
  116.     client.loop();

  117.     /*每隔一段时间向Easy-IoT发送消息*/
  118.     Serial.println("Sending message to cloud...");
  119.     joint = String("Latitude:") + str1 + String("   Longitude:" )+ String(str2);
  120.     Serial.println(joint); //将经度和纬度合并一起打印
  121.     client.publish(pubTopic, str.c_str()); //将字符串str转换为publish支持的格式:const char*
  122.     Serial.println("Message is sent.");
  123.     delay(10000);
  124. }
复制代码

演示视频:

链接:https://www.bilibili.com/video/BV1hd4y1D7fo






您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2022 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail