docker版jxTMS使用指南:代码文件说明

本文讲解4.2版jxTMS的python代码的组织,整个系列的文章请查看:docker版jxTMS使用指南:4.2版升级内容

docker版本的使用,请参考docker版jxTMS使用指南

4.0版jxTMS的说明,请查看:4.0版升级内容

docker版jxTMS的主目录是/home/tms目录,python代码放在/home/tms/python/目录下,后文所有相对路径的文件名或目录名,都是相对于/home/tms/python/目录。

数据类定义

在app/data/目录中统一存放业务需要使用到的数据类的定义与注册。整个python服务还有三个数据类是定义jx目录中的:

  • Site:保存站点信息的数据类

  • Device:保存设备信息的数据类

  • dsLog:保存站点、设备的状态信息

数据类的定义比较简单,直接和data文件中同名数据类进行对比一下就可以了。

数据类有三种相关功能可能需要注册:

  • ORM.register:将本数据类注册到ORM中,这样getBy等ORM功能才能使用

  • Device.register:保存设备数据的类需要将本数据类的创建函数注册到Device中,这样device设备在启动时才能正确的创建本设备所对应的保存设备数据的数据对象

  • ORM.registerSQL_createTable:为本数据类注册对应的数据表create table语句。jxTMS的数据管理主要是由java平台负责的,python服务是不负责数据库管理的。但部署在现场的从站考虑到种种限制是没有启动java主控平台的,所以python服务就必须接管数据库管理。为此,就需要注册自己的建表语句

python服务的数据库管理主要包括两个功能:

1、建表

调用ORM.createTable,就会创建所有通过ORM.registerSQL_createTable注册的数据类。

2、自动分表

每天零点,jxTMS都会检查通过ORM.registerSQL_createTable注册的数据类,如果指定了分表类型,就会在指定的时间完成分表工作

  • 分表类型为【day,即按天分表】的每天都会分表

  • 分表类型为【month,即按月分表】的每月1号会分表

  • 分表类型为【year,即按年分表】的每年的1月1号会分表

配置

在python目录中执行:

python3 catLocal.py

会显示local.pickle文件中的配置信息【忽略大量的日志信息】,配置信息以json格式保存,只有一个local节点,该节点下有五个子节点:

  • mqqtTopics:当前订阅的mqtt主题

  • allSite:当前配置的所有站点,目前配置了demoZhan01、hbc01两个站点

  • allResource:当前的所有资源,只定义了一个资源:vrs20-01,其属于web_op资源组

  • allUser:当前的mqtt所有用户,只定义了一个demoUser01,其指派了webServer角色

  • allRight:所有的权限,即【资源组-op-角色】关系,当前只定义了web_op资源组中的资源可以被角色是webServer的用户执行getDeviceData操作

后三者的权限配置目前只用于通过web端口10028提供REST访问,demoUser01用户登录后,可访问/api/getDeviceData来读取vrs20-01的实时数据。

站点

allSite是最为重要的一个配置,其指定了jxTMS的python服务中要启动的站点及其下属的设备:

1、demoZhan01站点:

{
	"name": "demoZhan01", 
	"type": "vrs20",
	"devices": 
		[{
			"name": "vrs20-01", 
			"saveDataInterval": "15", 
			"timeOut": "180", 
			"timeOutCheckInterval": "1", 
			"type": "vrs20"
		}],
}

其类型为vrs20,但我们找遍所有代码文件,都没有该类型的站点定义,所以其使用的就是最基本的site对象【单设备推送型站点】来管理设备以及传递设备数据。

其devices中只定义了一个设备:vrs20类型的vrs20-01。我们可以在app/vrs20目录中找到三个py文件:

  • device.py,定义了vrs20类型的设备的特殊处理,主要是如何设置潮位仪的标高以计算实际的潮水水位。最后,其还调用device.register注册了vrs20类型设备由dev_vrs20类进行处理

  • policy.py,定义了vrs20类型的设备接收到前端设备发送的消息字符串后该如何进行解析。当然也要进行注册,才能被设备正确加载

  • dualResult.py,定义了vrs20类型的设备的操作后处理【参考python服务之设备策略一文中的第五点:给操作后得到的数据增加SLA】,这个后处理并不是在接收到数据时进行的,而是用户在执行操作后对操作后的数据所做的后处理,如某个用户获取到海图的信息后,根据其等级,要执行精度上的限制。当然也要进行注册,才能在用户执行完操作后被正确加载

注:某类型数据的操作后处理如果未定义,则返回原始数据。这样由于疏忽、错误等就可能会导致泄露,可针对该类型数据,先注册一个【default】型的最低水平的后处理,这样就不会有泄露了

2、hbc01站点:

其类型为:sp30h_slave。而在【app/sinosoarSP30H/site_slave.py】中就定义并注册了sp30h_slave类型的站点。

大家在app/sinosoarSP30H/目录中可以看到还有一个sp30h_master.py文件,其定义了sp30h_master类型的站点,这主要是业务需要主从站点:

  • 现场的从站从现场设备采集modbus设备的数据,并进行本地保存等业务处理,然后通过mqtt推送给数据中心的主站

  • 主站只负责接收并保存数据

sp30h_slave主要完成三个任务:

1、配置并启用数据源

