有人物联口红DTU DR154配置与RS 485传感器数据处理

一、硬件设备

(1)有人物联口红DTU DR154(RS 485版本)
在这里插入图片描述
配置的话通过小程序【联博士】蓝牙配置(手机扫描DTU背后的二维码即可,蓝牙密码也在背面),省去了连接电脑硬件配置的繁琐步骤。

(2)温度传感器:速灵科RSDS5 (RS485接口)
在这里插入图片描述
注意速灵科RSDS5 设备地址默认为1,如果有多个传感器,需要设置不同地址,后面会介绍如何设置。
(3)12V电源适配器:为DTU和温度传感器供电

(4)腾讯云服务器
本博客是以自有的云服务器数据处理为例进行介绍的,使用有人云的例子请参考官网教程

二、设备参数配置

速灵科RSDS5参数配置

如果只有一个传感器,使用默认的地址即可,然后写hex指令读取温度(重点参考官网教程:http://www.jingsudz.com/Product/14625081.html):
在这里插入图片描述
【问题来了】,如果有多个传感器设备,那么需要配置寄存器,功能码为【06】,官方例子如下:
在这里插入图片描述
例子中没有说CRC校验位如何计算,产品说明提供了一段计算代码:
在这里插入图片描述
但更简单的方法是打开传感器对应的调试软件(可以不接传感器,需要打开串口),选择需要设置的参数,在下方会显示对应的hex指令,比如我现在有一个传感器默认地址是1,要设置地址为2,那么对应的指令为:
01060001000259CB01代表当前设备地址,06为写寄存器功能码,0001为设备地址寄存器(2个字节),0002为写入的设备地址(2个字节,范围1-255,这里设置为2),59CB为CRC校验位,2个字节。
以上设置完成后,再发送指令读取一下设备地址释放更改成功:
02 03 00 01 00 01 D5 F9
在这里插入图片描述

如果传感器还没接上DTU,那么可以使用速灵科对应的软件按照上述方法进行设置,如果已经安装在DTU上不想拆下来,也可以通过DTU自带的串口功能发送hex指令进行设置,首先通过小程序【联博士】连接DTU,选择【串口调试】,设置如下:
在这里插入图片描述

DTU DR154网络配置(心跳包,注册包)

DTU DR154支持4路独立socket连接,首先通过小程序【联博士】连接DTU,选择【参数设置】,设置如下:

  • 工作模式:网络透传模式
  • SOCK A开关:【地址】:‘xx.xx.xx.xx服务器地址’, 【端口号】:20086,【连接类型】:TCP协议,【连接方式】:长连接,如果有需要可以设置其他3路
  • 注册包和心跳包的设置如下图所示:
    在这里插入图片描述

三、服务器TCP服务

1.启用发送串口心跳包

如果启用了心跳包功能,会定时向服务器发送数据,此时在服务器上运行tcp服务用于监测和保存数据,代码如下:

# coding=gbk
'''
有人DTU DR154数据接收理服务,监听端口:20086,时间间隔300s

   速灵科 RS485读取温度指令:
   01  设备地址
   03  读指令功能码
   00  寄存器起始,地址高
   00  寄存器起始,地址低
   00  读取数量,高位
   01  读取数量,低位
   84  CRC校验,高位
   0A  CRC校验,低位
   
   返回数据:
   01  返回设备地址
   03  功能码
   02  返回数据数量,2个字节
   01  字节1,高位
   11  字节2,低位
   79  校验位,高位
   D8  校验位,低位
   
   有人DTU DR154设备返回数据:ICCID码+速灵科温度传感器返回数据(hex格式),例如:
   '89861122229046607070\x01\x03\x02\x00\xf9x\x06'

'''
import socketserver
import time
import os
import logging
logging.basicConfig(level=logging.DEBUG,#控制台打印的日志级别
                   filename='error.log',
                   filemode='a',##模式,有w和a,w就是写模式,每次都会重新写日志,覆盖之前的日志
                   #a是追加模式,默认如果不写的话,就是追加模式
                   format=
                   '%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'
                   #日志格式
                   )

class MyTCPHandler(socketserver.BaseRequestHandler):
   """
   1.读取数据
   2.分割数据
   3.温度转换
   4.数据显示
   5.数据保存
   """
   def save_data(self, data:str, file_root='data.txt'):
       with open(file_root,'a+') as f:
           f.write(data+'\n')
           
   def handle(self):
       # self.request is the TCP socket connected to the client
       # self.data = self.request.recv(1024)
       print("{} wrote:".format(self.client_address[0]))
       self.request.sendall(b'\x01\x03\x00\x00\x00\x01\x84\x0A')
       localtime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
       # print("{} wrote:".format(self.client_address[0]))
       try:
         self.data = self.request.recv(1024)
         IMEI, temp = self.data.split(b'\x01')[0].decode(), int(self.data.split(b'\x01\x03')[1][1:3].hex(),16)/10.0
         # time, IMEI, temperature
         tcpmsg = f'{localtime}, {IMEI}, {temp}'
         self.save_data(tcpmsg)
         print(tcpmsg)
         
       except:
         print('Failed to parse data: ', self.data)
         logging.debug(f'Failed to parse data!, raw data is: {self.data}')


if __name__ == "__main__":
   # 腾讯云服务器内网地址 
   HOST, PORT = "xxx.xxx.xxx.xxx", 20086
   socketserver.TCPServer.allow_reuse_address = True
   # Create the server, binding to localhost on port 9999
   with socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler) as server:
       # Activate the server; this will keep running until you
       # interrupt the program with Ctrl-C
       # 设置线程数量
       server.daemon_threads = True
       server.max_threads = 4
       server.serve_forever()

