import easymodbus.modbusClient from datetime import datetime as dt from functools import reduce class StabilitiController(object): '''''' def __init__(self, ipaddr, port=502, uid=240): self.client = easymodbus.modbusClient.ModbusClient(ipaddr, port) self.client.unitidentifier = uid def checkConnect(self): if not self.client.is_connected(): self.client.connect() def checkClose(self): if self.client.is_connected(): self.client.close() def reg2str(self, r): ms = (r & 0xff00) >> 8 ls = (r & 0xff) return chr(ms) + chr(ls) def getNetworkConfigs(self, config=None): self.checkConnect() configDict = {} from functools import reduce if config: pass else: holdingRegisters = self.client.read_holdingregisters(2030,8) configDict["ipaddr"] = (reduce (lambda a, b: str(a)+str(b), map(self.reg2str, holdingRegisters))) holdingRegisters = self.client.read_holdingregisters(2038,8) configDict["netmask"] = (reduce (lambda a, b: str(a)+str(b), map(self.reg2str, holdingRegisters))) return configDict def reg2utc(self, timel, timeu): return dt.fromtimestamp((timeu << 16) + timel) def reg2bits(self, reg): return bin(reg)[2:].zfill(16) def resetPcs(self): self.checkConnect() self.client.write_single_register(266, 0x8000) def checkOpMode(self): self.checkConnect() val = self.client.read_holdingregisters(267, 1) print (val) return val[0] == 1 def readFaultDetail(self, findex): if not (0<=findex<=63): return None self.checkConnect() self.client.write_single_register(0, findex) regs = self.client.read_holdingregisters(1, 9) flimit, fval, fcount, ftimel, ftimeu = regs[:5] fselector, fstatus = regs[-2:] fselector = bin(fselector)[2:].zfill(16)[-3:] print(bin(fstatus)[2:].zfill(16)) fseverity = bin(fstatus)[2:].zfill(16)[-3:] ''' b0-b2: The severity of the fault. 0x000 = Info: increments the fault counter only. 0x001 = Alert: increments the fault counter only. 0x010 = Alarm: fault is logged. 0x011 = Abort 0: fault is logged and unit is stopped. Reconnect timer 0 is used for restart. 0x100 = Abort 1: fault is logged and unit is stopped. Reconnect timer 1 is used for restart. 0x101 = Abort 2: fault is logged and unit is stopped. Reconnect timer 2 is used for restart. 0x110 = Lockdown: fault is logged, unit stops processing power and requires a reset. 0x111 = Reserved ''' fstatus = bin(fstatus)[2:].zfill(16)[-5:-3] ''' b3-b4: The status of the fault. 0x01 = No fault 0x10 = Active 0x11 = Occurred ''' print(flimit, fval, fcount, self.reg2utc(ftimel, ftimeu), fselector, fstatus, fseverity ) return { "Number": findex, "Limit": flimit, "Value": fval, "Occurence": fcount, "TimeStamp": self.reg2utc(ftimel, ftimeu), "Selector": fselector, "Severity": fseverity, "Status": fstatus, } def readFaultArray(self, start): import operator as op self.checkConnect() faults = self.client.read_holdingregisters(start,4) faultStrings = map(lambda x: bin(x)[2:].zfill(16)[::-1], faults) return reduce(op.add, faultStrings) def readFaultActivity(self): return self.readFaultArray(16) def readFaultOccurence(self): return self.readFaultArray(24) def printAllFaults(self, faults): fmt = " {} || {} | {} | {} | {} | {} | {} | {} | {} " sep = " ================================== " print (fmt.format(" ", *list(range(8)))) print (sep) for i in range(8): idx = i * 8 print (fmt.format(i, *faults[idx:idx+8])) def reconnectTimer(self): pass def getSystemStatus(self): pass