IOTOS物联中台modbus驱动对接雅达电表设备

本文章为原创,转载请注明出处!

登录平台:IOTOS®爱投斯物联中台

账号:iotos_test    密码:iotos123

代码地址:IOTOSDK-Python: IOTOS Python版本SDK,自带原生接口和采集引擎 (gitee.com)

目录

前言

驱动目的

适用范围

使用示例

驱动代码

驱动解析


  • 前言

        Modbus协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络例如以太网)和其它设备之间可以通信。它已经成为一通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。

        Modbus具有两种串行传输模式:分别为ASCII和RTU。Modbus是一种单主站的主从通信模式,Modbus网络上只能有一个主站存在,主站在Modbus网络上没有地址,每个从站必须有唯一的地址,从站的地址范围为0 - 247,其中0为广播地址,从站的实际地址范围为1 - 247。

        Modbus RTU通信以主从的方式进行数据传输,在传输的过程中Modbus RTU主站是主动方,即主站发送数据请求报文到从站,Modbus RTU从站返回响应报文。

  • 驱动目的

        驱动将以串口连接的雅达电表的数据拿到并上云

  • 适用范围

        雅达电表,以串口连接工控机或电脑

  • 使用示例

  •  首先,将雅达电表的串口连接至工控机或者电脑上:
  •  进入爱投斯中台,账号为iotos_test,密码为iotos123,创建网关

 

  • 填好网关名称后点击确认 

  • 创建设备示例点击【我的设备】 -> 【通信网关】 -> 【设备实例】->【创建设备】

  • 填写【设备名称】、选择刚刚创建的【模板驱动】和【通信网关】。参数topic为mqtt订阅的topic,用来拿去设备的数据,host和port为mqtt服务器的地址和端口号

  •  创建数据点,点击【我的设备】 -> 【通信网关】 -> 【设备实例】 -> 【数据点】,并在【设备实例】下拉列表选择刚刚创建的设备实例

 

  •  点击右边的创建数据点,填写名称

  并在高级配置中配置数据点的相关标志

 第一个点配置"private"属性用于驱动识别表示第一点

 其余的点配置point和index,point表示指向哪个点,index表示取第几个数据,下面示例为第二个数据点,这里point填第一个点的oid,index填1,后面的数据点一次,更改index获取不同位的数据即可

  •  在【我的设备】 -> 【通信网关】中找到刚才创建的网关,点击【高级】

  •  开启云网关,密码为账号密码

  • 点击 【我的设备】 -> 【通信网关】 -> 【设备实例】->【数据点】,选择刚才创建的设备实例

  •  即可查看数据已经上报成功

  • 驱动代码

  • 由于雅达电表与工控机或者电脑是串口连接,数据需要上报到线上的中台,但是工控机配置过低无法运行驱动文件,所以中间利用mqtt进行了数据的相关转移,若雅达电表连接的工控机或者电脑可以直接运行驱动则无需利用mqtt进行数据转移,可以直接上传至中台,这里的代码是包含了mqtt服务的。
  • 数据的获取和mqtt的发布(脚本)
# encoding: utf-8
# python 2.7
import random
import time
import threading
from paho.mqtt import client as mqtt_client
import serial
from serial import Serial
import modbus_tk.modbus_rtu as modbus_rtu

class info():
    def __init__(self):
        self.broker = '***.***.***.***' #mqtt服务器地址,需要自行填写
        self.port = ***    #mqtt的端口,需要自行填写
        self.topic_airc = "/python/mqtt/ammeter"
        # generate client ID with pub prefix randomly
        self.client_id = 'admin123'


    def connect_mqtt(self):
        def on_connect(client, userdata, flags, rc):
            if rc == 0:
                print("Connected to MQTT Broker!")
            else:
                print("Failed to connect, return code %d\n", rc)

        client = mqtt_client.Client(self.client_id)
        client.on_connect = on_connect
        client.connect(self.broker, self.port,60)
        return client


    def publish(self,client):
        while True:
            try:
                time.sleep(3)
                data_rtu = com_get_info()
                msg1 = data_rtu.master()
                msg_1 = "{}".format(msg1)
                result1 = client.publish(self.topic_airc, msg_1)
                status1 = result1[0]
                if status1 == 0:
                    print("Send {} to topic_airc {}".format(msg_1,self.topic_airc))
                else:
                    print("Failed to send message to topic_airc {}".format(self.topic_airc))
            except Exception,e:
                pass

    def run(self):
        self.client = self.connect_mqtt()
        self.client.loop_start()
        self.publish(self.client)

