mirror of
https://gitee.com/qpy-solutions/dtu.git
synced 2025-05-19 19:18:24 +08:00
更新文档和代码
This commit is contained in:
parent
3f935faeaf
commit
1d86858284
@ -190,6 +190,20 @@
|
|||||||
| pubTopic | str | true | 发布主题 |
|
| pubTopic | str | true | 发布主题 |
|
||||||
| serialD | int | true | MQTT通道捆绑的串口ID (1~3) |
|
| serialD | int | true | MQTT通道捆绑的串口ID (1~3) |
|
||||||
|
|
||||||
|
##### 通道类型:移远云
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
| **字段** | **type** | **Required** | **含义** |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| keepAlive | int | false | 通信之间允许的最长时间段(以秒为单位),默认为120,范围(60-1200)可不填 |
|
||||||
|
| ProductKey | str | true | 产品key |
|
||||||
|
| ProductSecret | str | false | 产品密钥|
|
||||||
|
| QOS | int | false | MQTT消息服务质量(默认0,可选择0或1)0:发送者只发送一次消息,不进行重试 1:发送者最少发送一次消息,确保消息到达Broker |
|
||||||
|
| SessionFlag | bool | true | 配置与云平台通信的数据是否采用session加密(默认值为False),True:加密,False:加密 |
|
||||||
|
| sendMode | str | true | 移远云数据收发模式,phy:物模型,pass:透传 |
|
||||||
|
| serialD | int | true | MQTT通道捆绑的串口ID (1~3) |
|
||||||
|
|
||||||
##### APN设置
|
##### APN设置
|
||||||
|
|
||||||
APN功能暂未上线
|
APN功能暂未上线
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
| :------ | ---------- | ---------- | --------------------- |
|
| :------ | ---------- | ---------- | --------------------- |
|
||||||
| 1.0 | 2021-11-25 | 陈驰 | 初始版本 |
|
| 1.0 | 2021-11-25 | 陈驰 | 初始版本 |
|
||||||
| 1.1 | 2021-11-30 | 陈驰 | 增加对DTU配套组件和服务的描述 |
|
| 1.1 | 2021-11-30 | 陈驰 | 增加对DTU配套组件和服务的描述 |
|
||||||
|
| 1.2 | 2022-01-14 | 陈驰 | 增加DTU代码和文档链接的描述 |
|
||||||
|
|
||||||
## DTU介绍
|
## DTU介绍
|
||||||
|
|
||||||
@ -178,3 +179,25 @@ QPYCom的使用文档,参见安装目录下的`docs`文件夹。
|
|||||||
### modbus模式
|
### modbus模式
|
||||||
|
|
||||||
modbus模式下,严格遵守modbus协议规范,且遵守modbus协议的DTU产品在行业内的应用规则:DTU作为主机,根据用户配置,周期性向从机设备索要数据,推送至云端。
|
modbus模式下,严格遵守modbus协议规范,且遵守modbus协议的DTU产品在行业内的应用规则:DTU作为主机,根据用户配置,周期性向从机设备索要数据,推送至云端。
|
||||||
|
|
||||||
|
## DTU代码下载和使用文档
|
||||||
|
|
||||||
|
### 代码下载
|
||||||
|
|
||||||
|
`git clone https://gitee.com/qpy-solutions/dtu.git`
|
||||||
|
或
|
||||||
|
`git clone git@gitee.com:qpy-solutions/dtu.git`
|
||||||
|
|
||||||
|
### 使用文档
|
||||||
|
|
||||||
|
- DTU产品介绍:[点此进入][1]
|
||||||
|
- DTU用户指导:[点此进入][2]
|
||||||
|
- DTU协议规范:[点此进入][3]
|
||||||
|
- DTU上位机工具用户指导:[点此进入][4]
|
||||||
|
|
||||||
|
|
||||||
|
[1]: https://python.quectel.com/doc/doc/Product_case/zh/dtu/DTU_Product_Introduction.html
|
||||||
|
[2]: https://python.quectel.com/doc/doc/Product_case/zh/dtu/DTU_User_Guides.html
|
||||||
|
[3]: https://python.quectel.com/doc/doc/Product_case/zh/dtu/DTU_Protocol_Specification.html
|
||||||
|
[4]: https://python.quectel.com/doc/doc/Product_case/zh/dtu/DTU_GUI_User_Guides.html
|
||||||
|
|
@ -17,9 +17,9 @@ DTU与云端通信报文使用json格式
|
|||||||
|
|
||||||
- 云端下行报文
|
- 云端下行报文
|
||||||
|
|
||||||
命令模式与modbus模式:
|
命令模式:
|
||||||
|
|
||||||
`{“msg_id”: msg_id, “data”: “1234”[, “cmd_code”: 0X40, “topic_id”: 1]}`
|
`{“msg_id”: msg_id, “data”: “1234”[, “cmd_code”: 40, “topic_id”: 1]}`
|
||||||
|
|
||||||
透传模式:
|
透传模式:
|
||||||
|
|
||||||
@ -35,11 +35,37 @@ cmd_code:可选字段,填写对应功能码,并又DTU执行相应的操作
|
|||||||
|
|
||||||
topic_id:可选字段,填写mqtt返回需要publish的topic_id,此字段仅在命令模式与使用MQTT/Aliyun/Txyun时生效
|
topic_id:可选字段,填写mqtt返回需要publish的topic_id,此字段仅在命令模式与使用MQTT/Aliyun/Txyun时生效
|
||||||
|
|
||||||
|
- modbus模式
|
||||||
|
|
||||||
|
`{“msg_id”: msg_id, “modbus”: {"groups": {"num": 0, "cmd": ["0x03", "0x00", "0x00", "0x00", "0x02"]}}}`
|
||||||
|
|
||||||
|
字段说明:
|
||||||
|
|
||||||
|
msg_id:报文id,一般为时间戳+3位随机数
|
||||||
|
|
||||||
|
data:报文消息字段
|
||||||
|
|
||||||
|
cmd_code:可选字段,填写对应功能码,并又DTU执行相应的操作,此字段仅在命令模式下生效
|
||||||
|
|
||||||
|
topic_id:可选字段,填写mqtt返回需要publish的topic_id,此字段仅在命令模式与使用MQTT/Aliyun/Txyun时生效
|
||||||
|
|
||||||
|
modbus:可选字段,此字段仅在modbus模式使用,此字段下有3个子字段:groups,task与command
|
||||||
|
|
||||||
|
    groups:可选字段,在modbus模式下向指定的地址组发送消息
|
||||||
|
|
||||||
|
        num:配置文件中的地址组编号
|
||||||
|
|
||||||
|
        cmd:向地址组发送的modbus命令
|
||||||
|
|
||||||
|
    task:可选字段,在modbus模式下执行代码中预置的task任务
|
||||||
|
|
||||||
|
    command:可选字段,在modbus下直接向UART口写入指定modbus命令
