ems/Connector/modules/modbus.py

114 lines
3 KiB
Python

'''
Created on 05.12.2013
@author: Philipp Rauch
'''
from pymodbus.client.sync import ModbusTcpClient
from datetime import datetime
import time
from profile.datasheet import Datasheet
import struct
import numpy
_csv_lookup = { 'offset' : 'offset',
'type' : 'value - type',
'size' : 'size (Byte)',
'name' : 'Value name',
'time_offset' : 797}
def setup(conf):
'''
load message definition and connect to all pacs
'''
PACS = []
csv = '%s/%s' % (conf['config_dictionary'], conf['pac_csvfile'])
pac_csv = Datasheet()
pac_csv.loadDatasheet(strFile = csv)
messages = pac_csv.readDatasheet()
### INITIALIZE ###
PACS.append(messages)
if isinstance(conf['pac_ip'], list):
for ip in conf['pac_ip']:
PACS.append(ModbusTcpClient(ip))
else:
PACS.append(ModbusTcpClient(conf['pac_ip']))
### CONNECT ###
for PAC in PACS[1::]:
PAC.connect()
_set_time(PAC, _csv_lookup['time_offset'])
return PACS
def loop(PACS, item):
'''
get value of message and convert it to the right datatype
return the result
'''
row = PACS[0][PACS[0][_csv_lookup['offset']] == item[1]]
inx = row.index.values[0]
#print row.get('value - type')[inx]
valType = row.get(_csv_lookup['type'])[inx]
reg = row.get(_csv_lookup['size'])[inx]/2
type_picker = {'double' : _to_double,
'float' : _to_float,
'float + timestamp' : _to_float_time,
'long' : _to_long,
'timestamp' : _to_time_abs,
'Unsigned long' : _to_ulong,
'Unsigned short' : _to_ushort }
func = type_picker.get(valType, None)
if func is None:
raise NotImplementedError
res = PACS[item[0]].read_holding_registers(item[1], reg, unit=1)
return { row.get(_csv_lookup['name'])[inx] : func(res.registers) }
def _to_float_time(reg):
res = { 'value' : _to_float(reg[0:2]) }
res.update({ 'time' : _to_time_abs(reg[2:6]) })
return res
def _to_long(reg):
tmp = _to_ulong(reg)
s = struct.pack('=i', tmp)
return numpy.float32(struct.unpack('=l', s)[0])
def _to_double(reg):
tmp = int(reg[0]) << 3*16 | int(reg[1]) << 2*16 | int(reg[2]) << 16 | int(reg[3])
s = struct.pack('=q', tmp)
return numpy.float64(struct.unpack('=d', s)[0])
def _to_time_abs(reg):
timestamp = _to_ulong(reg)
date = datetime.fromtimestamp(timestamp)
return date
def _to_ulong(reg):
return numpy.int32(reg[0]) << 16 | int(reg[1])
def _to_ushort(reg):
return numpy.int16(reg[0])
def _to_float(reg):
tmp = _to_ulong(reg)
s = struct.pack('=i', tmp)
return numpy.float32(struct.unpack('=f', s)[0])
def _set_time(PAC, offset):
stamp = time.time()
high = int(int(stamp) >> 16)
low = int(int(stamp) & int(0xFFFF))
PAC.write_registers(offset, (high, low, 0, 0), unit=1)
def close(PACS):
### CLOSE ###
for PAC in PACS[1::]:
PAC.close()