class com_get_info():
    def master(self):
        try:
            serialObjTmp = serial.Serial(port='com11', baudrate=9600, parity='N', bytesize=8, stopbits=1)
            master = modbus_rtu.RtuMaster(serialObjTmp)
            master.set_timeout(5)
            master.set_verbose(False)
            data7 = master.execute(6, 3, 0, 32)
            DLY601 = data7[0]*0.01
            DLY602 = data7[8]*0.01
            DLY603 = data7[16]*0.01
            DLY604 = data7[2]*0.0001
            DLY605 = data7[10]*0.0001
            DLY606 = data7[18]*0.0001
            DLY610 = data7[1]*0.01
            DLY611 = data7[9]*0.01
            DLY612 = data7[17]*0.01
            DLY607 = data7[27]*0.00106813
            DLY608 = (DLY601*DLY604+DLY602*DLY605+DLY603*DLY606)*0.001
            DLY609 = data7[29]*0.0001
            data_amm = (DLY601,DLY602,DLY603,DLY604,DLY605,DLY606,DLY610,DLY611,DLY612,DLY607,DLY608,DLY609,)
        
            return data_amm 
        except Exception,e:
            pass


if __name__ == '__main__':
    info = info()
    self = info.run()
  • mqtt的订阅,并将获得的数据上传至中台(驱动文件)
#!coding:utf8
import sys

sys.path.append("..")
from driver import *
import json
import time
import random
import paho.mqtt.client as mqtt

reload(sys)
sys.setdefaultencoding('utf8')

def on_subscribe(client, userdata, mid, granted_qos):
    print("On Subscribed: qos = %d" % granted_qos)


def on_disconnect(client, userdata, rc):
    if rc != 0:
        print("Unexpected disconnection %s" % rc)

