mirror of
https://gitee.com/qpy-solutions/dtu.git
synced 2025-05-19 11:08:25 +08:00
更新文档和代码
This commit is contained in:
parent
3f935faeaf
commit
1d86858284
@ -190,6 +190,20 @@
|
||||
| pubTopic | str | true | 发布主题 |
|
||||
| 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功能暂未上线
|
||||
|
@ -4,6 +4,7 @@
|
||||
| :------ | ---------- | ---------- | --------------------- |
|
||||
| 1.0 | 2021-11-25 | 陈驰 | 初始版本 |
|
||||
| 1.1 | 2021-11-30 | 陈驰 | 增加对DTU配套组件和服务的描述 |
|
||||
| 1.2 | 2022-01-14 | 陈驰 | 增加DTU代码和文档链接的描述 |
|
||||
|
||||
## DTU介绍
|
||||
|
||||
@ -178,3 +179,25 @@ QPYCom的使用文档,参见安装目录下的`docs`文件夹。
|
||||
### modbus模式
|
||||
|
||||
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时生效
|
||||
|
||||
- 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 | 查询指令 |
|
||||
| 0x00 | 查询IMEI |
|
||||
| 0x01 | 查询本机号码 |
|
||||
| 0x02 | 查询固件版本号 |
|
||||
| 0x03 | 查询信号强度 |
|
||||
| 0x04 | 查询当前配置参数 |
|
||||
| 0x05 | 诊断查询 |
|
||||
| 0X06 | 查询ICCID |
|
||||
| 0X07 | 查询ADC电压 |
|
||||
| 0X08 | 查询GPIO信息 |
|
||||
| 0X10 | 查询温湿度 |
|
||||
| 0X11 | 查询网络连接信息 |
|
||||
| 0X12 | 查询网络状态 |
|
||||
| 0X13 | 查询基站定位信息 |
|
||||
| 0x50~0x8f | 设置指令 |
|
||||
| 0x50 | 协议短信透传 |
|
||||
| 0x51 | 配置密码 |
|
||||
| 0x52 | 添加设备识别码IMEI |
|
||||
| 0x53 | 登录服务器发送注册信息 |
|
||||
| 0x54 | 固件版本号 |
|
||||
| 0x55 | 是否启用自动更新 |
|
||||
| 0x56 | 日志输出 |
|
||||
| 0x57 | 服务器获取配置参数 |
|
||||
| 0x58 | 串口参数 |
|
||||
| 0x59 | 通道配置参数 |
|
||||
| 0x60 | Apn设置 |
|
||||
| 0x61 | GPIO设置 |
|
||||
| 0x62 | GPS |
|
||||
| 0x63 | 数据流 |
|
||||
| 0x64 | 预警 |
|
||||
| 0x65 | 任务 |
|
||||
| 0xfd | 协议终止指令 |
|
||||
| 0xfe | DTU启动中,无法接收指令 |
|
||||
| 0xff | 复位指令 |
|
||||
|--------|---------------|
|
||||
| 0-49 | 查询指令 |
|
||||
| 0 | 查询IMEI |
|
||||
| 1 | 查询本机号码 |
|
||||
| 2 | 查询固件版本号 |
|
||||
| 3 | 查询信号强度 |
|
||||
| 4 | 查询当前配置参数 |
|
||||
| 5 | 诊断查询 |
|
||||
| 6 | 查询ICCID |
|
||||
| 7 | 查询ADC电压 |
|
||||
| 8 | 查询GPIO信息 |
|
||||
| 10 | 查询温湿度 |
|
||||
| 11 | 查询网络连接信息 |
|
||||
| 12 | 查询网络状态 |
|
||||
| 13 | 查询基站定位信息 |
|
||||
| 50~143 | 设置指令 |
|
||||
| 50 | 协议短信透传 |
|
||||
| 51 | 配置密码 |
|
||||
| 52 | 添加设备识别码IMEI |
|
||||
| 53 | 登录服务器发送注册信息 |
|
||||
| 54 | 固件版本号 |
|
||||
| 55 | 是否启用自动更新 |
|
||||
| 56 | 日志输出 |
|
||||
| 57 | 服务器获取配置参数 |
|
||||
| 58 | 串口参数 |
|
||||
| 59 | 通道配置参数 |
|
||||
| 60 | Apn设置 |
|
||||
| 61 | GPIO设置 |
|
||||
| 62 | OTA |
|
||||
| 63 | 参数设置 |
|
||||
| 255 | 复位指令 |
|
||||
|
||||
## 查询指令
|
||||
|
||||
@ -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卡的号码
|
||||
|
||||
功能码: 0x01
|
||||
功能码: 1
|
||||
|
||||
返回的数据内容:
|
||||
|
||||
`{"code": 0x01 , "data": "17201593988" , "success":1}`
|
||||
`{"code": 1 , "data": "17201593988" , "success":1}`
|
||||
|
||||
| **字段** | **类型** | **含义** |
|
||||
| --- | --- | --- |
|
||||
@ -150,11 +172,11 @@ DTU的IMEI号
|
||||
|
||||
固件版本号格式为: 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,值越大表示信号强度越好。
|
||||
|
||||
功能码: 0x03
|
||||
功能码: 3
|
||||
|
||||
返回的数据内容:
|
||||
|
||||
`{"code": 0x03 , "data": " CSQ17 " , "success":1}`
|
||||
`{"code": 3 , "data": " CSQ17 " , "success":1}`
|
||||
|
||||
| **字段** | **字符串** | **含义** |
|
||||
| --- | --- | --- |
|
||||
| **字段** | **类型** | **含义** |
|
||||
| --- |--------| --- |
|
||||
| code | str | 状态码 |
|
||||
| data | str | CSQ1~CSQ31 |
|
||||
| success | int | 0 失败 1成功 |
|
||||
|
||||
### 查询当前配置参数
|
||||
|
||||
功能码: 0x04
|
||||
功能码: 4
|
||||
|
||||
数据内容:
|
||||
```
|
||||
{"password": "012345",
|
||||
|
||||
"data":{}
|
||||
|
||||
"cmd_code": 4,
|
||||
}
|
||||
```
|
||||
返回的数据内容:
|
||||
|
||||
`{"code": 0x04 , "data": " req config " , "success":1}`
|
||||
`{"code": 4 , "data": " req config " , "success":1}`
|
||||
|
||||
| **字段** | **字符串** | **含义** |
|
||||
| --- | --- | --- |
|
||||
@ -206,13 +226,13 @@ DTU的IMEI号
|
||||
|
||||
说明: 查询当前DTU运行的错误上报信息
|
||||
|
||||
功能码: 0x05
|
||||
功能码: 5
|
||||
|
||||
返回的数据内容:
|
||||
```
|
||||
{"code":0x05,
|
||||
{"code":5,
|
||||
|
||||
"data":[{"func_code": "0x01" , "error_code": " 6001"}],
|
||||
"data":[{"func_code": "5" , "error_code": " 6001"}],
|
||||
|
||||
"success":1}
|
||||
```
|
||||
@ -228,11 +248,11 @@ DTU的IMEI号
|
||||
|
||||
说明: 查询iccid
|
||||
|
||||
功能码: 0x06
|
||||
功能码: 6
|
||||
|
||||
返回的数据内容:
|
||||
```
|
||||
{"code":0x06,
|
||||
{"code":6,
|
||||
|
||||
"data": "12456465486561516515153",
|
||||
|
||||
@ -249,11 +269,11 @@ DTU的IMEI号
|
||||
|
||||
说明: 查询adc
|
||||
|
||||
功能码: 0x07
|
||||
功能码: 7
|
||||
|
||||
返回的数据内容:
|
||||
```
|
||||
{"code":0x07,
|
||||
{"code":7,
|
||||
|
||||
"data": "3.7",
|
||||
|
||||
@ -269,11 +289,11 @@ DTU的IMEI号
|
||||
|
||||
说明: 查询gpio
|
||||
|
||||
功能码: 0x08
|
||||
功能码: 8
|
||||
|
||||
返回的数据内容:
|
||||
```
|
||||
{"code":0x08,
|
||||
{"code":8,
|
||||
|
||||
"data": "gpio_msg",
|
||||
|
||||
@ -286,15 +306,35 @@ DTU的IMEI号
|
||||
| data | str | gpio获取的信息 |
|
||||
| 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},
|
||||
"status":1}
|
||||
```
|
||||
@ -302,18 +342,18 @@ DTU的IMEI号
|
||||
| **字段** | **类型** | **含义** |
|
||||
| --- | --- | --- |
|
||||
| code | int | 状态码 |
|
||||
| data | dict | 温湿度信息{"temperature": temp, &##39;humidity&##39;: humid} |
|
||||
| data | dict | 温湿度信息{"temperature": temp, 'humidity': humid} |
|
||||
| status | str | 0 失败 1成功 |
|
||||
|
||||
### 查询网络连接信息
|
||||
|
||||
说明: 查询网络连接信息,每种连接类型返回对应连接状态
|
||||
|
||||
功能码: 0x11
|
||||
功能码: 11
|
||||
|
||||
返回的数据内容:
|
||||
```
|
||||
{"code":0x11,
|
||||
{"code":11,
|
||||
"data": "200",
|
||||
"status":1}
|
||||
```
|
||||
@ -324,36 +364,98 @@ DTU的IMEI号
|
||||
| data | str | 网络连接状态 |
|
||||
| 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}
|
||||
```
|
||||
|
||||
| **字段** | **类型** | **含义** |
|
||||
| --- | --- | --- |
|
||||
| --- | --- |---------------------------------------|
|
||||
| code | int | 状态码 |
|
||||
| data | turple | 基站连接状态 |
|
||||
| data | turple | voice_state:语音连接状态, data_state:数据连接状态 |
|
||||
| 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) ,
|
||||
|
||||
@ -368,12 +470,14 @@ DTU的IMEI号
|
||||
|
||||
## 复位指令
|
||||
|
||||
功能码: 0xff
|
||||
功能码: 255
|
||||
|
||||
数据内容:
|
||||
```
|
||||
{ Password: "012345",
|
||||
|
||||
"code":255,
|
||||
|
||||
"data":{}
|
||||
|
||||
}
|
||||
@ -381,7 +485,7 @@ DTU的IMEI号
|
||||
|
||||
返回的数据内容:
|
||||
|
||||
`{"code": 0x06 , "data": " reset dtu " , "success":1}`
|
||||
无
|
||||
|
||||
| **字段** | **类型** | **含义** |
|
||||
| --- | --- | --- |
|
||||
@ -395,7 +499,7 @@ DTU的IMEI号
|
||||
|
||||
#### 协议短信(SMS)透传 message
|
||||
|
||||
功能码: 0x50
|
||||
功能码: 50
|
||||
|
||||
数据内容:
|
||||
|
||||
@ -410,7 +514,7 @@ DTU的IMEI号
|
||||
|
||||
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":" ",
|
||||
"data":{ "password": "012345"}
|
||||
"data":{"new_password": "012345"}
|
||||
}
|
||||
```
|
||||
说明:初始密码为固件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,7 +608,9 @@ message: {"number":"12123123", -- 目标号码
|
||||
|
||||
修改固件版本号,用于fota升级(当开启fota升级,版本号小于服务器端的固件版本号就会进行fota升级)
|
||||
|
||||
功能码: 0x54
|
||||
固件版本号仅支持整数
|
||||
|
||||
功能码: 54
|
||||
|
||||
数据内容:
|
||||
```
|
||||
@ -518,7 +624,7 @@ message: {"number":"12123123", -- 目标号码
|
||||
|
||||
返回的数据内容:
|
||||
|
||||
`{"code": 0x54 , "data": " " , "success":1}`
|
||||
`{"code": 54 , "data": " " , "success":1}`
|
||||
|
||||
| **字段** | **类型** | **含义** |
|
||||
| --- | --- | --- |
|
||||
@ -532,7 +638,7 @@ message: {"number":"12123123", -- 目标号码
|
||||
|
||||
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口
|
||||
|
||||
功能码: 0x56
|
||||
功能码: 56
|
||||
|
||||
数据内容:
|
||||
```
|
||||
@ -582,7 +688,7 @@ Fota升级开关
|
||||
|
||||
#### 服务器获取配置参数
|
||||
|
||||
功能码: 0x57
|
||||
功能码: 57
|
||||
|
||||
数据内容:
|
||||
```
|
||||
@ -611,7 +717,9 @@ Fota升级开关
|
||||
|
||||
#### 串口参数 uconf
|
||||
|
||||
功能码: 0x58
|
||||
功能码: 58
|
||||
|
||||
**在透传模式下无法设置串口参数**
|
||||
|
||||
数据内容:
|
||||
```
|
||||
@ -639,13 +747,16 @@ Fota升级开关
|
||||
|
||||
#### 通道配置参数 conf
|
||||
|
||||
功能码: 0x59
|
||||
功能码: 59
|
||||
|
||||
**在透传模式下无法设置串口参数**
|
||||
|
||||
数据内容:
|
||||
```
|
||||
{"password":"",
|
||||
"data":{
|
||||
"conf":"1": {
|
||||
"conf":{
|
||||
"1": {
|
||||
"protocol": "aliyun",
|
||||
"type": "mos",
|
||||
"keepAlive": "",
|
||||
@ -659,7 +770,7 @@ Fota升级开关
|
||||
"subscribe": {"0": "/gbh26bFEA4M/ec600n/user/subtest"},
|
||||
"publish": {"0": "/gbh26bFEA4M/ec600n/user/pubtest"},
|
||||
"serialID": "0"}
|
||||
}}
|
||||
}}}
|
||||
```
|
||||
**对应通道的配置参数详见6.1.10.1的通道配置详解 :**
|
||||
|
||||
@ -719,7 +830,7 @@ Fota升级开关
|
||||
###### SOCKET udp 参数
|
||||
```
|
||||
{
|
||||
"protocol": "tcp",
|
||||
"protocol": "udp",
|
||||
"ping": "",
|
||||
"heartbeat": 30,
|
||||
"url": "220.180.239.212",
|
||||
@ -827,8 +938,7 @@ Fota升级开关
|
||||
| keepAlive | int | 通信之间允许的最长时间段(以秒为单位),默认为300,范围(60-1200)使用默认值就填""或者" "。 |
|
||||
| clientID | str | clientID ,自定义字符(不超过64) |
|
||||
| Devicename | str | 设备名称 |
|
||||
| ProductKey | str |
|
||||
|
|
||||
| ProductKey | str |产品密钥|
|
||||
| DeviceSecret | str | 设备密钥(使用一型一密认证此参数传入"") |
|
||||
| ProductSecret | str | 产品密钥(使用一机一密认证时此参数传入"") |
|
||||
| cleanSession | int | MQTT 保存会话标志位( 0则客户端是持久客户端,当客户端断开连接时,订阅信息和排队消息将被保留, 1代理将在其断开连接时删除有关此客户端的所有信息 ) |
|
||||
@ -837,11 +947,42 @@ Fota升级开关
|
||||
| pubTopic | str | 发布主题 |
|
||||
| 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
|
||||
|
||||
说明:这个指令只适合配置和使用不是同一张卡的场景
|
||||
|
||||
功能码: 0x60
|
||||
**在透传模式下无法设置串口参数**
|
||||
|
||||
功能码: 60
|
||||
|
||||
数据内容:
|
||||
```
|
||||
@ -860,7 +1001,7 @@ apn对应列表说明:
|
||||
|
||||
返回的数据内容:
|
||||
|
||||
`{"code": 0x60 , "status":1}`
|
||||
`{"code": 60 , "status":1}`
|
||||
|
||||
| **字段** | **类型** | **含义** |
|
||||
| --- | --- | --- |
|
||||
@ -870,20 +1011,24 @@ apn对应列表说明:
|
||||
|
||||
## GPIO pins
|
||||
|
||||
功能码: 0x61
|
||||
功能码: 61
|
||||
|
||||
**在透传模式下无法设置串口参数**
|
||||
|
||||
pins的长度必须为3
|
||||
|
||||
数据内容:
|
||||
```
|
||||
{"password": " ",
|
||||
"data":{"pins":[
|
||||
"pio2", -- 网路指示灯的GPIO (pio1~pio128)
|
||||
"pio4", -- 与服务器连上后通知GPIO (pio1~pio128)
|
||||
"pio4" -- 重置DTU参数的GPIO (pio1~pio128)
|
||||
"1", -- 网路指示灯的GPIO (pio1~pio128)
|
||||
"2", -- 与服务器连上后通知GPIO (pio1~pio128)
|
||||
"3" -- 重置DTU参数的GPIO (pio1~pio128)
|
||||
]}}
|
||||
```
|
||||
返回的数据内容:
|
||||
|
||||
`{"code": 0x61 , "status":1}`
|
||||
`{"code": 61 , "status":1}`
|
||||
|
||||
| **字段** | **类型** | **含义** |
|
||||
| --- | --- | --- |
|
||||
@ -893,7 +1038,7 @@ apn对应列表说明:
|
||||
|
||||
## OTA
|
||||
|
||||
功能码: 0x62
|
||||
功能码: 62
|
||||
|
||||
数据内容:
|
||||
```
|
||||
@ -903,30 +1048,33 @@ apn对应列表说明:
|
||||
```
|
||||
返回的数据内容:
|
||||
|
||||
`{"code": 0x62 , "status":1}`
|
||||
`{"code": 62 , "status":1}`
|
||||
|
||||
| **字段** | **类型** | **含义** |
|
||||
| --- | --- | --- |
|
||||
| code | Str | 状态码 |
|
||||
| data | str | OTA状态 |
|
||||
| success | int | 0 失败 1成功 |
|
||||
| status | int | 0 失败 1成功 |
|
||||
|
||||
## 参数设置
|
||||
|
||||
功能码: 0x63
|
||||
功能码: 63
|
||||
|
||||
数据内容:
|
||||
```
|
||||
{"password": " ",
|
||||
"data":{ 完整配置文件(省略)
|
||||
"data":{"dtu_config":{完整配置文件内容}
|
||||
}
|
||||
```
|
||||
|
||||
完整配置文件参照《DTU上手说明》
|
||||
|
||||
返回的数据内容:
|
||||
|
||||
`{"code": 0x63 ,"status":1}`
|
||||
`{"code": 63 , "status":1}`
|
||||
|
||||
| **字段** | **类型** | **含义** |
|
||||
| --- | --- | --- |
|
||||
| code | Str | 状态码 |
|
||||
| data | dict | 完整的配置文件 |
|
||||
| status | int | 0 失败 1成功 |
|
||||
|
||||
|
@ -41,7 +41,7 @@
|
||||
"url": "http://httpbin.org/get", //请求url
|
||||
"reg_data": "", //附带的固定文本
|
||||
"timeout": "", //超时
|
||||
"serialID": 1 //捆绑的串口(1-2)
|
||||
"serialID": 1 //捆绑的串口(1-2),需要为配置文件中uconf中存在的key
|
||||
},
|
||||
"2": {
|
||||
//TCP&UDP连接设置
|
||||
@ -51,7 +51,7 @@
|
||||
"url": "220.180.239.212", //请求url
|
||||
"port": "8305", //端口
|
||||
"keepAlive": 300, //保持连接时间
|
||||
"serialID": 2 //捆绑串口
|
||||
"serialID": 2 //捆绑串口,需要为配置文件中uconf中存在的key
|
||||
},
|
||||
"3": {
|
||||
//mqtt连接设置
|
||||
@ -67,8 +67,8 @@
|
||||
"retain": "1", //是否使用内部重连
|
||||
"serialID": "1" //捆绑的串口
|
||||
},
|
||||
//阿里云连接设置
|
||||
"4": {
|
||||
//阿里云连接设置
|
||||
"protocol": "aliyun", //连接类型
|
||||
"type": "mos", //一机一密/一型一密设置
|
||||
"keepAlive": "", // keep alive超时
|
||||
@ -98,6 +98,17 @@
|
||||
"subscribe": {"0": "H7MBLRYXN9/Smart_test01/control"},
|
||||
"publish": {"0": "H7MBLRYXN9/Smart_test01/event"},
|
||||
"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, //发送登陆消息
|
||||
@ -106,7 +117,8 @@
|
||||
"nolog": 0, //是否输出log
|
||||
"message": {}, //协议短信透传
|
||||
"uconf": { //串口设置
|
||||
"1": {
|
||||
"1": { //key为UART编号,使用UART0填入:“0”,使用UART1则填入“1”,以此类推;同时,
|
||||
//该值同时在通道配置的serialID项中使用
|
||||
"baudrate": "115200",
|
||||
"databits": "8",
|
||||
"parity": "0",
|
||||
@ -136,14 +148,31 @@
|
||||
"service_acquire": 0, //是否开启服务器获取参数
|
||||
"work_mode": "command", //工作模式
|
||||
"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"文件夹内
|
||||
|
||||
@ -183,7 +212,7 @@ DTU运行成功,下面为读取的配置文件。
|
||||
|
||||
## 报文格式
|
||||
|
||||
### 命令模式/modbus模式
|
||||
### 命令模式
|
||||
|
||||
支持多通道透传,通过配置文件中的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)
|
||||
|
||||
**返回报文:**
|
||||
|
||||
`“5,2e46f5,20001”`
|
||||
`“1,6,2584251182,ijklmn”`
|
||||
|
||||
#### 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)
|
||||
|
||||
**返回报文:**
|
||||
|
||||
`“5,2e46f5,20001”`
|
||||
`“6,2584251182,ijklmn”`
|
||||
|
||||
#### 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格式
|
||||
|
||||
#### 云端下行报文
|
||||
|
||||
- 命令模式与modbus模式:
|
||||
- 命令模式:
|
||||
|
||||
`{“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时生效
|
||||
|
||||
- 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”}`
|
||||
|
||||
|
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",
|
||||
"conf": {
|
||||
"1": {
|
||||
"protocol": "quecthing",
|
||||
"keepAlive": "",
|
||||
"ProductKey": "p1118c",
|
||||
"ProductSecret": "c3Jzd3ZaNzVrV2Vj",
|
||||
"qos": "1",
|
||||
"SessionFlag": false,
|
||||
"sendMode": "pass",
|
||||
"serialID": "2"
|
||||
"protocol": "hwyun",
|
||||
"url": "a1621ed65c.iot-mqtts.cn-north-4.myhuaweicloud.com",
|
||||
"port": "1883",
|
||||
"device_id": "621ece4cc4e6a958e354301e_869537055499330",
|
||||
"secret": "a306255686a71e56ad53965fc2771bf8",
|
||||
"keep_alive": 10,
|
||||
"cleanSession": true,
|
||||
"subscribe": {"0": "$oc/devices/621ece4cc4e6a958e354301e_869537055499330/sys/messages/down"},
|
||||
"publish": {"0": "$oc/devices/621ece4cc4e6a958e354301e_869537055499330/sys/messages/up"},
|
||||
"qos": 0,
|
||||
"serialID": 2
|
||||
}
|
||||
},
|
||||
"reg": 0,
|
||||
@ -40,7 +43,8 @@
|
||||
""
|
||||
],
|
||||
"service_acquire": 0,
|
||||
"work_mode": "command",
|
||||
"work_mode": "though",
|
||||
"auto_connect": 1,
|
||||
"offline_storage": false
|
||||
"offline_storage": false,
|
||||
"modbus": {}
|
||||
}
|
@ -8,7 +8,6 @@ from aLiYun import aLiYun
|
||||
from TenCentYun import TXyun
|
||||
from umqtt import MQTTClient
|
||||
from machine import UART
|
||||
import uos
|
||||
uos.chdir('/usr/')
|
||||
from singleton import Singleton
|
||||
from t_h import SensorTH
|
||||
@ -42,6 +41,7 @@ class RET:
|
||||
PROTOCOLERR = "4008"
|
||||
REQERR1 = "4009"
|
||||
QUECIOTERR = "4010"
|
||||
HWYUNERR = "4011"
|
||||
REQERR2 = "5000"
|
||||
# 功能错误
|
||||
PASSWORDERR = "5001"
|
||||
@ -89,6 +89,7 @@ error_map = {
|
||||
RET.TXYUNMQTTERR: u"txyun connect failed",
|
||||
RET.PROTOCOLERR: u"protocol parse error",
|
||||
RET.QUECIOTERR: u"quecthing connect failed",
|
||||
RET.HWYUNERR: u"huaweiyun connect failed",
|
||||
# 功能错误
|
||||
RET.PASSWORDERR: u"password not found",
|
||||
RET.PASSWDVERIFYERR: u"password verify error",
|
||||
@ -120,6 +121,8 @@ CONFIG = {
|
||||
|
||||
HISTORY_ERROR = []
|
||||
|
||||
SERIAL_MAP = dict()
|
||||
CHANNELS = dict()
|
||||
|
||||
|
||||
"""================================================= singleton ===================================================="""
|
||||
@ -132,6 +135,65 @@ class DTUException(Exception):
|
||||
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 ==================================================="""
|
||||
|
||||
|
||||
@ -247,7 +309,7 @@ class ProdDtu(object):
|
||||
# 升级包下载地址的请求
|
||||
version = self.parse_data.version
|
||||
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"}
|
||||
acquire_data = {
|
||||
"version": str(version),
|
||||
@ -342,12 +404,13 @@ class ProdDtu(object):
|
||||
return data
|
||||
|
||||
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():
|
||||
if int(channel.serialID) in self.channel.serial_channel_dict:
|
||||
self.channel.serial_channel_dict[int(channel.serialID)].append(cid)
|
||||
serial_id = int(channel.get("serialID"))
|
||||
if serial_id in self.channel.serial_channel_dict:
|
||||
self.channel.serial_channel_dict[serial_id].append(cid)
|
||||
else:
|
||||
self.channel.serial_channel_dict[int(channel.serialID)] = [cid]
|
||||
self.channel.serial_channel_dict[serial_id] = [cid]
|
||||
return self.parse_data.conf
|
||||
else:
|
||||
serv_map = dict()
|
||||
@ -369,6 +432,7 @@ class ProdDtu(object):
|
||||
# 透传与modbus服务器筛选
|
||||
serv_maps = self.server_filter()
|
||||
self._serv_connect(serv_maps, reg_data)
|
||||
print("SERV conn success")
|
||||
_thread.start_new_thread(self.uart.read, ())
|
||||
if self.parse_data.offline_storage:
|
||||
_thread.start_new_thread(self.offline_storage.retry_offline_handler, ())
|
||||
@ -495,10 +559,26 @@ class ProdDtu(object):
|
||||
print("quecthing connect waiting server...")
|
||||
else:
|
||||
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:
|
||||
continue
|
||||
|
||||
|
||||
@Singleton
|
||||
class ProdGPIO(object):
|
||||
def __init__(self):
|
||||
# self.gpio1 = Pin(Pin.GPIO1, Pin.OUT, Pin.PULL_DISABLE, 0)
|
||||
@ -530,65 +610,6 @@ class ProdGPIO(object):
|
||||
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==================================================="""
|
||||
|
||||
|
||||
@ -794,6 +815,8 @@ class AbstractDtuMqttTransfer(object):
|
||||
self.product_secret = ""
|
||||
self.device_name = ""
|
||||
self.device_secret = ""
|
||||
self.user = ""
|
||||
self.password = ""
|
||||
# self.control_channel = False
|
||||
self.pub_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)
|
||||
|
||||
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:
|
||||
topic = self.pub_topic.get(str(topic_id))
|
||||
self.publish(data, topic)
|
||||
@ -828,7 +856,11 @@ class AbstractDtuMqttTransfer(object):
|
||||
# 写入uart/远程控制
|
||||
rec = self.uart.output(msg.decode(), self.serial, mqtt_id=self.channel_id)
|
||||
if isinstance(rec, dict):
|
||||
if isinstance(rec, dict):
|
||||
if "topic_id" in rec:
|
||||
topic_id = rec.pop('topic_id')
|
||||
else:
|
||||
topic_id = list(self.pub_topic.keys())[0]
|
||||
self.send(rec, topic_id)
|
||||
|
||||
def disconnect(self):
|
||||
@ -843,6 +875,8 @@ class AbstractDtuMqttTransfer(object):
|
||||
self.client_id = data.get("clientID")
|
||||
self.device_name = data.get("Devicename")
|
||||
self.product_key = data.get("ProductKey")
|
||||
self.user = data.get("user")
|
||||
self.password = data.get("password")
|
||||
if self.iot_type == "mos":
|
||||
self.device_secret = data.get('DeviceSecret') if data.get("DeviceSecret") else None
|
||||
self.product_secret = None
|
||||
@ -875,7 +909,14 @@ class DtuMqttTransfer(AbstractDtuMqttTransfer):
|
||||
# self.code = code
|
||||
|
||||
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.connect(clean_session=self.clean_session)
|
||||
for tid, s_topic in self.sub_topic.items():
|
||||
@ -1045,7 +1086,10 @@ class QuecthingDtuTransfer:
|
||||
quecIot.setEventCB(self.callback)
|
||||
|
||||
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":
|
||||
quecIot.passTransSend(self.qos, send_data)
|
||||
else:
|
||||
@ -1115,6 +1159,91 @@ class QuecthingDtuTransfer:
|
||||
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==================================================="""
|
||||
|
||||
|
||||
@ -1135,7 +1264,7 @@ class DTUDocumentData(object):
|
||||
self.conf = dict()
|
||||
self.pins = []
|
||||
self.apn = []
|
||||
self.modbus = []
|
||||
self.modbus = dict()
|
||||
self.work_mode = "command"
|
||||
self.auto_connect = True
|
||||
self.offline_storage = False
|
||||
@ -1295,7 +1424,7 @@ class DtuUart(object):
|
||||
config_path = CONFIG["config_path"]
|
||||
config_params = ProdDocumentParse().refresh_document(config_path)
|
||||
uconf = ujson.loads(config_params)["uconf"]
|
||||
self.serial_map = dict()
|
||||
self.serial_map = SERIAL_MAP
|
||||
for sid, conf in uconf.items():
|
||||
uart_conn = UART(getattr(UART, 'UART%d' % int(sid)),
|
||||
int(conf.get("baudrate")),
|
||||
@ -1306,9 +1435,10 @@ class DtuUart(object):
|
||||
self.serial_map[sid] = uart_conn
|
||||
# 初始化方向gpio
|
||||
self._direction_pin(config_params)
|
||||
self.exec_cmd = DtuExecCommand()
|
||||
self.protocol = DtuProtocolData()
|
||||
self.channels = ChannelTransfer()
|
||||
self.exec_cmd = DtuExecCommand()
|
||||
self.exec_modbus = ModbusCommand()
|
||||
self.protocol = DtuProtocolData()
|
||||
self.concat_buffer = ""
|
||||
self.wait_length = 0
|
||||
self.wait_retry_count = 0
|
||||
@ -1332,7 +1462,7 @@ class DtuUart(object):
|
||||
print(data)
|
||||
if isinstance(data, (int, float)):
|
||||
data = str(data)
|
||||
if self.dtu_d.work_mode == 'command':
|
||||
if self.dtu_d.work_mode in ['command', "modbus"]:
|
||||
print("CMD START")
|
||||
try:
|
||||
if isinstance(data, str):
|
||||
@ -1356,7 +1486,12 @@ class DtuUart(object):
|
||||
rec['topic_id'] = msg_data.get("topic_id")
|
||||
return rec
|
||||
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:
|
||||
logger.info("{}: {}".format(error_map.get(RET.CMDPARSEERR), e))
|
||||
# package_data
|
||||
@ -1384,6 +1519,8 @@ class DtuUart(object):
|
||||
if len(msg_data) < data_len:
|
||||
self.concat_buffer = str_msg
|
||||
self.wait_length = data_len - len(msg_data)
|
||||
print("wait length")
|
||||
print(self.wait_length)
|
||||
return False
|
||||
elif len(msg_data) > data_len:
|
||||
self.concat_buffer = ""
|
||||
@ -1396,14 +1533,6 @@ class DtuUart(object):
|
||||
|
||||
# 设备to云端
|
||||
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_flag = self.gui_tools_parse(str_msg, sid)
|
||||
# gui命令主动终止
|
||||
@ -1411,6 +1540,8 @@ class DtuUart(object):
|
||||
return False, []
|
||||
# 避免后续pop操作影响已有数据
|
||||
channels_copy = [x for x in channels]
|
||||
print("dtu word mode")
|
||||
print(self.dtu_d.work_mode)
|
||||
try:
|
||||
if self.dtu_d.work_mode == 'command':
|
||||
params_list = str_msg.split(",", 4)
|
||||
@ -1462,6 +1593,23 @@ class DtuUart(object):
|
||||
return {'data': msg_data}, [channel, topic_id]
|
||||
else:
|
||||
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:
|
||||
params_list = str_msg.split(",", 3)
|
||||
@ -1586,7 +1734,13 @@ class DtuUart(object):
|
||||
if not channels:
|
||||
logger.error("Serial Config not exist!")
|
||||
return False
|
||||
try:
|
||||
if self.dtu_d.work_mode == "modbus":
|
||||
str_msg = ubinascii.hexlify(data, ',').decode()
|
||||
else:
|
||||
str_msg = data.decode()
|
||||
except:
|
||||
return False
|
||||
read_msg, send_params = self.unpackage_datas(str_msg, channels, sid)
|
||||
if read_msg is False:
|
||||
return False
|
||||
@ -1759,16 +1913,13 @@ class BasicSettingCommand(object):
|
||||
return {'code': code, 'status': 1}
|
||||
|
||||
def set_plate(self, code, data):
|
||||
self.set_int_data(code, data, 'plate')
|
||||
return {'code': code, 'status': 1}
|
||||
return self.set_int_data(code, data, 'plate')
|
||||
|
||||
def set_reg(self, code, data):
|
||||
self.set_int_data(code, data, 'reg')
|
||||
return {'code': code, 'status': 1}
|
||||
return self.set_int_data(code, data, 'reg')
|
||||
|
||||
def set_version(self, code, data):
|
||||
self.set_int_data(code, data, 'version')
|
||||
return {'code': code, 'status': 1}
|
||||
return self.set_int_data(code, data, 'version')
|
||||
|
||||
def set_passwd(self, code, data):
|
||||
try:
|
||||
@ -1782,8 +1933,7 @@ class BasicSettingCommand(object):
|
||||
return {'code': code, 'status': 1}
|
||||
|
||||
def set_fota(self, code, data):
|
||||
self.set_int_data(code, data, 'fota')
|
||||
return {'code': code, 'status': 1}
|
||||
return self.set_int_data(code, data, 'fota')
|
||||
|
||||
def set_ota(self, code, data):
|
||||
print("set_ota: ", code, data)
|
||||
@ -1805,12 +1955,10 @@ class BasicSettingCommand(object):
|
||||
return {'code': code, 'status': 1}
|
||||
|
||||
def set_nolog(self, code, data):
|
||||
self.set_int_data(code, data, 'nolog')
|
||||
return {'code': code, 'status': 1}
|
||||
return self.set_int_data(code, data, 'nolog')
|
||||
|
||||
def set_service_acquire(self, code, data):
|
||||
self.set_int_data(code, data, 'service_acquire')
|
||||
return {'code': code, 'status': 1}
|
||||
return self.set_int_data(code, data, 'service_acquire')
|
||||
|
||||
def set_uconf(self, code, data):
|
||||
# 透传模式不能配置
|
||||
@ -1958,14 +2106,71 @@ class BasicSettingCommand(object):
|
||||
return {'code': code, 'status': 0}
|
||||
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
|
||||
class ChannelTransfer(object):
|
||||
def __init__(self):
|
||||
self.dtu_c = DTUDocumentData()
|
||||
self.channel_dict = {}
|
||||
self.channel_dict = CHANNELS
|
||||
self.serial_channel_dict = dict()
|
||||
# self.control_code = None
|
||||
|
||||
@ -2050,22 +2255,6 @@ class DtuExecCommand(object):
|
||||
return {'code': cmd_code, 'status': 0, 'error': error_map.get(RET.POINTERR)}
|
||||
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
|
||||
class DTUOfflineHandler:
|
||||
@ -2099,7 +2288,9 @@ def modbus_crc(string_byte):
|
||||
gen_crc = hex(((crc & 0xff) << 8) + (crc >> 8))
|
||||
int_crc = int(gen_crc, 16)
|
||||
high, low = divmod(int_crc, 0x100)
|
||||
return high, low
|
||||
string_byte.append(high)
|
||||
string_byte.append(low)
|
||||
return string_byte
|
||||
|
||||
|
||||
"""=================================================== run ============================================================"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user