diff --git a/docs/Getting_started/zh/iot-advanced/external_gnss.md b/docs/Getting_started/zh/iot-advanced/external_gnss.md new file mode 100644 index 0000000000000000000000000000000000000000..78d6e43600c7d626d3cbe5baf6c32e37333c6850 --- /dev/null +++ b/docs/Getting_started/zh/iot-advanced/external_gnss.md @@ -0,0 +1,224 @@ +# 1. 简介 + +QuecPython提供了`gnss`功能模块来获取外置GNSS模块的定位数据。该功能模块直接在内部完成了原始定位数据的处理解析工作,将用户关心的一些定位参数提取出来并提供对应接口让用户可直接获取。避免了用户自己通过串口去读取原始的定位数据,并进行复杂的正则匹配查找和解析的情况,提高了用户开发效率。 + +目前该模块自动解析的NEMA语句包括:GGA、RMC和GSV。 + +> 本文档中示例代码前面有 `>>> `字符串的,表示在QuecPython的命令交互界面输入的代码。 + + + +# 2. 使用说明 + +`gnss`模块接口的详细说明,请参考QuecPython官网的Wiki文档中相关部分的说明。下面以L76K定位芯片为例,说明如何使用`gnss`模块的相关功能。 + +## 2.1 获取定位数据 + +下面将详细描述使用gnss模块接口获取定位数据的步骤,同时说明在使用过程中一些注意事项。 + +### 2.1.1 使用步骤 + +步骤1:确定串口信息 + +即确定L76K定位芯片接到模组哪个串口,以及使用的波特率等信息,本示例中将L76K接到了模组的UART2,波特率默认为9600bps(可在L76K使用手册中查询到)。 + + + +步骤2:实例化一个对象 + +```python +>>> from gnss import GnssGetData +>>> gnss_obj = GnssGetData(2, 9600, 8, 0, 1, 0) +``` + + + +步骤3:读取数据并解析 + +用户只需要调用如下接口,该接口直接完成定位数据的读取和解析工作: + +```python +>>> gnss_obj.read_gnss_data() +822 +``` + +上述接口将读取原始数据、以及复杂的解析操作都放在接口内部实现,只返回了通过串口读取的数据长度。如用户想看本次读取解析的原始数据,可调用如下接口: + +```python +>>> data = gnss_obj.getOriginalData() +>>> print(data) +$GNGGA,063957.000,3802.01852,N,11437.92027,E,1,13,1.2,129.2,M,-15.7,M,,*62 +$GNGLL,3802.01852,N,11437.92027,E,063957.000,A,A*40 +$GNGSA,A,3,01,03,06,14,30,194,,,,,,,1.8,1.2,1.4,1*00 +$GNGSA,A,3,13,23,33,38,40,43,59,,,,,,1.8,1.2,1.4,4*3C +$GPGSV,3,1,11,01,38,044,12,03,44,101,24,06,30,233,31,14,79,184,34,0*6F +$GPGSV,3,2,11,17,58,319,,19,40,296,04,21,11,051,,30,14,202,34,0*67 +$GPGSV,3,3,11,194,44,156,27,195,68,074,,199,44,160,25,0*6F +$BDGSV,3,1,11,03,44,186,,07,83,121,05,10,65,309,,13,37,206,31,0*79 +$BDGSV,3,2,11,23,21,181,31,28,69,354,14,33,24,115,27,38,65,190,30,0*7A +$BDGSV,3,3,11,40,70,093,18,43,28,065,15,59,38,143,29,0*44 +$GNRMC,063957.000,A,3802.01852,N,11437.92027,E,0.69,168.35,260422,,,A,V*0B +$GNVTG,168.35,T,,M,0.69,N,1.29,K,A*2F +$GNZDA,063957.000,26,04,2022,00,00*44 +$GPTXT,01,01,01,ANTENNA OPEN*25 +``` + + + +步骤4:确认是否定位成功 + +如用户只关心是否定位到经纬度坐标以及坐标是否有效,可使用如下接口,返回1即表示定位成功且有效: + +```python +>>> gnss_obj.isFix() +1 +``` + + + +步骤5:获取坐标信息 + +调用如下接口即可获取到定位坐标: + +```python +>>> gnss_obj.getLocation() +(114.6320045, 'E', 38.033642, 'N') +``` + + + +> 上述接口获取的坐标是WGS-84坐标系下的经纬度数据,不可直接用于高德地图、腾讯地图以及百度地图等地图上拾取位置信息,必须先转换为对应地图参考坐标系下的坐标。 + + + +### 2.1.2 示例代码 + +如下代码是一个完整的使用`gnss`模块方法来获取定位坐标的例程: + +```python + +import utime +from gnss import GnssGetData + + +def main(): + gnss_obj = GnssGetData(2, 9600, 8, 0, 1, 0) + while True: + try: + read_size = gnss_obj.read_gnss_data() + except Exception: + print('数据异常,解析出错!') + data = gnss_obj.getOriginalData() + print('===============================================') + print(data) + print('===============================================') + utime.sleep(2) + continue + + if read_size > 0: + if gnss_obj.isFix(): + coordinate = gnss_obj.getLocation() + longitude = coordinate[0] + latitude = coordinate[2] + print('定位成功,当前经纬度:({}, {})'.format(longitude, latitude)) + utime.sleep(10) + else: + print('定位中,请稍后...') + utime.sleep(2) + else: + print('未读取到定位数据...') + utime.sleep(2) + + +if __name__ == '__main__': + main() +``` + + + +## 2.2 配置NEMA串口波特率 + +查阅L76K的使用手册,确定默认使用的波特率为9600bps,如用户需要修改波特率,则需要使用PCAS语句来发送一条修改波特率的指令给L76K芯片。 + +### 2.2.1 PCAS01指令格式 + +PCAS01语句即用来配置L76K的NEMA串口波特率。格式如下: + +``` +$PCAS01,* +``` + +参数说明: + +| 字段 | 描述 | +| -------- | ------------------------------------------------------------ | +| CMD | 支持如下波特率:
0 - 4800
1 - 9600
2 - 19200
3 - 38400
4 - 57600
5 - 115200 | +| Checksum | 校验和,校验和是对语句中所有字符的 8 位(不包括起始和结束位)进行异或运算,所有字符是指在定界符“$”与“*”之间,但不包括这些定界符的全部字符,包括“,”在内。 | +| CR和LF | NEMA语句的结束字符,即`\r\n` | + + + +### 2.2.2 步骤说明 + +步骤1:确定波特率 + +即确定需要配置的波特率,以确定CMD的值。假如需要配置L76K NEMA串口波特率为115200,即CMD为5。则PCAS01语句为: + +``` +$PCAS01,5*\r\n +``` + +步骤2:checksum计算 + +确定波特率后,PCAS01语句就只差checksum待计算,可按照如下算法计算: + +```python + +""" +参数说明 +dstr - 需要计算校验和的字符串,对NEMA语句而言,即“$”与“*”之间的字符串 +返回值:返回十进制的校验和 +""" +def get_checksum(dstr): + lista = list(dstr) + list_len = len(lista) - 1 + checksum = ord(lista[0]) + i = 0 + while i < list_len: + checksum = checksum ^ ord(lista[i+1]) + i = i + 1 + return checksum + +# 取“$”与“*”之间的字符串 +dstr = 'PCAS01,5' +checksum = get_checksum(dstr) +print('checksum={},{}'.format(checksum, hex(checksum))) + +#计算结果 +checksum=25,0x19 +``` + +得到对应的checksum之后,可确定完整的PCAS01语句如下: + +``` +$PCAS01,5*19\r\n +``` + +步骤3:发送指令 + +使用machine类下的UART功能模块来发送该指令到L76K,本示例中将L76K接到了模组的UART2,具体如下: + +```python + +from machine import UART +from gnss import GnssGetData + +# L76K默认波特率是9600,故先需要配置9600波特率来打开串口 +uart2 = UART(UART.UART2, 9600, 8, 0, 1, 0) +# 发送波特率配置指令 +uart2.write('$PCAS01,5*19\r\n') +# 配置成功后须先关闭当前串口 +uart2.close() +# 按照115200波特率来示例话一个gnss对象 +gnss_obj = GnssGetData(2, 115200, 8, 0, 1, 0) +``` diff --git a/docs/Getting_started/zh/iot-advanced/gnss.md b/docs/Getting_started/zh/iot-advanced/gnss.md new file mode 100644 index 0000000000000000000000000000000000000000..1c2a2d6faf7be00c1d27e849ee4aad4346ef5a43 --- /dev/null +++ b/docs/Getting_started/zh/iot-advanced/gnss.md @@ -0,0 +1,57 @@ +# GNSS应用指导说明 + +本文中对GNSS一些基础概念进行了简要说明,描述了如何使用 QuecPython 的`gnss`模块和`quecgnss`模块的功能来获取定位信息,同时包含了一些注意事项。 + + + +## 1. 基础概念说明 + +### 1.1 什么是GNSS + +GNSS是指全球导航卫星系统(Global Navigation Satellite System),它是泛指所有的卫星导航系统。主要包括美国的全球定位系统(GPS)、欧洲的伽利略卫星导航系统(GALILEO)、俄罗斯的格洛纳斯卫星导航系统(GLONASS)、中国的北斗卫星导航系统(BDS)以及区域系统和增强系统。 + + + +### 1.2 什么是AGPS + +AGPS是指辅助全球卫星定位系统(Assisted Global Positioning System)。它本身并不是一种定位系统,而是一种辅助定位的方式,用来加快定位速度。传统GPS定位中需要全频段搜索以找到可用卫星而导致耗时较长,而AGPS可以通过无线网络直接下载当前地区的可用卫星信息,提高了搜星的速度,也就加快了定位速度,同时起到了减少设备电量消耗的作用。 + + + +> 目前以下型号模组均内置GNSS定位功能,并默认都支持AGPS: +> +> EC200UCNAA/EC200UCNLA/EC200UEUAA/EC800MCNGA/EC800GCNGA/EG810MCNGA/EG915NEUAG + + + +### 1.3 参考坐标系 + +坐标都是相对于某一参考系而言,才有意义,GNSS定位坐标也不例外。我们通过各种渠道获取到的经纬度坐标,很可能并不是同一个坐标系下的数据。如果想利用这些坐标在地图上做可视化相关功能,就需要经过计算转换为对应地图坐标系下的坐标。目前在中国比较常见的坐标系有: + +| 坐标系 | 说明 | +| ------ | ------------------------------------------------------------ | +| WGS-84 | 世界大地测量系统(World Geodetic System 1984),是全球通用的坐标系,也是使用最广泛的坐标系。一般GPS定位设备得到的经纬度坐标都是使用WGS-84坐标系。 | +| GCJ-02 | 由中国国家测绘局制定的地理信息系统的坐标系,也叫火星坐标系。它是由WGS-84坐标加密得到。国内的高德地图、腾讯地图使用的都是GCJ-02坐标系。 | +| BD-09 | 由百度开发定制的坐标系统,它是在GCJ-02坐标的基础上再次加密得到。百度地图使用的是BD-09坐标系。 | + +通过上述说明,应明确一点,通过GNSS定位芯片拿到的经纬度坐标是WGS-84坐标系下的数据。在中国,如果用户需要将获取的经纬度坐标放到地图上显示位置,则需要将WGS-84坐标进行计算转换为该地图所使用坐标系下的坐标,才可用于在地图上拾取位置。 + + + +### 1.4 QuecPython `gnss`和`quecgnss`的区别 + +QuecPython 的内置库中,有`gnss`模块和`quecgnss`模块,都是和GNSS定位相关的功能模块。具体区别如下: + +* `gnss` - 外置GNSS功能模块。 + +* `quecgnss` - 内置GNSS功能模块。 + +所谓的“内置”和“外置”,是相对模组而言。如果模组内部集成了GNSS定位功能,则为“内置”,须使用QuecPython的`quecgnss`模块来获取定位信息;如果模组是通过串口外接了L76K系列定位芯片,则为“外置”,须使用QuecPython的`gnss`模块来获取定位信息。 + + + +## 2. GNSS应用指导文档列表 + +* [外置GNSS功能应用指导](./external_gnss.md) + +* [内置GNSS功能应用指导](./internal_gnss.md) diff --git a/docs/Getting_started/zh/iot-advanced/internal_gnss.md b/docs/Getting_started/zh/iot-advanced/internal_gnss.md new file mode 100644 index 0000000000000000000000000000000000000000..ce97a645cb268d2a1d0cb57e1689a2be155c74ff --- /dev/null +++ b/docs/Getting_started/zh/iot-advanced/internal_gnss.md @@ -0,0 +1,449 @@ +# 1. 简介 + +QuecPython提供了`quecgnss`功能模块来获取模组内置GNSS的定位数据。当前`quecgnss`模块暂不支持像`gnss`模块那样直接完成了原始定位数据的处理解析功能,而是需要用户自己来完成原始数据的处理解析工作。为了提高用户开发效率和使用便捷性,本指导文档中会直接给出较为完整的数据处理解析例程,供用户参考使用。 + +> 本文档中示例代码前面有 `>>> `字符串的,表示在QuecPython的命令交互界面输入的代码。 + + + +# 2. 使用说明 + +quecgnss模块的接口详细说明,请参考QuecPython官网的Wiki文档中相关部分的说明。本文档中主要从整体流程上说明quecgnss模块的使用方式。 + + + +## 2.1 获取定位数据 + +### 2.2.1 使用步骤 + +步骤1:功能初始化 + +内置GNSS功能默认是关闭的,需要用户主动初始化并开启。直接调用quecgnss模块的init接口即可完成初始化并打开的工作。如果初始化成功,则会返回0,失败返回-1。 + +```python +>>> import quecgnss +>>> quecgnss.init() +0 +``` + + + +步骤2:确定GNSS的状态 + +内置GNSS功能初始化后,应确定GNSS当前的状态是否为”定位中“,只有处于这种状态,才可以开始读取NEMA数据。使用如下接口确定状态,返回值为2说明已经处于”定位中“的状态: + +```python +>>> quecgnss.get_state() +2 +``` + + + +步骤3:读取NEMA数据 + +当GNSS状态值为”定位中“时,即可使用如下接口去读取定位数据,读取出来的是尚未处理过的原始数据: + +```python +>>> data = quecgnss.read(2048) +>>> print(data) +(2048, '$GNRMC,020943.00,A,3149.30070,N,11706.93208,E,0.052,,310323,,,A,V*15\r\n$GNGGA,020943.00,3149.30070,N,11706.93208,E,1,29,0.54,101.2,M,,M,,*52\r\n$GNGSA,A,3,07,08,09,16,21,27,31,04,194,199,195,50,1.06,0.54,0.91,1*3B\r\n$GNGSA,A,3,02,03,05,10,11,25,36,,,,,,1.06,0.54,0.91,3*0A\r\n$GNGSA,A,3,78,88,67,66,76,86,87,68,,,,,1.06,0.54,0.91,2*0C\r\n$GPGSV,5,1,17,04,48,238,45,07,20,314,40,08,63,215,48,09,37,285,44,0*65\r\n$GPGSV,5,2,17,16,50,034,45,21,09,175,40,27,77,054,48,31,15,124,43,0*63\r\n$GPGSV,5,3,17,18,08,045,,26,24,068,,194,65,058,43,199,51,161,41,0*6A\r\n$GPGSV,5,4,17,195,47,127,43,41,37,232,45,42,45,141,,50,51,161,45,0*59\r\n$GPGSV,5,5,17,40,15,254,41,0*55\r\n$GAGSV,3,1,09,02,21,281,36,03,42,271,40,05,33,201,42,10,34,093,42,0*7F\r\n$GAGSV,3,2,09,11,32,127,37,25,57,330,43,36,09,172,36,08,13,317,36,0*78\r\n$GAGSV,3,3,09,12,26,065,,0*49\r\n$GLGSV,3,1,10,66,13,216,32,67,26,269,37,68,13,319,34,76,40,058,36,0*7D\r\n$GLGSV,3,2, ......')# 数据较多,仅列出部分数据 +``` + +需要注意的是,`quecgnss.read`接口返回值是一个元组,第一个参数是读取的数据长度,第二参数才是读取的数据,调试过程中,如果想让数据看起来整洁清晰,可按如下方式打印: + +```python +>>> print(data[1].decode()) +$GNRMC,020943.00,A,3149.30070,N,11706.93208,E,0.052,,310323,,,A,V*15 +$GNGGA,020943.00,3149.30070,N,11706.93208,E,1,29,0.54,101.2,M,,M,,*52 +$GNGSA,A,3,07,08,09,16,21,27,31,04,194,199,195,50,1.06,0.54,0.91,1*3B +$GNGSA,A,3,02,03,05,10,11,25,36,,,,,,1.06,0.54,0.91,3*0A +$GNGSA,A,3,78,88,67,66,76,86,87,68,,,,,1.06,0.54,0.91,2*0C +$GPGSV,5,1,17,04,48,238,45,07,20,314,40,08,63,215,48,09,37,285,44,0*65 +$GPGSV,5,2,17,16,50,034,45,21,09,175,40,27,77,054,48,31,15,124,43,0*63 +$GPGSV,5,3,17,18,08,045,,26,24,068,,194,65,058,43,199,51,161,41,0*6A +$GPGSV,5,4,17,195,47,127,43,41,37,232,45,42,45,141,,50,51,161,45,0*59 +...... # 数据较多,仅列出部分数据 +``` + +我们需要的定位信息就在上述这些NEMA语句中,比如经纬度坐标、海拔等。后面我们将讲述如何对这些数据进行处理解析,提取出我们需要的信息。 + + + +### 2.1.2 示例代码 + +如下例程,即是按照上述流程编写的较为完整的使用例程。 + +```python + +""" +本例程示范了如何使用quecgnss模块的方法 +例程中设定10s获取一次定位信息,仅为示例,实际可由用户自行决定获取定位信息的周期 +""" +import utime +import quecgnss + + +def main(): + if quecgnss.get_state() == 0: + ret = quecgnss.init() + if ret == 0: + print('GNSS 初始化成功') + else: + print('GNSS 初始化失败,请检查问题') + return -1 + + while True: + gnss_state = quecgnss.get_state() + if gnss_state == 2: + print('GNSS 开始定位') + break + elif gnss_state == 1: + print('GNSS 固件烧录中,请稍后') + utime.sleep(2) + continue + else: + print('GNSS 初始化异常,请检查问题') + return -1 + + while True: + try: + data = quecgnss.read(2048) + except Exception as e: + print('读取NEMA数据异常:{}'.format(e)) + utime.sleep(2) + continue + data_len = data[0] + nema_data = data[1] + if data_len == 0: + print('未读到定位数据,重试中') + utime.sleep(2) + else: + print('===============================================') + print(nema_data.decode()) + print('===============================================') + # 用户自行决定多久获取一次定位数据,此处10s仅为示例 + utime.sleep(10) + # 注[1] + try: + quecgnss.read(4096) + except Exception as e: + print('{}'.format(e)) + utime.sleep(2) + continue + + +if __name__ == '__main__': + main() + +``` + + + +> 注[1] +> +> 上述示例代码中,在休眠一段时间后,读取了4K的定位数据并丢弃了。这段代码的作用如下: +> +> 实际使用中,设备可能会间隔较长一段时间才会获取一次定位数据。有的模组,串口部分底层驱动代码缓存机制是如果缓存满了,就不会再接收新的数据;这就导致如果设备在移动中,间隔较长一段时间才获取一次定位信息时,获取到的是较长时间之前缓存的定位数据,而不是当前位置实时的定位信息。所以为了确保这种情形下,每次获取的定位信息都是实时的,需要在每次获取定位数据之前,先读一次串口数据,把串口缓存中的数据读出并丢弃,休眠1~2s后再读定位数据。 +> +> 如设备获取定位信息较为频繁,可去掉上述代码片段。 + + + +## 2.2 数据解析 + +NEMA语句都是以字符`$`开头,并且以`\r\n`作为结束。而从一堆原始数据中找到我们需要的某一条NEMA语句,本质上利用的就是NEMA语句的该特点,比如正则匹配或是判断字符串头尾。 + +下面以获取经纬度坐标信息为例,说明对NEMA语句的处理解析过程。经纬度坐标信息在RMC和GGA语句中都有包含,下面例程中以从RMC语句中提取经纬度信息为例进行说明。 + +### 2.2.1 解析步骤 + +步骤1:查找相关RMC语句 + +从读取的原始数据中找出RMC语句,这里使用的方式为——先分割再查找。 + +在这种先分割再查找的方式中,需要注意的是,对原始数据的分割,必须使用字符`$`来分割。理论上每一条NEMA语句都应以字符`$`开始,以`\r\n`结束。但在实际的定位数据中,会出现一些NEMA语句不完整的情况,即某一条或几条NEMA语句缺少了一部分,并且直接和下一条语句粘在了一起。比如: + +``` +$GPGSV,4,2,16,21,2$GNRMC,024843.00,A,3149.30313,N,11706.92780,E,0.157,,310323,,,A,V*16 +``` + +这种情况下,使用字符`$`来分割原始字符串数据,可以将这种两条粘在一起的语句分割开,再结合”NEMA语句都应以字符`$`开始,以`\r\n`结束“的特性加以判断,基本可以避免获取到不正常的语句导致后续解析出错的情况。 + +下面示例中data中就是通过`quecgnss.read`接口读出的原始数据,数据如下: + +```python +(2048,'*3B\r\n$GNGSA,A,3,02,11,25,30,34,36,,,,,,,1.20,0.65,$GNRMC,060154.00,A,3149.30510,N,11706.93089,E,0.016,,310323,,,A,V*17\r\n$GNGGA,0$GNRMC,062306.00,A,3149.30472,N,11706.93365,E,0.053,,310323,,,A,V*15\r\n$GNGGA,062306.00,3149.30472,N,11706.93365,E,1,28,0.59,91.9,M,,M,,*6C\r\n$GNGSA,A,3,01,03,07,14,17,21,30,194,199,195,19,06,0.99,0.59,0.80,1*3D\r\n$GNGSA,A,3,02,11,25,30,34,36,15,,,,,,0.99,0.59,0.80,3*07\r\n$GNGSA,A,3,78,80,79,88,82,81,,,,,,,0.99,0.59,0.80,2*0C\r\n$GPGSV,5,1,17,01,63,040,46,03,31,131,42,06,08,220,40,07,26,193,44,0*63\r\n$GPGSV,5,2,17,14,60,326,45,17,39,294,43,19,15,273,43,21,35,041,42,0*6E\r\n$GPGSV,5,3,17,30,43,234,45,08,14,073,,194,61,126,45,199,51,161,40,0*64\r\n$GPGSV,5,4,17,195,69,065,46,42,45,141,,50,51,161,44,40,15,254,41,0*53\r\n$GPGSV,5,5,17,41,37,232,44,0*51\r\n$GAGSV,2,1,07,02,82,078,40,11,12,040,32,15,10,223,35,25,33,129,36,0*7D\r\n$GAGSV,2,2,07,30,37,319,39,34,61,229,44,36,60,034,41,0*4D\r\n$GLGSV,2,1,07,78,52,161,45,79,68,316,41,80,15,330,34,81,61,325,38,0*79\r\n$GLGSV,2,2,07,82,34,252,33,88,26,031,33,65,04,073,,0*43\r\n$GNRMC,062307.00,A,3149.30472,N,11706.93366,E,0.023,,310323,,,A,V*10\r\n$GNGGA,062307.00,3149.30472,N,11706.93366,E,1,28,0.59,91.9,M,,M,,*6E\r\n$GNGSA,A,3,01,03,07,14,17,21,30,194,199,195,19,06,0.99,0.59,0.80,1*3D\r\n$GNGSA,A,3,02,11,25,30,34,36,15,,,,,,0.99,0.59,0.80,3*07\r\n$GNGSA,A,3,78,80,79,88,82,81,,,,,,,0.99,0.59,0.80,2*0C\r\n$GPGSV,5,1,17,01,63,040,46,03,31,131,42,06,08,220,40,07,26,193,44,0*63\r\n$GPGSV,5,2,17,14,60,326,44,17,39,294,45,19,15,273,43,21,35,041,42,0*69\r\n$GPGSV,5,3,17,30,43,234,44,08,14,073,,194,61,126,47,199,51,161,40,0*67\r\n$GPGSV,5,4,17,195,69,065,46,42,45,141,,50,51,161,43,40,15,254,42,0*57\r\n$GPGSV,5,5,17,41,37,232,44,0*51\r\n$GAGSV,2,1,07,02,82,078,40,11,12,040,32,15,10,223,34,25,33,129,36,0*7C\r\n$GAGSV,2,2,07,30,37,319,39,34,61,229,44,36,60,034,42,0*4E\r\n$GLGSV,2,1,07,78,52,161,45,79,68,316,41,80,15,330,35,81,61,325,38,0*78\r\n$GLGSV,2,2,07,82,34,252,33,88,26,031,32,65,04,073,,0*42\r\n$GNRMC,062308.00,A,3149.30473,N,11706.93366,E,0.032,,310323,,,A,V*1E\r\n$GNGGA,062308.00,3149.30473,N,11706.9336') +``` + +解析代码如下: + +```python + +rmc = '' +split_data = data[1].split('$') +for i in split_data: + # 查找RMC语句并进行数据完整性检查 + if i.startswith('GNRMC') and i.endswith('\r\n'): + rmc = i + split_rmc = rmc.split(',') + break +print(rmc) +print(split_rmc) + +############执行结果如下################ +GNRMC,060154.00,A,3149.30510,N,11706.93089,E,0.016,,310323,,,A,V*17 +['GNRMC', '060154.00', 'A', '3149.30510', 'N', '11706.93089', 'E', '0.016', '', '310323', '', '', 'A', 'V*17\r\n'] + +``` + + + +步骤2:语句完整性校验 + +上述解析代码中,判断是否以`GNRMC`开头并且以`\r\n`结尾,本身也是一种完整性检查。如果用户希望更准确的检查某一条NEMA语句的完整性,那就需要对该条语句进行checksum计算,并将计算结果与该条语句中的checksum进行比较,如果相等,则说明该条语句是完整且正确的。 + +这里提供一个校验NEMA语句checksum的接口: + +```python + +""" +功能:checksum计算 +参数说明: +dstr - 需要计算校验和的字符串,应取NEMA语句的”$“字符和”*“字符之间的部分,不包含”$“字符和”*“字符 +返回值:返回十六进制字符串类型的checksum +""" +def checksum(dstr): + lista = list(dstr) + list_len = len(lista) - 1 + tmp = ord(lista[0]) + i = 0 + while i < list_len: + tmp = tmp ^ ord(lista[i+1]) + i = i + 1 + strtmp = str(hex(tmp)) + return strtmp.replace('0x', '') + +""" +功能:NEMA语句checksum确认 +参数说明: +nema - 一条以‘$’字符开始和‘\r\n’字符结束的NEMA语句 +返回值:checksum校验通过返回Ture,否则返回False +""" +def checksum_verify(nema): + find_sck = ure.search("\*(.+?)\r\n", nema) + if find_sck: + sck = find_sck.group(1) + else: + return False + data = ure.search("\$(.+?)\*", nema) + if data: + print('待计算数据:{}'.format(nema)) + ck = checksum(data.group(1)) + print('计算checksum为:{}'.format(ck)) + if ck.upper() == sck.upper(): + return True + else: + return False + else: + return False + +``` + + + +步骤3:确认定位有效性 + +在获取经纬度数据之前,应先确认当前定位数据是有效的,这里是通过检查RMC语句中的`Status`位来判断是否有效,该位表示定位系统状态。当`Status`为字符`A`时,即表示有效。 + +RMC语句格式: + +``` +$RMC,,,,,,,,,,,,,* +``` + +以步骤1中查找到的RMC数据为例: + +```python + +# 通过步骤1可知split_rmc如下 +split_rmc = ['GNRMC', '060154.00', 'A', '3149.30510', 'N', '11706.93089', 'E', '0.016', '', '310323', '', '', 'A', 'V*17\r\n'] + +if split_rmc[2] == 'A': + print('有效定位') +else: + print('无效定位') + +``` + + + +步骤4:提取经纬度坐标 + +确定定位数据有效后,即可提取经纬度相关信息。需注意的是,提取出的数据默认都是字符串,需要转换为浮点数: + +```python + +lat = float(split_rmc[3]) +lon = float(split_rmc[5]) +print('经度信息:{}'.format(lon)) +print('纬度信息:{}'.format(lat)) + +############执行结果如下################ +经度信息:11706.93089 +纬度信息:3149.3051 + +``` + + + +步骤5:将经纬度数据转换为单位为”度“的坐标 + +查阅NEMA语句格式说明可知,NEMA语句中的经纬度格式如下: + +| 字段 | 格式 | 说明 | +| ---- | ----------- | ------------------------------------------------------------ | +| Lat | ddmm.mmmmm | 纬度
dd - 度(00-90)
mm - 分(00-59)
mmmmm - 分的十进制小数 | +| Lon | dddmm.mmmmm | 经度
ddd - 度(000-180)
mm - 分(00-59)
mmmmm - 分的十进制小数 | + +转换计算如下: + +```python + +longitude = lon // 100 + (lon % 100) / 60 +latitude = lat // 100 + (lat % 100) / 60 +print('({}, {})'.format(longitude, latitude)) + +############执行结果如下################ +(117.1155148333333, 31.82175166666667) + +``` + + + +> 此处计算出来的是WGS-84坐标系下经纬度坐标,不可直接用于高德、腾讯、百度等地图上。 + + + +### 2.2.2 示例代码 + +下面示例是基于2.1.2章节中的代码基础上,增加了数据解析部分的代码。 + +```python + +""" +本例程示范了如何使用quecgnss模块的方法 +例程中设定10s获取一次定位信息,仅为示例,实际可由用户自行决定获取定位信息的周期 +""" +import ure +import utime +import quecgnss + +cycle = 10 + +def checksum(dstr): + lista = list(dstr) + list_len = len(lista) - 1 + tmp = ord(lista[0]) + i = 0 + while i < list_len: + tmp = tmp ^ ord(lista[i+1]) + i = i + 1 + strtmp = str(hex(tmp)) + return strtmp.replace('0x', '') + +def checksum_verify(nema): + find_sck = ure.search("\*(.+?)\r\n", nema) + if find_sck: + sck = find_sck.group(1) + else: + return False + data = ure.search("\$(.+?)\*", nema) + if data: + print('待计算数据:{}'.format(nema)) + ck = checksum(data.group(1)) + print('计算checksum为:{}'.format(ck)) + if ck.upper() == sck.upper(): + return True + else: + return False + else: + return False + + +def main(): + global cycle + if quecgnss.get_state() == 0: + ret = quecgnss.init() + if ret == 0: + print('GNSS 初始化成功') + else: + print('GNSS 初始化失败,请检查问题') + return -1 + + while True: + gnss_state = quecgnss.get_state() + if gnss_state == 2: + print('GNSS 开始定位') + break + elif gnss_state == 1: + print('GNSS 固件烧录中,请稍后') + utime.sleep(2) + continue + else: + print('GNSS 初始化异常,请检查问题') + return -1 + + while True: + try: + data = quecgnss.read(2048) + except Exception as e: + print('读取NEMA数据异常:{}'.format(e)) + utime.sleep(2) + continue + data_len = data[0] + nema_data = data[1] + if data_len == 0: + print('未读到定位数据,重试中') + utime.sleep(2) + else: + print('===============================================') + print(nema_data.decode()) + print('===============================================') + split_nema = nema_data.split('$') + for i in split_nema: + if i.startswith('GNRMC') and i.endswith('\r\n'): + split_rmc = i.split(',') + if split_rmc[2] == 'A': + print('获取到有效定位') + # 确认定位有效后,再计算checksum确认语句完整性,避免对无效数据进行计算 + # 用户自行决定是否需要计算,如不需要可屏蔽checksum校验相关代码 + rmc = i.replace('GNRMC', '$GNRMC') + if not checksum_verify(rmc): + continue + print('checksum 校验通过') + + lat = float(split_rmc[3]) + lon = float(split_rmc[5]) + longitude = lon // 100 + (lon % 100) / 60 + latitude = lat // 100 + (lat % 100) / 60 + print('经纬度坐标:({}, {})'.format(longitude, latitude)) + break + else: + continue + # 用户自行决定多久获取一次定位数据,此处10s仅为示例 + utime.sleep(cycle) + # 下面这段代码是否需要,取决于用户获取定位的频繁程度。 + if cycle > 60: + try: + quecgnss.read(4096) + except Exception as e: + print('{}'.format(e)) + utime.sleep(2) + + continue + + +if __name__ == '__main__': + main() + +``` diff --git a/docs/Getting_started/zh/iot-advanced/ota.md b/docs/Getting_started/zh/iot-advanced/ota.md new file mode 100644 index 0000000000000000000000000000000000000000..76d7f26b76cb9a3c523627a17862d698ff78978c --- /dev/null +++ b/docs/Getting_started/zh/iot-advanced/ota.md @@ -0,0 +1,255 @@ +# OTA升级指导说明 + +本文主要介绍基于QuecPython模组的固件升级与软件升级方法, 描述了`fota`与`app_fota`模块的功能如何使用进行设备升级, 以及一些注意事项。 + +QuecPython模组的固件升级与软件升级支持不同平台, 本文以阿里云物联网平台为例介绍如何进行OTA升级操作, 后续会更新其他平台的OTA操作流程。 + +## 制作升级包 + +### 固件升级包 + +设备固件升级建议使用差分升级, 不建议使用全量升级, 目前只有 **EC600NCNLC/LF** 支持全量升级, 其他型号的模组只支持差分升级, 差分升级包制作方法请联系移远售后客服。 + +### 软件升级包 + +软件直接使用Python脚本进行升级即可, 无需进行特殊转换。 + +## 阿里云物联网平台 + +以下为阿里云物联网平台创建OTA升级计划的操作步骤说明, 阿里云物联网平台OTA升级功能详细说明, 可参考官网文档[阿里云物联网平台-运维监控-OTA升级](https://help.aliyun.com/document_detail/130990.html?spm=a2c4g.58328.0.0.1f0e3ed6i3ApkS) + +### 创建OTA升级计划 + +同一产品可以根据升级的功能模块的不同, 创建不同升级模块名称, 通常分为两类 + +- 固件模块, 又称为FOTA升级, 建议以模组的版本命名, 如: EC800E-CNLC +- 软件升级(Python脚本升级), 又称为SOTA升级, 可自行命名, 如: QuecPython-XXX + +### 创建FOTA(固件)升级计划 + +#### 添加升级模块 + +![](../media/iot-advanced/ota/aliyun-fota-create-module.png) + +#### 添加升级包 + +![](../media/iot-advanced/ota/aliyun-fota-create-package.png) + +![](../media/iot-advanced/ota/aliyun-fota-create-package-info.png) + +#### 创建升级计划 + +![](../media/iot-advanced/ota/aliyun-fota-create-plan.png) + +![](../media/iot-advanced/ota/aliyun-fota-create-plan-info-1.png) + +![](../media/iot-advanced/ota/aliyun-fota-create-plan-info-2.png) + +#### 查看升级结果 + +![](../media/iot-advanced/ota/aliyun-fota-create-plan-over.png) + +![](../media/iot-advanced/ota/aliyun-fota-plan-result-view.png) + +![](../media/iot-advanced/ota/aliyun-fota-plan-result-batches.png) + +![](../media/iot-advanced/ota/aliyun-fota-plan-result-devices.png) + +### 创建SOTA(软件)升级计划 + +#### 添加升级模块 + +![](../media/iot-advanced/ota/aliyun-sota-create-module.png) + +#### 添加升级包 + +**注意:** *阿里云使用Python脚本创建升级包, 需要将脚本后缀名`.py`改为`.bin`之后才可上传, 可以上传多个文件* + +![](../media/iot-advanced/ota/aliyun-fota-create-package.png) + +![](../media/iot-advanced/ota/aliyun-sota-create-package-info.png) + +#### 创建升级计划 + +![](../media/iot-advanced/ota/aliyun-sota-create-plan.png) + +![](../media/iot-advanced/ota/aliyun-sota-create-plan-info-1.png) + +![](../media/iot-advanced/ota/aliyun-sota-create-plan-info-2.png) + +![](../media/iot-advanced/ota/aliyun-sota-create-plan-over.png) + +#### 查看升级结果 + +![](../media/iot-advanced/ota/aliyun-sota-plan-result-view.png) + +![](../media/iot-advanced/ota/aliyun-sota-plan-result-batches.png) + +![](../media/iot-advanced/ota/aliyun-sota-plan-result-devices.png) + +### 设备端升级功能开发 + +阿里云物联网平台对接可以使用我们现成的`aliYun`功能模块进行开发即可, 该模块基于MQTT协议进行通信, 无需自行封装阿里云的功能接口。 + +以下示例中用到的相关模块功能可在[QuecPython API 参考手册](https://python.quectel.com/doc/API_reference/zh/index.html)中查看详细说明。 + +阿里云MQTT协议下发的OTA升级数据格式与说明, 详见[阿里云物联网平台-基于Alink协议开发-OTA升级](https://help.aliyun.com/document_detail/89307.html?spm=a2c4g.89307.0.0.12272110cm6wc6) + +**示例:** + +```python +import uos +import fota +import app_fota +import modem +import ujson +from misc import Power +from aliYun import aLiYun + +# 定义软件名称 +PROJECT_NAME = "QuecPython-XXX" +# 定义软件版本 +PROJECT_VERSION = "1.0.0" +# 获取固件型号 +FIRMWARE_NAME = uos.uname()[0].split("=")[1] +# 获取固件版本号 +FIRMWARE_VERSION = modem.getDevFwVersion() + +# 初始化aLiYun功能 +ProductKey = "xxx" +ProductSecret = "xxx" +DeviceName = "xxx" +DeviceSecret = "xxx" +MqttServer = "xxx" +cloud = aLiYun(ProductKey, ProductSecret, DeviceName, DeviceSecret, MqttServer) + +# 初始化OTA相关Topic +# 设备模块版本信息上报topic +ota_topic_device_inform = "/ota/device/inform/%s/%s" % (ProductKey, DeviceName) +# 设备OTA升级计划下发topic +ota_topic_device_upgrade = "/ota/device/upgrade/%s/%s" % (ProductKey, DeviceName) +# 设备升级进度上报topic +ota_topic_device_progress = "/ota/device/progress/%s/%s" % (ProductKey, DeviceName) +# 设备OTA升级计划查询topic +ota_topic_firmware_get = "/sys/%s/%s/thing/ota/firmware/get" % (ProductKey, DeviceName) +# 设备OTA升级计划查询应答topic +ota_topic_firmware_get_reply = "/sys/%s/%s/thing/ota/firmware/get_reply" % (ProductKey, DeviceName) + +# 设置MQTT连接 +client_id = modem.getDevImei() +clean_session = True +cloud.setMqtt(client_id, clean_session) + + +ota_module = None +# 订阅Topic回调函数 +def sub_cb(topic, data): + if topic in (ota_topic_device_upgrade, ota_topic_firmware_get_reply): + # OTA升级 + global ota_module + data = ujson.loads(data) + ota_module = data["module"] + ota_version = data["version"] + if ota_module == FIRMWARE_NAME: + # FOTA升级 + _fota = fota() + _fota.httpDownload(url1=data.get("url"), callback=fota_callback) + elif ota_module == PROJECT_NAME: + # SOTA升级 + ota_data = [{"url": i["fileUrl"], "filename": "/usr/" + i["fileName"].replace(".bin", ".py")} for i in data.get("files", [])] + _app_fota = app_fota.new() + res = _app_fota.bulk_download(ota_data) + # SOTA上报升级结果 + ota_process = 100 if not res else -1 + if ota_process == 100: + _app_fota.set_update_flag() + process_data = { + "id": 5, + "params": { + "step": ota_process, + "desc": "desc", + "module": ota_module, + } + } + cloud.publish(ota_topic_device_progress, ujson.dumps(process_data), qos=1) + # 升级完成之后需要重启设备 + Power.powerRestart() + + + +# FOTA升级进度回调函数 +def fota_callback(args): + print("Download status: %s, Download process: %s" % tuple(args)) + ota_process = None + if args[0] in (0, 1, 2) and args[1] == 100: + ota_process = 100 + else: + ota_process = -1 + if ota_process is not None: + # FOTA上报升级结果 + process_data = { + "id": 5, + "params": { + "step": ota_process, + "desc": "success", + "module": ota_module, + } + } + cloud.publish(ota_topic_device_progress, ujson.dumps(process_data), qos=1) + # 升级成功后会自动重启, 此处可无需手动重启 + Power.powerRestart() + + +# 设置订阅Topic回调函数 +cloud.setCallBack(sub_cb) + +# 订阅Topic +qos = 1 +cloud.subscribe(ota_topic_device_upgrade, qos) +cloud.subscribe(ota_topic_firmware_get_reply￿, qos) + +# 阿里云功能启动 +cloud.start() + +# 上报软件版本信息 +sota_data = { + "id": 1, + "params": { + "version": PROJECT_VERSION, + "module": PROJECT_NAME, + } +} +cloud.publish(ota_topic_device_inform, ujson.dumps(sota_data), qos=1) + +# 上报固件版本信息 +fota_data = { + "id": 2, + "params": { + "version": FIRMWARE_VERSION, + "module": FIRMWARE_NAME, + } +} +cloud.publish(ota_topic_device_inform, ujson.dumps(fota_data), qos=1) + +# 查询软件升级计划 +sota_query = { + "id": 3, + "version": "1.0", + "params": { + "module": PROJECT_NAME, + }, + "method": "thing.ota.firmware.get" +} +cloud.publish(ota_topic_firmware_get, ujson.dumps(sota_query), qos=1) + +# 查询固件升级计划 +sota_query = { + "id": 4, + "version": "1.0", + "params": { + "module": FIRMWARE_NAME, + }, + "method": "thing.ota.firmware.get" +} +cloud.publish(ota_topic_firmware_get, ujson.dumps(sota_query), qos=1) +``` diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-module.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-module.png new file mode 100644 index 0000000000000000000000000000000000000000..af5a6daa5f18c61716ecff363e4e331edefbebf9 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-module.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-package-info.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-package-info.png new file mode 100644 index 0000000000000000000000000000000000000000..189d1911402c432a0e9102ec143be5c78e96a587 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-package-info.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-package.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-package.png new file mode 100644 index 0000000000000000000000000000000000000000..99f16e3d74f1710e4b81a3ac02e5d5492284e3d1 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-package.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-plan-info-1.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-plan-info-1.png new file mode 100644 index 0000000000000000000000000000000000000000..6329ee1bae9b818565ed8ff5ee3f3700020ec868 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-plan-info-1.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-plan-info-2.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-plan-info-2.png new file mode 100644 index 0000000000000000000000000000000000000000..5306d777bf8b9104d13485cb25252bdf6f55e61f Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-plan-info-2.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-plan-over.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-plan-over.png new file mode 100644 index 0000000000000000000000000000000000000000..82a27e2e218f0ab4ae111ba99095393502d00e70 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-plan-over.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-plan.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-plan.png new file mode 100644 index 0000000000000000000000000000000000000000..3ae19830d1ba427f483e0961299e5ca9f28fb951 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-create-plan.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-plan-result-batches.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-plan-result-batches.png new file mode 100644 index 0000000000000000000000000000000000000000..44211da70867c752aa281bd28dc9fc8b19b66ee2 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-plan-result-batches.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-plan-result-devices.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-plan-result-devices.png new file mode 100644 index 0000000000000000000000000000000000000000..658d9fa3125d274e8575a0355bfeec4ec4b415d4 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-plan-result-devices.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-plan-result-view.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-plan-result-view.png new file mode 100644 index 0000000000000000000000000000000000000000..346862c5a9662e5c0be2dc7e2d816ed6d3cf41a0 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-fota-plan-result-view.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-module.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-module.png new file mode 100644 index 0000000000000000000000000000000000000000..af2e5cd62f7e1fc6379e313f6f03c6f6d08e7b07 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-module.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-package-info.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-package-info.png new file mode 100644 index 0000000000000000000000000000000000000000..f54efa5ed275fb5abd5cefe33423e048a75ecbb3 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-package-info.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-plan-info-1.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-plan-info-1.png new file mode 100644 index 0000000000000000000000000000000000000000..6da734ae08cb269b32f4e3fd755cae9fce5315c1 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-plan-info-1.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-plan-info-2.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-plan-info-2.png new file mode 100644 index 0000000000000000000000000000000000000000..73938014fd9602880fb9b1c231bc40b0a816903f Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-plan-info-2.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-plan-over.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-plan-over.png new file mode 100644 index 0000000000000000000000000000000000000000..69c08639990f903470ffdb5b857d896e5378f715 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-plan-over.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-plan.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-plan.png new file mode 100644 index 0000000000000000000000000000000000000000..1330c6b24e4114290f0a2b2385d70b3c7e39e6a7 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-create-plan.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-plan-result-batches.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-plan-result-batches.png new file mode 100644 index 0000000000000000000000000000000000000000..8efb79e2949bf6f6f68a39dfe43f13e634cc4f84 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-plan-result-batches.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-plan-result-devices.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-plan-result-devices.png new file mode 100644 index 0000000000000000000000000000000000000000..1b52b5d6911dc08250cbb3be3fd1179bdff6885e Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-plan-result-devices.png differ diff --git a/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-plan-result-view.png b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-plan-result-view.png new file mode 100644 index 0000000000000000000000000000000000000000..07219300c11d81433b469d6b4af6fb5f4cbf61c0 Binary files /dev/null and b/docs/Getting_started/zh/media/iot-advanced/ota/aliyun-sota-plan-result-view.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/EC600N-CNLA.jpg b/docs/Getting_started/zh/media/solutions/tracker/EC600N-CNLA.jpg new file mode 100644 index 0000000000000000000000000000000000000000..32ab7b11ce1b4158ea08fb6d8524352583bfbe9c Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/EC600N-CNLA.jpg differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/aliyun-device-auth.png b/docs/Getting_started/zh/media/solutions/tracker/aliyun-device-auth.png new file mode 100644 index 0000000000000000000000000000000000000000..6d936c2c0f5d1a53c8b3b2c5416c8439b091158c Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/aliyun-device-auth.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/aliyun-device-properties-info.png b/docs/Getting_started/zh/media/solutions/tracker/aliyun-device-properties-info.png new file mode 100644 index 0000000000000000000000000000000000000000..46f42cbebe6312040bc675bee85c2867db4f7182 Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/aliyun-device-properties-info.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/aliyun-product-auth.png b/docs/Getting_started/zh/media/solutions/tracker/aliyun-product-auth.png new file mode 100644 index 0000000000000000000000000000000000000000..73822da3a13a4b7ccb562900ef6421321f4cefe4 Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/aliyun-product-auth.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/qpycom-download-code.png b/docs/Getting_started/zh/media/solutions/tracker/qpycom-download-code.png new file mode 100644 index 0000000000000000000000000000000000000000..d558b4c8f40eee43756575bdd18e642eef2ece54 Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/qpycom-download-code.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/qpycom-download.png b/docs/Getting_started/zh/media/solutions/tracker/qpycom-download.png new file mode 100644 index 0000000000000000000000000000000000000000..5452c129bb14f3be66db525358952e333219f362 Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/qpycom-download.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/qpycom-project-main.png b/docs/Getting_started/zh/media/solutions/tracker/qpycom-project-main.png new file mode 100644 index 0000000000000000000000000000000000000000..d95d708d4e73ef6253fc0b1d93150a71cc29939c Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/qpycom-project-main.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/qpycom-project-running.png b/docs/Getting_started/zh/media/solutions/tracker/qpycom-project-running.png new file mode 100644 index 0000000000000000000000000000000000000000..d85b8524e71d23fb7b037ebdc054b301d1287f58 Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/qpycom-project-running.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/quecpython-firmware-download.png b/docs/Getting_started/zh/media/solutions/tracker/quecpython-firmware-download.png new file mode 100644 index 0000000000000000000000000000000000000000..bca91d1cffa891e032e1090af735f9ab32880c9d Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/quecpython-firmware-download.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/thingsboard-create-device-edit.png b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-create-device-edit.png new file mode 100644 index 0000000000000000000000000000000000000000..819c5fb7267f33a354e709ae87f441017e56ea66 Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-create-device-edit.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/thingsboard-create-device-select.png b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-create-device-select.png new file mode 100644 index 0000000000000000000000000000000000000000..4d826812a22736bf3ba682983cc38f7a5d0e0c9d Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-create-device-select.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/thingsboard-device-config.png b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-device-config.png new file mode 100644 index 0000000000000000000000000000000000000000..8c587fc6f8a4b047604ed676f460c9d2aa586613 Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-device-config.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/thingsboard-device-list.png b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-device-list.png new file mode 100644 index 0000000000000000000000000000000000000000..5987cbfc847fa7e020518727066a225013892a58 Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-device-list.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/thingsboard-device-running.png b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-device-running.png new file mode 100644 index 0000000000000000000000000000000000000000..64b40b86c662cdb520add61b524af2367af0bb95 Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-device-running.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/thingsboard-device-telemetry.png b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-device-telemetry.png new file mode 100644 index 0000000000000000000000000000000000000000..778634a3445655c9b06d2f8d3f38676ccd44c817 Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-device-telemetry.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/thingsboard-device-token.png b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-device-token.png new file mode 100644 index 0000000000000000000000000000000000000000..f6417c4486e9821aeb246d1d9be89485da7a4227 Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-device-token.png differ diff --git a/docs/Getting_started/zh/media/solutions/tracker/thingsboard-login.png b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-login.png new file mode 100644 index 0000000000000000000000000000000000000000..9f191a8a8dd40744f492abe2ad52fe7a0da41bd9 Binary files /dev/null and b/docs/Getting_started/zh/media/solutions/tracker/thingsboard-login.png differ diff --git a/docs/Getting_started/zh/sidebar.yaml b/docs/Getting_started/zh/sidebar.yaml index 9b53f50148c369135ce54f3b1690d39564adaadc..01eeb4320b173afea3f36d1fe397ec14c926523f 100644 --- a/docs/Getting_started/zh/sidebar.yaml +++ b/docs/Getting_started/zh/sidebar.yaml @@ -160,13 +160,13 @@ items: - label: '9.3: 短信' file: iot-advanced/sms.md - label: '9.4: 定位' - file: iot-advanced/location.md + - label: '9.4: GNSS定位' + file: iot-advanced/gnss.md - label: '9.5: OTA 升级' + - label: '9.5: OTA 升级' file: iot-advanced/ota.md - label: '9.6: AES-128 加解密' + - label: '9.6: AES-128 加解密' file: iot-advanced/aes128.md - label: '10: 其他开发资源' diff --git a/docs/Getting_started/zh/solutions/tracker.md b/docs/Getting_started/zh/solutions/tracker.md new file mode 100644 index 0000000000000000000000000000000000000000..14c9872793c60c9af4a407536f14c85b90340626 --- /dev/null +++ b/docs/Getting_started/zh/solutions/tracker.md @@ -0,0 +1,126 @@ +## 引言 + +当客户购买我们的QuecPython, EC600N, EC200U, EC800E开发板时, 通过本项目可以更直观在PC端查看设备上报数据。 + +项目会定期维护更新, 本说明仅供参考, 不排除后期有功能改动不符合本说明内容描述。 + +## 运行环境及外设介绍 + +### 模块型号 + +本项目可在所有支持QuecPython的模块上进行运行, 但根据不同模块的支持功能所有不同, 需要做相应的功能调整, 如 + +- EC600N, EC800E不支持内置GNSS定位, 需外挂GNSS模块才可使用GNSS定位功能。 +- EC200U支持内置GNSS定位功能, 可无需外挂GNSS模块直接使用GNSS定位功能。 +- 不同传感器需根据实际设备支持今天选择支持。 + +此文档中描述的实验基于EC600N运行。模块外形展示如下图: + +![](../media/solutions/tracker/EC600N-CNLA.jpg) + +### 外设型号 + +- 外挂GNSS: LC86L, L76K +- 温湿度传感器: HDC2080 + +### 固件版本 + +请使用 EC600N V0003 及以上版本进行调试开发。 + +固件下载地址: [https://python.quectel.com/download](https://python.quectel.com/download) + +![](../media/solutions/tracker/quecpython-firmware-download.png) + +## 支持平台简介 + +本项目支持多平台数据上报, 目前支持ThingsBoard(QuecPython私有平台), 阿里云等不同平台的数据交互。 + +### ThingsBoard平台操作说明 + +平台地址: [http://106.15.58.32:8080/login](http://106.15.58.32:8080/login) + +![](../media/solutions/tracker/thingsboard-login.png) + +#### 用户账户申请 + +如需对接该平台, 需向本司提交申请, 审核通过后会下发使用账户进行功能对接。 + +#### 添加设备 + +![](../media/solutions/tracker/thingsboard-create-device-select.png) + +![](../media/solutions/tracker/thingsboard-create-device-edit.png) + +#### 获取认证信息 + +![](../media/solutions/tracker/thingsboard-device-list.png) + +![](../media/solutions/tracker/thingsboard-device-token.png) + +![](../media/solutions/tracker/thingsboard-device-config.png) + +#### 设备功能启动后查看上报数据 + +![](../media/solutions/tracker/thingsboard-device-running.png) + +![](../media/solutions/tracker/thingsboard-device-telemetry.png) + +### 阿里云物联网平台操作说明 + +#### 注册账户与产品设备创建 + +阿里云物联网平台功能介绍与功能描述(产品设备创建)详见[阿里云文档中心](https://help.aliyun.com/document_detail/131611.html?spm=a2c4g.130816.0.0.7e193e06DaU4Mu) + +#### 获取设备认证信息 + +创建好产品设备后, 根据选择的认证模式, 一机一密或一型一密, 在`settings_cloud.py`中填写对应的配置参数。 + +- 一机一密需填写`product_key`, `device_name`, `device_secret` +- 一型一密需填写`product_key`, `product_secret`, `device_name` + +![](../media/solutions/tracker/aliyun-product-auth.png) + +![](../media/solutions/tracker/aliyun-device-auth.png) + +#### 运行项目后查看上报数据 + +![](../media/solutions/tracker/aliyun-device-properties-info.png) + +## 项目运行说明 + +### 项目代码下载 + +本项目已开源至GitHub, 直接使用Git下载到本地即可进行二次开发, 开源项目中有详细的软件功能架构说明与功能模块使用说明。 + +GitHub 开源地址: [https://github.com/QuecPython/solution-tracker](https://github.com/QuecPython/solution-tracker) + +### 调整项目配置文件 + +- `settings_cloud.py` 用于配置连接ThingsBoard或阿里云的配置参数 +- `settings_loc.py` 用于配置定位模块的配置参数 +- `settings_user.py` 用于配置软件业务相关配置参数 + +配置参数具体含义见[tracker公版方案功能接口](https://github.com/QuecPython/solution-tracker/blob/master/docs/tracker%E5%85%AC%E7%89%88%E6%96%B9%E6%A1%88%E5%8A%9F%E8%83%BD%E6%8E%A5%E5%8F%A3.md) + +### 使用QPYCom工具进行软件烧录 + +![](../media/solutions/tracker/qpycom-download-code.png) + +测试可直接选中`tracker_ali.py`或`tracker_tb.py`, 点击运行, 即可启动项目, 可在交互中进行查看设备运行状态与日志。 + +![](../media/solutions/tracker/qpycom-project-running.png) + +还可以烧入`main.py`脚本, 烧入完成后, 重启设备, 项目即可自动运行, 以后每次设备上电即可自动运行。 + +![](../media/solutions/tracker/qpycom-project-main.png) + +QPYCom软件下载地址: [https://python.quectel.com/download](https://python.quectel.com/download) + +![](../media/solutions/tracker/qpycom-download.png) + +## 常见问题处理 + +1. 设备注册时返回注册失败, 产品信息查询不到时请检查配置的产品ID以及产品密钥是否匹配。 +2. 数据采集为空或者失败应检查对应的传感器参数是否配置正确, 传感器的型号不同导致的配置参数可能会有差异。 +3. MQTT在尝试与云端进行连接时出现`MQTTEXException: 4`时请检查连接参数是否正确配置, MQTT服务地址是否正确。 如遇到域名解析失败时可尝试使用`usocket.getaddrinfo()`方法先尝试解析再进行连接。 +4. 查看代码中遇到存在疑惑的API时可查看我们的[QuecPython API 参考手册](https://python.quectel.com/doc/API_reference/zh/index.html), 里面有详细的方法介绍。