_msg=''
class XyDriver(IOTOSDriverI):
    def on_connect(self,client, userdata, flags, rc):
        print("Connected with result code " + str(rc))
        client.subscribe(self._topic)  # 订阅消息

    def on_message(self, client, userdata, msg):
        self.debug(msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
        # a = msg.payload
        global _msg
        _msg=tuple(eval(msg.payload))
        self.debug('data is collected')
        self.debug(_msg)

    def InitComm(self, attrs):
        self.online(True)
        self.setPauseCollect(False)
        self.setCollectingOneCircle(False)
        #获取中台填写的mqtt地址,端口以及需要订阅的topic
        self._topic = self.sysAttrs['config']['param']['topic']
        self._host = self.sysAttrs['config']['param']['host']
        self._port = self.sysAttrs['config']['param']['port']
        self.client=mqtt.Client()
        self.client.on_connect = self.on_connect
        self.client.on_message = self.on_message
        self.client.on_subscribe = on_subscribe
        self.client.on_disconnect = on_disconnect
        self.client.username_pw_set(username='', password='')
        # 连接到服务器
        self.client.connect(host=self._host.encode('utf-8'), port=self._port, keepalive=60)
        self.client.loop_start()


    def Collecting(self, dataId):
        try:

            # self.debug('111111111111111111111111111')
            self.client.on_message=self.on_message
            # self.debug('22222222222222222222222222')
            self.debug(_msg)
            if 'private' in self.data2attrs[dataId]['config']['param'] and self.data2attrs[dataId]['config']['param']['private']=='first_point':
                if type(_msg)==tuple:
                    return _msg
            else:
                return ()
        except Exception as e:
            self.debug('error'+e)

  • 驱动解析

  • 编写环境为python2(python3也可以),首先需要导入modbus_tk和paho.mqtt等、数据解析和modbus通讯的相关包
# encoding: utf-8
# python 3.6
import random
import time
import threading
from paho.mqtt import client as mqtt_client
import serial
from serial import Serial
import modbus_tk.modbus_rtu as modbus_rtu
  •  利用modbus_tk里面的modbus_rtu打开服务器的串口并向其发送指令,其中serialObjTmp = serial.Serial(port='com11', baudrate=9600, parity='N', bytesize=8, stopbits=1)中port表示串口号,baudrate表示波特率 parity表示校验位,timeout表示超时时间。打开串口后利用master.execute(6, 3, 0, 32)向串口发送数据,得到数据后依据协议文档进行数据处理。
class com_get_info():
    def master(self):
        try:
            serialObjTmp = serial.Serial(port='com11', baudrate=9600, parity='N', bytesize=8, stopbits=1)
            master = modbus_rtu.RtuMaster(serialObjTmp)
            master.set_timeout(5)
            master.set_verbose(False)
            data7 = master.execute(6, 3, 0, 32)
            DLY601 = data7[0]*0.01
            DLY602 = data7[8]*0.01
            DLY603 = data7[16]*0.01
            DLY604 = data7[2]*0.0001
            DLY605 = data7[10]*0.0001
            DLY606 = data7[18]*0.0001
            DLY610 = data7[1]*0.01
            DLY611 = data7[9]*0.01
            DLY612 = data7[17]*0.01
            DLY607 = data7[27]*0.00106813
            DLY608 = (DLY601*DLY604+DLY602*DLY605+DLY603*DLY606)*0.001
            DLY609 = data7[29]*0.0001
            data_amm = (DLY601,DLY602,DLY603,DLY604,DLY605,DLY606,DLY610,DLY611,DLY612,DLY607,DLY608,DLY609,)
        
            return data_amm 
        except Exception,e:
            pass


if __name__ == '__main__':
    info = info()
    self = info.run()
  • 读取数据并处理后返回,利用mqtt将其发布到对应的topic
class info():
    def __init__(self):
        self.broker = '***.***.***.***' #mqtt服务器地址,需要自行填写
        self.port = ***    #mqtt的端口,需要自行填写
        self.topic_airc = "/python/mqtt/ammeter"
        # generate client ID with pub prefix randomly
        self.client_id = 'admin123'


    def connect_mqtt(self):
        def on_connect(client, userdata, flags, rc):
            if rc == 0:
                print("Connected to MQTT Broker!")
            else:
                print("Failed to connect, return code %d\n", rc)

        client = mqtt_client.Client(self.client_id)
        client.on_connect = on_connect
        client.connect(self.broker, self.port,60)
        return client


    def publish(self,client):
        while True:
            try:
                time.sleep(3)
                data_rtu = com_get_info()
                msg1 = data_rtu.master()
                msg_1 = "{}".format(msg1)
                result1 = client.publish(self.topic_airc, msg_1)
                status1 = result1[0]
                if status1 == 0:
                    print("Send {} to topic_airc {}".format(msg_1,self.topic_airc))
                else:
                    print("Failed to send message to topic_airc {}".format(self.topic_airc))
            except Exception,e:
                pass

    def run(self):
        self.client = self.connect_mqtt()
        self.client.loop_start()
        self.publish(self.client)
  • 驱动文件(订阅并将数据上传至中台),首先先导入mqtt和驱动运行的依赖文件
#!coding:utf8
import sys

sys.path.append("..")
from driver import *
import json
import time
import random
import paho.mqtt.client as mqtt

reload(sys)
sys.setdefaultencoding('utf8')

  • 初始化mqtt和驱动,获取中台上设备示例的配置并且连接至mqtt
def on_subscribe(client, userdata, mid, granted_qos):
    print("On Subscribed: qos = %d" % granted_qos)


def on_disconnect(client, userdata, rc):
    if rc != 0:
        print("Unexpected disconnection %s" % rc)

_msg=''
class XyDriver(IOTOSDriverI):
    def on_connect(self,client, userdata, flags, rc):
        print("Connected with result code " + str(rc))
        client.subscribe(self._topic)  # 订阅消息

    def on_message(self, client, userdata, msg):
        self.debug(msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
        # a = msg.payload
        global _msg
        _msg=tuple(eval(msg.payload))
        self.debug('data is collected')
        self.debug(_msg)

    def InitComm(self, attrs):
        self.online(True)
        self.setPauseCollect(False)
        self.setCollectingOneCircle(False)
        self._topic = self.sysAttrs['config']['param']['topic']
        self._host = self.sysAttrs['config']['param']['host']
        self._port = self.sysAttrs['config']['param']['port']
        self.client=mqtt.Client()
        self.client.on_connect = self.on_connect
        self.client.on_message = self.on_message
        self.client.on_subscribe = on_subscribe
        self.client.on_disconnect = on_disconnect
        self.client.username_pw_set(username='', password='')
        # 连接到服务器
        self.client.connect(host=self._host.encode('utf-8'), port=self._port, keepalive=60)
        self.client.loop_start()
  • 循环采集订阅拿到的数据并且上传至中台
def Collecting(self, dataId):
        try:

            # self.debug('111111111111111111111111111')
            self.client.on_message=self.on_message
            # self.debug('22222222222222222222222222')
            self.debug(_msg)
            #只采集第一个点并将订阅得到的数据返回
            if 'private' in self.data2attrs[dataId]['config']['param'] and self.data2attrs[dataId]['config']['param']['private']=='first_point':
                if type(_msg)==tuple:
                    return _msg
            else:
                return ()
        except Exception as e:
            self.debug('error'+e)

 至此,雅达电表驱动的开发完成,即可实现精密空调的数据上云

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IOTOS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值