|
||||||
|
|
||||||
- 云端上行报文
|
- 云端上行报文
|
||||||
|
|
||||||
命令模式与modbus模式:
|
命令模式:
|
||||||
|
|
||||||
`{“msg_id”: msg_id, “data”: “1234”[, “cmd_code”: 0X40, “status”: 1]}`
|
`{"msg_id": msg_id, "data": "1234"[, "cmd_code": 40, "status": 1, "password": "123"]}`
|
||||||
|
|
||||||
透传模式:
|
透传模式:
|
||||||
|
|
||||||
@ -66,41 +92,37 @@ status:可选字段,仅在命令模式下生效,用于反馈命令是否
|
|||||||
### 功能码表
|
### 功能码表
|
||||||
|
|
||||||
| 功能码 | 功能 |
|
| 功能码 | 功能 |
|
||||||
| --- | --- |
|
|--------|---------------|
|
||||||
| 0x00-0x3f | 查询指令 |
|
| 0-49 | 查询指令 |
|
||||||
| 0x00 | 查询IMEI |
|
| 0 | 查询IMEI |
|
||||||
| 0x01 | 查询本机号码 |
|
| 1 | 查询本机号码 |
|
||||||
| 0x02 | 查询固件版本号 |
|
| 2 | 查询固件版本号 |
|
||||||
| 0x03 | 查询信号强度 |
|
| 3 | 查询信号强度 |
|
||||||
| 0x04 | 查询当前配置参数 |
|
| 4 | 查询当前配置参数 |
|
||||||
| 0x05 | 诊断查询 |
|
| 5 | 诊断查询 |
|
||||||
| 0X06 | 查询ICCID |
|
| 6 | 查询ICCID |
|
||||||
| 0X07 | 查询ADC电压 |
|
| 7 | 查询ADC电压 |
|
||||||
| 0X08 | 查询GPIO信息 |
|
| 8 | 查询GPIO信息 |
|
||||||
| 0X10 | 查询温湿度 |
|
| 10 | 查询温湿度 |
|
||||||
| 0X11 | 查询网络连接信息 |
|
| 11 | 查询网络连接信息 |
|
||||||
| 0X12 | 查询网络状态 |
|
| 12 | 查询网络状态 |
|
||||||
| 0X13 | 查询基站定位信息 |
|
| 13 | 查询基站定位信息 |
|
||||||
| 0x50~0x8f | 设置指令 |
|
| 50~143 | 设置指令 |
|
||||||
| 0x50 | 协议短信透传 |
|
| 50 | 协议短信透传 |
|
||||||
| 0x51 | 配置密码 |
|
| 51 | 配置密码 |
|
||||||
| 0x52 | 添加设备识别码IMEI |
|
| 52 | 添加设备识别码IMEI |
|
||||||
| 0x53 | 登录服务器发送注册信息 |
|
| 53 | 登录服务器发送注册信息 |
|
||||||
| 0x54 | 固件版本号 |
|
| 54 | 固件版本号 |
|
||||||
| 0x55 | 是否启用自动更新 |
|
| 55 | 是否启用自动更新 |
|
||||||
| 0x56 | 日志输出 |
|
| 56 | 日志输出 |
|
||||||
| 0x57 | 服务器获取配置参数 |
|
| 57 | 服务器获取配置参数 |
|
||||||
| 0x58 | 串口参数 |
|
| 58 | 串口参数 |
|
||||||
| 0x59 | 通道配置参数 |
|
| 59 | 通道配置参数 |
|
||||||
| 0x60 | Apn设置 |
|
| 60 | Apn设置 |
|
||||||
| 0x61 | GPIO设置 |
|
| 61 | GPIO设置 |
|
||||||
| 0x62 | GPS |
|
| 62 | OTA |
|
||||||
| 0x63 | 数据流 |
|
| 63 | 参数设置 |
|
||||||
| 0x64 | 预警 |
|
| 255 | 复位指令 |
|
||||||
| 0x65 | 任务 |
|
|
||||||
| 0xfd | 协议终止指令 |
|
|
||||||
| 0xfe | DTU启动中,无法接收指令 |
|
|
||||||
| 0xff | 复位指令 |
|
|
||||||
|
|
||||||
## 查询指令
|
## 查询指令
|
||||||
|
|
||||||
@ -114,7 +136,7 @@ DTU的IMEI号
|
|||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
|
|
||||||
`{"code": 0x00 , "data": "123456789012345" , "success":1}`
|
`{"code": 0 , "data": "123456789012345" , "success":1}`
|
||||||
|
|
||||||
字段说明:
|
字段说明:
|
||||||
|
|
||||||
@ -130,11 +152,11 @@ DTU的IMEI号
|
|||||||
|
|
||||||
查询SIM卡的号码
|
查询SIM卡的号码
|
||||||
|
|
||||||
功能码: 0x01
|
功能码: 1
|
||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
|
|
||||||
`{"code": 0x01 , "data": "17201593988" , "success":1}`
|
`{"code": 1 , "data": "17201593988" , "success":1}`
|
||||||
|
|
||||||
| **字段** | **类型** | **含义** |
|
| **字段** | **类型** | **含义** |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
@ -150,11 +172,11 @@ DTU的IMEI号
|
|||||||
|
|
||||||
固件版本号格式为: v 1
|
固件版本号格式为: v 1
|
||||||
|
|
||||||
功能码: 0x02
|
功能码: 2
|
||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
|
|
||||||
`{"code": 0x02 , "data": "v 1" , "success":1}`
|
`{"code": 2 , "data": "v 1" , "success":1}`
|
||||||
|
|
||||||
| **字段** | **类型** | **含义** |
|
| **字段** | **类型** | **含义** |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
@ -168,33 +190,31 @@ DTU的IMEI号
|
|||||||
|
|
||||||
网络信号强度值范围0~31,值越大表示信号强度越好。
|
网络信号强度值范围0~31,值越大表示信号强度越好。
|
||||||
|
|
||||||
功能码: 0x03
|
功能码: 3
|
||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
|
|
||||||
`{"code": 0x03 , "data": " CSQ17 " , "success":1}`
|
`{"code": 3 , "data": " CSQ17 " , "success":1}`
|
||||||
|
|
||||||
| **字段** | **字符串** | **含义** |
|
| **字段** | **类型** | **含义** |
|
||||||
| --- | --- | --- |
|
| --- |--------| --- |
|
||||||
| code | str | 状态码 |
|
| code | str | 状态码 |
|
||||||
| data | str | CSQ1~CSQ31 |
|
| data | str | CSQ1~CSQ31 |
|
||||||
| success | int | 0 失败 1成功 |
|
| success | int | 0 失败 1成功 |
|
||||||
|
|
||||||
### 查询当前配置参数
|
### 查询当前配置参数
|
||||||
|
|
||||||
功能码: 0x04
|
功能码: 4
|
||||||
|
|
||||||
数据内容:
|
数据内容:
|
||||||
```
|
```
|
||||||
{ "password": "012345",
|
{"password": "012345",
|
||||||
|
"cmd_code": 4,
|
||||||
"data":{}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
|
|
||||||
`{"code": 0x04 , "data": " req config " , "success":1}`
|
`{"code": 4 , "data": " req config " , "success":1}`
|
||||||
|
|
||||||
| **字段** | **字符串** | **含义** |
|
| **字段** | **字符串** | **含义** |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
@ -206,13 +226,13 @@ DTU的IMEI号
|
|||||||
|
|
||||||
说明: 查询当前DTU运行的错误上报信息
|
说明: 查询当前DTU运行的错误上报信息
|
||||||
|
|
||||||
功能码: 0x05
|
功能码: 5
|
||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
```
|
```
|
||||||
{"code":0x05,
|
{"code":5,
|
||||||
|
|
||||||
"data":[{"func_code": "0x01" , "error_code": " 6001"}],
|
"data":[{"func_code": "5" , "error_code": " 6001"}],
|
||||||
|
|
||||||
"success":1}
|
"success":1}
|
||||||
```
|
```
|
||||||
@ -228,11 +248,11 @@ DTU的IMEI号
|
|||||||
|
|
||||||
说明: 查询iccid
|
说明: 查询iccid
|
||||||
|
|
||||||
功能码: 0x06
|
功能码: 6
|
||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
```
|
```
|
||||||
{"code":0x06,
|
{"code":6,
|
||||||
|
|
||||||
"data": "12456465486561516515153",
|
"data": "12456465486561516515153",
|
||||||
|
|
||||||
@ -249,11 +269,11 @@ DTU的IMEI号
|
|||||||
|
|
||||||
说明: 查询adc
|
说明: 查询adc
|
||||||
|
|
||||||
功能码: 0x07
|
功能码: 7
|
||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
```
|
```
|
||||||
{"code":0x07,
|
{"code":7,
|
||||||
|
|
||||||
"data": "3.7",
|
"data": "3.7",
|
||||||
|
|
||||||
@ -269,11 +289,11 @@ DTU的IMEI号
|
|||||||
|
|
||||||
说明: 查询gpio
|
说明: 查询gpio
|
||||||
|
|
||||||
功能码: 0x08
|
功能码: 8
|
||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
```
|
```
|
||||||
{"code":0x08,
|
{"code":8,
|
||||||
|
|
||||||
"data": "gpio_msg",
|
"data": "gpio_msg",
|
||||||
|
|
||||||
@ -286,15 +306,35 @@ DTU的IMEI号
|
|||||||
| data | str | gpio获取的信息 |
|
| data | str | gpio获取的信息 |
|
||||||
| status | str | 0 失败 1成功 |
|
| status | str | 0 失败 1成功 |
|
||||||
|
|
||||||
|
### 电池电压查询
|
||||||
|
|
||||||
|
说明: 查询gpio
|
||||||
|
|
||||||
|
功能码: 9
|
||||||
|
|
||||||
|
返回的数据内容:
|
||||||
|
```
|
||||||
|
{"code":9,
|
||||||
|
|
||||||
|
"data": "3590",
|
||||||
|
|
||||||
|
"status":1}
|
||||||
|
```
|
||||||
|
|
||||||
|
| **字段** | **类型** | **含义** |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| code | int | 状态码 |
|
||||||
|
| data | str | gpio获取的信息 |
|
||||||
|
| status | str | 0 失败 1成功 |
|
||||||
### 查询温湿度
|
### 查询温湿度
|
||||||
|
|
||||||
说明: 查询温湿度
|
说明: 查询温湿度
|
||||||
|
|
||||||
功能码: 0x010
|
功能码: 10
|
||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
```
|
```
|
||||||
{"code":0x10,
|
{"code":10,
|
||||||
"data": {"temperature": 26.0, "humidity": 60.0},
|
"data": {"temperature": 26.0, "humidity": 60.0},
|
||||||
"status":1}
|
"status":1}
|
||||||
```
|
```
|
||||||
@ -302,18 +342,18 @@ DTU的IMEI号
|
|||||||
| **字段** | **类型** | **含义** |
|
| **字段** | **类型** | **含义** |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| code | int | 状态码 |
|
| code | int | 状态码 |
|
||||||
| data | dict | 温湿度信息{"temperature": temp, &##39;humidity&##39;: humid} |
|
| data | dict | 温湿度信息{"temperature": temp, 'humidity': humid} |
|
||||||
| status | str | 0 失败 1成功 |
|
| status | str | 0 失败 1成功 |
|
||||||
|
|
||||||
### 查询网络连接信息
|
### 查询网络连接信息
|
||||||
|
|
||||||
说明: 查询网络连接信息,每种连接类型返回对应连接状态
|
说明: 查询网络连接信息,每种连接类型返回对应连接状态
|
||||||
|
|
||||||
功能码: 0x11
|
功能码: 11
|
||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
```
|
```
|
||||||
{"code":0x11,
|
{"code":11,
|
||||||
"data": "200",
|
"data": "200",
|
||||||
"status":1}
|
"status":1}
|
||||||
```
|
```
|
||||||
@ -324,36 +364,98 @@ DTU的IMEI号
|
|||||||
| data | str | 网络连接状态 |
|
| data | str | 网络连接状态 |
|
||||||
| status | str | 0 失败 1成功 |
|
| status | str | 0 失败 1成功 |
|
||||||
|
|
||||||
|
网络连接状态说明
|
||||||
|
|
||||||
|
| **连接类型** | **含义** |
|
||||||
|
|-----------|--------------------------------|
|
||||||
|
| http | 返回http状态码 |
|
||||||
|
| tcp/udp | 参照套接字状态表 |
|
||||||
|
| mqtt | 0:连接成功 1:连接中 2:服务端连接关闭 -1:连接异常 |
|
||||||
|
| aliyun | 0:连接成功 1:连接中 2:服务端连接关闭 -1:连接异常 |
|
||||||
|
| txyun | 0:连接成功 1:连接中 2:服务端连接关闭 -1:连接异常 |
|
||||||
|
| quecthing | 参照quecthing连接状态表 |
|
||||||
|
|
||||||
|
套接字状态表
|
||||||
|
|
||||||
|
| **状态值** | **状态** | **描述** |
|
||||||
|
|------|------------|---------------------------------------------------------------|
|
||||||
|
|0 | CLOSED | 套接字创建了,但没有使用这个套接字 |
|
||||||
|
|1 | LISTEN | 套接字正在监听连接 |
|
||||||
|
|2 | SYN_SENT | 套接字正在试图主动建立连接,即发送SYN后还没有收到ACK |
|
||||||
|
|3 | SYN_RCVD | 套接字正在处于连接的初始同步状态,即收到对方的SYN,但还没收到自己发过去的SYN的ACK |
|
||||||
|
|4 | ESTABLISHED | 连接已建立 |
|
||||||
|
|5 | FIN_WAIT_1 | 套接字已关闭,正在关闭连接,即发送FIN,没有收到ACK也没有收到FIN |
|
||||||
|
|6 | FIN_WAIT_2 | 套接字已关闭,正在等待远程套接字关闭,即在FIN_WAIT_1状态下收到发过去FIN对应的ACK |
|
||||||
|
|7 | CLOSE_WAIT | 远程套接字已经关闭,正在等待关闭这个套接字,被动关闭的一方收到FIN |
|
||||||
|
|8 | CLOSING | 套接字已关闭,远程套接字正在关闭,暂时挂起关闭确认,即在FIN_WAIT_1状态下收到被动方的FIN |
|
||||||
|
|9 | LAST_ACK | 远程套接字已关闭,正在等待本地套接字的关闭确认,被动方在CLOSE_WAIT状态下发送FIN |
|
||||||
|
|10 | TIME_WAIT | 套接字已经关闭,正在等待远程套接字的关闭,即FIN、ACK、FIN、ACK都完毕,经过2MSL时间后变为CLOSED状态 |
|
||||||
|
|
||||||
|
quecthing连接状态表
|
||||||
|
|
||||||
|
|**整型**| **状态编号** |
|
||||||
|
|---|------------|
|
||||||
|
|0 | 未初始化 |
|
||||||
|
|1 | 已初始化 |
|
||||||
|
|2 | 正在认证 |
|
||||||
|
|3 | 认证成功 |
|
||||||
|
|4 | 认证失败 |
|
||||||
|
|5 | 正在注册 |
|
||||||
|
|6 | 注册成功,等待订阅 |
|
||||||
|
|7 | 注册失败 |
|
||||||
|
|8 | 已订阅,数据可发送 |
|
||||||
|
|9 | 订阅失败 |
|
||||||
|
|10 | 正在注销 |
|
||||||
|
|11 | 注销成功 |
|
||||||
|
|12 | 注销失败 |
|
||||||
|
|
||||||
### 查询网络状态
|
### 查询网络状态
|
||||||
|
|
||||||
说明: 查询网络连接状态,返回基站信息
|
说明: 查询网络连接状态,返回基站信息
|
||||||
|
|
||||||
功能码: 0x12
|
功能码: 12
|
||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
```
|
```
|
||||||
{"code":0x12,
|
{"code":12,
|
||||||
|
|
||||||
"data": ([], [], [(0, 14071232, 1120, 0, 123….),
|
"data": {"voice_state": 1, "data_state": 1},
|
||||||
|
|
||||||
"status":1}
|
"status":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
| **字段** | **类型** | **含义** |
|
| **字段** | **类型** | **含义** |
|
||||||
| --- | --- | --- |
|
| --- | --- |---------------------------------------|
|
||||||
| code | int | 状态码 |
|
| code | int | 状态码 |
|
||||||
| data | turple | 基站连接状态 |
|
| data | turple | voice_state:语音连接状态, data_state:数据连接状态 |
|
||||||
| status | str | 0 失败 1成功 |
|
| status | str | 0 失败 1成功 |
|
||||||
|
|
||||||
|
状态说明
|
||||||
|
|
||||||
|
| **值** | **状态说明** |
|
||||||
|
| --- | --- |
|
||||||
|
| 0 | not registered, MT is not currently searching an operator to register to |
|
||||||
|
| 1 | registered, home network |
|
||||||
|
| 2 | not registered, but MT is currently trying to attach or searching an operator to register to |
|
||||||
|
| 3 | registration denied |
|
||||||
|
| 4 | unknown |
|
||||||
|
| 5 | registered, roaming |
|
||||||
|
| 6 | egistered for “SMS only”, home network (not applicable) |
|
||||||
|
| 7 | registered for “SMS only”, roaming (not applicable) |
|
||||||
|
| 8 | attached for emergency bearer services only |
|
||||||
|
| 9 | registered for “CSFB not preferred”, home network (not applicable) |
|
||||||
|
| 10 | registered for “CSFB not preferred”, roaming (not applicable) |
|
||||||
|
| 11 | emergency bearer services only |
|
||||||
|
|
||||||
### 查询基站定位信息
|
### 查询基站定位信息
|
||||||
|
|
||||||
说明: 查询基站定位信息
|
说明: 查询基站定位信息
|
||||||
|
|
||||||
功能码: 0x13
|
功能码: 13
|
||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
```
|
```
|
||||||
{"code":0x13,
|
{"code":13,
|
||||||
|
|
||||||
"data": (117.1138, 31.82279, 550) ,
|
"data": (117.1138, 31.82279, 550) ,
|
||||||
|
|
||||||
@ -368,12 +470,14 @@ DTU的IMEI号
|
|||||||
|
|
||||||
## 复位指令
|
## 复位指令
|
||||||
|
|
||||||
功能码: 0xff
|
功能码: 255
|
||||||
|
|
||||||
数据内容:
|
数据内容:
|
||||||
```
|
```
|
||||||
{ Password: "012345",
|
{ Password: "012345",
|
||||||
|
|
||||||
|
"code":255,
|
||||||
|
|
||||||
"data":{}
|
"data":{}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -381,7 +485,7 @@ DTU的IMEI号
|
|||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
|
|
||||||
`{"code": 0x06 , "data": " reset dtu " , "success":1}`
|
无
|
||||||
|
|
||||||
| **字段** | **类型** | **含义** |
|
| **字段** | **类型** | **含义** |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
@ -395,7 +499,7 @@ DTU的IMEI号
|
|||||||
|
|
||||||
#### 协议短信(SMS)透传 message
|
#### 协议短信(SMS)透传 message
|
||||||
|
|
||||||
功能码: 0x50
|
功能码: 50
|
||||||
|
|
||||||
数据内容:
|
数据内容:
|
||||||
|
|
||||||
@ -410,7 +514,7 @@ DTU的IMEI号
|
|||||||
|
|
||||||
message: {"number":"12123123", -- 目标号码
|
message: {"number":"12123123", -- 目标号码
|
||||||
|
|
||||||
"data:" " -- 发送短信
|
"sms_msg:" " -- 发送短信
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -419,7 +523,7 @@ message: {"number":"12123123", -- 目标号码
|
|||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
|
|
||||||
`{"code": 0x50 , "data": " " , "success":1}`
|
`{"code": 50 , "data": " " , "success":1}`
|
||||||
|
|
||||||
| **字段** | **类型** | **含义** |
|
| **字段** | **类型** | **含义** |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
@ -437,13 +541,13 @@ message: {"number":"12123123", -- 目标号码
|
|||||||
|
|
||||||
是否开启自动更新需要密码
|
是否开启自动更新需要密码
|
||||||
|
|
||||||
功能码: 0x51
|
功能码: 51
|
||||||
|
|
||||||
数据内容:
|
数据内容:
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"password":" ",
|
"password":" ",
|
||||||
"data":{ "password": "012345"}
|
"data":{"new_password": "012345"}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
说明:初始密码为固件IMEI的后六位
|
说明:初始密码为固件IMEI的后六位
|
||||||
@ -457,7 +561,7 @@ message: {"number":"12123123", -- 目标号码
|
|||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
|
|
||||||
`{"code": 0x51 , "data": " " , "success":1}`
|
`{"code": 51 , "data": " " , "success":1}`
|
||||||
|
|
||||||
| **字段** | **含义** |
|
| **字段** | **含义** |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
@ -472,7 +576,7 @@ message: {"number":"12123123", -- 目标号码
|
|||||||
|
|
||||||
首次登陆服务器发送注册信息
|
首次登陆服务器发送注册信息
|
||||||
|
|
||||||
功能码: 0x53
|
功能码: 53
|
||||||
|
|
||||||
数据内容:
|
数据内容:
|
||||||
```
|
```
|
||||||
@ -490,7 +594,7 @@ message: {"number":"12123123", -- 目标号码
|
|||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
|
|
||||||
`{"code": 0x53 , "data": " " , "success":1}`
|
`{"code": 53 , "data": " " , "success":1}`
|
||||||
|
|
||||||
| **字段** | **类型** | **含义** |
|
| **字段** | **类型** | **含义** |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
@ -504,21 +608,23 @@ message: {"number":"12123123", -- 目标号码
|
|||||||
|
|
||||||
修改固件版本号,用于fota升级(当开启fota升级,版本号小于服务器端的固件版本号就会进行fota升级)
|
修改固件版本号,用于fota升级(当开启fota升级,版本号小于服务器端的固件版本号就会进行fota升级)
|
||||||
|
|
||||||
功能码: 0x54
|
固件版本号仅支持整数
|
||||||
|
|
||||||
|
功能码: 54
|
||||||
|
|
||||||
数据内容:
|
数据内容:
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"password":"",
|
"password":"",
|
||||||
"data":{
|
"data":{
|
||||||
" version ": "100" --- 版本号(使用数字字符串)
|
"version ": "100" --- 版本号(使用数字字符串)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
|
|
||||||
`{"code": 0x54 , "data": " " , "success":1}`
|
`{"code": 54 , "data": " " , "success":1}`
|
||||||
|
|
||||||
| **字段** | **类型** | **含义** |
|
| **字段** | **类型** | **含义** |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
@ -532,7 +638,7 @@ message: {"number":"12123123", -- 目标号码
|
|||||||
|
|
||||||
Fota升级开关
|
Fota升级开关
|
||||||
|
|
||||||
功能码: 0x55
|
功能码: 55
|
||||||
|
|
||||||
数据内容:
|
数据内容:
|
||||||
```
|
```
|
||||||
@ -545,7 +651,7 @@ Fota升级开关
|
|||||||
```
|
```
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
|
|
||||||
`{"code": 0x55 , "data": " fota" , "success":1}`
|
`{"code": 55 , "data": " fota" , "success":1}`
|
||||||
|
|
||||||
| **字段** | **类型** | **含义** |
|
| **字段** | **类型** | **含义** |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
@ -559,7 +665,7 @@ Fota升级开关
|
|||||||
|
|
||||||
串口打印日志记录,目前不支持。日志输出连接Debug口
|
串口打印日志记录,目前不支持。日志输出连接Debug口
|
||||||
|
|
||||||
功能码: 0x56
|
功能码: 56
|
||||||
|
|
||||||
数据内容:
|
数据内容:
|
||||||
```
|
```
|
||||||
@ -582,7 +688,7 @@ Fota升级开关
|
|||||||
|
|
||||||
#### 服务器获取配置参数
|
#### 服务器获取配置参数
|
||||||
|
|
||||||
功能码: 0x57
|
功能码: 57
|
||||||
|
|
||||||
数据内容:
|
数据内容:
|
||||||
```
|
```
|
||||||
@ -611,7 +717,9 @@ Fota升级开关
|
|||||||
|
|
||||||
#### 串口参数 uconf
|
#### 串口参数 uconf
|
||||||
|
|
||||||
功能码: 0x58
|
功能码: 58
|
||||||
|
|
||||||
|
**在透传模式下无法设置串口参数**
|
||||||
|
|
||||||
数据内容:
|
数据内容:
|
||||||
```
|
```
|
||||||
@ -639,27 +747,30 @@ Fota升级开关
|
|||||||
|
|
||||||
#### 通道配置参数 conf
|
#### 通道配置参数 conf
|
||||||
|
|
||||||
功能码: 0x59
|
功能码: 59
|
||||||
|
|
||||||
|
**在透传模式下无法设置串口参数**
|
||||||
|
|
||||||
数据内容:
|
数据内容:
|
||||||
```
|
```
|
||||||
{"password":"",
|
{"password":"",
|
||||||
"data":{
|
"data":{
|
||||||
"conf":"1": {
|
"conf":{
|
||||||
"protocol": "aliyun",
|
"1": {
|
||||||
"type": "mos",
|
"protocol": "aliyun",
|
||||||
"keepAlive": "",
|
"type": "mos",
|
||||||
"clientID": "0",
|
"keepAlive": "",
|
||||||
"Devicename": "ec600n",
|
"clientID": "0",
|
||||||
"ProductKey": "gbh26bFEA4M",
|
"Devicename": "ec600n",
|
||||||
"DeviceSecret": "b7ff5acc0671d40adfd0eff57e7605f6",
|
"ProductKey": "gbh26bFEA4M",
|
||||||
"ProductSecret": "",
|
"DeviceSecret": "b7ff5acc0671d40adfd0eff57e7605f6",
|
||||||
"cleanSession": true,
|
"ProductSecret": "",
|
||||||
"qos": "1",
|
"cleanSession": true,
|
||||||
"subscribe": {"0": "/gbh26bFEA4M/ec600n/user/subtest"},
|
"qos": "1",
|
||||||
"publish": {"0": "/gbh26bFEA4M/ec600n/user/pubtest"},
|
"subscribe": {"0": "/gbh26bFEA4M/ec600n/user/subtest"},
|
||||||
"serialID": "0"}
|
"publish": {"0": "/gbh26bFEA4M/ec600n/user/pubtest"},
|
||||||
}}
|
"serialID": "0"}
|
||||||
|
}}}
|
||||||
```
|
```
|
||||||
**对应通道的配置参数详见6.1.10.1的通道配置详解 :**
|
**对应通道的配置参数详见6.1.10.1的通道配置详解 :**
|
||||||
|
|
||||||
@ -719,7 +830,7 @@ Fota升级开关
|
|||||||
###### SOCKET udp 参数
|
###### SOCKET udp 参数
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"protocol": "tcp",
|
"protocol": "udp",
|
||||||
"ping": "",
|
"ping": "",
|
||||||
"heartbeat": 30,
|
"heartbeat": 30,
|
||||||
"url": "220.180.239.212",
|
"url": "220.180.239.212",
|
||||||
@ -827,8 +938,7 @@ Fota升级开关
|
|||||||
| keepAlive | int | 通信之间允许的最长时间段(以秒为单位),默认为300,范围(60-1200)使用默认值就填""或者" "。 |
|
| keepAlive | int | 通信之间允许的最长时间段(以秒为单位),默认为300,范围(60-1200)使用默认值就填""或者" "。 |
|
||||||
| clientID | str | clientID ,自定义字符(不超过64) |
|
| clientID | str | clientID ,自定义字符(不超过64) |
|
||||||
| Devicename | str | 设备名称 |
|
| Devicename | str | 设备名称 |
|
||||||
| ProductKey | str |
|
| ProductKey | str |产品密钥|
|
||||||
|
|
|
||||||
| DeviceSecret | str | 设备密钥(使用一型一密认证此参数传入"") |
|
| DeviceSecret | str | 设备密钥(使用一型一密认证此参数传入"") |
|
||||||
| ProductSecret | str | 产品密钥(使用一机一密认证时此参数传入"") |
|
| ProductSecret | str | 产品密钥(使用一机一密认证时此参数传入"") |
|
||||||
| cleanSession | int | MQTT 保存会话标志位( 0则客户端是持久客户端,当客户端断开连接时,订阅信息和排队消息将被保留, 1代理将在其断开连接时删除有关此客户端的所有信息 ) |
|
| cleanSession | int | MQTT 保存会话标志位( 0则客户端是持久客户端,当客户端断开连接时,订阅信息和排队消息将被保留, 1代理将在其断开连接时删除有关此客户端的所有信息 ) |
|
||||||
@ -837,11 +947,42 @@ Fota升级开关
|
|||||||
| pubTopic | str | 发布主题 |
|
| pubTopic | str | 发布主题 |
|
||||||
| serialD | int | MQTT通道捆绑的串口ID (1~3) |
|
| serialD | int | MQTT通道捆绑的串口ID (1~3) |
|
||||||
|
|
||||||
|
###### 移远云参数
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"protocol": "quecthing",
|
||||||
|
"keepAlive": "", // lifetime
|
||||||
|
"ProductKey": " a1QNbCDxIWM ",
|
||||||
|
"ProductSecret": "",
|
||||||
|
"qos": "1",
|
||||||
|
"SessionFlag": "",
|
||||||
|
"sendMode": "phy",
|
||||||
|
"serialID": "1",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
| **字段** | **类型** | **含义** |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| quecthing | str | 腾讯云IOT的标识 |
|
||||||
|
| keepAlive | int | 通信之间允许的最长时间段(以秒为单位),默认为120,范围(60-1200)使用默认值就填""或者" "。 |
|
||||||
|
| ProductKey | str |产品id|
|
||||||
|
| ProductSecret | str | 产品密钥|
|
||||||
|
| QOS | int | MQTT消息服务质量(默认0,可选择0或1)0:发送者只发送一次消息,不进行重试 1:发送者最少发送一次消息,确保消息到达Broker |
|
||||||
|
| SessionFlag | bool | 配置与云平台通信的数据是否采用session加密(默认值为False),True:加密,False:加密 |
|
||||||
|
| sendMode | str | 移远云数据收发模式,phy:物模型,pass:透传 |
|
||||||
|
| serialD | int | MQTT通道捆绑的串口ID (1~3) |
|
||||||
|
|
||||||
|
|
||||||
|
移远云开发说明请点击以下连接获取文档:
|
||||||
|
|
||||||
|
[Quectel_移远通信物联网设备管理平台设备接入_应用指导_(Python)_2.9.0.pdf](https://quec-pro-oss.oss-cn-shanghai.aliyuncs.com/documentCenter/Quectel_%E7%A7%BB%E8%BF%9C%E9%80%9A%E4%BF%A1%E7%89%A9%E8%81%94%E7%BD%91%E8%AE%BE%E5%A4%87%E7%AE%A1%E7%90%86%E5%B9%B3%E5%8F%B0%E8%AE%BE%E5%A4%87%E6%8E%A5%E5%85%A5_%E5%BA%94%E7%94%A8%E6%8C%87%E5%AF%BC_(Python)_2.9.0.pdf)
|
||||||
|
|
||||||
## 设置APN
|
## 设置APN
|
||||||
|
|
||||||
说明:这个指令只适合配置和使用不是同一张卡的场景
|
说明:这个指令只适合配置和使用不是同一张卡的场景
|
||||||
|
|
||||||
功能码: 0x60
|
**在透传模式下无法设置串口参数**
|
||||||
|
|
||||||
|
功能码: 60
|
||||||
|
|
||||||
数据内容:
|
数据内容:
|
||||||
```
|
```
|
||||||
@ -860,7 +1001,7 @@ apn对应列表说明:
|
|||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
|
|
||||||
`{"code": 0x60 , "status":1}`
|
`{"code": 60 , "status":1}`
|
||||||
|
|
||||||
| **字段** | **类型** | **含义** |
|
| **字段** | **类型** | **含义** |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
@ -870,20 +1011,24 @@ apn对应列表说明:
|
|||||||
|
|
||||||
## GPIO pins
|
## GPIO pins
|
||||||
|
|
||||||
功能码: 0x61
|
功能码: 61
|
||||||
|
|
||||||
|
**在透传模式下无法设置串口参数**
|
||||||
|
|
||||||
|
pins的长度必须为3
|
||||||
|
|
||||||
数据内容:
|
数据内容:
|
||||||
```
|
```
|
||||||
{"password": " ",
|
{"password": " ",
|
||||||
"data":{"pins":[
|
"data":{"pins":[
|
||||||
"pio2", -- 网路指示灯的GPIO (pio1~pio128)
|
"1", -- 网路指示灯的GPIO (pio1~pio128)
|
||||||
"pio4", -- 与服务器连上后通知GPIO (pio1~pio128)
|
"2", -- 与服务器连上后通知GPIO (pio1~pio128)
|
||||||
"pio4" -- 重置DTU参数的GPIO (pio1~pio128)
|
"3" -- 重置DTU参数的GPIO (pio1~pio128)
|
||||||
]}}
|
]}}
|
||||||
```
|
```
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
|
|
||||||
`{"code": 0x61 , "status":1}`
|
`{"code": 61 , "status":1}`
|
||||||
|
|
||||||
| **字段** | **类型** | **含义** |
|
| **字段** | **类型** | **含义** |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
@ -893,7 +1038,7 @@ apn对应列表说明:
|
|||||||
|
|
||||||
## OTA
|
## OTA
|
||||||
|
|
||||||
功能码: 0x62
|
功能码: 62
|
||||||
|
|
||||||
数据内容:
|
数据内容:
|
||||||
```
|
```
|
||||||
@ -903,30 +1048,33 @@ apn对应列表说明:
|
|||||||
```
|
```
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
|
|
||||||
`{"code": 0x62 , "status":1}`
|
`{"code": 62 , "status":1}`
|
||||||
|
|
||||||
| **字段** | **类型** | **含义** |
|
| **字段** | **类型** | **含义** |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| code | Str | 状态码 |
|
| code | Str | 状态码 |
|
||||||
| data | str | OTA状态 |
|
| data | str | OTA状态 |
|
||||||
| success | int | 0 失败 1成功 |
|
| status | int | 0 失败 1成功 |
|
||||||
|
|
||||||
## 参数设置
|
## 参数设置
|
||||||
|
|
||||||
功能码: 0x63
|
功能码: 63
|
||||||
|
|
||||||
数据内容:
|
数据内容:
|
||||||
```
|
```
|
||||||
{"password": " ",
|
{"password": " ",
|
||||||
"data":{ 完整配置文件(省略)
|
"data":{"dtu_config":{完整配置文件内容}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
完整配置文件参照《DTU上手说明》
|
||||||
|
|
||||||
返回的数据内容:
|
返回的数据内容:
|
||||||
|
|
||||||
`{"code": 0x63 ,"status":1}`
|
`{"code": 63 , "status":1}`
|
||||||
|
|
||||||
| **字段** | **类型** | **含义** |
|
| **字段** | **类型** | **含义** |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| code | Str | 状态码 |
|
| code | Str | 状态码 |
|
||||||
| data | dict | 完整的配置文件 |
|
|
||||||
| status | int | 0 失败 1成功 |
|
| status | int | 0 失败 1成功 |
|
||||||
|
|
||||||
|
@ -34,27 +34,27 @@
|
|||||||
"plate": 1, //是否在报文中添加IMEI
|
"plate": 1, //是否在报文中添加IMEI
|
||||||
"password": "123", //设置密码
|
"password": "123", //设置密码
|
||||||
"conf": { //设置在线连接
|
"conf": { //设置在线连接
|
||||||
"1": { //通道序号
|
"1": { //通道序号
|
||||||
//HTTP连接设置
|
//HTTP连接设置
|
||||||
"protocol": "http", //连接类型,固定为http
|
"protocol": "http", //连接类型,固定为http
|
||||||
"method": "get", //请求方式
|
"method": "get", //请求方式
|
||||||
"url": "http://httpbin.org/get", //请求url
|
"url": "http://httpbin.org/get", //请求url
|
||||||
"reg_data": "", //附带的固定文本
|
"reg_data": "", //附带的固定文本
|
||||||
"timeout": "", //超时
|
"timeout": "", //超时
|
||||||
"serialID": 1 //捆绑的串口(1-2)
|
"serialID": 1 //捆绑的串口(1-2),需要为配置文件中uconf中存在的key
|
||||||
},
|
},
|
||||||
"2": {
|
"2": {
|
||||||
//TCP&UDP连接设置
|
//TCP&UDP连接设置
|
||||||
"protocol": "tcp", //连接类型,TCP填写”tcp”,UDP填写”udp”
|
"protocol": "tcp", //连接类型,TCP填写”tcp”,UDP填写”udp”
|
||||||
"ping": "", //ping
|
"ping": "", //ping
|
||||||
"heartbeat": 30, //心跳时间
|
"heartbeat": 30, //心跳时间
|
||||||
"url": "220.180.239.212", //请求url
|
"url": "220.180.239.212", //请求url
|
||||||
"port": "8305", //端口
|
"port": "8305", //端口
|
||||||
"keepAlive": 300, //保持连接时间
|
"keepAlive": 300, //保持连接时间
|
||||||
"serialID": 2 //捆绑串口
|
"serialID": 2 //捆绑串口,需要为配置文件中uconf中存在的key
|
||||||
},
|
},
|
||||||
"3": {
|
"3": {
|
||||||
//mqtt连接设置
|
//mqtt连接设置
|
||||||
"protocol": "mqtt", //连接类型
|
"protocol": "mqtt", //连接类型
|
||||||
"clientID": "test_mqtt", //客户端id
|
"clientID": "test_mqtt", //客户端id
|
||||||
"keepAlive": "", //keep alive超时
|
"keepAlive": "", //keep alive超时
|
||||||
@ -67,8 +67,8 @@
|
|||||||
"retain": "1", //是否使用内部重连
|
"retain": "1", //是否使用内部重连
|
||||||
"serialID": "1" //捆绑的串口
|
"serialID": "1" //捆绑的串口
|
||||||
},
|
},
|
||||||
//阿里云连接设置
|
|
||||||
"4": {
|
"4": {
|
||||||
|
//阿里云连接设置
|
||||||
"protocol": "aliyun", //连接类型
|
"protocol": "aliyun", //连接类型
|
||||||
"type": "mos", //一机一密/一型一密设置
|
"type": "mos", //一机一密/一型一密设置
|
||||||
"keepAlive": "", // keep alive超时
|
"keepAlive": "", // keep alive超时
|
||||||
@ -83,8 +83,8 @@
|
|||||||
"publish": {"0": "/a1QNbCDxIWM/light01/user/update"}, //发布的主题(支持多个)
|
"publish": {"0": "/a1QNbCDxIWM/light01/user/update"}, //发布的主题(支持多个)
|
||||||
"serialID": "1" //捆绑的串口
|
"serialID": "1" //捆绑的串口
|
||||||
},
|
},
|
||||||
"5": {
|
"5": {
|
||||||
//腾讯云设置
|
//腾讯云设置
|
||||||
"protocol": "txyun",
|
"protocol": "txyun",
|
||||||
"type": "mos",
|
"type": "mos",
|
||||||
"keepAlive": "",
|
"keepAlive": "",
|
||||||
@ -98,6 +98,17 @@
|
|||||||
"subscribe": {"0": "H7MBLRYXN9/Smart_test01/control"},
|
"subscribe": {"0": "H7MBLRYXN9/Smart_test01/control"},
|
||||||
"publish": {"0": "H7MBLRYXN9/Smart_test01/event"},
|
"publish": {"0": "H7MBLRYXN9/Smart_test01/event"},
|
||||||
"serialID": "1"
|
"serialID": "1"
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
//移远云设置
|
||||||
|
"protocol": "quecthing", //连接类型
|
||||||
|
"keepAlive": "", //心跳时间
|
||||||
|
"ProductKey": "p1118c", //product key
|
||||||
|
"ProductSecret": "c3Jzd3ZaNzVrV2Vj", //product secret
|
||||||
|
"qos": "1", //qos
|
||||||
|
"SessionFlag": false, //是否采用session加密
|
||||||
|
"sendMode": "phy", //发送模式
|
||||||
|
"serialID": "1" //捆绑的串口
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"reg": 1, //发送登陆消息
|
"reg": 1, //发送登陆消息
|
||||||
@ -106,7 +117,8 @@
|
|||||||
"nolog": 0, //是否输出log
|
"nolog": 0, //是否输出log
|
||||||
"message": {}, //协议短信透传
|
"message": {}, //协议短信透传
|
||||||
"uconf": { //串口设置
|
"uconf": { //串口设置
|
||||||
"1": {
|
"1": { //key为UART编号,使用UART0填入:“0”,使用UART1则填入“1”,以此类推;同时,
|
||||||
|
//该值同时在通道配置的serialID项中使用
|
||||||
"baudrate": "115200",
|
"baudrate": "115200",
|
||||||
"databits": "8",
|
"databits": "8",
|
||||||
"parity": "0",
|
"parity": "0",
|
||||||
@ -136,14 +148,31 @@
|
|||||||
"service_acquire": 0, //是否开启服务器获取参数
|
"service_acquire": 0, //是否开启服务器获取参数
|
||||||
"work_mode": "command", //工作模式
|
"work_mode": "command", //工作模式
|
||||||
"auto_connect": 1, //自动连接
|
"auto_connect": 1, //自动连接
|
||||||
"offline_storage": false //离线存储
|
"offline_storage": false, //离线存储
|
||||||
|
"modbus": { //modbus配置
|
||||||
|
"groups": [ //设备分组,分组编号为其在列表中的下标,从0开始,以此类推
|
||||||
|
{
|
||||||
|
"device_type": "temp_humid_sensor", //设备类型
|
||||||
|
"device_model": "TH10S-B", //设备型号
|
||||||
|
"slave_address":["0x01"] //群组modbus地址,可以填入多个地址
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"device_type": "light_sensor",
|
||||||
|
"device_model": "YGC-BG-M",
|
||||||
|
"slave_address":["0x02", "0x03"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
配置文件中"serialID"字段配置说明:
|
||||||
|
|
||||||
|
conf通道配置中的“serialID”字段为捆绑的UART口编号,serialID中的数值必须是uconf串口配置中已经配置的UART口编号
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
按需求编写配置文件后将配置文件保存为"dtu_config.json",并保存至DTU代码库中的"dtu"文件夹内
|
按需求编写配置文件后将配置文件保存为"dtu_config.json",并保存至DTU代码库中的"dtu"文件夹内
|
||||||
|
|
||||||
@ -183,7 +212,7 @@ DTU运行成功,下面为读取的配置文件。
|
|||||||
|
|
||||||
## 报文格式
|
## 报文格式
|
||||||
|
|
||||||
### 命令模式/modbus模式
|
### 命令模式
|
||||||
|
|
||||||
支持多通道透传,通过配置文件中的serialID字段可以对通道与串口进行绑定,每个串口均支持绑定多个通道。在发送数据时需要传入通道id,DTU会向指定的通道发送数据。
|
支持多通道透传,通过配置文件中的serialID字段可以对通道与串口进行绑定,每个串口均支持绑定多个通道。在发送数据时需要传入通道id,DTU会向指定的通道发送数据。
|
||||||
|
|
||||||
@ -215,13 +244,13 @@ msg_data:消息体,当msg_len为0时,此项可省略
|
|||||||
|
|
||||||
**发送报文:**
|
**发送报文:**
|
||||||
|
|
||||||
`“1,6,376e6e7,abcedf”` (msg_len不为0)
|
`“1,6,1398235801,abcedf”` (msg_len不为0)
|
||||||
|
|
||||||
`“1,0”` (msg_len为0)
|
`“1,0”` (msg_len为0)
|
||||||
|
|
||||||
**返回报文:**
|
**返回报文:**
|
||||||
|
|
||||||
`“5,2e46f5,20001”`
|
`“1,6,2584251182,ijklmn”`
|
||||||
|
|
||||||
#### MQTT/Aliyun/Txyun
|
#### MQTT/Aliyun/Txyun
|
||||||
|
|
||||||
@ -247,13 +276,76 @@ msg_data:消息体,当msg_len为0时此项也不可省略
|
|||||||
|
|
||||||
- 示例报文:
|
- 示例报文:
|
||||||
|
|
||||||
**发送报文:**
|
- 发送报文:
|
||||||
|
|
||||||
`“1,1,6,376e6e7,abcedf”`
|
`“1,1,6,1398235801,abcedf”`
|
||||||
|
|
||||||
**返回报文:**
|
- 返回报文:
|
||||||
|
|
||||||
`“1,1,5,2e46f5,20002”`
|
`“1,1,6,2584251182,ijklmn”`
|
||||||
|
#### quecthing
|
||||||
|
|
||||||
|
- 上行数据报文格式:
|
||||||
|
|
||||||
|
`"<channel_id>,<pkgid>,<msg_len>","<crc32>",<msg_data>"`
|
||||||
|
|
||||||
|
- 下行数据报文格式:
|
||||||
|
|
||||||
|
`"<channel_id>,<pkgid>,<msg_len>","<crc32>",<msg_data>"`
|
||||||
|
|
||||||
|
- 字段说明:
|
||||||
|
|
||||||
|
channel_id:通道id,配置文件中通道id
|
||||||
|
|
||||||
|
pkgid:quecthing物模型pkgid,透传模式上行、下行报文与物模型上行非应答报文时该字段固定值为0
|
||||||
|
|
||||||
|
msg_len:消息体长度,字符串格式,可以为0
|
||||||
|
|
||||||
|
crc32:消息数据crc32校验码,当msg_len为0时此项也不可省略
|
||||||
|
|
||||||
|
msg_data:消息体,当msg_len为0时此项也不可省略
|
||||||
|
|
||||||
|
**示例报文:**
|
||||||
|
|
||||||
|
- 发送报文:
|
||||||
|
|
||||||
|
`“1,0,6,1398235801,abcedf”` (透传&物模型非应答)
|
||||||
|
|
||||||
|
`“1,16929,6,1398235801,abcedf”` (物模型应答)
|
||||||
|
|
||||||
|
- 返回报文:
|
||||||
|
|
||||||
|
`“1,0,6,2584251182,ijklmn”` (透传报文)
|
||||||
|
|
||||||
|
`“1,16930,6,2584251182,ijklmn”` (物模型报文)
|
||||||
|
|
||||||
|
#### 从串口执行控制命令
|
||||||
|
|
||||||
|
- 发送命令报文格式:
|
||||||
|
|
||||||
|
`"<identify>,<msg_len>","<crc32>",<msg_data>"`
|
||||||
|
|
||||||
|
- 返回命令报文格式:
|
||||||
|
|
||||||
|
`"<msg_len>","<crc32>",<msg_data>"`
|
||||||
|
|
||||||
|
- 字段说明:
|
||||||
|
|
||||||
|
identify: 串口控制命令识别码,固定值为"99"
|
||||||
|
|
||||||
|
msg_len:消息体长度,字符串格式,可以为0
|
||||||
|
|
||||||
|
crc32:消息数据crc32校验码,当msg_len为0时此项也不可省略
|
||||||
|
|
||||||
|
msg_data:消息体,当msg_len为0时此项也不可省略
|
||||||
|
|
||||||
|
- 上行报文:
|
||||||
|
|
||||||
|
`“99,6,1398235801,abcedf”`
|
||||||
|
|
||||||
|
- 下行报文:
|
||||||
|
|
||||||
|
`“99,6,2584251182,ijklmn”`
|
||||||
|
|
||||||
### 透传模式
|
### 透传模式
|
||||||
|
|
||||||
@ -285,13 +377,13 @@ msg_data:消息体,当msg_len为0时,此项可省略
|
|||||||
|
|
||||||
**发送报文:**
|
**发送报文:**
|
||||||
|
|
||||||
`“6,376e6e7,abcedf”` (msg_len不为0)
|
`“6,1398235801,abcedf”` (msg_len不为0)
|
||||||
|
|
||||||
`“0”` (msg_len为0)
|
`“0”` (msg_len为0)
|
||||||
|
|
||||||
**返回报文:**
|
**返回报文:**
|
||||||
|
|
||||||
`“5,2e46f5,20001”`
|
`“6,2584251182,ijklmn”`
|
||||||
|
|
||||||
#### MQTT/Aliyun/Txyun
|
#### MQTT/Aliyun/Txyun
|
||||||
|
|
||||||
@ -317,19 +409,66 @@ msg_data:消息体,当msg_len为0时此项也不可省略
|
|||||||
|
|
||||||
**发送报文:**
|
**发送报文:**
|
||||||
|
|
||||||
`“6,376e6e7,abcedf”`
|
`“6,1398235801,abcedf”`
|
||||||
|
|
||||||
**返回报文:**
|
**返回报文:**
|
||||||
|
|
||||||
`“5,2e46f5,20002”`
|
`“6,2584251182,ijklmn”`
|
||||||
|
|
||||||
|
#### quecthing
|
||||||
|
|
||||||
|
- 发送数据报文格式:
|
||||||
|
|
||||||
|
`"<pkgid>,<msg_len>","<crc32>",<msg_data>"`
|
||||||
|
|
||||||
|
- 返回数据报文格式:
|
||||||
|
|
||||||
|
`"<pkgid>,<msg_len>","<crc32>",<msg_data>"`
|
||||||
|
|
||||||
|
- 字段说明:
|
||||||
|
|
||||||
|
pkgid:quecthing物模型pkgid,透传模式上行、下行报文与物模型上行非应答报文时该字段固定值为0
|
||||||
|
|
||||||
|
msg_len:消息体长度,字符串格式,可以为0
|
||||||
|
|
||||||
|
crc32:消息数据crc32校验码,当msg_len为0时此项也不可省略
|
||||||
|
|
||||||
|
msg_data:消息体,当msg_len为0时此项也不可省略
|
||||||
|
|
||||||
|
**示例报文:**
|
||||||
|
|
||||||
|
- 上行报文:
|
||||||
|
|
||||||
|
`“0,6,1398235801,abcedf”` (透传&物模型非应答)
|
||||||
|
|
||||||
|
`“16929,6,1398235801,abcedf”` (物模型应答)
|
||||||
|
|
||||||
|
- 下行报文:
|
||||||
|
|
||||||
|
`“0,6,2584251182,ijklmn”` (透传报文)
|
||||||
|
|
||||||
|
`“16930,6,2584251182,ijklmn”` (物模型报文)
|
||||||
|
|
||||||
|
### modbus模式
|
||||||
|
|
||||||
|
modbus模式会完整透传上行与上行报文,上行与下行都为bytes类型
|
||||||
|
|
||||||
|
**示例报文:**
|
||||||
|
|
||||||
|
- 发送报文
|
||||||
|
|
||||||
|
`b'\x01\x03\x04\x01\x01\x02\x0c\xabj'`
|
||||||
|
|
||||||
|
- 返回报文
|
||||||
|
|
||||||
|
`b'\x01\x03\x04\x01\x01\x02\rj\xaa'`
|
||||||
### 与云端通信报文
|
### 与云端通信报文
|
||||||
|
|
||||||
DTU与云端通信报文使用json格式
|
DTU与云端通信报文使用json格式
|
||||||
|
|
||||||
#### 云端下行报文
|
#### 云端下行报文
|
||||||
|
|
||||||
- 命令模式与modbus模式:
|
- 命令模式:
|
||||||
|
|
||||||
`{“msg_id”: msg_id, “data”: “1234”[, “cmd_code”: 0X40, “topic_id”: 1]}`
|
`{“msg_id”: msg_id, “data”: “1234”[, “cmd_code”: 0X40, “topic_id”: 1]}`
|
||||||
|
|
||||||
@ -347,13 +486,36 @@ cmd_code:可选字段,填写对应功能码,并又DTU执行相应的操作
|
|||||||
|
|
||||||
topic_id:可选字段,填写mqtt返回需要publish的topic\_id,此字段仅在命令模式与使用MQTT/Aliyun/Txyun时生效
|
topic_id:可选字段,填写mqtt返回需要publish的topic\_id,此字段仅在命令模式与使用MQTT/Aliyun/Txyun时生效
|
||||||
|
|
||||||
|
- modbus模式
|
||||||
|
|
||||||
|
`{“msg_id”: msg_id, “modbus”: {"groups": {"num": 0, "cmd": ["0x03", "0x00", "0x00", "0x00", "0x02"]}}}`
|
||||||
|
|
||||||
|
字段说明:
|
||||||
|
|
||||||
|
msg_id:报文id,一般为时间戳+3位随机数
|
||||||
|
|
||||||
|
data:报文消息字段
|
||||||
|
|
||||||
|
cmd_code:可选字段,填写对应功能码,并又DTU执行相应的操作,此字段仅在命令模式下生效
|
||||||
|
|
||||||
|
topic_id:可选字段,填写mqtt返回需要publish的topic_id,此字段仅在命令模式与使用MQTT/Aliyun/Txyun时生效
|
||||||
|
|
||||||
|
modbus:可选字段,此字段仅在modbus模式使用,此字段下有2个子字段:groups与command
|
||||||
|
|
||||||
|
    groups:可选字段,在modbus模式下向指定的地址组发送消息
|
||||||
|
|
||||||
|
        num:配置文件中的地址组编号
|
||||||
|
|
||||||
|
        cmd:向地址组发送的modbus命令
|
||||||
|
|
||||||
|
    command:可选字段,在modbus下直接向UART口写入指定modbus命令
|
||||||
#### 云端上行报文
|
#### 云端上行报文
|
||||||
|
|
||||||
命令模式与modbus模式:
|
- 命令模式与modbus模式:
|
||||||
|
|
||||||
`{“msg_id”: msg_id, “data”: “1234”[, “cmd_code”: 0X40, “status”: 1]}`
|
`{“msg_id”: msg_id, “data”: “1234”[, “cmd_code”: 0X40, “status”: 1]}`
|
||||||
|
|
||||||
透传模式:
|
- 透传模式:
|
||||||
|
|
||||||
`{“msg_id”: msg_id, “data”: “1234”}`
|
`{“msg_id”: msg_id, “data”: “1234”}`
|
||||||
|
|
||||||
|
BIN
docs/media/config_serial_id.png
Normal file
BIN
docs/media/config_serial_id.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
BIN
docs/media/gui_quecthing.png
Normal file
BIN
docs/media/gui_quecthing.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 55 KiB |
@ -3,14 +3,17 @@
|
|||||||
"password": "123",
|
"password": "123",
|
||||||
"conf": {
|
"conf": {
|
||||||
"1": {
|
"1": {
|
||||||
"protocol": "quecthing",
|
"protocol": "hwyun",
|
||||||
"keepAlive": "",
|
"url": "a1621ed65c.iot-mqtts.cn-north-4.myhuaweicloud.com",
|
||||||
"ProductKey": "p1118c",
|
"port": "1883",
|
||||||
"ProductSecret": "c3Jzd3ZaNzVrV2Vj",
|
"device_id": "621ece4cc4e6a958e354301e_869537055499330",
|
||||||
"qos": "1",
|
"secret": "a306255686a71e56ad53965fc2771bf8",
|
||||||
"SessionFlag": false,
|
"keep_alive": 10,
|
||||||
"sendMode": "pass",
|
"cleanSession": true,
|
||||||
"serialID": "2"
|
"subscribe": {"0": "$oc/devices/621ece4cc4e6a958e354301e_869537055499330/sys/messages/down"},
|
||||||
|
"publish": {"0": "$oc/devices/621ece4cc4e6a958e354301e_869537055499330/sys/messages/up"},
|
||||||
|
"qos": 0,
|
||||||
|
"serialID": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"reg": 0,
|
"reg": 0,
|
||||||
@ -40,7 +43,8 @@
|
|||||||
""
|
""
|
||||||
],
|
],
|
||||||
"service_acquire": 0,
|
"service_acquire": 0,
|
||||||
"work_mode": "command",
|
"work_mode": "though",
|
||||||
"auto_connect": 1,
|
"auto_connect": 1,
|
||||||
"offline_storage": false
|
"offline_storage": false,
|
||||||
}
|
"modbus": {}
|
||||||
|
}
|
||||||
|
@ -8,7 +8,6 @@ from aLiYun import aLiYun
|
|||||||
from TenCentYun import TXyun
|
from TenCentYun import TXyun
|
||||||
from umqtt import MQTTClient
|
from umqtt import MQTTClient
|
||||||
from machine import UART
|
from machine import UART
|
||||||
import uos
|
|
||||||
uos.chdir('/usr/')
|
uos.chdir('/usr/')
|
||||||
from singleton import Singleton
|
from singleton import Singleton
|
||||||
from t_h import SensorTH
|
from t_h import SensorTH
|
||||||
@ -42,6 +41,7 @@ class RET:
|
|||||||
PROTOCOLERR = "4008"
|
PROTOCOLERR = "4008"
|
||||||
REQERR1 = "4009"
|
REQERR1 = "4009"
|
||||||
QUECIOTERR = "4010"
|
QUECIOTERR = "4010"
|
||||||
|
HWYUNERR = "4011"
|
||||||
REQERR2 = "5000"
|
REQERR2 = "5000"
|
||||||
# 功能错误
|
# 功能错误
|
||||||
PASSWORDERR = "5001"
|
PASSWORDERR = "5001"
|
||||||
@ -89,6 +89,7 @@ error_map = {
|
|||||||
RET.TXYUNMQTTERR: u"txyun connect failed",
|
RET.TXYUNMQTTERR: u"txyun connect failed",
|
||||||
RET.PROTOCOLERR: u"protocol parse error",
|
RET.PROTOCOLERR: u"protocol parse error",
|
||||||
RET.QUECIOTERR: u"quecthing connect failed",
|
RET.QUECIOTERR: u"quecthing connect failed",
|
||||||
|
RET.HWYUNERR: u"huaweiyun connect failed",
|
||||||
# 功能错误
|
# 功能错误
|
||||||
RET.PASSWORDERR: u"password not found",
|
RET.PASSWORDERR: u"password not found",
|
||||||
RET.PASSWDVERIFYERR: u"password verify error",
|
RET.PASSWDVERIFYERR: u"password verify error",
|
||||||
@ -120,6 +121,8 @@ CONFIG = {
|
|||||||
|
|
||||||
HISTORY_ERROR = []
|
HISTORY_ERROR = []
|
||||||
|
|
||||||
|
SERIAL_MAP = dict()
|
||||||
|
CHANNELS = dict()
|
||||||
|
|
||||||
|
|
||||||
"""================================================= singleton ===================================================="""
|
"""================================================= singleton ===================================================="""
|
||||||
@ -132,6 +135,65 @@ class DTUException(Exception):
|
|||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
|
|
||||||
|
class ProdDocumentParse(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.document = ""
|
||||||
|
|
||||||
|
def read(self, config_path):
|
||||||
|
if not self.document:
|
||||||
|
self.refresh_document(config_path)
|
||||||
|
|
||||||
|
def refresh_document(self, config_path):
|
||||||
|
try:
|
||||||
|
with open(config_path, mode="r") as f:
|
||||||
|
self.document = f.read()
|
||||||
|
return self.document # new
|
||||||
|
except Exception as e:
|
||||||
|
# 加载旧版本文件
|
||||||
|
try:
|
||||||
|
with open(config_path + ".bak", mode="r") as f:
|
||||||
|
self.document = f.read()
|
||||||
|
return self.document
|
||||||
|
except Exception as e:
|
||||||
|
# 加载出厂文件
|
||||||
|
try:
|
||||||
|
with open(CONFIG['config_backup_path'], mode="r") as f:
|
||||||
|
self.document = f.read()
|
||||||
|
return self.document
|
||||||
|
except:
|
||||||
|
print("'dtu_config.json', last version and default config not exist")
|
||||||
|
raise Exception(RET.READFILEERR)
|
||||||
|
|
||||||
|
def _parse_document(self, parser_obj):
|
||||||
|
try:
|
||||||
|
document_loader = ujson.loads(self.document)
|
||||||
|
except Exception as e:
|
||||||
|
print(error_map.get(RET.JSONLOADERR))
|
||||||
|
raise RET.JSONLOADERR
|
||||||
|
try:
|
||||||
|
dtu_data_obj = parser_obj.reload(**document_loader)
|
||||||
|
except Exception as e:
|
||||||
|
# print("e = {}".format(e))
|
||||||
|
print("{}: {}".format(error_map.get(RET.JSONLOADERR), e))
|
||||||
|
raise RET.JSONPARSEERR
|
||||||
|
return dtu_data_obj
|
||||||
|
|
||||||
|
def parse(self, parser_obj):
|
||||||
|
config_path = CONFIG["config_path"]
|
||||||
|
if not self.exist_config_file(config_path):
|
||||||
|
# 从uart口读取数据
|
||||||
|
print(error_map.get(RET.CONFIGNOTEXIST))
|
||||||
|
else:
|
||||||
|
self.read(config_path=config_path)
|
||||||
|
return self._parse_document(parser_obj=parser_obj)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def exist_config_file(config_path):
|
||||||
|
config_split = config_path.rsplit("/", 1)
|
||||||
|
return config_split[1] in uos.listdir(config_split[0])
|
||||||
|
|
||||||
|
|
||||||
"""=================================================== dtu object ==================================================="""
|
"""=================================================== dtu object ==================================================="""
|
||||||
|
|
||||||
|
|
||||||
@ -247,7 +309,7 @@ class ProdDtu(object):
|
|||||||
# 升级包下载地址的请求
|
# 升级包下载地址的请求
|
||||||
version = self.parse_data.version
|
version = self.parse_data.version
|
||||||
moduleType = ota[1]
|
moduleType = ota[1]
|
||||||
download_url = "https://cloudota.quectel.com:8100/v2/fota/fw"
|
download_url = "https://cloudota.quectel.com:8100/v1/fota/fw"
|
||||||
headers = {"access_token": access_token, "Content-Type": "application/json"}
|
headers = {"access_token": access_token, "Content-Type": "application/json"}
|
||||||
acquire_data = {
|
acquire_data = {
|
||||||
"version": str(version),
|
"version": str(version),
|
||||||
@ -342,12 +404,13 @@ class ProdDtu(object):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
def server_filter(self):
|
def server_filter(self):
|
||||||
if self.parse_data == 'command':
|
if self.parse_data.work_mode == 'command':
|
||||||
for cid, channel in self.parse_data.conf.items():
|
for cid, channel in self.parse_data.conf.items():
|
||||||
if int(channel.serialID) in self.channel.serial_channel_dict:
|
serial_id = int(channel.get("serialID"))
|
||||||
self.channel.serial_channel_dict[int(channel.serialID)].append(cid)
|
if serial_id in self.channel.serial_channel_dict:
|
||||||
|
self.channel.serial_channel_dict[serial_id].append(cid)
|
||||||
else:
|
else:
|
||||||
self.channel.serial_channel_dict[int(channel.serialID)] = [cid]
|
self.channel.serial_channel_dict[serial_id] = [cid]
|
||||||
return self.parse_data.conf
|
return self.parse_data.conf
|
||||||
else:
|
else:
|
||||||
serv_map = dict()
|
serv_map = dict()
|
||||||
@ -369,6 +432,7 @@ class ProdDtu(object):
|
|||||||
# 透传与modbus服务器筛选
|
# 透传与modbus服务器筛选
|
||||||
serv_maps = self.server_filter()
|
serv_maps = self.server_filter()
|
||||||
self._serv_connect(serv_maps, reg_data)
|
self._serv_connect(serv_maps, reg_data)
|
||||||
|
print("SERV conn success")
|
||||||
_thread.start_new_thread(self.uart.read, ())
|
_thread.start_new_thread(self.uart.read, ())
|
||||||
if self.parse_data.offline_storage:
|
if self.parse_data.offline_storage:
|
||||||
_thread.start_new_thread(self.offline_storage.retry_offline_handler, ())
|
_thread.start_new_thread(self.offline_storage.retry_offline_handler, ())
|
||||||
@ -495,10 +559,26 @@ class ProdDtu(object):
|
|||||||
print("quecthing connect waiting server...")
|
print("quecthing connect waiting server...")
|
||||||
else:
|
else:
|
||||||
logger.error(error_map.get(RET.QUECIOTERR))
|
logger.error(error_map.get(RET.QUECIOTERR))
|
||||||
|
|
||||||
|
elif protocol.startswith("hwyun"):
|
||||||
|
hw_req = HuaweiCloudTransfer()
|
||||||
|
status = hw_req.serialize(data)
|
||||||
|
try:
|
||||||
|
_thread.start_new_thread(hw_req.connect, ())
|
||||||
|
utime.sleep_ms(100)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("{}: {}".format(error_map.get(RET.HWYUNERR), e))
|
||||||
|
else:
|
||||||
|
if status == RET.OK:
|
||||||
|
self.channel.channel_dict[cid] = hw_req
|
||||||
|
hw_req.channel_id = cid
|
||||||
|
print("hwyun conn succeed")
|
||||||
|
else:
|
||||||
|
logger.error(error_map.get(RET.HWYUNERR))
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@Singleton
|
||||||
class ProdGPIO(object):
|
class ProdGPIO(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# self.gpio1 = Pin(Pin.GPIO1, Pin.OUT, Pin.PULL_DISABLE, 0)
|
# self.gpio1 = Pin(Pin.GPIO1, Pin.OUT, Pin.PULL_DISABLE, 0)
|
||||||
@ -530,65 +610,6 @@ class ProdGPIO(object):
|
|||||||
self.gpio1.write(1)
|
self.gpio1.write(1)
|
||||||
|
|
||||||
|
|
||||||
class ProdDocumentParse(object):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.document = ""
|
|
||||||
|
|
||||||
def read(self, config_path):
|
|
||||||
if not self.document:
|
|
||||||
self.refresh_document(config_path)
|
|
||||||
|
|
||||||
def refresh_document(self, config_path):
|
|
||||||
try:
|
|
||||||
with open(config_path, mode="r") as f:
|
|
||||||
self.document = f.read()
|
|
||||||
return self.document # new
|
|
||||||
except Exception as e:
|
|
||||||
# 加载旧版本文件
|
|
||||||
try:
|
|
||||||
with open(config_path + ".bak", mode="r") as f:
|
|
||||||
self.document = f.read()
|
|
||||||
return self.document
|
|
||||||
except Exception as e:
|
|
||||||
# 加载出厂文件
|
|
||||||
try:
|
|
||||||
with open(CONFIG['config_backup_path'], mode="r") as f:
|
|
||||||
self.document = f.read()
|
|
||||||
return self.document
|
|
||||||
except:
|
|
||||||
logger.info("'dtu_config.json', last version and default config not exist")
|
|
||||||
raise Exception(RET.READFILEERR)
|
|
||||||
|
|
||||||
def _parse_document(self, parser_obj):
|
|
||||||
try:
|
|
||||||
document_loader = ujson.loads(self.document)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(error_map.get(RET.JSONLOADERR))
|
|
||||||
raise RET.JSONLOADERR
|
|
||||||
try:
|
|
||||||
dtu_data_obj = parser_obj.reload(**document_loader)
|
|
||||||
except Exception as e:
|
|
||||||
# logger.info("e = {}".format(e))
|
|
||||||
logger.error("{}: {}".format(error_map.get(RET.JSONLOADERR), e))
|
|
||||||
raise RET.JSONPARSEERR
|
|
||||||
return dtu_data_obj
|
|
||||||
|
|
||||||
def parse(self, parser_obj):
|
|
||||||
config_path = CONFIG["config_path"]
|
|
||||||
if not self.exist_config_file(config_path):
|
|
||||||
# 从uart口读取数据
|
|
||||||
logger.error(error_map.get(RET.CONFIGNOTEXIST))
|
|
||||||
else:
|
|
||||||
self.read(config_path=config_path)
|
|
||||||
return self._parse_document(parser_obj=parser_obj)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def exist_config_file(config_path):
|
|
||||||
config_split = config_path.rsplit("/", 1)
|
|
||||||
return config_split[1] in uos.listdir(config_split[0])
|
|
||||||
|
|
||||||
|
|
||||||
"""===================================================socket protocol==================================================="""
|
"""===================================================socket protocol==================================================="""
|
||||||
|
|
||||||
|
|
||||||
@ -794,6 +815,8 @@ class AbstractDtuMqttTransfer(object):
|
|||||||
self.product_secret = ""
|
self.product_secret = ""
|
||||||
self.device_name = ""
|
self.device_name = ""
|
||||||
self.device_secret = ""
|
self.device_secret = ""
|
||||||
|
self.user = ""
|
||||||
|
self.password = ""
|
||||||
# self.control_channel = False
|
# self.control_channel = False
|
||||||
self.pub_topic_map = dict()
|
self.pub_topic_map = dict()
|
||||||
self.sub_topic_map = dict()
|
self.sub_topic_map = dict()
|
||||||
@ -816,6 +839,11 @@ class AbstractDtuMqttTransfer(object):
|
|||||||
rec = self.cli.publish(topic, send_msg, qos=self.qos)
|
rec = self.cli.publish(topic, send_msg, qos=self.qos)
|
||||||
|
|
||||||
def send(self, data, topic_id=None, *args):
|
def send(self, data, topic_id=None, *args):
|
||||||
|
if topic_id is None:
|
||||||
|
topic_list = self.pub_topic.keys()
|
||||||
|
for topic in topic_list:
|
||||||
|
self.publish(data, topic)
|
||||||
|
print("send data:", data)
|
||||||
try:
|
try:
|
||||||
topic = self.pub_topic.get(str(topic_id))
|
topic = self.pub_topic.get(str(topic_id))
|
||||||
self.publish(data, topic)
|
self.publish(data, topic)
|
||||||
@ -828,7 +856,11 @@ class AbstractDtuMqttTransfer(object):
|
|||||||
# 写入uart/远程控制
|
# 写入uart/远程控制
|
||||||
rec = self.uart.output(msg.decode(), self.serial, mqtt_id=self.channel_id)
|
rec = self.uart.output(msg.decode(), self.serial, mqtt_id=self.channel_id)
|
||||||
if isinstance(rec, dict):
|
if isinstance(rec, dict):
|
||||||
|
if isinstance(rec, dict):
|
||||||
|
if "topic_id" in rec:
|
||||||
topic_id = rec.pop('topic_id')
|
topic_id = rec.pop('topic_id')
|
||||||
|
else:
|
||||||
|
topic_id = list(self.pub_topic.keys())[0]
|
||||||
self.send(rec, topic_id)
|
self.send(rec, topic_id)
|
||||||
|
|
||||||
def disconnect(self):
|
def disconnect(self):
|
||||||
@ -843,6 +875,8 @@ class AbstractDtuMqttTransfer(object):
|
|||||||
self.client_id = data.get("clientID")
|
self.client_id = data.get("clientID")
|
||||||
self.device_name = data.get("Devicename")
|
self.device_name = data.get("Devicename")
|
||||||
self.product_key = data.get("ProductKey")
|
self.product_key = data.get("ProductKey")
|
||||||
|
self.user = data.get("user")
|
||||||
|
self.password = data.get("password")
|
||||||
if self.iot_type == "mos":
|
if self.iot_type == "mos":
|
||||||
self.device_secret = data.get('DeviceSecret') if data.get("DeviceSecret") else None
|
self.device_secret = data.get('DeviceSecret') if data.get("DeviceSecret") else None
|
||||||
self.product_secret = None
|
self.product_secret = None
|
||||||
@ -875,7 +909,14 @@ class DtuMqttTransfer(AbstractDtuMqttTransfer):
|
|||||||
# self.code = code
|
# self.code = code
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
self.cli = MQTTClient(self.client_id, self.url, self.port, keepalive=self.keep_alive)
|
print("mqt connect")
|
||||||
|
print(self.url)
|
||||||
|
print(self.port)
|
||||||
|
print(self.client_id)
|
||||||
|
print(self.user)
|
||||||
|
print(self.password)
|
||||||
|
self.cli = MQTTClient(client_id=self.client_id, server=self.url, port=self.port,
|
||||||
|
user=self.user, password=self.password, keepalive=self.keep_alive)
|
||||||
self.cli.set_callback(self.callback)
|
self.cli.set_callback(self.callback)
|
||||||
self.cli.connect(clean_session=self.clean_session)
|
self.cli.connect(clean_session=self.clean_session)
|
||||||
for tid, s_topic in self.sub_topic.items():
|
for tid, s_topic in self.sub_topic.items():
|
||||||
@ -1045,7 +1086,10 @@ class QuecthingDtuTransfer:
|
|||||||
quecIot.setEventCB(self.callback)
|
quecIot.setEventCB(self.callback)
|
||||||
|
|
||||||
def send(self, data, pkgid=None, *args):
|
def send(self, data, pkgid=None, *args):
|
||||||
send_data = data['data']
|
if isinstance(data, str):
|
||||||
|
send_data = data
|
||||||
|
else:
|
||||||
|
send_data = ujson.dumps(data)
|
||||||
if self.send_mode == "pass":
|
if self.send_mode == "pass":
|
||||||
quecIot.passTransSend(self.qos, send_data)
|
quecIot.passTransSend(self.qos, send_data)
|
||||||
else:
|
else:
|
||||||
@ -1115,6 +1159,91 @@ class QuecthingDtuTransfer:
|
|||||||
return quecIot.getWorkState()
|
return quecIot.getWorkState()
|
||||||
|
|
||||||
|
|
||||||
|
class HuaweiCloudTransfer(DtuMqttTransfer):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.conn_type = "hwyun"
|
||||||
|
self.device_id = ""
|
||||||
|
self.client_id = ""
|
||||||
|
self.user = ""
|
||||||
|
self.password = ""
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def hmac_sha256_digest(key_K, data):
|
||||||
|
|
||||||
|
def xor(x, y):
|
||||||
|
return bytes(x[i] ^ y[i] for i in range(min(len(x), len(y))))
|
||||||
|
|
||||||
|
if len(key_K) > 64:
|
||||||
|
raise ValueError('The key must be <= 64 bytes in length')
|
||||||
|
padded_K = key_K + b'\x00' * (64 - len(key_K))
|
||||||
|
ipad = b'\x36' * 64
|
||||||
|
opad = b'\x5c' * 64
|
||||||
|
h_inner = uhashlib.sha256(xor(padded_K, ipad))
|
||||||
|
h_inner.update(data)
|
||||||
|
h_outer = uhashlib.sha256(xor(padded_K, opad))
|
||||||
|
h_outer.update(h_inner.digest())
|
||||||
|
return ubinascii.hexlify(h_outer.digest()).decode()
|
||||||
|
|
||||||
|
def register(self):
|
||||||
|
local_time = utime.localtime()
|
||||||
|
time_sign = "%s%s%s%s" % (local_time[0], "%02d" % local_time[1], "%02d" % local_time[2], "%02d" % local_time[3])
|
||||||
|
self.client_id = self.device_id + "_0_0_" + time_sign
|
||||||
|
print("client id")
|
||||||
|
print(self.client_id)
|
||||||
|
self.user = self.device_id
|
||||||
|
# self.password = hmac.new(time_sign.encode("utf-8"), self.device_secret.encode("utf-8"), digestmod=uhashlib.sha256).hexdigest()
|
||||||
|
self.password = self.hmac_sha256_digest(time_sign.encode("utf-8"), self.device_secret.encode("utf-8"))
|
||||||
|
print("pw")
|
||||||
|
print(self.password)
|
||||||
|
|
||||||
|
def serialize(self, data):
|
||||||
|
print("hwy data")
|
||||||
|
print(data)
|
||||||
|
try:
|
||||||
|
self.url = data.get("url")
|
||||||
|
self.port = data.get("port")
|
||||||
|
self.device_id = data.get("device_id")
|
||||||
|
self.device_secret = data.get("secret")
|
||||||
|
self.keep_alive = int(data.get("keepAlive")) if data.get("keepAlive") else 60
|
||||||
|
clr_ses = data.get('cleanSession')
|
||||||
|
if clr_ses in ["1", 1, True, 'true']:
|
||||||
|
self.clean_session = True
|
||||||
|
else:
|
||||||
|
self.clean_session = False
|
||||||
|
self.sub_topic = data.get('subscribe')
|
||||||
|
self.pub_topic = data.get('publish')
|
||||||
|
self.qos = int(data.get('qos')) if data.get('qos') else 0
|
||||||
|
# self.retain = int(data.get('retain')) if data.get('retain') else 0
|
||||||
|
self.serial = int(data.get('serialID'))
|
||||||
|
except Exception as e:
|
||||||
|
print("SERIAL ERR")
|
||||||
|
print(e)
|
||||||
|
return RET.PARSEERR
|
||||||
|
else:
|
||||||
|
return RET.OK
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
self.register()
|
||||||
|
print("hw connect")
|
||||||
|
print(self.url)
|
||||||
|
print(self.port)
|
||||||
|
print(self.client_id)
|
||||||
|
print(self.user)
|
||||||
|
print(self.password)
|
||||||
|
self.cli = MQTTClient(client_id=self.client_id, server=self.url, port=self.port,
|
||||||
|
user=self.user, password=self.password, keepalive=self.keep_alive, ssl=False)
|
||||||
|
self.cli.set_callback(self.callback)
|
||||||
|
self.cli.connect(clean_session=self.clean_session)
|
||||||
|
for tid, s_topic in self.sub_topic.items():
|
||||||
|
self.cli.subscribe(s_topic, qos=self.qos)
|
||||||
|
for tid, p_topic in self.pub_topic.items():
|
||||||
|
self.cli.publish(p_topic, "hello world", qos=self.qos)
|
||||||
|
logger.info("hw set successful")
|
||||||
|
|
||||||
|
|
||||||
"""===================================================data document protocol==================================================="""
|
"""===================================================data document protocol==================================================="""
|
||||||
|
|
||||||
|
|
||||||
@ -1135,7 +1264,7 @@ class DTUDocumentData(object):
|
|||||||
self.conf = dict()
|
self.conf = dict()
|
||||||
self.pins = []
|
self.pins = []
|
||||||
self.apn = []
|
self.apn = []
|
||||||
self.modbus = []
|
self.modbus = dict()
|
||||||
self.work_mode = "command"
|
self.work_mode = "command"
|
||||||
self.auto_connect = True
|
self.auto_connect = True
|
||||||
self.offline_storage = False
|
self.offline_storage = False
|
||||||
@ -1295,7 +1424,7 @@ class DtuUart(object):
|
|||||||
config_path = CONFIG["config_path"]
|
config_path = CONFIG["config_path"]
|
||||||
config_params = ProdDocumentParse().refresh_document(config_path)
|
config_params = ProdDocumentParse().refresh_document(config_path)
|
||||||
uconf = ujson.loads(config_params)["uconf"]
|
uconf = ujson.loads(config_params)["uconf"]
|
||||||
self.serial_map = dict()
|
self.serial_map = SERIAL_MAP
|
||||||
for sid, conf in uconf.items():
|
for sid, conf in uconf.items():
|
||||||
uart_conn = UART(getattr(UART, 'UART%d' % int(sid)),
|
uart_conn = UART(getattr(UART, 'UART%d' % int(sid)),
|
||||||
int(conf.get("baudrate")),
|
int(conf.get("baudrate")),
|
||||||
@ -1306,9 +1435,10 @@ class DtuUart(object):
|
|||||||
self.serial_map[sid] = uart_conn
|
self.serial_map[sid] = uart_conn
|
||||||
# 初始化方向gpio
|
# 初始化方向gpio
|
||||||
self._direction_pin(config_params)
|
self._direction_pin(config_params)
|
||||||
self.exec_cmd = DtuExecCommand()
|
|
||||||
self.protocol = DtuProtocolData()
|
|
||||||
self.channels = ChannelTransfer()
|
self.channels = ChannelTransfer()
|
||||||
|
self.exec_cmd = DtuExecCommand()
|
||||||
|
self.exec_modbus = ModbusCommand()
|
||||||
|
self.protocol = DtuProtocolData()
|
||||||
self.concat_buffer = ""
|
self.concat_buffer = ""
|
||||||
self.wait_length = 0
|
self.wait_length = 0
|
||||||
self.wait_retry_count = 0
|
self.wait_retry_count = 0
|
||||||
@ -1332,7 +1462,7 @@ class DtuUart(object):
|
|||||||
print(data)
|
print(data)
|
||||||
if isinstance(data, (int, float)):
|
if isinstance(data, (int, float)):
|
||||||
data = str(data)
|
data = str(data)
|
||||||
if self.dtu_d.work_mode == 'command':
|
if self.dtu_d.work_mode in ['command', "modbus"]:
|
||||||
print("CMD START")
|
print("CMD START")
|
||||||
try:
|
try:
|
||||||
if isinstance(data, str):
|
if isinstance(data, str):
|
||||||
@ -1356,7 +1486,12 @@ class DtuUart(object):
|
|||||||
rec['topic_id'] = msg_data.get("topic_id")
|
rec['topic_id'] = msg_data.get("topic_id")
|
||||||
return rec
|
return rec
|
||||||
elif modbus_data is not None:
|
elif modbus_data is not None:
|
||||||
pass
|
uart_port = self.serial_map.get(str(serial_id))
|
||||||
|
if uart_port is None:
|
||||||
|
print("UART serial id error")
|
||||||
|
return False
|
||||||
|
rec = self.exec_modbus.exec_modbus_cmd(modbus_data, uart_port)
|
||||||
|
return rec
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.info("{}: {}".format(error_map.get(RET.CMDPARSEERR), e))
|
logger.info("{}: {}".format(error_map.get(RET.CMDPARSEERR), e))
|
||||||
# package_data
|
# package_data
|
||||||
@ -1384,6 +1519,8 @@ class DtuUart(object):
|
|||||||
if len(msg_data) < data_len:
|
if len(msg_data) < data_len:
|
||||||
self.concat_buffer = str_msg
|
self.concat_buffer = str_msg
|
||||||
self.wait_length = data_len - len(msg_data)
|
self.wait_length = data_len - len(msg_data)
|
||||||
|
print("wait length")
|
||||||
|
print(self.wait_length)
|
||||||
return False
|
return False
|
||||||
elif len(msg_data) > data_len:
|
elif len(msg_data) > data_len:
|
||||||
self.concat_buffer = ""
|
self.concat_buffer = ""
|
||||||
@ -1396,14 +1533,6 @@ class DtuUart(object):
|
|||||||
|
|
||||||
# 设备to云端
|
# 设备to云端
|
||||||
def unpackage_datas(self, str_msg, channels, sid):
|
def unpackage_datas(self, str_msg, channels, sid):
|
||||||
# str_msg = bytestream.decode()
|
|
||||||
if self.concat_buffer:
|
|
||||||
if len(str_msg) > self.wait_length:
|
|
||||||
self.concat_buffer = ""
|
|
||||||
self.wait_length = 0
|
|
||||||
else:
|
|
||||||
str_msg = self.concat_buffer + str_msg
|
|
||||||
self.concat_buffer = ""
|
|
||||||
# 移动gui判断逻辑
|
# 移动gui判断逻辑
|
||||||
gui_flag = self.gui_tools_parse(str_msg, sid)
|
gui_flag = self.gui_tools_parse(str_msg, sid)
|
||||||
# gui命令主动终止
|
# gui命令主动终止
|
||||||
@ -1411,6 +1540,8 @@ class DtuUart(object):
|
|||||||
return False, []
|
return False, []
|
||||||
# 避免后续pop操作影响已有数据
|
# 避免后续pop操作影响已有数据
|
||||||
channels_copy = [x for x in channels]
|
channels_copy = [x for x in channels]
|
||||||
|
print("dtu word mode")
|
||||||
|
print(self.dtu_d.work_mode)
|
||||||
try:
|
try:
|
||||||
if self.dtu_d.work_mode == 'command':
|
if self.dtu_d.work_mode == 'command':
|
||||||
params_list = str_msg.split(",", 4)
|
params_list = str_msg.split(",", 4)
|
||||||
@ -1462,6 +1593,23 @@ class DtuUart(object):
|
|||||||
return {'data': msg_data}, [channel, topic_id]
|
return {'data': msg_data}, [channel, topic_id]
|
||||||
else:
|
else:
|
||||||
return False, []
|
return False, []
|
||||||
|
elif self.dtu_d.work_mode == 'modbus':
|
||||||
|
channel_id = channels_copy.pop()
|
||||||
|
channel = self.channels.channel_dict.get(str(channel_id))
|
||||||
|
if not channel:
|
||||||
|
print("Channel id not exist. Check serialID config.")
|
||||||
|
return False, []
|
||||||
|
print("modbus str_msg")
|
||||||
|
print(type(str_msg))
|
||||||
|
print(str_msg)
|
||||||
|
modbus_data_list = str_msg.split(",")
|
||||||
|
hex_list = ["0x" + x for x in modbus_data_list]
|
||||||
|
# 返回channel
|
||||||
|
if channel.conn_type in ['http', 'tcp', 'udp']:
|
||||||
|
return hex_list, [channel]
|
||||||
|
else:
|
||||||
|
topics = list(channel.pub_topic.keys())
|
||||||
|
return hex_list, [channel, topics[0]]
|
||||||
# 透传模式
|
# 透传模式
|
||||||
else:
|
else:
|
||||||
params_list = str_msg.split(",", 3)
|
params_list = str_msg.split(",", 3)
|
||||||
@ -1586,7 +1734,13 @@ class DtuUart(object):
|
|||||||
if not channels:
|
if not channels:
|
||||||
logger.error("Serial Config not exist!")
|
logger.error("Serial Config not exist!")
|
||||||
return False
|
return False
|
||||||
|
try:
|
||||||
|
if self.dtu_d.work_mode == "modbus":
|
||||||
|
str_msg = ubinascii.hexlify(data, ',').decode()
|
||||||
|
else:
|
||||||
str_msg = data.decode()
|
str_msg = data.decode()
|
||||||
|
except:
|
||||||
|
return False
|
||||||
read_msg, send_params = self.unpackage_datas(str_msg, channels, sid)
|
read_msg, send_params = self.unpackage_datas(str_msg, channels, sid)
|
||||||
if read_msg is False:
|
if read_msg is False:
|
||||||
return False
|
return False
|
||||||
@ -1759,16 +1913,13 @@ class BasicSettingCommand(object):
|
|||||||
return {'code': code, 'status': 1}
|
return {'code': code, 'status': 1}
|
||||||
|
|
||||||
def set_plate(self, code, data):
|
def set_plate(self, code, data):
|
||||||
self.set_int_data(code, data, 'plate')
|
return self.set_int_data(code, data, 'plate')
|
||||||
return {'code': code, 'status': 1}
|
|
||||||
|
|
||||||
def set_reg(self, code, data):
|
def set_reg(self, code, data):
|
||||||
self.set_int_data(code, data, 'reg')
|
return self.set_int_data(code, data, 'reg')
|
||||||
return {'code': code, 'status': 1}
|
|
||||||
|
|
||||||
def set_version(self, code, data):
|
def set_version(self, code, data):
|
||||||
self.set_int_data(code, data, 'version')
|
return self.set_int_data(code, data, 'version')
|
||||||
return {'code': code, 'status': 1}
|
|
||||||
|
|
||||||
def set_passwd(self, code, data):
|
def set_passwd(self, code, data):
|
||||||
try:
|
try:
|
||||||
@ -1782,8 +1933,7 @@ class BasicSettingCommand(object):
|
|||||||
return {'code': code, 'status': 1}
|
return {'code': code, 'status': 1}
|
||||||
|
|
||||||
def set_fota(self, code, data):
|
def set_fota(self, code, data):
|
||||||
self.set_int_data(code, data, 'fota')
|
return self.set_int_data(code, data, 'fota')
|
||||||
return {'code': code, 'status': 1}
|
|
||||||
|
|
||||||
def set_ota(self, code, data):
|
def set_ota(self, code, data):
|
||||||
print("set_ota: ", code, data)
|
print("set_ota: ", code, data)
|
||||||
@ -1805,12 +1955,10 @@ class BasicSettingCommand(object):
|
|||||||
return {'code': code, 'status': 1}
|
return {'code': code, 'status': 1}
|
||||||
|
|
||||||
def set_nolog(self, code, data):
|
def set_nolog(self, code, data):
|
||||||
self.set_int_data(code, data, 'nolog')
|
return self.set_int_data(code, data, 'nolog')
|
||||||
return {'code': code, 'status': 1}
|
|
||||||
|
|
||||||
def set_service_acquire(self, code, data):
|
def set_service_acquire(self, code, data):
|
||||||
self.set_int_data(code, data, 'service_acquire')
|
return self.set_int_data(code, data, 'service_acquire')
|
||||||
return {'code': code, 'status': 1}
|
|
||||||
|
|
||||||
def set_uconf(self, code, data):
|
def set_uconf(self, code, data):
|
||||||
# 透传模式不能配置
|
# 透传模式不能配置
|
||||||
@ -1958,14 +2106,71 @@ class BasicSettingCommand(object):
|
|||||||
return {'code': code, 'status': 0}
|
return {'code': code, 'status': 0}
|
||||||
return {'code': code, 'status': 1}
|
return {'code': code, 'status': 1}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class ModbusCommand:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
print("modbusCMD start")
|
||||||
|
config_params = ProdDocumentParse().refresh_document(CONFIG["config_path"])
|
||||||
|
mode = ujson.loads(config_params)['work_mode']
|
||||||
|
if mode == "modbus":
|
||||||
|
self.modbus_conf = ujson.loads(config_params)['modbus']
|
||||||
|
print(self.modbus_conf)
|
||||||
|
self.groups = dict()
|
||||||
|
self._load_groups()
|
||||||
|
|
||||||
|
def _load_groups(self):
|
||||||
|
print("modbus load groups")
|
||||||
|
groups_conf = self.modbus_conf.get("groups", [])
|
||||||
|
idx = 0
|
||||||
|
print(groups_conf)
|
||||||
|
for group in groups_conf:
|
||||||
|
print(group)
|
||||||
|
self.groups[idx] = [int(x, 16) for x in group['slave_address']]
|
||||||
|
idx += 1
|
||||||
|
|
||||||
|
def exec_modbus_cmd(self, data, uart_port):
|
||||||
|
print("exec modbus cmd")
|
||||||
|
if "groups" in data:
|
||||||
|
groups_num = data['groups'].get("num")
|
||||||
|
cmd = data['groups'].get("cmd")
|
||||||
|
try:
|
||||||
|
int_cmd = [int(x, 16) for x in cmd]
|
||||||
|
except Exception as e:
|
||||||
|
print("modbus command error: %s" % e)
|
||||||
|
return {"status": 0, "error": e}
|
||||||
|
groups_addr = self.groups.get(int(groups_num))
|
||||||
|
for addr in groups_addr:
|
||||||
|
modbus_cmd = [addr]
|
||||||
|
modbus_cmd.extend(int_cmd)
|
||||||
|
crc_cmd = modbus_crc(bytearray(modbus_cmd))
|
||||||
|
print("modbus uart write")
|
||||||
|
print(crc_cmd)
|
||||||
|
uart_port.write(crc_cmd)
|
||||||
|
utime.sleep(1)
|
||||||
|
return {'code': cmd, 'status': 1}
|
||||||
|
elif "command" in data:
|
||||||
|
command = data['command']
|
||||||
|
try:
|
||||||
|
int_cmd = [int(x, 16) for x in command]
|
||||||
|
crc_cmd = modbus_crc(bytearray(int_cmd))
|
||||||
|
except Exception as e:
|
||||||
|
print("modbus command error: %s" % e)
|
||||||
|
return {"status": 0, "error": e}
|
||||||
|
print("modbus write cmd")
|
||||||
|
print(crc_cmd)
|
||||||
|
uart_port.write(crc_cmd)
|
||||||
|
return {'code': command, 'status': 1}
|
||||||
|
else:
|
||||||
|
err_msg = "can't get any modbus params"
|
||||||
|
print(err_msg)
|
||||||
|
return {'code': 0, "status": 0, "error": err_msg}
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class ChannelTransfer(object):
|
class ChannelTransfer(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.dtu_c = DTUDocumentData()
|
self.dtu_c = DTUDocumentData()
|
||||||
self.channel_dict = {}
|
self.channel_dict = CHANNELS
|
||||||
self.serial_channel_dict = dict()
|
self.serial_channel_dict = dict()
|
||||||
# self.control_code = None
|
# self.control_code = None
|
||||||
|
|
||||||
@ -2050,22 +2255,6 @@ class DtuExecCommand(object):
|
|||||||
return {'code': cmd_code, 'status': 0, 'error': error_map.get(RET.POINTERR)}
|
return {'code': cmd_code, 'status': 0, 'error': error_map.get(RET.POINTERR)}
|
||||||
return rec
|
return rec
|
||||||
|
|
||||||
def exec_modbus_cmd(self, modbus_cmd, data):
|
|
||||||
if isinstance(modbus_cmd, list):
|
|
||||||
mod_array = bytearray(modbus_cmd)
|
|
||||||
crc_val = modbus_crc(mod_array)
|
|
||||||
for num in crc_val:
|
|
||||||
mod_array.append(num)
|
|
||||||
|
|
||||||
elif isinstance(modbus_cmd, int):
|
|
||||||
pass
|
|
||||||
elif isinstance(modbus_cmd, str):
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
return {'code': modbus_cmd, 'status': 0, 'error': error_map.get(RET.MODBUSERR)}
|
|
||||||
|
|
||||||
return {'code': modbus_cmd, 'status': 1}
|
|
||||||
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class DTUOfflineHandler:
|
class DTUOfflineHandler:
|
||||||
@ -2099,7 +2288,9 @@ def modbus_crc(string_byte):
|
|||||||
gen_crc = hex(((crc & 0xff) << 8) + (crc >> 8))
|
gen_crc = hex(((crc & 0xff) << 8) + (crc >> 8))
|
||||||
int_crc = int(gen_crc, 16)
|
int_crc = int(gen_crc, 16)
|
||||||
high, low = divmod(int_crc, 0x100)
|
high, low = divmod(int_crc, 0x100)
|
||||||
return high, low
|
string_byte.append(high)
|
||||||
|
string_byte.append(low)
|
||||||
|
return string_byte
|
||||||
|
|
||||||
|
|
||||||
"""=================================================== run ============================================================"""
|
"""=================================================== run ============================================================"""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user