家庭安全相册(四)- 手机端(监护人))
开发板简介物联网与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接口说明
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
这些数据代表的含义如下,我们可以根据自己的需要来解析相应字段的数据。
代码:
- //$GNGGA,023100.000,2240.63547,N,11403.56956,E,1,22,0.7,230.0,M,0.0,M,,*7D
- 字段0:$GPGGA,语句ID,表明该语句为Global Positioning System Fix Data(GGA)GPS定位信息
- 字段1:UTC 时间,hhmmss.sss,时分秒格式
- 字段2:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
- 字段3:纬度N(北纬)或S(南纬)
- 字段4:经度dddmm.mmmm,度分格式(前导位数不足则补0)
- 字段5:经度E(东经)或W(西经)
- 字段6:GPS状态,0=未定位,1=非差分定位,2=差分定位,3=无效PPS,6=正在估算
- 字段7:正在使用的卫星数量(00 - 12)(前导位数不足则补0)
- 字段8:HDOP水平精度因子(0.5 - 99.9)
- 字段9:海拔高度(-9999.9 - 99999.9)
- 字段10:M
- 字段11:地球椭球面相对大地水准面的高度
- 字段12:M
- 字段13:差分修正的数据龄期
- 字段14:差分参考站的ID
- 字段15:CRC
- 字段16:回车换行
复制代码
GNSS示例程序
本项目中,我们只需要经纬度信息(及时间信息),几乎所有示例程序我们都可以使用,这里我们使用GNSS示例程序,它返回的有时间信息、位置信息和卫星信息。
代码:
复制代码
改写程序
因为我们使用wifi来进行MQTT连接并发布消息,所以需要添加wifi头文件。
虽然使用Tinkernode发送消息没有20个字符的限制(如下图是在EasyIoT上接收到的Tinkernode发送的消息),但是由于我们在行空板已经进行了数据格式的定义,所以在Tinkernode端我们也需要对经纬度进行编码。即经度、纬度加上100再乘以10的6次方,连同家庭成员ID一起发送。
进行编码后再发送的经纬度消息:
使用相同的经纬度数据,家庭成员ID在1~6中随机产生。
头文件
代码: - #include "DFRobot_BC20.h"
- #include <WiFi.h>
- #include <PubSubClient.h>
- #include "DFRobot_Iot.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
复制代码
配置wifi
代码: - /*配置WIFI名和密码*/
- const char * WIFI_SSID = ""; //填入WiFi SSID
- const char * WIFI_PASSWORD = ""; //填入WiFi 密码
复制代码
配置MQTT参数
代码: - *配置设备的认证信息*/
- String Iot_id = ""; //填入Iot_id
- String Client_ID = ""; //任意数值,用于区分不同设备
- String Iot_pwd = ""; //填入Iot_pwd
-
- /*配置IoT云平台的IP地址和端口号*/
- String EasyIot_SERVER = "182.254.130.180";
- uint16_t PORT = 1883;
-
- /*配置要推送(Publish)或订阅(Subscribe)的topic*/
- const char * pubTopic = ""; //填入发布消息的Topic
复制代码
定义变量
代码: - /*位置信息变量*/
- float Latitude; /* 经度原始值*/
- float Longitude; /* 纬度原始值*/
- int Latitude_int; /* 经度转换为整数值*/
- int Longitude_int; /* 纬度转换为整数值*/
-
- int id; /*家庭成员ID号,1:爸爸, 2: 妈妈, 3:爷爷, 4:奶奶, 5: 大宝, 6: 小宝*/
- String str; /*存放待发送的MQTT消息:ID号,转换为整数的经纬度值*/
- String str1; /*存放转换为字符串的原始的经度*/
- String str2; /*存放转换为字符串的原始的纬度*/
- String joint; /*用于合并信息发送*/
复制代码
连接wifi
代码: - /*连接WiFi*/
- void connectWiFi() {
- WiFi.disconnect();
- delay(100);
- Serial.print("Connecting to ");
- Serial.println(WIFI_SSID);
- WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
- while (WiFi.status() != WL_CONNECTED) {
- delay(500);
- Serial.print(".");
- }
- Serial.println();
- Serial.println("WiFi connected");
- Serial.print("IP Adderss: ");
- Serial.println(WiFi.localIP());
- }
复制代码
连接到IoT云服务器
代码: - /*连接到IoT云服务器*/
- void ConnectCloud() {
- while (!client.connected()) {
- Serial.print("Attempting MQTT connection...");
- if (client.connect(myEasyIoT._clientId, myEasyIoT._username, myEasyIoT._password)) {
- Serial.println("Connect Server OK");
- } else {
- Serial.print("failed, rc=");
- Serial.print(client.state());
- Serial.println(" Try again in 5 seconds");
- delay(5000);
- }
- }
- }
复制代码
对经纬度进行编码
由于需要在空旷的地方才能获得卫星信号并传回经纬度信息,为了方便展示,这里我们使用固定数值来演示。只要程序能够测试通过,等实际使用时效果是完全一样的。
为了能够在20位以内的字符将信息完整的发送出去,我们仍然要对经纬度进行适当的编码。经度、纬度加上100后再乘以10的6次方转换为整数,前面拼接上ID发送到行空板,行空板再进行解码即可获得原始的经纬度数据。
代码: - /*显示位置信息*/
- void Display_Location_Information(){
-
- Serial.print("Latitude:\t");
- Serial.print(sGGNS.LatitudeVal,6);
- Serial.print(" deg ");
- Serial.println(sRMC.LatitudeDir);
- //Latitude = sGGNS.LatitudeVal;
- Latitude = 22.70537;
- Serial.print("Longitude:\t");
- Serial.print(sGGNS.LongitudeVal,6);
- Serial.print(" deg ");
- Serial.println(sRMC.LongitudeDir);
- //Longitude = sGGNS.LongitudeVal;
- Longitude = 114.2185209;
- str1 = String(Longitude,6);
- str2 = String(Latitude,6);
- Longitude_int = (Longitude+100) * pow(10,6); /* 将经度编码,加100后转换为整数*/
- Latitude_int = (Latitude+100) * pow(10,6); /* 将纬度编码,加100后转换为整数*/
- str = (String(rand()%6+1)) + String(Longitude_int) + String(Latitude_int); /* 将随机生成的id号和经度纬度拼接*/
- }
复制代码
setup函数
代码: - void setup(){
- Serial.begin(115200);
-
- /*连接WIFI*/
- connectWiFi();
-
- /*配置需要连接的IoT云服务器(Easy-IoT)*/
- myEasyIoT.init(EasyIot_SERVER, Iot_id, Client_ID, Iot_pwd);
- client.setServer(myEasyIoT._mqttServer, PORT);
-
- /*连接到Easy-IoT*/
- ConnectCloud();
-
- /*启动BC20*/
- Serial.print("Starting the BC20.Please wait. . . ");
- while(!myBC20.powerOn()){
- delay(1000);
- Serial.print(".");
- }
- Serial.println("BC20 started successfully !");
- Serial.println("check OK");
- if(myBC20.getQGNSSC() == OFF){
- Serial.println("open QGNSSC");
- myBC20.setQGNSSC(ON);
- }
- }
复制代码
loop函数
代码: - void loop(){
- delay(5000);
- myBC20.getQGNSSRD();
- Display_Location_Information();
- // Display_Satellite_Information();
-
- /*IoT云服务器断线重连*/
- if (!client.connected()) {
- ConnectCloud();
- }
- client.loop();
-
- /*每隔一段时间向Easy-IoT发送消息*/
- Serial.println("Sending message to cloud...");
- joint = String("Latitude:") + str1 + String(" Longitude:" )+ String(str2);
- Serial.println(joint); //将经度和纬度合并一起打印
- client.publish(pubTopic, str.c_str()); //将字符串str转换为publish支持的格式:const char*
- Serial.println("Message is sent.");
- delay(10000);
- }
- ArduinoCopy
复制代码
完整的程序:
代码: - #include "DFRobot_BC20.h"
- #include <WiFi.h>
- #include <PubSubClient.h>
- #include "DFRobot_Iot.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- /*配置WIFI名和密码*/
- const char * WIFI_SSID = ""; //填入WiFi SSID
- const char * WIFI_PASSWORD = ""; //填入WiFi 密码
-
- /*配置设备的认证信息*/
- String Iot_id = "S1ZmZq37SX"; //填入Iot_id
- String Client_ID = "12345"; //任意数值,用于区分不同设备
- String Iot_pwd = "SkGQ-937Hm"; //填入Iot_pwd
-
- /*配置IoT云平台的IP地址和端口号*/
- String EasyIot_SERVER = "182.254.130.180";
- uint16_t PORT = 1883;
-
- /*配置要推送(Publish)或订阅(Subscribe)的topic*/
- const char * pubTopic = ""; //填入Topic
-
- /*位置信息变量*/
- float Latitude; /* 经度原始值*/
- float Longitude; /* 纬度原始值*/
- int Latitude_int; /* 经度转换为整数值*/
- int Longitude_int; /* 纬度转换为整数值*/
- int id; /*家庭成员ID号,1:爸爸, 2: 妈妈, 3:爷爷, 4:奶奶, 5: 大宝, 6: 小宝*/
- String str; /*存放待发送的MQTT消息:ID号,转换为整数的经纬度值*/
- String str1; /*存放转换为字符串的原始的经度*/
- String str2; /*存放转换为字符串的原始的纬度*/
- String joint; /*用于合并信息发送*/
-
- DFRobot_Iot myEasyIoT;
- WiFiClient espClient;
- PubSubClient client(espClient);
- DFRobot_BC20 myBC20;
-
- /*连接WiFi*/
- void connectWiFi() {
- WiFi.disconnect();
- delay(100);
- Serial.print("Connecting to ");
- Serial.println(WIFI_SSID);
- WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
- while (WiFi.status() != WL_CONNECTED) {
- delay(500);
- Serial.print(".");
- }
- Serial.println();
- Serial.println("WiFi connected");
- Serial.print("IP Adderss: ");
- Serial.println(WiFi.localIP());
- }
-
- /*连接到IoT云服务器*/
- void ConnectCloud() {
- while (!client.connected()) {
- Serial.print("Attempting MQTT connection...");
- if (client.connect(myEasyIoT._clientId, myEasyIoT._username, myEasyIoT._password)) {
- Serial.println("Connect Server OK");
- } else {
- Serial.print("failed, rc=");
- Serial.print(client.state());
- Serial.println(" Try again in 5 seconds");
- delay(5000);
- }
- }
- }
-
- /*显示位置信息*/
- void Display_Location_Information(){
-
- //UTC time of the anchor point
-
- Serial.print("Latitude:\t");
- Serial.print(sGGNS.LatitudeVal,6);
- Serial.print(" deg ");
- Serial.println(sRMC.LatitudeDir);
- //Latitude = sGGNS.LatitudeVal;
- Latitude = 22.70537;
- Serial.print("Longitude:\t");
- Serial.print(sGGNS.LongitudeVal,6);
- Serial.print(" deg ");
- Serial.println(sRMC.LongitudeDir);
- //Longitude = sGGNS.LongitudeVal;
- Longitude = 114.2185209;
- str1 = String(Longitude,6);
- str2 = String(Latitude,6);
- Longitude_int = (Longitude+100) * pow(10,6); /* 将经度加100后转换为整数*/
- Latitude_int = (Latitude+100) * pow(10,6); /* 将纬度加100后转换为整数*/
- str = (String(rand()%6+1)) + String(Longitude_int) + String(Latitude_int); /* 将随机生成的id号和经度纬度拼接*/
- }
-
- void setup(){
- Serial.begin(115200);
-
- /*连接WIFI*/
- connectWiFi();
-
- /*配置需要连接的IoT云服务器(Easy-IoT)*/
- myEasyIoT.init(EasyIot_SERVER, Iot_id, Client_ID, Iot_pwd);
- client.setServer(myEasyIoT._mqttServer, PORT);
-
- /*连接到Easy-IoT*/
- ConnectCloud();
-
- /*启动BC20*/
- Serial.print("Starting the BC20.Please wait. . . ");
- while(!myBC20.powerOn()){
- delay(1000);
- Serial.print(".");
- }
- Serial.println("BC20 started successfully !");
- Serial.println("check OK");
- if(myBC20.getQGNSSC() == OFF){
- Serial.println("open QGNSSC");
- myBC20.setQGNSSC(ON);
- }
- }
-
- void loop(){
- delay(5000);
- myBC20.getQGNSSRD();
- Display_Location_Information();
- // Display_Satellite_Information();
-
- /*IoT云服务器断线重连*/
- if (!client.connected()) {
- ConnectCloud();
- }
- client.loop();
-
- /*每隔一段时间向Easy-IoT发送消息*/
- Serial.println("Sending message to cloud...");
- joint = String("Latitude:") + str1 + String(" Longitude:" )+ String(str2);
- Serial.println(joint); //将经度和纬度合并一起打印
- client.publish(pubTopic, str.c_str()); //将字符串str转换为publish支持的格式:const char*
- Serial.println("Message is sent.");
- delay(10000);
- }
复制代码
演示视频:
链接:https://www.bilibili.com/video/BV1hd4y1D7fo
|