前言
电信物联网官网:https://www.ctwing.cn
注册登录:可以参考我之前的一篇文章有介绍 :
https://blog.csdn.net/weixin_45603792/article/details/122982468
一、准备工作?
1. 先进入官网的在线文档阅读下平台的TCP协议规范:https://www.ctwing.cn/sbjr/67#see
- 获取TPC接入地址和端口
通信协议 | 地址 | 端口 |
---|---|---|
TCP | tcp.ctwing.cn | 8996 |
2. TCP业务数据流程:[https://www.ctwing.cn/sbjr/71#see](https://www.ctwing.cn/sbjr/71#see) - 大致了解下TCP业务数据流程,登录、上报、心跳交互方式
3. 接口介绍:https://www.ctwing.cn/sbjr/70#see
- 通过接口介绍文档示例能更清晰的了解登录请求、数据上下行以及响应和心跳的消息格式
本篇介绍非透传物模型接入:
消息类型 | 类型描述 | 消息格式 | 备注 |
---|---|---|---|
0x01 | 登录请求 | 0x01 +deviceId_length(2字节) +deviceId +password_length(2字节) +password +version_length(2字节) +version | deviceId是由产品ID和设备编号拼接而成的字符串; password由平台生成,在设备管理业务可以查看; version固定1.1 业务数据非透传格式遵循物模型,上下行业务数据需要响应。 |
0x02 | 上行数据报文 | 0x02+数据长度(2字节)+msgid(2字节)+serviceid(2字节)+param1+params2+param3+…… | 数据长度:从msgid开始,到报文结尾的长度;msgid:报文标识,由终端分配;serviceId:平台分配的服务ID;param:平台服务包含的属性 |
0x82 | 上行数据响应 | 0x82+数据长度(2字节)+msgid(2字节)+结果码(2字节) | 数据长度:从msgid开始,到报文结尾的长度;msgid:报文标识,跟上行报文中msgid对应;结果码:0-成功、1-报文解析失败数据长度:从msgid开始,到报文结尾的长度;msgid:报文标识,由平台分配;serviceId:平台分配的服务ID;param:平台服务包含的属性(参数)注:msgid字段即为指令的taskId |
0x03 | 下行数据报文 | 0x03+数据长度(2字节)+msgid(2字节)+serviceId(2字节)+param1+param2+param3+…… | 数据长度:从msgid开始,到报文结尾的长度;msgid:报文标识,对应下行指令中的msgid;结果码:0-成功,不带serviceId和参数;1-成功,带serviceId和参数;2-下行数据处理失败,不带serviceId和参数 |
0x83 | 下行数据响应 | 0x83+数据长度(2字节)+msgid(2字节)+结果码(2字节)+serviceId(2字节)+param1+param2+param3+…… | 数据长度:从msgid开始,到报文结尾的长度;msgid:报文标识,对应下行指令中的msgid;结果码:0-成功,不带serviceId和参数;1-成功,带serviceId和参数;2-下行数据处理失败,不带serviceId和参数 |
0x04 | 心跳 | 0x04 | 平台心跳周期为5分钟,设备需在5分钟内发送心跳报文 |
0x05 | 登录响应 | 0x05+结果码(2字节) | 登录结果:0-成功;1-未知错误;2-设备未注册;3-设备认证失败 |
0x06 | 心跳响应 | 0x06 | 平台回复终端心跳报的响应 |
二、使用步骤
计算工具:
- 文本转十六进制: https://www.sojson.com/hexadecimal.html
- 整数(浮点数)转十六进:https://lostphp.com/hexconvert/
提示:消息格式应用层数据报文以1个字节的类型字段作为分割,平台支持登录、心跳、上下行业务数据等消息类型。消息携带的参数必须包含两个字节的参数长度。
1.登录请求
- 根据电信天翼物联在线文档提供的示例,我们需要用的到参数有:
-
消息类型:
消息类型:01
-
设备ID
设备ID DeviceId:1009599120200917
文本转十六进制:31303039353939313230323030393137
长度:32/2
十转十六进制:0010 -
特征串:
特征串 PassWord:STLOAndMeriUzOgQIGkiEE5FCU7vLkyXeGiE-3mjlnM
文本转十六进制:53544c4f416e644d657269557a4f675149476b6945453546435537764c6b7958654769452d336d6a6c6e4d
长度:86/2
十转十六进制:002b -
版本号:
版本号 version:1.1 版本号为固定值
文本转十六进制:312e31
长度:6/2
十转十六进制:0003 -
登录报文:
登录请求完整报文:01001031303039353939313230323030393137002b53544c4f416e644d657269557a4f675149476b6945453546435537764c6b7958654769452d336d6a6c6e4d0003312e31
-
登录代码如下(主体):
rom socket import * # 1.创建套接字 tcp_socket = socket(AF_INET, SOCK_STREAM) tcp_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, True) serve_ip = '180.106.148.146' # 接入地址 serve_port = 8996 # 端口 # 2.准备连接服务器,建立连接 tcp_socket.connect((serve_ip, serve_port)) # 连接服务器,建立连接,参数是元组形式 # tcp登录验证 # @logon 登录报文 logon = '01001031303039353939313230323030393137002b53544c4f416e644d657269557a4f675149476b6945453546435537764c6b7958654769452d336d6a6c6e4d0003312e31' tcp_socket.send(bytes.fromhex(logon)) tcp_reMsgData = tcp_socket.recv(1024).hex() # 注意这个1024byte,大小根据需求自己设置 print('登录响应:', tcp_reMsgData) # 响应回复
-
登录响应:
登录响应: 050000
-
通过平台设备管理查看到设备已激活并在线
2. 发送数据
-
消息类型
02
-
服务ID和属性值
msgId:0001
serviced:0001 (自定义标识数)
payload:current_temperature:000a
current_humidity:000a总体长度:24/2
十转十六进:000c -
上行报文:
发送数据完整报文: 02000c000100010000000a0000000a
-
上报代码如下(示例):
# 发送数据 send_data = '02000c000100010000000a0000000a' hex_bytesData = bytes.fromhex(send_data) tcp_socket.send(hex_bytesData) tcp_reMsgData = tcp_socket.recv(1024).hex() # 注意这个1024byte,大小根据需求自己设置 print('上行数据报文:', tcp_reMsgData)
-
上行数据报文响应:
82000400010000
-
通过平台数据查看上报数据:
3. 指令下发及响应
- 通过平台设备管理页面右侧指令下发按钮实现下模拟下发功能:
- 创建持续接入接收代码如下(示例):
while True: tcp_reMsgData = tcp_socket.recv(1024).hex() # 注意这个1024byte,大小根据需求自己设置 print(tcp_reMsgData)
- 收到下发指令完整报文:
03000500021f4701
数据类型 | 参数长度 | 指令ID | 服务ID | 参数值 |
---|---|---|---|---|
03 | 0005 | 0002 | 1f47 | 01 |
- 0002为taskId,携带taskId响应回复:
数据类型 | 参数长度 | 指令ID | 结果码(自定义) | 服务ID(10转16进) | 参数值 |
---|---|---|---|---|---|
83 | 0007 | 0002 | 0001 | 232f | 01 |
- 指令响应回复完整报文:
83000700020001232f01
-
响应回复代码(示例):
send_data = '83000700020001232f01' hex_bytesData = bytes.fromhex(send_data) tcp_socket.send(hex_bytesData) tcp_reMsgData = tcp_socket.recv(1024).hex() # 注意这个1024byte,大小根据需求自己设置 print('下行数据响应:', tcp_reMsgData)
- 平台指令下发日志显示已完成,并查看是否有返回内容:
三、多线程收发数据
import time
from socket import *
import threading
# 这里我设计了填写设备id和特征串自动计算与上报数据自动计算十六进的两个方法,有兴趣的可以联系我。
from TCP.TCP_Logon import Logon
from TCP.TCP_hex import HexMain
# 接收平台消息并对指令响应做自动回复
def read(TCP_Socket):
while True:
recv_data = TCP_Socket.recv(1024)
if recv_data:
receiveData = recv_data.hex()
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())), '收到的信息:', receiveData)
typeNum = receiveData[0:2]
if typeNum == '05':
print('登录成功响应回复::', receiveData)
if typeNum == '03':
taskId = receiveData[6:10]
servicedId = int(receiveData[10:14], 16) + 1000
response = '830007' + taskId + '0001' + hex(servicedId)[2:6] + receiveData[14:16]
TCP_Socket.send(bytes.fromhex(response))
print('指令响应成功回复:', response)
elif typeNum == '82':
print('数据上报响应回复', receiveData)
elif typeNum == '06':
print('心跳响应成功回复:', receiveData)
'''
温度10湿度10:02000c000100010000000a0000000a
'''
# 登录请求
def write(TCP_Socket):
logon = '01001031303039353939313230323030393137002b53544c4f416e644d657269557a4f675149476b6945453546435537764c6b7958654769452d336d6a6c6e4d0003312e31'
# logon = Logon('1009599120200917', 'STLOAndMeriUzOgQIGkiEE5FCU7vLkyXeGiE-3mjlnM')
TCP_Socket.send(bytes.fromhex(logon))
time.sleep(0.5)
while True:
# serviceId, *data = map(int, input('\033[1;39;33m''(服务id,*data)以逗号隔开:\n''\033[0m').split(','))
# data = HexMain(serviceId, data)
# TCP_Socket.send(bytes.fromhex(data))
inputData = input('\033[1;39;33m''请键入上报数据:\n''\033[0m')
TCP_Socket.send(bytes.fromhex(inputData))
time.sleep(2)
# 平台心跳最大5分钟
def heartbeat(TCP_Socket):
while True:
time.sleep(300)
Time = '04'
TCP_Socket.send(bytes.fromhex(Time))
def main():
tcp_socket = socket(AF_INET, SOCK_STREAM)
tcp_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, True)
# serve_ip = '192.168.186.1'
# serve_port = 5555
serve_ip = '180.106.148.146'
serve_port = 8996
tcp_socket.connect((serve_ip, serve_port)) # 连接服务器,建立连接,参数是元组形式
Threading1 = threading.Thread(target=read, args=(tcp_socket,))
Threading2 = threading.Thread(target=write, args=(tcp_socket,))
Threading3 = threading.Thread(target=heartbeat, args=(tcp_socket,))
Threading1.start()
Threading2.start()
Threading3.start()
# 客户端套接字关闭
# tcp_socket.close() #服务器一般不关闭 此时服务端口因为需要一直执行所以也不能关闭
if __name__ == '__main__':
main()
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容