2.未启用发送串口心跳包

如果未启用心跳包功能,那么需要通过tcp服务器定时发送hex温度获取指令,python代码如下(简单版本):

# coding:gbk

from socket import *
from time import ctime
import time
print("=====================时间戳TCP服务器=====================");

HOST, PORT = "xxx.xxx.xxx.xxx", 20086
BUFSIZ = 1024  #接收数据缓冲大小
ADDR = (HOST, PORT)

tcpSerSock = socket(AF_INET, SOCK_STREAM) #创建TCP服务器套接字
tcpSerSock.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
tcpSerSock.bind(ADDR)  #套接字与地址绑定

tcpSerSock.listen(5) #监听连接,同时连接请求的最大数目
data = None

while True:
   print('等待客户端的连接...')
   tcpCliSock, addr = tcpSerSock.accept()   #接收客户端连接请求
   print('取得连接:', addr)

   while True:
       tcpCliSock.sendall(b'\x01\x03\x00\x00\x00\x01\x84\x0A') # 发送16进制指令
       localtime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
       try:
           data = tcpCliSock.recv(BUFSIZ)  #连续接收指定字节的数据,接收到的是字节数组
           IMEI, temp = data.split(b'\x01')[0].decode(), int(data.split(b'\x01\x03')[1][1:3].hex(),16)/10.0
           tcpmsg = f'{localtime}, {IMEI}, {temp}'
           print(tcpmsg)
       except:
           print('Failed to parse data: ', data)
       time.sleep(1) # 间隔1秒

   tcpCliSock.close()  #关闭与客户端的连接
tcpSerSock.close()  #关闭服务器socket

4.服务器python dash Web服务

使用python dash库在服务器端构建一个简单的web服务,然后用waittress-serve部署即可(waittress-serve可以通过pip安装),服务端代码如下:

'''
dash_app.py,dash app应用
'''
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import plotly.express as px
from dash import Dash, dcc, html, Input, Output
import dash_bootstrap_components as dbc
import dash_auth
import random
import datetime
import time

def fetch_youren_data(plot=False):
    data_file= 'data.txt'
    # IMEI: 460042216617235, 460042216617237
    df = pd.read_table(data_file, sep=',', names=['date','sn','temperature'])
    df.date = pd.to_datetime(df.date)
    return df

app = Dash(__name__,external_stylesheets=[dbc.themes.BOOTSTRAP])
server = app.server
df = fetch_youren_data()
fig = px.line(df,x="date", y='temperature',)
# 定义用户名和密码
VALID_USERNAME_PASSWORD_PAIRS = {
    'aaa': 'bbbccc'
}
Auth = dash_auth.BasicAuth(
    app,
    VALID_USERNAME_PASSWORD_PAIRS
)

app.layout = dbc.Container(
    [
    html.H2('有人DR154 Iot温度数据展示',style={'textAlign': 'center'}),
    html.Hr(),
    html.Div(id='time_label'),
    dcc.Graph(id="graph", figure=fig),

    dcc.Interval(
        id='interval-component',
        interval=1*1000, # in milliseconds
        n_intervals=0
    ),
    dcc.Interval(
        id='interval-time',
        interval=5*1000, # in milliseconds
        n_intervals=0
    )
],
  fluid=True,
)

@app.callback(Output('time_label', 'children'),
              Input('interval-component', 'n_intervals'))
def update_time(n):
    now = datetime.datetime.now()
    current_time = now.strftime("%Y-%m-%d %H:%M:%S")
    style = {'padding': '5px', 'fontSize': '16px'}
    return html.Span('{}'.format(current_time), style=style)
    
@app.callback(
    Output("graph", "figure"),
    Input('interval-time', 'n_intervals')
    )
def update_graph(n):
    # update data  
    df = fetch_youren_data()
    fig = px.line(df,x="date", y='temperature',)
    fig.update_yaxes(title_text="temperature")
    return fig

if __name__ == "__main__":

    app.run(host='0.0.0.0', port=20088, threaded=True)

然后执行下来命令进行部署:

 waitress-serve --port=8050 dash_app:app.server

效果如下:
在这里插入图片描述

存在的问题:

  • 数据太多dash绘图会很慢,可以按天存储,或者通过pandas筛选一些数据,也可以增加心跳包的发送间隔时间
  • web服务运行一段时间后服务器CPU资源会爆满,目前暂时没有解决方案
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值