其启用了一个modbus类型的数据源【在module/dataSource_modbus.py中定义并注册】,并为其进行相关的配置,并提供了数据源所需要的后处理函数、消息回送通知函数、回送数据的保存等

2、主从同步

这主要包括三部分工作:

  • 网络连通时接收到数据就直接向主站推送

  • 当网络断开【MQTT失去连接】时保存断连时间点

  • 当网络连接恢复后,将断连时间至连接恢复的时间点内的数据从数据库中读出然后发送给主站

注1:主从同步的数据是支持分表的,即从站读取数据时,如果该数据保存在分表中,则会自动从相应的分表中读取;而主站在收到丢失的数据时,如果已经不是当天的数据了,也会自动识别插入到相应的分表中

注2:行文到此,才发现有一个bug导致主站不会完成分表的自动插入,而会全部插入到当天的表中。由于已经将镜像push到docker hub上了,读者可自行修复,很简单的:在app/data目录的DieselGenerator.py、EnergyStorage.py、PCS.py三文件中在各自数据类的__init__函数后添加一个对象函数即可:

def renameType(self):
    return 'day'

继承自ORM的数据类在重载了renameType函数并返回自己的分表级别【此三表都是按天分表】后,在插入时jxTMS会自动识别并根据待插入的数据的创建时间来确定应该插入到哪个表中。

3、为下属设备操作数据源提供支持

封装了数据源的addWantReceive、addWantReceive两函数。

设备

hbc01站点的配置中还定义了三个设备,这些设备类型中带【_slave】后缀的设备,其相应的定义与注册都在app/sinosoarSP30H/目录中的相应代码文件中。

这三个slave的device,主要有两个工作:

1、利用站点提供的addWantReceive函数添加数据点的拉取参数

拉取时所需要的从站地址、功能码、寄存器号、读取数量,都是根据设备厂家提供的手册来确定就好了。

需要注意的是,每个数据点笔者都设置了productStatement表达式,而大家仔细看site_slave.py中sp30h_slave的构造函数,其默认了:Test=True,所以数据源会工作在Test模式下,这样的话,大家虽然没有接modbus设备,但启动主程序后:

cd /home/tms/python
python3 main.py

大约过了几分钟,系统就会突突的吐出数据了。这些数据就是由这些productStatement所指定的表达式自动产生的。

有了这个功能,我们就可以脱离现场环境来测试整个业务处理过程了,最后再把Test改为False进行实机测试就可以了。

2、在onReceive函数中对拉取到的数据进行类型转换

modbus一个寄存器只有16位,有些数据16位太小,有的厂家是通过读同一个寄存器号的多个寄存器来实现扩容;有的厂家是通过读多个寄存器号来扩容的。

而且有的是16位有符号、有的是16位无符号。所有这些都需要在拉取到数据后进行相应的转换与合并。我们虽然在数据源中指定了后处理函数,但后处理函数是针对整个数据源统一处理的,所以笔者将这些具有语义特点的转换与合并都放到了数据点拉取参数定义的相应的设备类中了。

而设备中比较好的地方就是onReceive事件响应函数,其在设备的recevie函数中触发。

注:大家看local.pickle文件中的配置时,会发现dg-sp30h-01、es-sp30h-01两设备还指定了参数【“id”: 0】,其中这主要是由于这两种设备的modbus参数中,都是按设备号来确定寄存器号或从站地址的,如从寄存器号500开始是第一台设备的实时数据,520开始的是第二台设备的实时数据。笔者在示例中都只保留了一台设备的配置,有多台设备时需要利用id来确定各设备实际的modbus拉取参数

主站及其设备

大家看下带master的py文件就理解了,非常简单,就是简单继承并注册而已。笔者还一定要写这几个看起来有点多余的代码文件的原因有两个:

1、设置配置参数

这里主要是将各设备的延时周期设为600秒,超时检测间隔timeOutCheckInterval设为6分钟,最重要的是把数据保存间隔saveDataInterval设为了0分钟,即每次拉取到数据就立刻保存。

2、执行自己的特殊处理

sp30h_master重载了receive函数。这是因为默认的site是单设备推送型站点,而sp30h_master站点是多设备推送型站点【数据由sp30h_slave通过MQTT推送】

注:sp30h_slave站点是多设备拉取型站点

建议大家还是针对每种新的站点类型、设备类型专门编写各自的处理类并注册,这样需要增加特殊处理时只需要修改相应的代码文件即可。关键是其他人阅读与理解起来也非常容易,不会出现对因为采用了默认站点和默认设备的处理而无法理解系统是如何工作的困惑

自动注册

由于jxTMS全面采用了【按类型注册-配置时按类型生成】模式来松弛整个系统,所以预先加载所有需注册的功能模块就很有必要了。

为统一起见,所有需要注册的代码文件,都应在各自目录下的__init__.py中逐级加以引用,然后只要在main.py文件中统一加载即可:

import app
import module

这就保证了在系统投入工作前,所有该注册的功能部件都已经注册完毕了。

参考资料:

jxTMS设计思想

jxTMS编程手册

下面的系列文章讲述了如何用jxTMS开发一个实用的业务功能:

如何用jxTMS开发一个功能

下面的系列文章讲述了jxTMS的一些基本开发能力:

jxTMS的HelloWorld

你可能感兴趣的:(jxTMS,docker,python,SaaS,jxTMS)