class ModbusClientRS: def __init__(self): self.client = ModbusClient() def writeRegister(self, address, value): if self.client.is_open(): return self.client.write_single_register(address, value) return None def readRegister(self, address, value): if self.client.is_open(): self.client.read_holding_registers(address, value) def connect(self, host, port): # self.client.debug(True) self.client.host(SERVER_HOST) self.client.port(SERVER_PORT) if not self.client.is_open(): if not self.client.open(): print("unable to connect to " + SERVER_HOST + ":" + str(SERVER_PORT)) def is_open(self): return self.client.is_open() def disconnect(self): return self.client.close()
def test(): c = ModbusClient() # uncomment this line to see debug message # c.debug(True) # define modbus server host, port c.host(SERVER_HOST) c.port(SERVER_PORT) while True: # open or reconnect TCP to server if not c.is_open(): if not c.open(): print("unable to connect to " + SERVER_HOST + ":" + str(SERVER_PORT)) # if open() is ok, read register (modbus function 0x03) if c.is_open(): print c.write_single_register(504, intToUint16(-216)) # sleep 2s before next polling time.sleep(2)
class TestClientServer(unittest.TestCase): def setUp(self): # modbus server self.server = ModbusServer(port=5020, no_block=True) self.server.start() # modbus client self.client = ModbusClient(port=5020) self.client.open() def tearDown(self): self.client.close() def test_read_and_write(self): # word space self.assertEqual(self.client.read_holding_registers(0), [0], 'Default value is 0 when server start') self.assertEqual(self.client.read_input_registers(0), [0], 'Default value is 0 when server start') # single read/write self.assertEqual(self.client.write_single_register(0, 0xffff), True) self.assertEqual(self.client.read_input_registers(0), [0xffff]) # multi-write at max size words_l = [randint(0, 0xffff)] * 0x7b self.assertEqual(self.client.write_multiple_registers(0, words_l), True) self.assertEqual(self.client.read_holding_registers(0, len(words_l)), words_l) self.assertEqual(self.client.read_input_registers(0, len(words_l)), words_l) # write over sized words_l = [randint(0, 0xffff)] * 0x7c self.assertEqual(self.client.write_multiple_registers(0, words_l), None) # bit space self.assertEqual(self.client.read_coils(0), [False], 'Default value is False when server start') self.assertEqual(self.client.read_discrete_inputs(0), [False], 'Default value is False when server start') # single read/write self.assertEqual(self.client.write_single_coil(0, True), True) self.assertEqual(self.client.read_coils(0), [True]) self.assertEqual(self.client.read_discrete_inputs(0), [True]) # multi-write at min size bits_l = [getrandbits(1)] * 0x1 self.assertEqual(self.client.write_multiple_coils(0, bits_l), True) self.assertEqual(self.client.read_coils(0, len(bits_l)), bits_l) self.assertEqual(self.client.read_discrete_inputs(0, len(bits_l)), bits_l) # multi-write at max size bits_l = [getrandbits(1)] * 0x7b0 self.assertEqual(self.client.write_multiple_coils(0, bits_l), True) self.assertEqual(self.client.read_coils(0, len(bits_l)), bits_l) self.assertEqual(self.client.read_discrete_inputs(0, len(bits_l)), bits_l) # multi-write over sized bits_l = [getrandbits(1)] * 0x7b1 self.assertEqual(self.client.write_multiple_coils(0, bits_l), None)
class Plugin(LoggerPlugin): """ Zeichnet die Messdaten einer Heliotherm-Wärmepumpe (mit Remote Control Gateway X SERIES EL-005-0001 ab v1.0.3.2 - 10.12.2018) auf. Modbus-TCP muss im Webinterface der Wärmepumpe aktiviert sein und im Anschluss die IP-Adresse der Wärmepumpe im Parameter "IP_Adresse" eingetragen werden. """ def __init__(self, *args, **kwargs): # Plugin setup super(Plugin, self).__init__(*args, **kwargs) self.setDeviceName('Heliotherm') self._connected = False self.__doc_connected__ = "Zeigt an, ob eine Wärmepumpe verbunden ist" self.status = "" self.__doc_status__ = "Zeigt Verbindungs-Informationen an, falls vorhanden" self._firstStart = True self._lastStoerung = False self._lastExtAnf = True self._lastMode = 0 self._c = None # Initialize persistant attributes self.IP_Adresse = self.initPersistentVariable('IP_Adresse', '') self.__doc_IP_Adresse__ = "IP-Adresse des RCG2 der Heliotherm-Wärmepumpe" self.samplerate = self.initPersistentVariable('samplerate', 1) self.__doc_samplerate__ = "Aufzeichnungsrate in Herz" self.Port = self.initPersistentVariable('Port', 502) self.__doc_Port__ = "ModbusTCP-Port (Standart: 502)" self._groups = self.initPersistentVariable('_groups', {'Global': True}) # Load mapping.json file self._groupInfo = {} self._mappingWrite = [] self._mappingRead = [] self._loadMapping() # Update self._groups for group in self._groupInfo.keys(): if group not in self._groups.keys(): self._groups[group] = False self._createGroupAttributes(self._groups) # Create attributes for self._createAttributes(self._mappingWrite) self.connect() @property def connected(self): return self._connected @connected.setter def connected(self, value): if value is True: self.connect() elif value is False: self.disconnect() # self._connected = value def _loadMapping(self): packagedir = self.getDir(__file__) with open(packagedir+"/mapping.json", encoding="UTF-8") as jsonfile: mapping = json.load(jsonfile, encoding="UTF-8") self._groupInfo = mapping['groups'] self._mappingWrite = mapping['mappingWrite'] self._mappingRead = mapping['mappingRead'] def _createAttributes(self, mappingWrite): groups = self._activeGroups() for parameter in mappingWrite: if parameter['group'] in groups: # Replace invalid chars for attribute names name = self._formatAttributeName(parameter['sname']) # Create 'private' parameter with _ in front: self._name setattr(self.__class__, '_'+name, None) # This intermediate function handles the strange double self arguments def setter(self, name, parameter, selfself, value): self._setAttribute(name, value, parameter) # Make sure, that the parameters are "the values, which would be represented at this point with print(...)" setpart = partial(setter, self, name, parameter) getpart = partial(getattr, self, '_'+name) # Create an attribute with the actual name. The getter refers to it's self._name attribute. The setter function to self._setGroupAttribute(name, value, parameter) setattr(self.__class__, name, property(getpart, setpart)) # If parameter contains docs, create a third attribute at self.__doc_PARNAME__ if "doc" in parameter.keys(): setattr(self, '__doc_'+name+'__', parameter['doc']) def _activeGroups(self): groups = [] for group in self._groups.keys(): if self._groups[group] is True: groups.append(group) return groups def _createGroupAttributes(self, groups): for groupname in groups.keys(): # Replace invalid chars for attribute names name = 'Gruppe_'+self._formatAttributeName(groupname) # Create 'private' parameter with _ in front: self._name setattr(self.__class__, '_'+name, groups[groupname]) # This intermediate function handles the strange double self arguments def setter(self, name, parameter, selfself, value): self._setGroupAttribute(name, value, parameter) # Make sure, that the parameters are "the values, which would be represented at this point with print(...)" setpart = partial(setter, self, name, groupname) getpart = partial(getattr, self, '_'+name) # Create an attribute with the actual name. The getter refers to it's self._name attribute. The setter function to self._setAttribute(name, value, parameter) setattr(self.__class__, name, property(getpart, setpart)) setattr(self, '__doc_'+name+'__', self._groupInfo[groupname]) def _setAttribute(self, name, value, parameter): if self._c is None: return if parameter['write'] is False: self.warning('This parameter cannot be changed') self.status = 'This parameter cannot be changed' else: ok = self._writeModbusRegister(parameter, value) if ok: self.info('Wrote register in WP') self.status = 'Wrote register in WP' else: self.error('Failed to write register in WP') self.status = 'Failed to write register in WP' def _setAttributeRef(self, name, value, parameter): name = self._formatAttributeName(name) setattr(self, '_'+name, value) def _formatAttributeName(self, name): return name.replace(' ','_').replace('/','_').replace('.','_').replace('-','_') def _setGroupAttribute(self, name, value, groupname): name = self._formatAttributeName(name) setattr(self, '_'+name, value) self._groups[groupname] = value self.savePersistentVariable('_groups', self._groups) def connect(self, ip=None): """ Verbinde dich mit einer Heliotherm Wärmepumpe (mit RCG2). Gib dazu die IP-Adresse/den Hostnamen an. Wenn die IP-Adresse schonmal konfiguriert wurde, lasse das Feld einfach leer. """ if ip != None and ip != '' and type(ip) is str: self.IP_Adresse = ip self.savePersistentVariable('IP_Adresse', self.IP_Adresse) self.info('Connecting with {}'.format(self.IP_Adresse)) if not self._connected: try: self.setPerpetualTimer(self._readModbusRegisters, samplerate=self.samplerate) self._c = ModbusClient(host=self.IP_Adresse, port=self.Port, auto_open=True, auto_close=True) if self._c is None: self.error('Could not connect with {}'.format(self.IP_Adresse)) self.status = 'Could not connect with {}'.format(self.IP_Adresse) return False self._c.timeout(10) self.status = 'Trying to connect...' self.start() self._connected = True return True except Exception as e: self.error('Could not connect with {}:\n{}'.format(self.IP_Adresse, e)) self.status = 'Could not connect with {}:\n{}'.format(self.IP_Adresse, e) return False else: self.status = 'Already connected. Disconnect first' return False def disconnect(self): """ Trenne die Verbindung zu der Heliotherm Wärmepumpe """ if self._connected: self.cancel() self._connected = False self._c = None self.status = 'Successfully disconnected' return True else: self.status = 'Cannot disconnect. Not connected.' return False def _mappingMinMaxRegister(self, mapping): min = 9999999999999 max = 0 for parameter in mapping: if parameter['register']> max: max = parameter['register'] if parameter['register']< min: min = parameter['register'] return min, max def _readModbusRegisters(self): if self._c == None: return active_groups = self._activeGroups() writeStart=100 writeEnd=159 resultWrite = self._c.read_holding_registers(writeStart, writeEnd-writeStart+1) if type(resultWrite) != list: writeStart=100 writeEnd=134 resultWrite = self._c.read_holding_registers(writeStart, writeEnd-writeStart+1) ans = {} if type(resultWrite) == list: for parameter in self._mappingWrite: if parameter['group'] in active_groups: regIdx= parameter['register']-writeStart if regIdx >= len(resultWrite): continue writeableValue = resultWrite[regIdx] if writeableValue>=2 **16/2: writeableValue = 2 **16 - writeableValue writeableValue = writeableValue/parameter['scale'] if parameter['record']: ans[parameter['sname']]=[writeableValue, parameter['unit']] # if parameter['write'] is True: self._setAttributeRef(self._formatAttributeName(parameter['sname']), writeableValue, parameter) if parameter['sname'] == "Betriebsart": if not self._firstStart and writeableValue != self._lastMode: mode = self._modes[writeableValue] self.event('Betriebsart wurde verändert: {}'.format(mode),parameter['sname'],self._devicename, 0, 'ModusChanged') self._lastMode = writeableValue elif parameter['sname'] == "Externe Anforderung": if not self._firstStart and writeableValue != self._lastExtAnf: if writeableValue == 1: self.event('Externe Anforderung angeschaltet',parameter['sname'],self._devicename, 0, 'ExtAnfAn') else: self.event('Externe Anforderung ausgeschaltet',parameter['sname'],self._devicename, 0, 'ExtAnfAus') self._lastExtAnf = writeableValue else: self.warning('Could not read writeable-registers, {}'.format(resultWrite)) self.status = 'Could not read writeable-registers, {}'.format(resultWrite) readStart=10 readEnd=75 resultRead = self._c.read_input_registers(readStart, readEnd-readStart+1) if type(resultRead) == list: for parameter in self._mappingRead: if parameter['group'] in active_groups: regIdx= parameter['register']-readStart if regIdx >= len(resultRead): continue writeableValue = resultRead[regIdx] if writeableValue>=2 **16/2: writeableValue = 2 **16 - writeableValue writeableValue = writeableValue/parameter['scale'] if parameter['record']: ans[parameter['sname']]=[writeableValue, parameter['unit']] if parameter['sname'] == 'Stoerung': if not self._firstStart and writeableValue != self._lastStoerung: if writeableValue != 0: self.event('Störung aufgetreten: {}!'.format(writeableValue),parameter['sname'],self._devicename, 2, 'StoerungAn') else: self.event('Störung wurde behoben!',parameter['sname'],self._devicename, 0, 'StoerungAus') self._lastStoerung = writeableValue self._firstStart = False self.status = 'Connected' else: self.warning('Could not read read-registers, {}'.format(resultRead)) self.status = 'Could not read read-registers, {}'.format(resultRead) self.stream(sdict={self._devicename:ans}) def _writeModbusRegister(self, parameter, reg_value): # if str(reg_addr) in self._mappingWrite.keys(): ans = self._c.write_single_register(parameter['register'],reg_value*parameter['scale']) if ans == True: return True else: return False
class TestClientServer(unittest.TestCase): port = 5020 def setUp(self): # modbus server self.server = ModbusServer(port=TestClientServer.port, no_block=True) self.server.start() # modbus client self.client = ModbusClient(port=TestClientServer.port) self.client.open() # to prevent address taken errors TestClientServer.port += 1 def tearDown(self): self.client.close() @repeat def test_word_init(self): # word space self.assertEqual(self.client.read_holding_registers(0), [0], 'Default value is 0 when server start') self.assertEqual(self.client.read_input_registers(0), [0], 'Default value is 0 when server start') @repeat def test_word_single(self): # single read/write self.assertEqual(self.client.write_single_register(0, 0xffff), True) self.assertEqual(self.client.read_input_registers(0), [0xffff]) @repeat def test_word_multi(self): # multi-write at max size words_l = [randint(0, 0xffff)] * 0x7b self.assertEqual(self.client.write_multiple_registers(0, words_l), True) self.assertEqual(self.client.read_holding_registers(0, len(words_l)), words_l) self.assertEqual(self.client.read_input_registers(0, len(words_l)), words_l) @repeat def test_word_oversize(self): # write over sized words_l = [randint(0, 0xffff)] * 0x7c self.assertEqual(self.client.write_multiple_registers(0, words_l), None) @repeat def test_bit_init(self): # bit space self.assertEqual(self.client.read_coils(0), [False], 'Default value is False when server start') self.assertEqual(self.client.read_discrete_inputs(0), [False], 'Default value is False when server start') @repeat def test_bit_single(self): # single read/write self.assertEqual(self.client.write_single_coil(0, True), True) self.assertEqual(self.client.read_coils(0), [True]) self.assertEqual(self.client.read_discrete_inputs(0), [True]) @repeat def test_bit_multi_min(self): # multi-write at min size bits_l = [getrandbits(1)] * 0x1 self.assertEqual(self.client.write_multiple_coils(0, bits_l), True) self.assertEqual(self.client.read_coils(0, len(bits_l)), bits_l) self.assertEqual(self.client.read_discrete_inputs(0, len(bits_l)), bits_l) @repeat def test_bit_multi_max(self): # multi-write at max size bits_l = [getrandbits(1)] * 0x7b0 self.assertEqual(self.client.write_multiple_coils(0, bits_l), True) self.assertEqual(self.client.read_coils(0, len(bits_l)), bits_l) self.assertEqual(self.client.read_discrete_inputs(0, len(bits_l)), bits_l) @repeat def test_bit_multi_oversize(self): # multi-write over sized bits_l = [getrandbits(1)] * 0x7b1 self.assertEqual(self.client.write_multiple_coils(0, bits_l), None)
class ModbusClass(): def __init__(self, host, port): self.c = ModbusClient(host=host, port=port) self.registers = {i: 0 for i in range(10)} self.connectLock = threading.Lock() self.regiLock = threading.Lock() # count = 5 if self.c.open(): print("connect success") else: print("connect failed") print("start reading threading") readThread = threading.Thread(target=self.readFromSlaveLoop) readThread.start() def connection(f): def checkConnection(self, *args, **kwargs): while not self.c.is_open(): self.connectLock.acquire() self.c.open() print("reconnecting") self.connectLock.release() if self.c.is_open(): print("reconnected") break time.sleep(2) f(self) return checkConnection def readFromSlaveLoop(self): while True: self.readFromSlave() @connection def readFromSlave(self): self.regiLock.acquire() self.connectLock.acquire() if self.c.is_open(): # print("reading...") tempR = self.registers try: t = self.c.read_holding_registers(0, 10) self.registers = {i: t[i] for i in range(0, len(t))} print(self.registers) except: self.registers = tempR # print("end reading") self.regiLock.release() self.connectLock.release() time.sleep(1) def writeToSlave(self, writeDict): self.connectLock.acquire() if self.c.is_open(): for k, v in writeDict.items(): self.c.write_single_register(k, v) print("write success") return True self.connectLock.release() return False # def getGoodsFromAGV(self, orderId): # self.writeToSlave(self.addSerialNum(orderId, COMMAND['TakeGoodsToAGV'])) # def takeGoodsToAGV(self, orderId): # self.writeToSlave(self.addSerialNum(orderId, COMMAND['GetGoodsFromAGV'])) def getRegisters(self): self.regiLock.acquire() temp = self.registers self.regiLock.release() for k, v in temp.items(): temp[k] = "%04d" % int(v) return temp def addSerialNum(self, work_order, wDict): wDict[0] = ord(work_order[0]) * 10 + int(work_order[1]) wDict[1] = int(work_order[2]) * 1000 + int(work_order[3]) * 100 + int( work_order[4]) * 10 + int(work_order[5]) * 1 return wDict def reconnect(self): self.c.open()
def set_FW_power(ModbusClient): # Sets the forward power set point to 200 W # c is ModbusClient wr = ModbusClient.write_single_register(0, 0) print('set_FW_power:' + str(int(wr))) return wr
while True: # open or reconnect TCP to server if not c.is_open(): if not c.open(): print("unable to connect to " + SERVER_HOST + ":" + str(SERVER_PORT)) # if open() is ok, write coils (modbus function 0x01) if c.is_open(): # write 4 bits in modbus address 0 to 3 print("") print("write register") print("----------") print("") if (toggle): is_ok = c.write_single_register(addr, 0xF0) if is_ok: print("register #" + str(addr) + ": write to " + str(0xF0)) else: print("bit #" + str(addr) + ": unable to write " + str(0xF0)) time.sleep(0.5) else: is_ok = c.write_single_register(addr, 0x0F) if is_ok: print("register #" + str(addr) + ": write to " + str(0x0F)) else: print("bit #" + str(addr) + ": unable to write " + str(0x0F)) time.sleep(0.5) time.sleep(1)
from pyModbusTCP.client import ModbusClient import time SERVER_HOST = "192.168.0.104" SERVER_PORT = 502 c = ModbusClient() # uncomment this line to see debug message #c.debug(True) # define modbus server host, port c.host(SERVER_HOST) c.port(SERVER_PORT) while True: # open or reconnect TCP to server if not c.is_open(): if not c.open(): print("unable to connect to "+SERVER_HOST+":"+str(SERVER_PORT)) # if open() is ok, read register (modbus function 0x03) if c.is_open(): print c.write_single_register(544, 220) # sleep 2s before next polling time.sleep(2)
class DRV90L(): """The "DRV90L" class contains methods to control the robot. """ def __init__(self): rospy.init_node("RobotArm") ip = rospy.get_param("/robot_ip") self.resetService = rospy.Service('/reset_robot', reset_errors, self.resetErrors) self.powerService = rospy.Service('/power_robot', power, self.powerCallback) self.teachService = rospy.Service("/teach_position", teach_position, self.teachCurrentToolPose) self.c = ModbusClient(host=ip, auto_open=True, auto_close=False, port=502, debug=False, unit_id=2) self.bits = 0 self.name = getpass.getuser() def enableRobot(self): """This function enables the robot. After this function is called, the robot is ready to move. !!!Be aware the motors get enabled after calling this function!!! """ if not self.c.is_open(): if not self.c.open(): print("Unable to connect\nTrying to connect...") if self.c.is_open(): self.c.write_single_register(0x0006, 0x101) self.c.write_single_register(0x0007, 0x101) self.c.write_single_register(0x0000, 0x101) print("Enabling robot...") time.sleep(3) def disableRobot(self): """This function disables the robot. After this function is called, the robot can't move. The motors aren't powered anymore. """ if not self.c.is_open(): if not self.c.open(): print("Unable to connect\nTrying to connect...") if self.c.is_open(): self.c.write_single_register(0x0006, 0x000) self.c.write_single_register(0x0007, 0x000) self.c.write_single_register(0x0000, 0x000) time.sleep(3) print("Robot is disabled") def sendPositionMove(self, x, y, z, rx, ry, rz, speed, frame): """This function is used to move the end effector of the robot to a certain position. !!!The robot needs to be enables for this function to work!!! Arguments: x {int} -- [x position in mm] y {int} -- [y position in mm] z {int} -- [z position in mm] rx {int} -- [rotation around x axis in degrees] ry {int} -- [rotation around y axis in degrees] rz {int} -- [rotation around z axis in degrees] speed {int} -- [speed in % [0 to 100]] frame {string} -- [Reference frame (world is base of robot)] """ if not self.c.is_open(): if not self.c.open(): print("Unable to connect\nTrying to connect...") if self.c.is_open(): xu = int(np.binary_repr(x*1000, width=32), 2) yu = int(np.binary_repr(y*1000, width=32), 2) zu = int(np.binary_repr(z*1000, width=32), 2) rxu = int(np.binary_repr(rx*1000, width=32), 2) ryu = int(np.binary_repr(ry*1000, width=32), 2) rzu = int(np.binary_repr(rz*1000, width=32), 2) xh = xu >> 16 xl = xu & 0x0000FFFF yh = yu >> 16 yl = yu & 0x0000FFFF zh = zu >> 16 zl = zu & 0x0000FFFF rxh = rxu >> 16 rxl = rxu & 0x0000FFFF ryh = ryu >> 16 ryl = ryu & 0x0000FFFF rzh = rzu >> 16 rzl = rzu & 0x0000FFFF print("Moving to position: x=%s, y=%s, z=%s, rx=%s, ry=%s, rz=%s" % (x,y,z,rx,ry,rz)) self.c.write_single_register(0x0330, xl) self.c.write_single_register(0x0331, xh) self.c.write_single_register(0x0332, yl) self.c.write_single_register(0x0333, yh) self.c.write_single_register(0x0334, zl) self.c.write_single_register(0x0335, zh) self.c.write_single_register(0x0336, rxl) self.c.write_single_register(0x0337, rxh) self.c.write_single_register(0x0338, ryl) self.c.write_single_register(0x0339, ryh) self.c.write_single_register(0x033A, rzl) self.c.write_single_register(0x033B, rzh) self.c.write_single_register(0x033E, 0) self.c.write_single_register(0x0324, speed) self.c.write_single_register(0x300, 301) self.waitForEndMove([x,y,z,rx,ry,rz]) def sendArcMove(self, p1, p2): """With this function it's possible to do a arc move. The arm will move to p2 through p1. Arguments: p1 {list} -- 1st position [x,y,z,rx,ry,rz] p2 {list} -- 2nd position [x,y,z,rx,ry,rz] """ if not self.c.is_open(): if not self.c.open(): print("Unable to connect\nTrying to connect...") if self.c.is_open(): x1 = int(np.binary_repr(p1[0], width=16), 2) y1 = int(np.binary_repr(p1[1], width=16), 2) z1 = int(np.binary_repr(p1[2], width=16), 2) rx1 = int(np.binary_repr(p1[3], width=16), 2) ry1 = int(np.binary_repr(p1[4], width=16), 2) rz1 = int(np.binary_repr(p1[5], width=16), 2) x2 = int(np.binary_repr(p2[0], width=16), 2) y2 = int(np.binary_repr(p2[1], width=16), 2) z2 = int(np.binary_repr(p2[2], width=16), 2) rx2 = int(np.binary_repr(p2[3], width=16), 2) ry2 = int(np.binary_repr(p2[4], width=16), 2) rz2 = int(np.binary_repr(p2[5], width=16), 2) self.c.write_single_register(0x1000, x1) self.c.write_single_register(0x1001, y1) self.c.write_single_register(0x1002, z1) self.c.write_single_register(0x1003, rx1) self.c.write_single_register(0x1004, ry1) self.c.write_single_register(0x1005, rz1) self.c.write_single_register(0x1006, x2) self.c.write_single_register(0x1007, y2) self.c.write_single_register(0x1008, z2) self.c.write_single_register(0x1009, rx2) self.c.write_single_register(0x100A, ry2) self.c.write_single_register(0x100B, rz2) self.c.write_single_register(0x0220, 4) self.c.write_single_register(0x0228, 6) print("Moving arc through %s to %s" % (p1, p2)) self.waitForEndMove(p2) def jogRobot(self, direction, stop=False): """With this function it's possible to jog the robot in a certain direction. Arguments: direction {string} -- "X+", "Y+", "Z+", "RX+", "RY+", "RZ+", "X-", "Y-", "Z-", "RX-", "RY-", "RZ-" Keyword Arguments: stop {bool} -- if True the robot will stop jogging (default: {False}) """ if not self.c.is_open(): if not self.c.open(): print("Unable to connect\nTrying to connect...") if self.c.is_open(): self.c.write_single_register(0x033E, 0) self.c.write_single_register(0x0324, 80) if stop == True: self.c.write_single_register(0x0300, 0) elif direction == "X+": self.c.write_single_register(0x0300, 601) elif direction == "X-": self.c.write_single_register(0x0300, 602) elif direction == "Y+": self.c.write_single_register(0x0300, 603) elif direction == "Y-": self.c.write_single_register(0x0300, 604) elif direction == "Z+": self.c.write_single_register(0x0300, 605) elif direction == "Z-": self.c.write_single_register(0x0300, 606) elif direction == "RX+": self.c.write_single_register(0x0300, 607) elif direction == "RX-": self.c.write_single_register(0x0300, 608) elif direction == "RY+": self.c.write_single_register(0x0300, 609) elif direction == "RY-": self.c.write_single_register(0x0300, 610) elif direction == "RZ+": self.c.write_single_register(0x0300, 611) elif direction == "RZ-": self.c.write_single_register(0x0300, 612) def goHome(self): """This function moves the robot to the home position that is set in the robot software. !!!The robot needs to be enables for this function to work!!! """ if not self.c.is_open(): if not self.c.open(): print("Unable to connect\nTrying to connect...") if self.c.is_open(): self.c.write_single_register(0x0300, 1405) print("Arm is homing...") #self.waitForEndMove() def writeDigitalOutput(self, output, state): """With this function it's possible to control the user digital outputs of the robot. Arguments: output {int} -- [The user digital output number that needs to be used [1 to 12] state {boolean} -- [The state that the output needs to be [True=HIGH (24V), False=LOW (0V)]] """ if state == True: self.bits = self.bits | (1 << output-1) elif state == False: self.bits = self.bits & (0 << output-1) self.b = format(self.bits, 'b').zfill(16) print(self.b) self.c.write_single_register(0x02FE, int(self.b, 2)) def getUserDigitalInputs(self): """With this function it's possible to get the states of all user digital inputs. Returns: [list] -- [Containing all states of the digital inputs [0 or 1]] """ if not self.c.is_open(): if not self.c.open(): print("Unable to connect\nTrying to connect...") if self.c.is_open(): di = list(map(int, "{0:b}".format(self.c.read_holding_registers(0x02FA, 2)[0])))[::-1] l = 24 - len(di) for _ in range(0, l): di.append(0) print(di) return di def getUserDigitalOutputs(self): """With this function it's possible to get the states of all user digital outputs. Returns: [list] -- [Containing all states of the digital outputs [0 or 1]] """ if not self.c.is_open(): if not self.c.open(): print("Unable to connect\nTrying to connect...") if self.c.is_open(): do = list(map(int, "{0:b}".format(self.c.read_holding_registers(0x02FC, 2)[0])))[::-1] l = 12 - len(do) for _ in range(0, l): do.append(0) print(do) return do def getToolPosition(self): """With this function it's possible to get the tool position. Returns: [list] -- [x,y,z,rx,ry,rz] in mm / degrees """ if not self.c.is_open(): if not self.c.open(): print("Unable to connect\nTrying to connect...") if self.c.is_open(): x_r = self.c.read_holding_registers(0x00F0, 2) x = struct.unpack('i', struct.pack('HH', x_r[0], x_r[1]))[0]/1000 y_r = self.c.read_holding_registers(0x00F2, 2) y = struct.unpack('i', struct.pack('HH', y_r[0], y_r[1]))[0]/1000 z_r = self.c.read_holding_registers(0x00F4, 2) z = struct.unpack('i', struct.pack('HH', z_r[0], z_r[1]))[0]/1000 rx_r = self.c.read_holding_registers(0x00F6, 2) rx = struct.unpack('i', struct.pack('HH', rx_r[0], rx_r[1]))[0]/1000 ry_r = self.c.read_holding_registers(0x00F8, 2) ry = struct.unpack('i', struct.pack('HH', ry_r[0], ry_r[1]))[0]/1000 rz_r = self.c.read_holding_registers(0x00FA, 2) rz = struct.unpack('i', struct.pack('HH', rz_r[0], rz_r[1]))[0]/1000 return [x,y,z,rx,ry,rz] def getJointPositions(self): """With this function it's possible to get the joint positions Returns: [list] -- [1, 2, 3, 4, 5, 6] joint angles in radians """ if not self.c.is_open(): if not self.c.open(): print("Unable to connect\nTrying to connect...") if self.c.is_open(): j1 = self.c.read_holding_registers(0x0168, 2) j1_a = struct.unpack('i', struct.pack('HH', j1[0], j1[1]))[0] j1_angle = radians(j1_a/1000) j2 = self.c.read_holding_registers(0x016A, 2) j2_a = struct.unpack('i', struct.pack('HH', j2[0], j2[1]))[0] j2_angle = radians(j2_a/1000) j3 = self.c.read_holding_registers(0x016C, 2) j3_a = struct.unpack('i', struct.pack('HH', j3[0], j3[1]))[0] j3_angle = radians(j3_a/1000) j4 = self.c.read_holding_registers(0x016E, 2) j4_a = struct.unpack('i', struct.pack('HH', j4[0], j4[1]))[0] j4_angle = radians(j4_a/1000) j5 = self.c.read_holding_registers(0x0150, 2) j5_a = struct.unpack('i', struct.pack('HH', j5[0], j5[1]))[0] j5_angle = radians(j5_a/1000) j6 = self.c.read_holding_registers(0x0152, 2) j6_a = struct.unpack('i', struct.pack('HH', j6[0], j6[1]))[0] j6_angle = radians(j6_a/1000) return [j1_angle, j2_angle, j3_angle, j4_angle, j5_angle, j6_angle] def saveToolPose(self, name, pose): """With this function it's possible to save a position to the poses.yaml yaml file. Arguments: name {string} -- Position name pose {[type]} -- [x,y,z,rx,ry,rz] position in mm / degrees Returns: [type] -- [description] """ f = open('/home/%s/catkin_ws/src/delta/arm_driver/yaml/poses.yaml' % self.name, 'r') d = yaml.load(f) try: for n in d: if n == name: f.close() print("Pose %s already exists, delete the old pose and try again" % name) return False except TypeError: pass f = open('/home/%s/catkin_ws/src/delta/arm_driver/yaml/poses.yaml' % self.name, 'a') d = {name: pose} yaml.dump(d, f, default_flow_style=False) f.close() print("Pose %s is saved" % name) return True def teachCurrentToolPose(self, msg): """With this function it's possible to save the current robot position to the poses.yaml yaml file. Arguments: msg {teach_position.srv} -- Name = position name Returns: [bool] -- True if succesfull """ return self.saveToolPose(msg.name, self.getToolPosition()) def getSavedToolPose(self, name): """Load a position from the poses.yaml yaml file. Arguments: name {string} -- Position name to load Returns: [list] -- [x,y,z,rx,ry,rz] position in mm /degrees """ f = open('/home/%s/catkin_ws/src/delta/arm_driver/yaml/poses.yaml' % self.name, 'r') d = yaml.load(f) f.close() try: return d.get(name) except AttributeError: return "Position does not exist" def resetUserDigitalOutputs(self): """With this function it's possible to reset all user digital outputs to 0. """ if not self.c.is_open(): if not self.c.open(): print("Unable to connect\nTrying to connect...") if self.c.is_open(): self.c.write_single_register(0x02FE, 0) def resetErrors(self, msg): """With this function it's possible to reset all errors. !!!ONLY USE THIS FUNCTION WHEN IT'S SAFE!!! """ if not self.c.is_open(): if not self.c.open(): print("Unable to connect\nTrying to connect...") return False if self.c.is_open(): self.c.write_single_register(0x0180, 0xFFFF) time.sleep(0.1) self.c.write_single_register(0x0180, 0x0000) return True def waitForEndMove(self, pos): done = 0 while done == 0: if self.getToolPosition() == pos and self.c.read_holding_registers(0x00E0, 1)[0] == 0: done = 1 print("Position reached") time.sleep(1) def powerCallback(self, msg): if msg.on == True: self.enableRobot() return True elif msg.on == False: self.disableRobot() return True else: return False
""" #Given fsm = fsm_targets[unit.value] fnd_api = fsm.get_fnd_api() sleep(10) setup_modbus_gateway(logger, fsm, io_channel) sleep(2) ip_target = fsm_targets[unit.value].get_ip_eth_point(io_channel) logger.info("Target ip is {}".format(ip_target)) modbus_client = ModbusClient(host=ip_target, port=502, auto_open=True, auto_close=True) logger.info("modbus_client response {}".format(modbus_client)) #When #Then logger.info("Write on single register") modbus_client.write_single_register(30001,1) sleep(0.4) current_time = datetime.now() sleep(5) response = get_command_to_run_journal(logger,fsm_targets,current_time,4) assert response <= 10.00 sleep(5) @pytest.mark.parametrize("unit, io_channel", unit_io_tuples, ids=unit_io_ids) def test_modbus_log_invalid_input_registers(target_testrig, logger, fsm_targets, unit, io_channel): """ Requirement : WINGDECSAT-213 Description Test Case 1: Modbus: Log unsuccessful master read access with invalid address
found, x, y = Kuka.find(mask) cv2.circle(frame, (x, y), 7, (0, 0, 0), -1) cv2.putText(frame, "Red", (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2) if found: color = 3 if blue and color == 0: mask = cv2.inRange(hsv, thresholds[6], thresholds[7]) found, x, y = Kuka.find(mask) cv2.circle(frame, (x, y), 7, (0, 0, 0), -1) cv2.putText(frame, "Blue", (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2) if found: color = 4 # write variables for x- and y-position and color to modbus client.write_single_register(32001, x) client.write_single_register(32002, y) client.write_single_register(32003, color) #show video feed cv2.imshow("result", frame) # if esc key is pressed, break the loop and end the program key = cv2.waitKey(5) if key == 27: break if event == 'quit': break Cap.release() cv2.destroyAllWindows()
pass elif (keyboard.is_pressed('p')): aux = vOut + 10 vOut = 100 if (aux > 90) else aux pass #System canoIn = True if (vIn > 0) else False canoOut = True if (vOut > 0) else False aux = nivel + vIn / 10 - vOut / 10 nivel = 100 if (aux > 99) else (0 if (aux < 1) else aux) ledAlarm = True if (nivel >= 75) else False vIn = 0 if (nivel == 100) else vIn # Sending Data to ScadaBr c.write_single_register(0, vIn) c.write_single_register(1, vOut) c.write_single_register(2, nivel) c.write_single_coil(3, canoIn) c.write_single_coil(4, canoOut) c.write_single_coil(5, ledAlarm) # Terminal Data Printing print("vIn: %d" % vIn) print("vOut: %d" % vOut) print("Nivel: %d" % nivel) # Waiting Time time.sleep(0.2)
from pyModbusTCP.client import ModbusClient client = ModbusClient("192.168.1.192", 502) print("open:", client.open()) while True: action = input("action: ") client.open() try: adr = int(input("adress: ")) if action == "rr": print(f"value at {adr}: {client.read_holding_registers(adr)}") if action == "rc": print(f"value at {adr}: {client.read_coils(adr)}") if action == "wr": val = int(input("value: ")) print(f"old value at {adr}: {client.read_holding_registers(adr)}") client.write_single_register(adr, val) time.sleep(0.1) print(f"new value at {adr}: {client.read_holding_registers(adr)}") if action == "wc": val = input("value: ") print(f"old value at {adr}: {client.read_coils(adr)}") if val == "t": client.write_single_coil(adr, True) time.sleep(0.1) print(f"new value at {adr}: {client.read_coils(adr)}") else: client.write_single_coil(adr, False) time.sleep(0.1) print(f"new value at {adr}: {client.read_coils(adr)}") except: print("Try again")
c2.host("192.168.1.30") c2.port(502) c2.unit_id(1) c2.open() c2.close() cmds = ["config switch physical-port", "edit port4", "set status down", "end"] exec_ssh_cmds(cmds) # open or reconnect TCP to server if not c.is_open(): if not c.open(): print("unable to connect to " + SERVER_HOST + ":" + str(SERVER_PORT)) if c.is_open(): while True: # Turn pump on c.write_single_coil(1, True) # Set pump to 100% c.write_single_register(3, 0x64) val = c.read_coils(5)[0] print(val) c2.write_single_coil(1, True) if val: c.write_single_coil(1, False) time.sleep(0.2)
class ConveyorNode(object): __reg_A_servo_on = 0 __reg_A_command = 1 __reg_A_velocity = 2 __reg_B_servo_on = 3 __reg_B_command = 4 __reg_B_velocity = 5 def __init__(self): rospy.init_node("conveyor_node") rospy.loginfo("Starting ConveyorNode as conveyor_node.") host = rospy.get_param("~host", default="10.42.0.21") port = rospy.get_param("~port", default=502) publish_rate = rospy.get_param("~rate", default=20) self.ratio_vel_A = rospy.get_param("~ratio_vel_A", default="1") self.ratio_vel_B = rospy.get_param("~ratio_vel_B", default="1") self.ratio_cmd_A = rospy.get_param("~ratio_cmd_A", default="1") self.ratio_cmd_B = rospy.get_param("~ratio_cmd_B", default="1") self.min_vel = rospy.get_param("~min_vel", default="-0.2") self.max_vel = rospy.get_param("~max_vel", default="0.2") self.rate = rospy.Rate(publish_rate) rospy.Subscriber("conveyorA/command", Float32, self.set_velocityA) # unit [m/s] self.stateA_pub = rospy.Publisher("conveyorA/state", conveyor, queue_size=1) # state of conveyor rospy.Subscriber("conveyorB/command", Float32, self.set_velocityB) # unit [m/s] self.stateB_pub = rospy.Publisher("conveyorB/state", conveyor, queue_size=1) # state of conveyor self.stateA_msg = conveyor() self.stateA_msg.target_vel = 0.0 self.stateA_msg.current_vel = 0.0 self.stateB_msg = conveyor() self.stateB_msg.target_vel = 0.0 self.stateB_msg.current_vel = 0.0 self.__timeout_timeA = time.time() self.__timeout_timeB = time.time() try: self.client = ModbusClient(host, port, auto_open=True) rospy.loginfo("Setup complete") except ValueError: rospy.logerr("Error with conveyor Host or Port params") self.__register_data = None self.__input_data = None @staticmethod def clamp(n, minn, maxn): return max(min(maxn, n), minn) @staticmethod def map_velocity_to_value(velocity): # value = (velocity/0.05*100*2*math.pi*60)/500 velocity = (velocity * 60) / (0.052 * 2 * math.pi * 4) value = int(velocity / 10.0 * 27648.0) return utils.get_2comp(value) & 0xFFFF @staticmethod def map_value_to_velocity(value): voltage = float(utils.get_2comp(value)) / 27648.0 * 10.0 velocity = voltage * 4.0 * 2.0 * math.pi * 0.052 / 60.0 return velocity def set_velocityA(self, msg): self.stateA_msg.target_vel = self.clamp(msg.data, self.min_vel, self.max_vel) # [m/s] self.__timeout_timeA = time.time() def set_velocityB(self, msg): self.stateB_msg.target_vel = self.clamp(msg.data, self.min_vel, self.max_vel) # [m/s] self.__timeout_timeB = time.time() def run(self): while not rospy.is_shutdown(): try: self.__input_data = self.client.read_discrete_inputs(0, 6) self.stateA_msg.sensor_1 = self.__input_data[0] self.stateA_msg.sensor_2 = self.__input_data[1] self.stateA_msg.sensor_3 = self.__input_data[2] self.stateB_msg.sensor_1 = self.__input_data[3] self.stateB_msg.sensor_2 = self.__input_data[4] self.stateB_msg.sensor_3 = self.__input_data[5] self.__register_data = self.client.read_holding_registers(0, 6) if time.time() - self.__timeout_timeA > 1.0: self.stateA_msg.target_vel = 0 self.client.write_single_register(self.__reg_A_servo_on, 0) else: value = self.map_velocity_to_value( self.stateA_msg.target_vel) * self.ratio_cmd_A self.client.write_single_register(self.__reg_A_servo_on, 1) self.client.write_single_register(self.__reg_A_command, value) if time.time() - self.__timeout_timeB > 1.0: self.stateB_msg.target_vel = 0 self.client.write_single_register(self.__reg_B_servo_on, 0) else: value = self.map_velocity_to_value( self.stateB_msg.target_vel) * self.ratio_cmd_B self.client.write_single_register(self.__reg_B_servo_on, 1) self.client.write_single_register(self.__reg_B_command, value) velocity = self.map_value_to_velocity( self.__register_data[self.__reg_A_velocity]) self.stateA_msg.current_vel = velocity * self.ratio_vel_A velocity = self.map_value_to_velocity( self.__register_data[self.__reg_B_velocity]) self.stateB_msg.current_vel = velocity * self.ratio_vel_B self.stateA_pub.publish(self.stateA_msg) self.stateB_pub.publish(self.stateB_msg) except Exception as e: rospy.logerr(e) self.rate.sleep()
class Modbus(): def __init__(self, smarthome, gateway_ip, gateway_port=502, gateway_id=1, update_cycle=60): logger.info("Modbus: init plugin") self._sh = smarthome self._gateway_id = int(gateway_id) self._update_cycle = int(update_cycle) self._keylist = {} #self._client = ModbusTcpClient(gateway_ip,port=gateway_port) self._client = ModbusClient(host=gateway_ip, port=gateway_port, auto_open=True, auto_close=True) self._client.unit_id(2) self._client.debug(True) if not self._client.is_open(): if not self._client.open(): logger.error("Modbus: connection to gateway can not be established") else: logger.info("Modbus: connection to gateway established") self._client.close() def run(self): self.alive = True self._sh.scheduler.add('MODBUS', self._update_values, prio=5, cycle=self._update_cycle) def stop(self): self.alive = False self._sh.scheduler.remove('MODBUS') def parse_item(self, item): if 'modbus_gateway_id' in item.conf: gateid = int(item.conf['modbus_gateway_id']) else: gateid = 1 if gateid != self._gateway_id: #logger.debug("Modbus: parse item error (gateway_id is not configured as plugin): {0}".format(item)) return None if 'modbus_cmd' not in item.conf: #logger.debug("Modbus: parse item error (modbus_cmd missing): {0}".format(item)) return None if 'modbus_scaling' not in item.conf: #logger.debug("Modbus: parse item error (modbus_scaling missing): {0}".format(item)) return None if 'modbus_register' in item.conf: logger.debug("Modbus: parse item: {0}".format(item)) register = item.conf['modbus_register'] if not register in self._keylist: self._keylist[register] = {'items': [item], 'logics': []} else: self._keylist[register]['items'].append(item) return None # return self.update_item #else: # return None def parse_logic(self, logic): pass def _update_values(self): for register in self._keylist: for item in self._keylist[register]['items']: if int(item.conf['modbus_cmd']) == 4: reg_list = self._client.read_input_registers(int(item.conf['modbus_register'])-30001, 1) logger.info("Modbus: Plain value: {}".format(str(reg_list[0]))) if reg_list is None: return None if len(reg_list) > 0: phys_value = reg_list[0] / (int(item.conf['modbus_scaling']))# * pow(10, int(item.conf['modbus_decimal'])) logger.info("Modbus: Physical value: {0}".format(phys_value)) item(phys_value, 'MODBUS', ' {0}'.format(phys_value)) elif int(item.conf['modbus_cmd']) == 6: sendvalue = int(item()*int(item.conf['modbus_scaling'])) reg_list = self._client.write_single_register(int(item.conf['modbus_register'])-40001, sendvalue) if not reg_list: logger.info("Modbus: Error writing register") def update_item(self, item, caller=None, source=None, dest=None): if caller != 'MODBUS': logger.info("update item: {0}".format(item.id())) if int(item.conf['modbus_cmd']) == 4: reg_list = self._client.read_input_registers(int(item.conf['modbus_register'])-30001, 1) logger.info("Modbus: Plain value: {}".format(str(reg_list[0]))) if reg_list is None: return None if len(reg_list) > 0: phys_value = reg_list[0] / (int(item.conf['modbus_scaling']))# * pow(10, int(item.conf['modbus_decimal'])) logger.info("Modbus: Physical value: {0}".format(phys_value)) item(phys_value, 'MODBUS', ' {0}'.format(phys_value))
def set_start_mode_ramp(ModbusClient): # Sets the start mode to ramp # c is ModbusClient wr = ModbusClient.write_single_register(3, 2) # print('set_start_mode_ramp:' + str(int(wr))) return wr
def onCommand(self, u, Command, Level, Hue): Domoticz.Debug( str(Devices[u].DeviceID) + ": onCommand called: Parameter '" + str(Command) + "', Level: " + str(Level)) try: client = ModbusClient(host=self.TCP_IP, port=int(self.TCP_PORT), unit_id=int(1), auto_open=True, auto_close=True, timeout=2) except: Domoticz.Error("Can not connect to Modbus TCP/IP: " + self.TCP_IP + ":" + self.TCP_PORT) try: # == ControlMode : man = 1, auto = 0, docasny = 2 | "|Manuál|Automat|Dočasný" if (u == self.uControlMode): #if Level == 10: atreaControlMode = 1 if Level == 20: atreaControlMode = 0 elif Level == 30: atreaControlMode = 2 client.write_single_register(1015, atreaControlMode) client.write_single_register(1016, atreaControlMode) # == HeatingSeason : 0 = non-heating, 1 = heating elif (u == self.uHeatingSeason): client.write_single_coil(1200, int(Command == "On")) # == NightlyCooling : 0 = recuperation, 1 = cooling elif (u == self.uNightlyCooling): client.write_single_coil(902, int(Command == "On")) # == uPowerCur # == uPowerReq elif (u == self.uPowerCur): atreaPower = int(self._powerDomoticzValueToPercent(Level)) Domoticz.Debug( str(Devices[u].DeviceID) + ": COMMAND: Level=" + str(Level) + ", atreaPower='" + str(atreaPower) + "'") client.write_single_register(1009, atreaPower) client.write_single_register(1013, atreaPower) client.write_single_register(1015, 2) client.write_single_register(1016, 2) # == ModeCur "Vypnuto | Periodické větrání | Větrání |Čidlo vlhkosti|IN2|D1|D2|Koupelny+WC|Odsavač kuchyň|Náběh|Doběh|Odmrazování rekuperátoru" # == ModeReq "Vypnuto | Periodické větrání | Větrání" # H01008 Nastavení požadovaného režimu, pokud H01015=1, 0 = Periodické větrání, 1 = Větrání # H01012 Nastavení požadovaného režimu, pokud H01015= 0/2, 0 = Vypnuto, 1 = Periodické větrání, 2 = Větrání elif (u == self.uModeCur): if Level == 0: atreaMode = 1 self.onCommand(self.uPowerCur, Command, 0, Hue) elif Level == 10: atreaMode = 0 elif Level == 20: atreaMode = 1 Domoticz.Debug( str(Devices[u].DeviceID) + ": COMMAND: Level=" + str(Level) + ", atreaMode='" + str(atreaMode) + "'") client.write_single_register(1008, atreaMode) client.write_single_register(1012, atreaMode) client.write_single_register(1015, 2) client.write_single_register(1016, 2) except: Domoticz.Error( str(Devices[u].DeviceID) + ": Modbus update error. Check it out!") # Update values now! self.onHeartbeat() return
c.write_single_coil(1, coil_value) logger.debug(f"写 coil,值为 {coil_value}") coil_value = not coil_value time.sleep(1) # 读 discrete_inputs inputs = c.read_discrete_inputs(1) if inputs is None: logger.error("读 discrete_inputs 失败") time.sleep(2) continue logger.debug(f"读 discrete_input,值为 {inputs[0]}") # 写 holding_registers c.write_single_register(1, holding_reg_value) logger.debug(f"写 holding_register,值为 {holding_reg_value}") holding_reg_value = (holding_reg_value + 1) % range_value time.sleep(1) # 读 input_register regs = c.read_input_registers(1) if regs is None: logger.error("读 input_registers 失败") time.sleep(2) continue logger.debug(f"读 input_register,值为 {regs[0]}") time.sleep(1)
if not c.is_open(): if not c.open(): print("unable to connect to " + client_host + ":" + str(client_port)) def int32_to_int8(n): mask = (1 << 16) - 1 return [(n >> k) & mask for k in range(0, 32, 16)] var_int = utils.encode_ieee(7.5) print(var_int) sonuc=int32_to_int8(var_int) print(sonuc) if c.is_open(): # read 10 registers at address 0, store result in regs list print(var_int) c.write_single_register(0,5) c.write_multiple_registers(1,sonuc) regs = c.read_holding_registers(0,100) # if success display registers if regs: print("reg ad #0 to 9: " , regs) bits = c.read_discrete_inputs(0, 16) # if success display registers if bits: print("bit ad #0 to 9: " + str(bits))
def doTest(): # TCP auto connect on modbus request, close after it c = ModbusClient(host="192.168.1.1", auto_open=True, auto_close=True) regs = c.read_holding_registers(0, 100) if regs: print(regs) else: print("read error") def doWrite(goToPos): c = ModbusClient(host="192.168.1.1", auto_open=True, auto_close=True) if c.write_single_register(1, goToPos): print("write ok") else: print("write error") if __name__ == '__main__': c = ModbusClient(host="192.168.1.1", auto_open=True, auto_close=True) while (True): if c.write_single_register(0, 0): print("Waiting for instruction") goto = int(input("Enter Go To Pos: ")) doWrite(goto) if c.write_single_register(0, 1): print("Going!") time.sleep(.1)
class MitsubishiAirConditioner: # 自上次读取一次新信息起经过了多久 lastRefreshTimestamp = time.time() client = None messageQueue = None messageThread = None # 待发送的需要等待回复的命令,成员格式为:{"code":"XX", "cmd":"XXXXXXX", "type": "query", "timestamp": timestamp} arrayCmdNeedWait = [] # 正在等待回应的命令 dicCmdWaiting = None # 存储各个空调控制器的dic, key:字符串表示的控制器模块编码(HEX) value:LJAircon对象 dicAircon = {} # nValue/sValue至寄存器Payload的map - 开关 mapVPPowerOn = None # 寄存器Payload至nValue/sValue的map - 开关 mapPVPowerOn = None # nValue/sValue至寄存器Payload的map - 运行模式 mapVPMode = None # 寄存器Payload至nValue/sValue的map - 运行模式 mapPVMode = None # nValue/sValue至寄存器Payload的map - 风速 mapVPFanSpeed = None # 寄存器Payload至nValue/sValue的map - 风速 mapPVFanSpeed = None # nValue/sValue至寄存器Payload的map - 目标温度 mapVPSetPoint = None # 寄存器Payload至nValue/sValue的map - 目标温度 mapPVSetPoint = None # nValue/sValue至寄存器Payload的map - 室温 mapVPRoomPoint = None # 寄存器Payload至nValue/sValue的map - 室温 mapPVRoomPoint = None # nValue/sValue至寄存器Payload的map - 风向 mapVPFanDirect = None # 寄存器Payload至nValue/sValue的map - 风向 mapPVFanDirect = None def __init__(self): self.messageQueue = queue.Queue() self.messageThread = threading.Thread( name="QueueThread", target=MitsubishiAirConditioner.handleMessage, args=(self, )) # 0:关1:开 self.mapVPPowerOn = {0: 0, 1: 1} self.mapPVPowerOn = self.revertDic(self.mapVPPowerOn) # 0:自动,1:制冷,2:送风,3:除湿,4:制热 self.mapVPMode = {'10': 0, '20': 1, '30': 2, '40': 3, '50': 4} self.mapPVMode = self.revertDic(self.mapVPMode) # 0:自动,2:低,3:中2,5:中1,6:高 self.mapVPFanSpeed = {'10': 0, '20': 2, '30': 3, '40': 5, '50': 6} self.mapPVFanSpeed = self.revertDic(self.mapVPFanSpeed) # 16~31°C (x10),最小单位0.5°C self.mapPVSetPoint = {} for i in range(190, 300, 5): self.mapPVSetPoint[i] = str((int((i - 190) / 5) + 1) * 10) self.mapVPSetPoint = self.revertDic(self.mapPVSetPoint) # 10~38°C (x10),最小单位1°C self.mapPVRoomPoint = {} for i in range(100, 385, 5): if i % 10 == 0: self.mapPVRoomPoint[i] = str(i // 10) elif i % 5 == 0: self.mapPVRoomPoint[i] = str(float(i) / 10) self.mapVPRoomPoint = self.revertDic(self.mapPVRoomPoint) # 0:自动,1~5:位置1~5 7:摆风 self.mapVPFanDirect = { '10': 0, '20': 1, '30': 2, '40': 3, '50': 4, '60': 5, '70': 7 } self.mapPVFanDirect = self.revertDic(self.mapVPFanDirect) return def onStart(self): Domoticz.Heartbeat(5) if Parameters["Mode2"] == "Debug": Domoticz.Debugging(1) else: Domoticz.Debugging(0) # 从Domoticz重新加载硬件和设备信息 self.reloadFromDomoticz() debug = False if Parameters["Mode2"] == "Debug": debug = True if self.client and self.client.is_open(): self.client.close() self.client = ModbusClient(host=Parameters["Address"], port=Parameters["Port"], auto_open=True, auto_close=False, timeout=1) self.messageThread.start() self.client.mode(2) self.messageQueue.put({ "Type": "Log", "Text": "Heartbeat test message" }) def onStop(self): # signal queue thread to exit self.messageQueue.put(None) Domoticz.Log("Clearing message queue...") self.messageQueue.join() # Wait until queue thread has exited Domoticz.Log("Threads still active: " + str(threading.active_count()) + ", should be 1.") while (threading.active_count() > 1): for thread in threading.enumerate(): if (thread.name != threading.current_thread().name): Domoticz.Log( "'" + thread.name + "' is still running, waiting otherwise Domoticz will abort on plugin exit." ) time.sleep(0.1) return def onConnect(self, Connection, Status, Description): return def onMessage(self, Connection, Data): return def clientConnected(self): if not self.client: return False if self.client.is_open(): return True elif not self.client.open(): Domoticz.Log('Warning: Modbus connect failed') return False def handleMessage(self): try: Domoticz.Debug("Entering message handler") while True: Message = self.messageQueue.get(block=True) if Message is None: Domoticz.Debug("Exiting message handler") self.messageQueue.task_done() break self.queryStatus() self.messageQueue.task_done() except Exception as err: Domoticz.Error("handleMessage: " + str(err)) def queryStatus(self): if not self.clientConnected(): for aircon in self.dicAircon.values(): aircon.goOffline() return for aircon in self.dicAircon.values(): #if not aircon.online: #continue # 设备已连接才发送查询指令 dicOptions = aircon.devicePowerOn.Options if not dicOptions or 'LJCode' not in dicOptions or 'LJShift' not in dicOptions: return self.client.unit_id(int(dicOptions['LJCode'], 16)) time.sleep(0.2) regs = self.client.read_holding_registers(0, 7) if not regs or regs is None: Domoticz.Log('Warning: Reading Regs Fail! 0x' + dicOptions['LJCode']) aircon.goOffline() continue elif len(regs) != 7: Domoticz.Log( 'Warning: Reading Regs Fail! 0x{}, recevied:{}'.format( dicOptions['LJCode'], str(regs))) aircon.goOffline() continue aircon.goOnline() Domoticz.Debug('Receive Regs:' + str(regs)) if aircon.devicePowerOn and regs[0] in self.mapPVPowerOn: nValue = self.mapPVPowerOn[regs[0]] sValue = aircon.devicePowerOn.sValue device = aircon.devicePowerOn UpdateDevice(Unit=int(device.Options['LJUnit']), nValue=nValue, sValue=sValue, TimedOut=0) if aircon.deviceMode and regs[1] in self.mapPVMode: nValue = 1 sValue = self.mapPVMode[regs[1]] device = aircon.deviceMode UpdateDevice(Unit=int(device.Options['LJUnit']), nValue=nValue, sValue=sValue, TimedOut=0) if aircon.deviceFanSpeed and regs[2] in self.mapPVFanSpeed: nValue = 1 sValue = self.mapPVFanSpeed[regs[2]] device = aircon.deviceFanSpeed UpdateDevice(Unit=int(device.Options['LJUnit']), nValue=nValue, sValue=sValue, TimedOut=0) if aircon.deviceSetPoint and regs[3] in self.mapPVSetPoint: nValue = 1 sValue = self.mapPVSetPoint[regs[3]] device = aircon.deviceSetPoint UpdateDevice(Unit=int(device.Options['LJUnit']), nValue=nValue, sValue=sValue, TimedOut=0) if aircon.deviceRoomPoint and regs[4] in self.mapPVRoomPoint: nValue = 1 sValue = self.mapPVRoomPoint[regs[4]] device = aircon.deviceRoomPoint UpdateDevice(Unit=int(device.Options['LJUnit']), nValue=nValue, sValue=sValue, TimedOut=0) if aircon.deviceFanDirect and regs[5] in self.mapPVFanDirect: nValue = 1 sValue = self.mapPVFanDirect[regs[5]] device = aircon.deviceFanDirect UpdateDevice(Unit=int(device.Options['LJUnit']), nValue=nValue, sValue=sValue, TimedOut=0) if aircon.deviceFaultCode: nValue = 1 hexText = str(hex(regs[6])) if len(hexText) >= 4 and hexText[-4:] == '8000': sValue = '运行正常' else: sValue = '错误!故障代码: ' + hexText device = aircon.deviceFaultCode UpdateDevice(Unit=int(device.Options['LJUnit']), nValue=nValue, sValue=sValue, TimedOut=0) def onCommand(self, Unit, Command, Level, Hue): if not self.clientConnected(): Domoticz.Log('Modbus connect failed!') for aircon in self.dicAircon.values(): aircon.goOffline() return Domoticz.Log("onCommand called for Unit " + str(Unit) + ": Parameter '" + str(Command) + "', Level: " + str(Level)) Command = Command.strip() action, sep, params = Command.partition(' ') action = action.capitalize() params = params.capitalize() device = Devices[Unit] options = device.Options if not options or 'LJCode' not in options or 'LJShift' not in options or 'LJUnit' not in options: return code = device.Options['LJCode'] shift = device.Options['LJShift'] if not code or code not in self.dicAircon or not shift or int( shift) < 0 or int(shift) > 6: return aircon = self.dicAircon[code] #if not aircon.online: #return if shift == '00': # 开关 if action == 'On': nValue = 1 elif action == 'Off': nValue = 0 self.sendCmdByNValue(aircon, self.mapVPPowerOn, aircon.devicePowerOn, nValue) elif shift == '01': # 模式 if action == 'Set' and params == 'Level': if aircon.devicePowerOn.nValue == 0: # 关机状态,先开机 #TODO测试连续写 self.sendCmdByNValue(aircon, self.mapVPPowerOn, aircon.devicePowerOn, 1) self.sendCmdBySValue(aircon, self.mapVPMode, aircon.deviceMode, str(Level)) elif shift == '02': # 风速 if action == 'Set' and params == 'Level': if aircon.devicePowerOn.nValue == 0: # 关机状态,先开机 self.sendCmdByNValue(aircon, self.mapVPPowerOn, aircon.devicePowerOn, 1) self.sendCmdBySValue(aircon, self.mapVPFanSpeed, aircon.deviceFanSpeed, str(Level)) elif shift == '03': # 温度 if action == 'Set' and params == 'Level': if aircon.devicePowerOn.nValue == 0: # 关机状态,先开机 self.sendCmdByNValue(aircon, self.mapVPPowerOn, aircon.devicePowerOn, 1) self.sendCmdBySValue(aircon, self.mapVPSetPoint, aircon.deviceSetPoint, str(Level)) elif shift == '04': # 室温 if action == 'Set' and params == 'Level': if aircon.devicePowerOn.nValue == 0: # 关机状态,先开机 self.sendCmdByNValue(aircon, self.mapVPPowerOn, aircon.devicePowerOn, 1) self.sendCmdBySValue(aircon, self.mapVPRoomPoint, aircon.deviceRoomPoint, str(Level)) elif shift == '05': # 风向 if action == 'Set' and params == 'Level': if aircon.devicePowerOn.nValue == 0: # 关机状态,先开机 self.sendCmdByNValue(aircon, self.mapVPPowerOn, aircon.devicePowerOn, 1) self.sendCmdBySValue(aircon, self.mapVPFanDirect, aircon.deviceFanDirect, str(Level)) # 从sValue取值,找Payload,并写寄存器 def sendCmdBySValue(self, aircon, mapVP, device, sValue): if not self.clientConnected(): return Domoticz.Log('sendCmdBySValue\(mapVP={}, device={}, sValue={}'.format( mapVP, device, sValue)) # TODO if not device or not mapVP or sValue not in mapVP: return None registerText = device.Options['LJShift'] self.client.unit_id(int(device.Options['LJCode'], 16)) if (self.client.write_single_register(int(registerText, 16), mapVP[str(sValue)])): Domoticz.Log('write_single_register\(0x{}, {}\) success!'.format( registerText, mapVP[sValue])) # TODO timedOut = 0 result = True else: Domoticz.Log('write_single_register\(0x{}, {}\) failed!'.format( registerText, mapVP[sValue])) # TODO timedOut = 1 result = False aircon.goOffline() sValue = device.sValue UpdateDevice(Unit=int(device.Options['LJUnit']), nValue=device.nValue, sValue=str(sValue), TimedOut=timedOut) return result # 从nValue取值,找Payload,并写寄存器 def sendCmdByNValue(self, aircon, mapVP, device, nValue): if not self.clientConnected(): return Domoticz.Log('sendCmdByNValue\(mapVP={}, device={}, nValue={}'.format( mapVP, device, nValue)) # TODO if not device or not mapVP or nValue not in mapVP: return None registerText = device.Options['LJShift'] self.client.unit_id(int(device.Options['LJCode'], 16)) if (self.client.write_single_register(int(registerText, 16), mapVP[nValue])): Domoticz.Log('write_single_register\(0x{}, {}\) success!'.format( registerText, mapVP[nValue])) # TODO timedOut = 0 result = True else: Domoticz.Log('write_single_register\(0x{}, {}\) failed!'.format( registerText, mapVP[nValue])) # TODO timedOut = 1 result = False aircon.goOffline() nValue = device.nValue UpdateDevice(Unit=int(device.Options['LJUnit']), nValue=nValue, sValue=str(device.sValue), TimedOut=timedOut) return result def onNotification(self, Name, Subject, Text, Status, Priority, Sound, ImageFile): Domoticz.Log("Notification: " + Name + "," + Subject + "," + Text + "," + Status + "," + str(Priority) + "," + Sound + "," + ImageFile) def onDisconnect(self, Connection): Domoticz.Log("onDisconnect called") def onHeartbeat(self): # Domoticz.Log('onHeartbeat Called ---------------------------------------') # 如果没连接则尝试重新连接 if not self.clientConnected(): for aircon in self.dicAircon.values(): aircon.goOffline() return # 查询空调状态 self.messageQueue.put({ "Type": "Log", "Text": "Heartbeat test message" }) def reloadFromDomoticz(self): self.dicAircon = {} strListCode = Parameters["Mode1"] strListCode = strListCode.replace(',', '') strListCode = strListCode.replace('|', '') strListCode = strListCode.replace(' ', '') strListCode = strListCode.replace('0X', '0x') strListCode = strListCode.replace('X', '0x') setCode = set(strListCode.split('0x')) setCode2 = set([]) for tmp in setCode: if not tmp: continue setCode2.add(tmp.upper()) for tmp2 in setCode2: if not tmp2: continue if len(tmp2) > 2: tmp2 = tmp2[-2:] tmp2 = '{:0>2}'.format(tmp2) Domoticz.Log('Detected Code:' + tmp2) self.dicAircon[tmp2] = LJAircon(tmp2) # 记录已有的unit setUnit = set([]) # 待删除的device对应的unit setUnitDel = set([]) # 所有的Unit集合 setUnitAll = set(range(1, 256)) # 将Device放入对应的控制器对象中,多余的device删除 for unit in Devices: device = Devices[unit] dicOptions = device.Options Domoticz.Log("DEVICE FROM PANEL " + descDevice(device=device, unit=unit)) shouldDelete = False if dicOptions and 'LJCode' in dicOptions and 'LJShift' in dicOptions and dicOptions[ 'LJCode'] in self.dicAircon: # 有匹配的控制器,赋值 aircon = self.dicAircon[dicOptions['LJCode']] if dicOptions['LJShift'] == '00': # 开关 if aircon.devicePowerOn: #已经有现成的设备,加入待删除 Domoticz.Log( 'Already have devicePowerOn, add to delete list. ' + device.Name) shouldDelete = True else: aircon.devicePowerOn = device aircon.dicDevice[unit] = device elif dicOptions['LJShift'] == '01': # 运行模式 if aircon.deviceMode: #已经有现成的设备,加入待删除 Domoticz.Log( 'Already have deviceMode, add to delete list. ' + device.Name) shouldDelete = True else: aircon.deviceMode = device aircon.dicDevice[unit] = device elif dicOptions['LJShift'] == '02': # 风速 if aircon.deviceFanSpeed: #已经有现成的设备,加入待删除 Domoticz.Log( 'Already have deviceFanSpeed, add to delete list. ' + device.Name) shouldDelete = True else: aircon.deviceFanSpeed = device aircon.dicDevice[unit] = device elif dicOptions['LJShift'] == '03': # 目标温度 if aircon.deviceSetPoint: #已经有现成的设备,加入待删除 Domoticz.Log( 'Already have deviceSetPoint, add to delete list. ' + device.Name) shouldDelete = True else: aircon.deviceSetPoint = device aircon.dicDevice[unit] = device elif dicOptions['LJShift'] == '04': # 室温 if aircon.deviceRoomPoint: #已经有现成的设备,加入待删除 Domoticz.Log( 'Already have deviceRoomPoint, add to delete list. ' + device.Name) shouldDelete = True else: aircon.deviceRoomPoint = device aircon.dicDevice[unit] = device elif dicOptions['LJShift'] == '05': # 风向 if aircon.deviceFanDirect: #已经有现成的设备,加入待删除 Domoticz.Log( 'Already have deviceFanDirect, add to delete list. ' + device.Name) shouldDelete = True else: aircon.deviceFanDirect = device aircon.dicDevice[unit] = device elif dicOptions['LJShift'] == '06': # 状态 if aircon.deviceFaultCode: #已经有现成的设备,加入待删除 Domoticz.Log( 'Already have deviceFaultCode, add to delete list. ' + device.Name) shouldDelete = True else: aircon.deviceFaultCode = device aircon.dicDevice[unit] = device else: shouldDelete = True else: shouldDelete = True if shouldDelete: setUnitDel.add(unit) else: setUnit.add(unit) Domoticz.Log("DELETE DEVICES IN UNIT: " + str(setUnitDel)) # 删除多余的Device for unit in setUnitDel: Devices[unit].Delete() # Check if images are in database #if "LJCountDown" not in Images: # Domoticz.Image("LJCountDown.zip").Create() #image = Images["LJCountDown"].ID # 遍历控制器,补全控制器对应的device for aircon in self.dicAircon.values(): setAvariable = setUnitAll.difference(setUnit) if not setAvariable or len(setAvariable) == 0: continue if not aircon.devicePowerOn: newUnit = setAvariable.pop() setUnit.add(newUnit) optionsCustom = { "LJUnit": str(newUnit), 'LJCode': aircon.code, 'LJShift': '00' } name = '0x{} 开关'.format(aircon.code) aircon.devicePowerOn = Domoticz.Device(Name=name, Unit=newUnit, Type=244, Subtype=73, Switchtype=0, Options=optionsCustom) aircon.devicePowerOn.Create() aircon.dicDevice[newUnit] = aircon.devicePowerOn Domoticz.Log( 'ADD DEVICE :' + descDevice(device=aircon.devicePowerOn, unit=newUnit)) if not aircon.deviceMode and len(setAvariable) > 0: newUnit = setAvariable.pop() setUnit.add(newUnit) optionsCustom = { "LJUnit": str(newUnit), 'LJCode': aircon.code, 'LJShift': '01' } levelNames = 'Off|自动|制冷|送风|除湿|制热' optionsGradient = { 'LevelActions': '|' * levelNames.count('|'), 'LevelNames': levelNames, 'LevelOffHidden': 'true', 'SelectorStyle': '0' } name = '0x{} 模式'.format(aircon.code) aircon.deviceMode = Domoticz.Device(Name=name, Unit=newUnit, TypeName="Selector Switch", Switchtype=18, Image=0, Options=dict( optionsCustom, **optionsGradient)) aircon.deviceMode.Create() aircon.dicDevice[newUnit] = aircon.deviceMode Domoticz.Log( 'ADD DEVICE :' + descDevice(device=aircon.deviceMode, unit=newUnit)) if not aircon.deviceFanSpeed and len(setAvariable) > 0: newUnit = setAvariable.pop() setUnit.add(newUnit) optionsCustom = { "LJUnit": str(newUnit), 'LJCode': aircon.code, 'LJShift': '02' } levelNames = 'Off|自动|低|中2|中1|高' optionsGradient = { 'LevelActions': '|' * levelNames.count('|'), 'LevelNames': levelNames, 'LevelOffHidden': 'true', 'SelectorStyle': '0' } name = '0x{} 风速'.format(aircon.code) aircon.deviceFanSpeed = Domoticz.Device( Name=name, Unit=newUnit, TypeName="Selector Switch", Switchtype=18, Image=0, Options=dict(optionsCustom, **optionsGradient)) aircon.deviceFanSpeed.Create() aircon.dicDevice[newUnit] = aircon.deviceFanSpeed Domoticz.Log( 'ADD DEVICE :' + descDevice(device=aircon.deviceFanSpeed, unit=newUnit)) if not aircon.deviceSetPoint and len(setAvariable) > 0: newUnit = setAvariable.pop() setUnit.add(newUnit) optionsCustom = { "LJUnit": str(newUnit), 'LJCode': aircon.code, 'LJShift': '03' } levelNames = 'Off' for i in range(190, 300, 5): if i % 10 == 0: levelNames += '|' + str(i // 10) + '℃' elif i % 5 == 0: levelNames += '|' + str(float(i) / 10) + '℃' optionsGradient = { 'LevelActions': '|' * levelNames.count('|'), 'LevelNames': levelNames, 'LevelOffHidden': 'true', 'SelectorStyle': '1' } name = '0x{} 设定温度'.format(aircon.code) aircon.deviceSetPoint = Domoticz.Device( Name=name, Unit=newUnit, TypeName="Selector Switch", Switchtype=18, Image=0, Options=dict(optionsCustom, **optionsGradient)) aircon.deviceSetPoint.Create() aircon.dicDevice[newUnit] = aircon.deviceSetPoint Domoticz.Log( 'ADD DEVICE :' + descDevice(device=aircon.deviceSetPoint, unit=newUnit)) if not aircon.deviceRoomPoint and len(setAvariable) > 0: newUnit = setAvariable.pop() setUnit.add(newUnit) optionsCustom = { "LJUnit": str(newUnit), 'LJCode': aircon.code, 'LJShift': '04' } name = '0x{} 室温'.format(aircon.code) aircon.deviceRoomPoint = Domoticz.Device( Name=name, Unit=newUnit, TypeName="Temperature", Options=optionsCustom) aircon.deviceRoomPoint.Create() aircon.dicDevice[newUnit] = aircon.deviceRoomPoint Domoticz.Log( 'ADD DEVICE :' + descDevice(device=aircon.deviceRoomPoint, unit=newUnit)) if not aircon.deviceFanDirect and len(setAvariable) > 0: newUnit = setAvariable.pop() setUnit.add(newUnit) optionsCustom = { "LJUnit": str(newUnit), 'LJCode': aircon.code, 'LJShift': '05' } levelNames = 'Off|自动|位置1|位置2|位置3|位置4|位置5|摆风' optionsGradient = { 'LevelActions': '|' * levelNames.count('|'), 'LevelNames': levelNames, 'LevelOffHidden': 'true', 'SelectorStyle': '0' } name = '0x{} 风向'.format(aircon.code) aircon.deviceFanDirect = Domoticz.Device( Name=name, Unit=newUnit, TypeName="Selector Switch", Switchtype=18, Image=0, Options=dict(optionsCustom, **optionsGradient)) aircon.deviceFanDirect.Create() aircon.dicDevice[newUnit] = aircon.deviceFanDirect Domoticz.Log( 'ADD DEVICE :' + descDevice(device=aircon.deviceFanDirect, unit=newUnit)) if not aircon.deviceFaultCode and len(setAvariable) > 0: newUnit = setAvariable.pop() setUnit.add(newUnit) optionsCustom = { "LJUnit": str(newUnit), 'LJCode': aircon.code, 'LJShift': '06' } name = '0x{} 状态'.format(aircon.code) aircon.deviceRoomPoint = Domoticz.Device(Name=name, Unit=newUnit, TypeName="Text", Image=17, Options=optionsCustom) aircon.deviceRoomPoint.Create() aircon.dicDevice[newUnit] = aircon.deviceRoomPoint Domoticz.Log( 'ADD DEVICE :' + descDevice(device=aircon.deviceRoomPoint, unit=newUnit)) def revertDic(self, dic): if dic: return {v: k for k, v in dic.items()} return None
def set_start_time(ModbusClient): # Sets the start time to 60s # c is ModbusClient wr = ModbusClient.write_single_register(4, 200) print('set_start_time:' + str(int(wr))) return wr
from pyModbusTCP.client import ModbusClient import time #TCP auto connect on first Modbus Request c = ModbusClient(host="localhost", port=502, auto_open=True) #TCP auto connect on Modbus Request, close after it c = ModbusClient(host="127.0.0.1", auto_open=True, auto_close=True) c = ModbusClient() c.host("localhost") c.port(502) cont = 0 tanque = c.write_single_register(2, 0) valvula = c.write_single_register(3, 0) LED = c.write_single_register(1, 0) while True: # managing TCP sessions with call to c.open()/c.close() c.open() led = c.read_holding_registers(1) tanque_valor = c.read_holding_registers(2) if led[0] == 1: cont = cont + 1 c.write_single_register(2, cont) tanque_valor = c.read_holding_registers(2) if tanque_valor[0] == 10: c.write_single_register(1, 0) if led[0] == 0:
def set_freq(ModbusClient): # Sets the reflected power set point to 100 W # c is ModbusClient wr = ModbusClient.write_single_register(9, 24000) print('set_freq:' + str(int(wr))) return wr
class ClientGUI: def __init__(self): self.lock = RLock() self.calibgui = None self.client = ModbusClient() self.register_values_widgets = {} self.counter = 1 self.find_thread = None self.obj_data = None self.stop_signal = False self.__build_ui() def run_ui(self): self.root.mainloop() def __build_ui(self): # ui hierarchy: # #root # connectframe # connectlabel # connectbutton # snapshotbutton # calibbuton # mainframe # registerframe # reglabel # registergridframe # ... # outputframe # outputlabel # outputtext root = Tk() self.root = root root.wm_title("RemoteSurf Modbus Client") root.protocol("WM_DELETE_WINDOW", self.__delete_window) self.font = tkFont.Font(root=root, family="Helvetica", size=12) connectframe = Frame(root) connectbutton = Button(connectframe, text="Connect", command=self.__connectbutton_click) connectlabel = Label(connectframe, text="Not connected.") calibbutton = Button(connectframe, text="Calibrate", command=self.__calibbutton_click) homebutton = Button(connectframe, text="Home", command=self.__homebutton_click) findbutton = Button(connectframe, text="Find", command=self.__findbutton_click) mainframe = Frame(root) registerframe = Frame(mainframe) reglabel = Label(registerframe, text="Set registers") registergridframe = Frame(registerframe) # outputframe = Frame(mainframe) # outputlabel = Label(outputframe, text = "Output") # vscrollbar = Scrollbar(outputframe) # hscrollbar = Scrollbar(outputframe) # outputtext = ThreadSafeConsole(outputframe, root, vscrollbar, font = self.font, wrap = NONE) connectframe.pack(side=TOP, fill=X) connectlabel.pack(side=BOTTOM, anchor=W) homebutton.pack(side=RIGHT) findbutton.pack(side=RIGHT) calibbutton.pack(side=RIGHT) connectbutton.pack(side=RIGHT) mainframe.pack(side=BOTTOM, fill=BOTH, expand=YES) registerframe.pack(side=TOP, expand=YES, anchor=W) # outputframe.pack(side = BOTTOM, fill = BOTH, expand = YES) reglabel.pack(side=TOP, anchor=CENTER) registergridframe.pack(side=BOTTOM, anchor=W) # registerframe.config(bg = "cyan") # mainframe.config(bg = "pink") # registergridframe.config(bg = "red") registergridframe.columnconfigure(0, weight=1) registergridframe.columnconfigure(1, weight=1) registergridframe.columnconfigure(2, weight=1) registergridframe.columnconfigure(3, weight=1) self.x_pad = 10 registergrid_widgets = [] titles = ["Address", "Label", "Value", ""] col = 0 for title in titles: title_label = Label(registergridframe, text=title) title_label.grid(row=0, column=col, padx=self.x_pad) registergrid_widgets.append(title_label) col += 1 registers_data = [ (500, "x"), (501, "y"), (502, "z"), (503, "A"), (504, "B"), (505, "C"), ] for i in range(len(registers_data)): reg_data = registers_data[i] row = i + 1 self.__add_register(registergridframe, reg_data, row, registergrid_widgets) # hscrollbar.config(orient = HORIZONTAL, command = outputtext.xview) # hscrollbar.pack(side = BOTTOM, fill = X) # outputtext.config(state = DISABLED, yscrollcommand = vscrollbar.set, xscrollcommand = hscrollbar.set) #must change to NORMAL before writing text programmatically # outputtext.pack(side = LEFT, fill = BOTH, expand = YES, padx = x_padding, pady = y_padding) # vscrollbar.config(command = outputtext.yview) # vscrollbar.pack(side = RIGHT, fill = Y) self.connectframe = connectframe self.connectlabel = connectlabel self.connectbutton = connectbutton self.mainframe = mainframe self.registerframe = registerframe self.reglabel = reglabel self.registergridframe = registergridframe self.calibbutton = calibbutton # self.outputframe = outputframe # self.outputlabel = outputlabel # self.vscrollbar = vscrollbar # self.hscrollbar = hscrollbar # self.outputtext = outputtext root.update() w, h = root.winfo_width(), root.winfo_height() root.minsize(w, h) x, y = MAINFRAME_POS root.geometry('%dx%d+%d+%d' % (w, h, x, y)) def __homebutton_click(self): values = { 500: 300, 501: 0, 502: 500, 503: 180, 504: 0, 505: 180, } self.set_values(values, go_to_value=False) def __add_register(self, master, data, row, widget_list): regaddresslabel = Label(master, text=str(data[0])) regaddresslabel.grid(row=row, column=0) reglabellabel = Label(master, text=data[1]) reglabellabel.grid(row=row, column=1) regvalueentry = AccessibleEntry(master, justify=RIGHT) regvalueentry.set("0") regvalueentry.grid(row=row, column=2, padx=self.x_pad) regsetbtn = Button(master, text="Set", command=self.__setbutton_click) regsetbtn.grid(row=row, column=3) widget_list.append(regaddresslabel) widget_list.append(reglabellabel) widget_list.append(regvalueentry) widget_list.append(regsetbtn) self.register_values_widgets[data[0]] = (0, regvalueentry) def __calibbutton_click(self): if not self.calibgui: self.calibgui = CalibGUI(self) def __findbutton_click(self): if self.find_thread is None: self.find_thread = Thread(target=self.__find_object) self.find_thread.start() def __find_object(self): import DataCache as DC from glob import glob from os.path import join import numpy as np from SFMSolver import SFMSolver, find_ext_params import Utils print "FINDING" np.set_printoptions(precision=3, suppress=True) files_dir = "out/2017_3_8__14_51_22/" files = glob(join(files_dir, "*.jpg")) masks = [] for f in files: m = f.replace(".jpg", "_mask.png") masks.append(m) sfm = SFMSolver(files, masks) if self.obj_data is None: imgs, kpts, points, data = sfm.calc_data_from_files_triang_simple() self.obj_data = imgs, kpts, points, data else: imgs, kpts, points, data = self.obj_data arr_calib = DC.getData("out/%s/arrangement_calib.p" % ARRANGEMENT_CALIB_DIR) ttc = arr_calib["ttc"] tor = arr_calib["tor"] if "cam_mtx" in arr_calib: print "camMtx, distcoeffs load" Utils.camMtx = arr_calib["cam_mtx"] Utils.dist_coeffs = arr_calib["dist_coeffs"] if self.stop_signal: self.stop_signal = False return for point in FIND_POINTS: values = { 500: point[0], 501: point[1], 502: point[2], 503: point[3], 504: point[4], 505: point[5], } print "set_values call" self.set_values(values, True) print "set_values return" time.sleep(0.5) CamGrabber.capture_if_no_chessboard = True CamGrabber.capture = True time.sleep(0.5) if self.stop_signal: self.stop_signal = False return find_dir = logger.outputdir files = glob("%s/*.jpg" % find_dir) print files # files_dir = "out/2017_4_5__15_57_20/" # files = glob(join(files_dir, "*.jpg")) files.sort() files = files[-len(FIND_POINTS):] results = [] for f in files: res = find_ext_params(f, imgs, kpts, points, data, tor, ttc) results.append(res) if self.stop_signal: self.stop_signal = False return for i in range(len(results)): print i, results[i] write_log((i, results[i])) result = max(results, key=lambda x: x[2]) write_log(result) values = { 500: int(result[0][0] * 10), 501: int(result[0][1] * 10), 502: int(result[0][2] * 10) + 200, 503: int(result[1][2]), 504: int(result[1][1]), 505: int(result[1][0]), } print "num inl: ", result[2] pprint(values) self.set_values(values, go_to_value=False) self.find_thread = None def __connectbutton_click(self): if self.client.is_open(): self.client.close() else: self.client.host(SERVER_HOST) self.client.port(SERVER_PORT) if self.client.open(): write_log("Connection established") self.refresh_values() self.read_robot_pos() else: write_log("ERROR: Connecting failed") self.__update_gui() def read_robot_pos(self): write_log("Reading robot position:") posdict = {} for i in range(1000, 1006): if self.client.is_open(): with self.lock: real_val_uint = self.client.read_input_registers(i)[0] real_val_holding_uint = self.client.read_holding_registers( i)[0] assert real_val_uint == real_val_holding_uint real_val_int = uintToInt16(real_val_uint) posdict[i] = real_val_int write_log("%d, %d" % (i, real_val_int)) else: write_log( "ERROR: Read could not be completed, client not connected." ) self.__update_gui() break write_log("Read done.") return posdict def refresh_values(self): for address in self.register_values_widgets: if self.client.is_open(): value, widget = self.register_values_widgets[address] with self.lock: real_val_uint = self.client.read_input_registers( address)[0] real_val_holding_uint = self.client.read_holding_registers( address)[0] assert real_val_uint == real_val_holding_uint real_val_int = uintToInt16(real_val_uint) widget.set(str(real_val_int)) self.register_values_widgets[address] = (real_val_int, widget) else: write_log( "ERROR: Read could not be completed, client not connected." ) self.__update_gui() break write_log("Refresh done.") return self.register_values_widgets def __update_gui(self): if self.client.is_open(): self.connectlabel.config(text="Connected to: %s:%d" % (SERVER_HOST, SERVER_PORT)) self.connectbutton.config(text="Disconnect") else: self.connectbutton.config(text="Connect") self.connectlabel.config(text="Not connected.") self.root.update() def __print_memory(self): self.refresh_values() write_log("Memory dump:") write_log("------------") for address in self.register_values_widgets: val, widget = self.register_values_widgets[address] write_log("%d, %d" % (address, val)) write_log("------------") def __setbutton_click(self, wait=False): if not self.client.is_open(): write_log("ERROR: Not connected to client") return # writing message counter retval = self.__write_register(COUNTER_REGISTER_OUT, self.counter) if not retval: self.__update_gui() return # writing registers for address in self.register_values_widgets: value, widget = self.register_values_widgets[address] widgetvalue_int = None try: widgetvalue_int = int(widget.get()) except ValueError: write_log( "ERROR: Wrong input format in value entry for address: %d" % address) continue if value == widgetvalue_int: continue retval = self.__write_register(address, widgetvalue_int) if retval: self.register_values_widgets[address] = (widgetvalue_int, widget) else: self.__update_gui() self.refresh_values() # message counter wait if wait: global break_wait while not break_wait: with self.lock: counter = self.client.read_input_registers( COUNTER_REGISTER_IN)[0] if counter == self.counter: break time.sleep(0.1) break_wait = False # counter increment self.counter = (self.counter + 1) % 20 if PRINT_ALL_MEMORY_ON_WRITE: self.__print_memory() self.read_robot_pos() def __write_register(self, address, value): if not (-32768 <= value <= 32767): write_log( "ERROR: -32768 <= value <= 32767 is false for address: %d" % address) return False widgetvalue_uint = intToUint16(value) if self.client.is_open(): with self.lock: retval = self.client.write_single_register( address, widgetvalue_uint) if retval: write_log("Register written. Address: %d, value: %d" % (address, value)) return True else: write_log("ERROR: Write failed. Address: %d, value: %d" % (address, value)) else: write_log("ERROR: client not connected.") return False def set_values(self, values, wait=True, go_to_value=True): """ :param values: dictionary of { address : value} both int :return: """ for address in values: if address not in self.register_values_widgets: continue val, widget = self.register_values_widgets[address] widget.set(str(values[address])) if go_to_value: self.__setbutton_click(wait) def __delete_window(self): CamGrabber.exit = True self.stop_signal = True self.client.close() self.root.quit()
# define o cliente c = ModbusClient() # debug do cliente #c.debug(True) # ip/porta do servidor modbus (para se conectar) c.host("10.13.110.215") c.port(502) while True: # para abrir a conexao TCP com o servidor if not c.is_open(): if not c.open(): print ("unable to connect") # read_coils() para leitura de dados vindo do servidor/supervisorio on = c.read_coils(6) # se a conexao estabelecida, entao escreve (write coils (modbus function 0x01)) if c.is_open(): c.write_single_coil(v1, valvula1) c.write_single_coil(v2, valvula2) c.write_single_register(n1, nivel1) c.write_single_register(n2, nivel2) # ... logica de codigo a implementar de acordo com a aplicacao a ser desenvolvida
class ClienteMODBUS(): """ Classe Cliente MODBUS """ def __init__(self, server_ip, porta, device_id=1, scan_time=0.1, valor=0, dbpath="C:\database.db"): """ Construtor """ self._scan_time = scan_time self._server_ip = server_ip self._device_id = device_id self._port = porta self._cliente = ModbusClient(host=server_ip, port=porta, unit_id=device_id) self._dbpath = dbpath self._valor = valor self._con = sqlite3.connect(self._dbpath) self._cursor = self._con.cursor() def atendimento(self): """ Método para atendimento do usuário """ try: self._cliente.open() print('\n\033[33m --> Cliente Modbus conectado..\033[m\n') except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') try: atendimento = True while atendimento: print('-' * 100) print('\033[34mCliente Modbus\033[m'.center(100)) print('-' * 100) sel = input( "Qual serviço? \n1- Leitura \n2- Escrita \n3- Configuração \n4- Sair \nNº Serviço: " ) if sel == '1': self.createTable() self.createTableF01() self.createTableF02() self.createTableF03() self.createTableF04() print('\nQual tipo de dado deseja ler?') print( "1- Coil Status \n2- Input Status \n3- Holding Register \n4- Input Register" ) while True: tipo = int(input("Type: ")) if tipo > 4: print('\033[31mDigite um tipo válido..\033[m') sleep(0.5) else: break if tipo == 3 or tipo == 4: while True: val = int( input( "\n1- Decimal \n2- Floating Point \n3- Float Swapped \nLeitura: " )) if val > 3: print('\033[31mDigite um tipo válido..\033[m') sleep(0.5) else: break if val == 1: #valores decimais addr = int(input(f'\nAddress: ')) leng = int(input(f'Length: ')) nvezes = input('Quantidade de leituras: ') print('\nComeçando leitura Decimal..\n') sleep(0.5) try: for i in range(0, int(nvezes)): print(f'\033[33mLeitura {i+1}:\033[m', end='') print( self.lerDado(int(tipo), int(addr), leng)) sleep(self._scan_time) print( '\nValores lidos e inseridos no DB com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') try: sleep(0.5) print( '\033[33m\nTentando novamente..\033[m') if not self._cliente.is_open(): self._cliente.open() sleep(0.5) for i in range(0, int(nvezes)): print( f'\033[33mLeitura {i + 1}:\033[m', end='') print( self.lerDado( int(tipo), int(addr), leng)) sleep(self._scan_time) print( '\nValores lidos e inseridos no DB com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') print( '\nO Cliente não conseguiu receber uma resposta.. \nVoltando ao menu..\n\n' ) sleep(1.5) elif val == 2: #valores FLOAT addr = input(f'\nAddress: ') leng = int(input(f'Length: ')) nvezes = input('Quantidade de leituras: ') print('\nComeçando leitura FLOAT..\n') sleep(0.5) try: for i in range(0, int(nvezes)): print(f'\033[33mLeitura {i + 1}:\033[m', end='') print( self.lerDadoFloat( int(tipo), int(addr), leng)) sleep(self._scan_time) print( '\nValores lidos e inseridos no DB com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m\n') print( 'O Cliente não conseguiu receber uma resposta.. \nVoltando ao menu..\n\n' ) sleep(1.5) elif val == 3: #valores FLOAT SWAPPED addr = input(f'\nAddress: ') leng = int(input(f'Length: ')) nvezes = input('Quantidade de leituras: ') print('\nComeçando leitura FLOAT SWAPPED..\n') sleep(0.5) try: for i in range(0, int(nvezes)): print(f'\033[33mLeitura {i + 1}:\033[m', end='') print( self.lerDadoFloatSwapped( int(tipo), int(addr), leng)) sleep(self._scan_time) print( '\nValores lidos e inseridos no DB com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m\n') print( 'O Cliente não conseguiu receber uma resposta.. \nVoltando ao menu..\n\n' ) sleep(1.5) else: print('\033[31mSeleção inválida..\033[m\n') sleep(0.7) else: addr = input(f'\nAddress: ') leng = int(input(f'Length: ')) nvezes = input('Quantidade de leituras: ') print('\nComeçando leitura..\n') sleep(0.5) try: for i in range(0, int(nvezes)): print(f'\033[33mLeitura {i + 1}:\033[m', end='') print(self.lerDado(int(tipo), int(addr), leng)) sleep(self._scan_time) print( '\nValores lidos e inseridos no DB com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m\n') print( 'O Cliente não conseguiu receber uma resposta.. \nVoltando ao menu..\n\n' ) sleep(1.5) elif sel == '2': print( '\nQual tipo de dado deseja escrever? \n1- Coil Status \n2- Holding Register' ) while True: tipo = int(input("Tipo: ")) if tipo > 2: print('\033[31mDigite um tipo válido..\033[m') sleep(0.5) else: break addr = input(f'Digite o endereço: ') valor = int(input(f'Digite o valor que deseja escrever: ')) try: print('\nEscrevendo..') sleep(0.5) self.escreveDado(int(tipo), int(addr), valor) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') print( '\nO Cliente não conseguiu escrever.. \nVoltando ao menu..\n\n' ) sleep(1.5) elif sel == '3': print('') print('-' * 100) print('Configurações de Leitura'.center(100)) print( f'\n\033[32m->\033[m Configuração atual: - IP Addrs: \033[35m{self._server_ip}\033[m - TCP Port: \033[35m{self._port}\033[m - Device ID: \033[35m{self._device_id}\033[m - Scan_Time: \033[35m{self._scan_time}\033[ms' ) print( '\nQual tipo de configuração deseja fazer? \n1- Endereço IP \n2- Porta TCP \n3- Device ID \n4- ScanTime \n5- Voltar' ) config = int(input("Configuração: ")) if config == 1: ipserv = str(input(' Novo endereço IP: ')) try: self._cliente.close() self._server_ip = ipserv self._cliente = ModbusClient(host=self._server_ip) self._cliente.open() print( f'\nServer IP alterado para {ipserv} com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') print( '\nNão foi possível alterar o endereço IP.. \nVoltando ao menu..\n\n' ) sleep(0.5) elif config == 2: porttcp = input(' Nova porta TCP: ') try: self._cliente.close() self._port = int(porttcp) self._cliente = ModbusClient(port=self._port) self._cliente.open() print( f'\nTCP port alterado para {porttcp} com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') print( '\nNão foi possível alterar a porta.. \nVoltando ao menu..\n\n' ) sleep(0.5) elif config == 3: while True: iddevice = input(' Novo device ID: ') if 0 <= int(iddevice) < 256: break else: print( '\033[31mDevice ID deve ser um número inteiro entre 0 e 256.\033[m', end='') sleep(0.5) try: self._cliente.close() self._device_id = int(iddevice) self._cliente = ModbusClient( unit_id=self._device_id) self._cliente.open() print( f'\nDevice ID alterado para {iddevice} com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') print( '\nNão foi possível alterar o ID do device.. \nVoltando ao menu..\n\n' ) sleep(0.5) elif config == 4: scant = input(' Novo tempo de varredura [s]: ') try: self._scan_time = float(scant) print( f'\nScan_time alterado para {scant}s com sucesso!!\n' ) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') print( '\nNão foi possível alterar o tempo de varredura.. \nVoltando ao menu..\n\n' ) sleep(0.5) elif config == 5: print('\nVoltando ao menu inicial..\n') sleep(0.5) else: print('\033[31mSeleção inválida..\033[m\n') sleep(0.7) elif sel == '4': sleep(0.2) print('\n\033[32mFechando sistema..\033[m') sleep(0.5) self._cliente.close() atendimento = False else: print('\033[31mSeleção inválida..\033[m\n') sleep(0.7) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def createTable(self): """ Método que cria a tabela para armazenamento dos dados, caso ela não exista """ try: sql_str = f""" CREATE TABLE IF NOT EXISTS pointValues ( ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Address TEXT, Type TEXT, Display TEXT, Value REAL, TimeStamp1 TEXT NOT NULL) """ self._cursor.execute(sql_str) self._con.commit() except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def inserirDB(self, addrs, tipo, disp, value): """ Método para inserção dos dados no DB """ try: date = str( datetime.datetime.fromtimestamp(int( time.time())).strftime("%Y-%m-%d %H:%M:%S")) str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'" sql_str = f'INSERT INTO pointValues (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})' self._cursor.execute(sql_str) self._con.commit() except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def createTableF01(self): """ Método que cria a tabela para armazenamento dos dados, caso ela não exista """ try: sql_str = f""" CREATE TABLE IF NOT EXISTS pointValuesF01 ( ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Address TEXT, Type TEXT, Display TEXT, Value REAL, TimeStamp1 TEXT NOT NULL) """ self._cursor.execute(sql_str) self._con.commit() except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def createTableF02(self): """ Método que cria a tabela para armazenamento dos dados, caso ela não exista """ try: sql_str = f""" CREATE TABLE IF NOT EXISTS pointValuesF02 ( ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Address TEXT, Type TEXT, Display TEXT, Value REAL, TimeStamp1 TEXT NOT NULL) """ self._cursor.execute(sql_str) self._con.commit() except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def createTableF03(self): """ Método que cria a tabela para armazenamento dos dados, caso ela não exista """ try: sql_str = f""" CREATE TABLE IF NOT EXISTS pointValuesF03 ( ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Address TEXT, Type TEXT, Display TEXT, Value REAL, TimeStamp1 TEXT NOT NULL) """ self._cursor.execute(sql_str) self._con.commit() except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def createTableF04(self): """ Método que cria a tabela para armazenamento dos dados, caso ela não exista """ try: sql_str = f""" CREATE TABLE IF NOT EXISTS pointValuesF04 ( ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Address TEXT, Type TEXT, Display TEXT, Value REAL, TimeStamp1 TEXT NOT NULL) """ self._cursor.execute(sql_str) self._con.commit() except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def inserirDBF0(self, addrs, tipo, disp, value): """ Método para inserção dos dados no DB """ try: if tipo == "'F01-CoilStatus'": date = str( datetime.datetime.fromtimestamp(int( time.time())).strftime("%Y-%m-%d %H:%M:%S")) str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'" sql_str = f'INSERT INTO pointValuesF01 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})' self._cursor.execute(sql_str) self._con.commit() elif tipo == "'F02-InputStatus'": date = str( datetime.datetime.fromtimestamp(int( time.time())).strftime("%Y-%m-%d %H:%M:%S")) str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'" sql_str = f'INSERT INTO pointValuesF02 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})' self._cursor.execute(sql_str) self._con.commit() elif tipo == "'F03-HoldingRegister'": date = str( datetime.datetime.fromtimestamp(int( time.time())).strftime("%Y-%m-%d %H:%M:%S")) str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'" sql_str = f'INSERT INTO pointValuesF03 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})' self._cursor.execute(sql_str) self._con.commit() elif tipo == "'F04-InputRegister'": date = str( datetime.datetime.fromtimestamp(int( time.time())).strftime("%Y-%m-%d %H:%M:%S")) str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'" sql_str = f'INSERT INTO pointValuesF04 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})' self._cursor.execute(sql_str) self._con.commit() except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def inserirDBFP(self, addrs, tipo, disp, value): """ Método para inserção dos dados no DB """ try: if tipo == "'F03-HoldingRegister'": date = str( datetime.datetime.fromtimestamp(int( time.time())).strftime("%Y-%m-%d %H:%M:%S")) str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'" sql_str = f'INSERT INTO pointValuesF03 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})' self._cursor.execute(sql_str) self._con.commit() elif tipo == "'F04-InputRegister'": date = str( datetime.datetime.fromtimestamp(int( time.time())).strftime("%Y-%m-%d %H:%M:%S")) str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'" sql_str = f'INSERT INTO pointValuesF04 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})' self._cursor.execute(sql_str) self._con.commit() else: print( "Erro ao inserir no DB com Floating Point e Float Swapped!!" ) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def lerDado(self, tipo, addr, leng=1): """ Método para leitura MODBUS """ if tipo == 1: co = self._cliente.read_coils(addr - 1, leng) ic = 0 while ic <= leng: if ic == leng: break else: value = co[0 + ic] ic += 1 # print(value) if value == True: value = 1 else: value = 0 ende = str(addr + ic - 1).zfill(5) self.inserirDB(addrs=str(ende), tipo="'F01-CoilStatus'", disp="'Booleano'", value=value) self.inserirDBF0(addrs=str(ende), tipo="'F01-CoilStatus'", disp="'Booleano'", value=value) return co elif tipo == 2: di = self._cliente.read_discrete_inputs(addr - 1, leng) idi = 0 while idi <= leng: if idi == leng: break else: value = di[0 + idi] idi += 1 # print(value) self.inserirDB(addrs=(10000 + addr + idi - 1), tipo="'F02-InputStatus'", disp="'Booleano'", value=value) self.inserirDBF0(addrs=(10000 + addr + idi - 1), tipo="'F02-InputStatus'", disp="'Booleano'", value=value) return di elif tipo == 3: hr = self._cliente.read_holding_registers(addr - 1, leng) ihr = 0 while ihr <= leng: if ihr == leng: break else: value = hr[0 + ihr] ihr += 1 # print(value) self.inserirDB(addrs=(40000 + addr + ihr - 1), tipo="'F03-HoldingRegister'", disp="'Decimal'", value=value) self.inserirDBF0(addrs=(40000 + addr + ihr - 1), tipo="'F03-HoldingRegister'", disp="'Decimal'", value=value) return hr elif tipo == 4: ir = self._cliente.read_input_registers(addr - 1, leng) iir = 0 while iir <= leng: if iir == leng: break else: value = ir[0 + iir] iir += 1 # print(value) self.inserirDB(addrs=(30000 + addr + iir - 1), tipo="'F04-InputRegister'", disp="'Decimal'", value=value) self.inserirDBF0(addrs=(30000 + addr + iir - 1), tipo="'F04-InputRegister'", disp="'Decimal'", value=value) return ir else: print('Tipo de leitura inválido..') def lerDadoFloat(self, tipo, addr, leng): """ Método para leitura FLOAT MODBUS """ i = 0 g = 0 e1 = [] listfloat = [] while i < leng: if tipo == 3: i1 = self._cliente.read_holding_registers(addr - 1 + g, 2) tipore = "'F03-HoldingRegister'" ende = 40000 elif tipo == 4: i1 = self._cliente.read_input_registers(addr - 1 + g, 2) tipore = "'F04-InputRegister'" ende = 30000 else: print('Tipo inválido..') for x in i1: x = bin(x).lstrip("0b") e1.insert(0 + g, x) i += 1 g += 2 e = 0 while e <= leng: e2 = '' for x in e1: e2 = str(f'{e2}{x.rjust(16, "0")} ') e += 1 b2 = str(f'{e2}') e3 = b2.split() y = 0 while y < len(e3): ieee = f'{e3[0+y]}{e3[1+y]}' sign = int(ieee[0]) expo = str(ieee[1:9]) expodec = 0 expopot = 7 for i in range(8): expodec = expodec + (int(expo[i]) * (2**expopot)) expopot -= 1 mant = str(ieee[9:]) mantdec = 0 mantpot = -1 for i in range(23): mantdec = mantdec + (int(mant[i]) * (2**mantpot)) mantpot -= 1 value = ((-1)**sign) * (1 + mantdec) * 2**(expodec - 127) # print(f'{round(value, 3)}') listfloat.append(round(value, 3)) y += 2 self.inserirDB(addrs=(ende + addr + y - 2), tipo=tipore, disp="'Floating Point'", value=round(value, 3)) self.inserirDBFP(addrs=(ende + addr + y - 2), tipo=tipore, disp="'Floating Point'", value=round(value, 3)) return listfloat def lerDadoFloatSwapped(self, tipo, addr, leng): """ Método para leitura FLOAT SWAPPED MODBUS """ i = 0 g = 0 e1 = [] listfloatsp = [] while i < leng: if tipo == 3: i1 = self._cliente.read_holding_registers(addr - 1 + g, 2) tipore = "'F03-HoldingRegister'" ende = 40000 elif tipo == 4: i1 = self._cliente.read_input_registers(addr - 1 + g, 2) tipore = "'F04-InputRegister'" ende = 30000 else: print('Tipo inválido..') i2 = i1[::-1] for x in i2: x = bin(x).lstrip("0b") e1.insert(0 + g, x) i += 1 g += 2 e = 0 while e <= leng: e2 = '' for x in e1: e2 = str(f'{e2}{x.rjust(16, "0")} ') e += 1 b2 = str(f'{e2}') e3 = b2.split() y = 0 while y < len(e3): ieee = f'{e3[0+y]}{e3[1+y]}' sign = int(ieee[0]) expo = str(ieee[1:9]) expodec = 0 expopot = 7 for i in range(8): expodec = expodec + (int(expo[i]) * (2**expopot)) expopot -= 1 mant = str(ieee[9:]) mantdec = 0 mantpot = -1 for i in range(23): mantdec = mantdec + (int(mant[i]) * (2**mantpot)) mantpot -= 1 value = ((-1)**sign) * (1 + mantdec) * 2**(expodec - 127) # print(f'{round(value, 3)}') listfloatsp.append(round(value, 3)) y += 2 self.inserirDB(addrs=(ende + addr + y - 2), tipo=tipore, disp="'Float (Swapped)'", value=round(value, 3)) self.inserirDBFP(addrs=(ende + addr + y - 2), tipo=tipore, disp="'Float (Swapped)'", value=round(value, 3)) return listfloatsp def escreveDado(self, tipo, addr, valor): """ Método para escrita MODBUS """ try: if tipo == 1: print( f'\033[33mValor {valor} escrito no endereço {addr}\033[m\n' ) return self._cliente.write_single_coil(addr - 1, valor) elif tipo == 2: print( f'\033[33mValor {valor} escrito no endereço {addr}\033[m\n' ) return self._cliente.write_single_register(addr - 1, valor) else: print('Tipo de escrita inválido..\n') except Exception as e: print('\033[31mERRO: ', e.args, '\033[m')
class ET7000: ranges = { 0x00: { 'min': -0.015, 'max': 0.015, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0x01: { 'min': -0.05, 'max': 0.05, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0x02: { 'min': -0.1, 'max': 0.1, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0x03: { 'min': -0.5, 'max': 0.5, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0x04: { 'min': -1., 'max': 1., 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0x05: { 'min': -2.5, 'max': 2.5, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0x06: { 'min': -20.0e-3, 'max': 20.0e-3, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'A' }, 0x07: { 'units': 'A', 'min': 4.0e-3, 'min_code': 0x0000, 'max_code': 0xffff, 'max': 20.0e-3 }, 0x08: { 'units': 'V', 'min': -10., 'max': 10., 'min_code': 0x8000, 'max_code': 0x7fff, }, 0x09: { 'units': 'V', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -5., 'max': 5. }, 0x0A: { 'units': 'V', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -1., 'max': 1. }, 0x0B: { 'units': 'V', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -.5, 'max': .5 }, 0x0C: { 'units': 'V', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -.15, 'max': .15 }, 0x0D: { 'min': -20.0e-3, 'max': 20.0e-3, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'A' }, 0x0E: { 'units': 'degC', 'min_code': 0xdca2, 'max_code': 0x7fff, 'min': -210.0, 'max': 760.0 }, 0x0F: { 'units': 'degC', 'min_code': 0xe6d0, 'max_code': 0x7fff, 'min': -270.0, 'max': 1372.0 }, 0x10: { 'units': 'degC', 'min_code': 0xa99a, 'max_code': 0x7fff, 'min': -270.0, 'max': 400.0 }, 0x11: { 'units': 'degC', 'min_code': 0xdd71, 'max_code': 0x7fff, 'min': -270.0, 'max': 1000.0 }, 0x12: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 1768.0 }, 0x13: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 1768.0 }, 0x14: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 1820.0 }, 0x15: { 'units': 'degC', 'min_code': 0xe56b, 'max_code': 0x7fff, 'min': -270.0, 'max': 1300.0 }, 0x16: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 2320.0 }, 0x17: { 'units': 'degC', 'min_code': 0xe000, 'max_code': 0x7fff, 'min': -200.0, 'max': 800.0 }, 0x18: { 'units': 'degC', 'min_code': 0x8000, 'max_code': 0x4000, 'min': -200.0, 'max': 100.0 }, 0x19: { 'units': 'degC', 'min_code': 0xe38e, 'max_code': 0xffff, 'min': -200.0, 'max': 900.0 }, 0x1A: { 'min': 0.0, 'max': 20.0e-3, 'min_code': 0x0000, 'max_code': 0xffff, 'units': 'A' }, 0x20: { 'units': 'degC', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -100.0, 'max': 100.0 }, 0x21: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 100.0 }, 0x22: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 200.0 }, 0x23: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 600.0 }, 0x24: { 'units': 'degC', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -100.0, 'max': 100.0 }, 0x25: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 100.0 }, 0x26: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 200.0 }, 0x27: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 600.0 }, 0x28: { 'units': 'degC', 'min_code': 0x999a, 'max_code': 0x7fff, 'min': -80.0, 'max': 100.0 }, 0x29: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 100.0 }, 0x2A: { 'units': 'degC', 'min_code': 0xd556, 'max_code': 0x7fff, 'min': -200.0, 'max': 600.0 }, 0x2B: { 'units': 'degC', 'min_code': 0xeeef, 'max_code': 0x7fff, 'min': -20.0, 'max': 150.0 }, 0x2C: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 200.0 }, 0x2D: { 'units': 'degC', 'min_code': 0xeeef, 'max_code': 0x7fff, 'min': -20.0, 'max': 150.0 }, 0x2E: { 'units': 'degC', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -200.0, 'max': 200.0 }, 0x2F: { 'units': 'degC', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -200.0, 'max': 200.0 }, 0x80: { 'units': 'degC', 'min_code': 0xd556, 'max_code': 0x7fff, 'min': -200.0, 'max': 600.0 }, 0x81: { 'units': 'degC', 'min_code': 0xd556, 'max_code': 0x7fff, 'min': -200.0, 'max': 600.0 }, 0x82: { 'units': 'degC', 'min_code': 0xd556, 'max_code': 0x7fff, 'min': -50.0, 'max': 150.0 }, 0x83: { 'min_code': 0xd556, 'max_code': 0x7fff, 'units': 'degC', 'min': -60.0, 'max': 180.0 }, 0x30: { 'min_code': 0x0000, 'max_code': 0xffff, 'min': 0.0, 'max': 20.0e-3, 'units': 'A' }, 0x31: { 'min_code': 0x0000, 'max_code': 0xffff, 'min': 4.0e-3, 'max': 20.0e-3, 'units': 'A' }, 0x32: { 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 10.0, 'units': 'V' }, 0x33: { 'min': -10.0, 'max': 10.0, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0x34: { 'min': 0.0, 'max': 5.0, 'min_code': 0x0000, 'max_code': 0x7fff, 'units': 'V' }, 0x35: { 'min': -5.0, 'max': 5.0, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0xff: { 'min': 0, 'max': 0xffff, 'min_code': 0x0000, 'max_code': 0xffff, 'units': '?' } } devices = {0x7015: {}, 0x7016: {}, 0x7018: {}, 0x7060: {}, 0x7026: {}} @staticmethod def range(r): if r in ET7000.ranges: return (ET7000.ranges[r]) return ET7000.ranges[0xff] # default conversion from quanta to real units @staticmethod def convert(b, amin, amax): b = float(b) # обрабатывается 2 случая - минимум нулевой или больше 0 if amin >= 0 and amax > 0: return amin + (amax - amin) * b / 0xffff # и минимум и максимум разного знака if amin < 0 and amax > 0: range = max(-amin, amax) if b <= 0x7fff: return range * b / 0x7fff else: return range * (0x8000 - b) / 0x8000 # в других случаях ошибка return float('nan') @staticmethod def ai_convert_function(r): v_min = 0 v_max = 0xffff c_min = 0 c_max = 0xffff try: v_min = ET7000.ranges[r]['min'] v_max = ET7000.ranges[r]['max'] c_min = ET7000.ranges[r]['min_code'] c_max = ET7000.ranges[r]['max_code'] except: pass if c_min < c_max: k = (v_max - v_min) / (c_max - c_min) b = v_min - k * c_min return lambda x: k * x + b k_max = v_max / c_max k_min = v_min / (0x10000 - c_min) #return lambda x: (x < 0x8000) * k_max * x + (x >= 0x8000) * k_min * (0x10000 - x) return lambda x: k_max * x if x < 0x8000 else k_min * (0x10000 - x) @staticmethod def ao_convert_function(r): v_min = 0 v_max = 0xffff c_min = 0 c_max = 0xffff try: v_min = ET7000.ranges[r]['min'] v_max = ET7000.ranges[r]['max'] c_min = ET7000.ranges[r]['min_code'] c_max = ET7000.ranges[r]['max_code'] except: pass #print(hex(r), v_min, v_max, c_min, c_max) if c_min < c_max: k = (c_max - c_min) / (v_max - v_min) b = c_min - k * v_min return lambda x: int(k * x + b) k_max = c_max / v_max k_min = (0xffff - c_min) / v_min #return lambda x: int((x >= 0) * k_max * x + (x < 0) * (0xffff - k_min * x)) return lambda x: int(k_max * x) if (x >= 0) else int(0xffff - k_min * x ) @staticmethod def convert_to_raw(v, amin, amax): v = float(v) # обрабатывается 2 случая - минимум нулевой или больше 0 if amin >= 0 and amax > 0: return int((v - amin) / (amax - amin) * 0xffff) # и минимум и максимум разного знака if amin < 0 and amax > 0: if v >= 0.0: return int(v * 0x7fff / amax) else: return int(0x8000 - v / amax * 0x7fff) # в других случаях ошибка return 0 def __init__(self, host, port=502, timeout=0.15, logger=None): self.host = host self.port = port # logger confid if logger is None: logger = logging.getLogger(__name__) self.logger = logger # default device type self._name = 0 self.type = '0000' # default ai self.AI_n = 0 self.AI_masks = [] self.AI_ranges = [] self.AI_min = [] self.AI_max = [] self.AI_units = [] self.AI_raw = [] self.AI_values = [] # default ao self.AO_n = 0 self.AO_masks = [] self.AO_ranges = [] self.AO_min = [] self.AO_max = [] self.AO_units = [] self.AO_raw = [] self.AO_values = [] self.AO_write_raw = [] self.AO_write_values = [] self.AO_write_result = False # default di self.DI_n = 0 self.DI_values = [] # default do self.DO_n = 0 self.DO_values = [] # modbus client self._client = ModbusClient(host, port, auto_open=True, auto_close=True, timeout=timeout) status = self._client.open() if not status: self.logger.error('ET7000 device at %s is offline' % host) return # read module name self._name = self.read_module_name() self.type = hex(self._name).replace('0x', '') if self._name not in ET7000.devices: self.logger.warning( 'ET7000 device type %s probably not supported' % hex(self._name)) # ai self.AI_n = self.read_AI_n() self.AI_masks = [False] * self.AI_n self.AI_ranges = [0xff] * self.AI_n self.AI_raw = [0] * self.AI_n self.AI_values = [float('nan')] * self.AI_n self.AI_units = [''] * self.AI_n self.read_AI_masks() self.read_AI_ranges() self.AI_convert = [lambda x: x] * self.AI_n for n in range(self.AI_n): r = self.AI_ranges[n] self.AI_units[n] = ET7000.ranges[r]['units'] self.AI_convert[n] = ET7000.ai_convert_function(r) # ao self.AO_n = self.read_AO_n() self.AO_masks = [True] * self.AO_n self.read_AO_masks() self.AO_ranges = [0xff] * self.AO_n self.AO_raw = [0] * self.AO_n self.AO_values = [float('nan')] * self.AO_n self.AO_write_values = [float('nan')] * self.AO_n self.AO_units = [''] * self.AO_n self.AO_write = [0] * self.AO_n self.AO_write_raw = [0] * self.AO_n self.read_AO_ranges() self.AO_convert = [lambda x: x] * self.AI_n self.AO_convert_write = [lambda x: 0] * self.AI_n for n in range(self.AO_n): r = self.AO_ranges[n] self.AO_units[n] = ET7000.ranges[r]['units'] self.AO_convert[n] = ET7000.ai_convert_function( r) # !!! ai_convert for reading self.AO_convert_write[n] = ET7000.ao_convert_function( r) # !!! ao_convert for writing # di self.DI_n = self.read_DI_n() self.DI_values = [False] * self.DI_n # do self.DO_n = self.read_DO_n() self.DO_values = [False] * self.DO_n self.DO_write = [False] * self.DO_n def read_module_name(self): regs = self._client.read_holding_registers(559, 1) if regs and regs[0] != 0: return regs[0] regs = self._client.read_holding_registers(260, 1) if regs: return regs[0] return 0 # AI functions def read_AI_n(self): regs = self._client.read_input_registers(320, 1) if regs and regs[0] != 0: return regs[0] regs = self._client.read_input_registers(120, 1) if regs: return regs[0] return 0 def read_AI_masks(self): coils = self._client.read_coils(595, self.AI_n) if coils and len(coils) == self.AI_n: self.AI_masks = coils return coils def read_AI_ranges(self): regs = self._client.read_holding_registers(427, self.AI_n) if regs and len(regs) == self.AI_n: self.AI_ranges = regs return regs def read_AI_raw(self, channel=None): if channel is None: n = self.AI_n channel = 0 else: n = 1 regs = self._client.read_input_registers(0 + channel, n) if regs and len(regs) == n: self.AI_raw[channel:channel + n] = regs if n == 1: return regs[0] return regs def convert_AI(self): for k in range(self.AI_n): if self.AI_masks[k]: self.AI_values[k] = self.AI_convert[k](self.AI_raw[k]) else: self.AI_values[k] = float('nan') return self.AI_values def read_AI(self, channel=None): if channel is None: self.read_AI_raw() self.convert_AI() return self.AI_values return self.read_AI_channel(channel) def read_AI_channel(self, k: int): v = float('nan') if self.AI_masks[k]: regs = self._client.read_input_registers(0 + k, 1) if regs: self.AI_raw[k] = regs[0] v = self.AI_convert[k](regs[0]) self.AI_values[k] = v return v # AO functions def read_AO_n(self): regs = self._client.read_input_registers(330, 1) if regs and regs[0] != 0: return regs[0] regs = self._client.read_input_registers(130, 1) if regs: return regs[0] return 0 def read_AO_masks(self): return self.AO_masks def read_AO_ranges(self): regs = self._client.read_holding_registers(459, self.AO_n) if regs and len(regs) == self.AO_n: self.AO_ranges = regs return regs def read_AO_raw(self, channel=None): if channel is None: n = self.AO_n channel = 0 else: n = 1 regs = self._client.read_holding_registers(0 + channel, n) if regs and len(regs) == n: self.AO_raw[channel:channel + n] = regs if n == 1: return regs[0] return regs def write_AO_raw(self, regs): result = self._client.write_multiple_registers(0, regs) self.AO_write_result = result if len(regs) == self.AO_n: self.AO_write_raw = regs return result def convert_AO(self): raw = self.AO_raw for k in range(self.AO_n): self.AO_values[k] = self.AO_convert[k](raw[k]) return self.AO_values def convert_to_raw_AO(self, values=None): if values is None: values = self.AO_write_values answer = [] for k in range(len(values)): answer.append(self.AO_convert_write[k](values[k])) return answer def read_AO(self): self.AO_raw = self.read_AO_raw() self.convert_AO() return self.AO_values def read_AO_channel(self, k: int): v = float('nan') if self.AO_masks[k]: regs = self._client.read_holding_registers(0 + k, 1) if regs: v = self.AO_convert[k](regs[0]) self.AO_values[k] = v return v def write_AO(self, values): self.AO_write_values = values regs = ET7000.convert_to_raw_AO(values) result = self.write_AO_raw(regs) return result def write_AO_channel(self, k: int, value): raw = self.AO_convert_write[k](value) result = self._client.write_single_register(0 + k, raw) self.AO_write_result = result if result: self.AO_write_values[k] = value self.AO_write_raw[k] = raw pass return result # DI functions def read_DI_n(self): regs = self._client.read_input_registers(300, 1) if regs and regs[0] != 0: return regs[0] regs = self._client.read_input_registers(100, 1) if regs: return regs[0] return 0 def read_DI(self): regs = self._client.read_discrete_inputs(0, self.DI_n) if regs: self.DI_values = regs return self.DI_values def read_DI_channel(self, k: int): reg = self._client.read_discrete_inputs(0 + k, 1) if reg: self.DI_values[k] = reg[0] return reg[0] return None # DO functions def read_DO_n(self): self.DO_time = time.time() regs = self._client.read_input_registers(310, 1) if regs and regs[0] != 0: return regs[0] regs = self._client.read_input_registers(110, 1) if regs: return regs[0] return 0 def read_DO(self): regs = self._client.read_coils(0, self.DI_n) if regs: self.DI_values = regs return self.DI_values def read_DO_channel(self, k: int): reg = self._client.read_coils(0 + k, 1) if reg: self.DO_values[k] = reg[0] return reg[0] return None def write_DO(self, values): self.DO_write = values self.DO_write_result = self._client.write_multiple_coils(0, values) return self.DO_write_result def write_DO_channel(self, k: int, value: bool): result = self._client.write_single_coil(0 + k, value) self.DO_write_result = result if result: self.DO_write[k] = value return result
class HeatPump(): def __init__(self, ipOrHostName, portNumber, unitId, code): self.code = code self.registers = HeatPumpRegisters() self.mbClient = ModbusClient() self.mbClient.host(ipOrHostName) self.mbClient.port(portNumber) self.mbClient.unit_id(unitId) self.mbClient.open() self.outsideTemperature = HeatPumpConstants.NAN_VALUE self.currentRoomTemperature = HeatPumpConstants.NAN_VALUE self.currentExhaustFanSpeed = HeatPumpConstants.NAN_VALUE self.currentSupplyFanSpeed = HeatPumpConstants.NAN_VALUE self.airingLevelDay = HeatPumpConstants.NAN_VALUE self.airingLevelNight = HeatPumpConstants.NAN_VALUE self.powerConsumptionHeatingDay = HeatPumpConstants.NAN_VALUE self.powerConsumptionWarmWaterDay = HeatPumpConstants.NAN_VALUE return def setAiringLevelDay(self, airingLevel, code): return self._setAiringLevel(self.registers.AIRING_LEVEL_DAY.Address, airingLevel, code) def setAiringLevelNight(self, airingLevel, code): return self._setAiringLevel(self.registers.AIRING_LEVEL_NIGHT.Address, airingLevel, code) def _setAiringLevel(self, registerAddress, airingLevel, code): if int(code) != self.code: return (False, "Invalid security code") if not self.mbClient.is_open() and not self.mbClient.open(): return (False, "Unable to connect to {}:{}".format(self.mbClient.host(), self.mbClient.port())) if type(airingLevel) == str: try: airingLevel = int(airingLevel) except: raise TypeError("Could not convert {} to type 'int'".format(airingLevel)) retVal = self.mbClient.write_single_register(registerAddress, airingLevel) if not retVal: return (False, "Failed to set airing level") else: return (True, "Setting airing level successful") def readCurrentValues(self): if not self.mbClient.is_open() and not self.mbClient.open(): print ("Unable to connect to {}:{}".format(self.mbClient.host(), self.mbClient.port())) return False regVal_outsideTemperature = self.mbClient.read_input_registers(self.registers.OUTSIDE_TEMPERATURE.Address, self.registers.OUTSIDE_TEMPERATURE.SequenceSize) regVal_currentRoomTemperature = self.mbClient.read_input_registers(self.registers.CURRENT_ROOM_TEMPERATURE.Address, self.registers.CURRENT_ROOM_TEMPERATURE.SequenceSize) regVal_currentExhaustFanSpeed = self.mbClient.read_input_registers(self.registers.CURRENT_EXHAUST_FAN_SPEED.Address, self.registers.CURRENT_EXHAUST_FAN_SPEED.SequenceSize) regVal_currentSupplyFanSpeed = self.mbClient.read_input_registers(self.registers.CURRENT_SUPPLY_FAN_SPEED.Address, self.registers.CURRENT_SUPPLY_FAN_SPEED.SequenceSize) regVal_airingLevelDay = self.mbClient.read_holding_registers(self.registers.AIRING_LEVEL_DAY.Address, self.registers.AIRING_LEVEL_DAY.SequenceSize) regVal_airingLevelNight = self.mbClient.read_holding_registers(self.registers.AIRING_LEVEL_NIGHT.Address, self.registers.AIRING_LEVEL_NIGHT.SequenceSize) regVal_powerConsumptionHeatingDay = self.mbClient.read_input_registers(self.registers.POWER_CONSUMPTION_HEATING_DAY.Address, self.registers.POWER_CONSUMPTION_HEATING_DAY.SequenceSize) regVal_powerConsumptionWarmWaterDay = self.mbClient.read_input_registers(self.registers.POWER_CONSUMPTION_WARMWATER_DAY.Address, self.registers.POWER_CONSUMPTION_WARMWATER_DAY.SequenceSize) outsideTemperature = self.registers.shiftValue(regVal_outsideTemperature, self.registers.OUTSIDE_TEMPERATURE.SequenceSize) # outsideTemperature can be less than zero self.outsideTemperature = self.registers.convertSignedValue(outsideTemperature, HeatPumpConstants.MBREG_BITWIDTH) * 0.1 self.currentRoomTemperature = self.registers.shiftValue(regVal_currentRoomTemperature, self.registers.CURRENT_ROOM_TEMPERATURE.SequenceSize) * 0.1 self.currentExhaustFanSpeed = self.registers.shiftValue(regVal_currentExhaustFanSpeed, self.registers.CURRENT_EXHAUST_FAN_SPEED.SequenceSize) self.currentSupplyFanSpeed = self.registers.shiftValue(regVal_currentSupplyFanSpeed, self.registers.CURRENT_SUPPLY_FAN_SPEED.SequenceSize) self.airingLevelDay = self.registers.shiftValue(regVal_airingLevelDay, self.registers.AIRING_LEVEL_DAY.SequenceSize) self.airingLevelNight = self.registers.shiftValue(regVal_airingLevelNight, self.registers.AIRING_LEVEL_NIGHT.SequenceSize) self.powerConsumptionHeatingDay = self.registers.shiftValue(regVal_powerConsumptionHeatingDay, self.registers.POWER_CONSUMPTION_HEATING_DAY.SequenceSize) self.powerConsumptionWarmWaterDay = self.registers.shiftValue(regVal_powerConsumptionWarmWaterDay, self.registers.POWER_CONSUMPTION_WARMWATER_DAY.SequenceSize) return True
import time from pyModbusTCP.client import ModbusClient # Equipamentos no chão de fábrica nivel0 = 0 nivel1 = 0 nivel2 = 0 c = ModbusClient('172.17.115.225', port=502, unit_id=1) while True: if c.is_open(): c.write_single_register(0, nivel0) c.write_single_register(1, nivel1) c.write_single_register(2, nivel2) print('nivel0: ' + str(nivel0) + '; nivel1: ' + str(nivel1) + '; nivel2: ' + str(nivel2)) nivel0 = nivel0 + 2 nivel1 = nivel1 + 3 nivel2 = nivel2 + 5 else: print('opening client...') c.open() print('client open!') time.sleep(1)
#contours1, hierarchy1 = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contours1, hierarchy1 = cv2.findContours(roi, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) approx_result = cv2.approxPolyDP(contours1[0], 30, True) cv2.drawContours(roi, contours1, -1, (0, 255, 0), 3) cv2.drawContours(roi, [approx_result], -1, (0, 255, 0), 3) length = (len(approx_result)) print(length) result = length #print(result) if length == 6: cv2.putText(frame, "Hexagon", (x, y + 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0)) print('Hexagon') rc = c.write_single_register(0x1100, 6) rc = c.write_single_register(0x1101, 1) #動作 #print(length) elif length == 4: cv2.putText(frame, "Rectangle", (x, y + 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0)) print('Rectangle') rc = c.write_single_register(0x1100, 4) rc = c.write_single_register(0x1101, 1) #print(length) elif length == 3: cv2.putText(frame, "Triangle", (x, y + 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0)) print('Triangle')
def send_heartbeat(ModbusClient): # sends MODBUS heart beat # c is ModbusClient wr = ModbusClient.write_single_register(20, 128) # modbus heartbeat
class Storage: def __init__( self, maxpower=3300, addr_command=63245, addr_time=63243, addr_disPower=63248, addr_chaPower=63246, timeBatt=36000, SERVER_HOST="192.168.0.51", SERVER_PORT=502, PWRNET_API_BASE_URL='http://pwrnet-158117.appspot.com/api/v1/'): self.maxPower = maxpower self.addr_command = addr_command self.addr_time = addr_time self.addr_disPower = addr_disPower self.addr_chaPower = addr_chaPower self.timeBatt = timeBatt # How long to (dis)charge [s]: uint32 self.SERVER_HOST = SERVER_HOST self.SERVER_PORT = SERVER_PORT self.tcpClient = ModbusClient(host=self.SERVER_HOST, port=self.SERVER_PORT, unit_id=247, timeout=2, auto_open=True) self.PWRNET_API_BASE_URL = PWRNET_API_BASE_URL self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.DEBUG) self.handler = RotatingFileHandler('my_log.log', maxBytes=2000, backupCount=10) self.logger.addHandler(self.handler) self.logger.info('Storage class called') def realtime(self, battVal=0.0, cosPhi=1.0): #self.logger.info('StorageRT function called') if battVal > 0: command_mode = 4 # Discharging (positive values) elif battVal < 0: command_mode = 3 # Charging (negative values) else: command_mode = 1 # Battery power battPower = abs(battVal) # [W]: float32: [-3300W ... 3300W] powerFloat = utils.encode_ieee(battPower) # Converting to ieee float32 if self.tcpClient.is_open(): # Setting time self.tcpClient.write_multiple_registers( self.addr_time, [self.timeBatt & 0xffff, (self.timeBatt & 0xffff0000) >> 16]) # Setting mode self.tcpClient.write_single_register(self.addr_command, command_mode) # Setting power if command_mode == 4: regs_disPower = self.tcpClient.write_multiple_registers( self.addr_disPower, [powerFloat & 0xffff, (powerFloat & 0xffff0000) >> 16]) if str(regs_disPower ) != "True": # Check if write function worked return 0 else: return float(time.time()) elif command_mode == 3: regs_chaPower = self.tcpClient.write_multiple_registers( self.addr_chaPower, [powerFloat & 0xffff, (powerFloat & 0xffff0000) >> 16]) if str(regs_chaPower ) != "True": # Check if write function worked return 0 else: return float(time.time()) else: return 0 else: self.tcpClient.open() return -1 def urlBased(self, devId, state=None, powerReal=0, cosPhi=1.0): #self.logger.info('Storage URL function called') if state == None: batt = requests.get(url=self.PWRNET_API_BASE_URL + "device/" + devId + "/", timeout=10) battStatus = batt.json()["status"] power = batt.json()["value"] phi = batt.json()["cosphi"] print "power: ", power print "phi: ", phi else: battStatus = state if (battStatus == "DISCHARGE"): command_mode = 4 elif (battStatus == "CHARGE"): command_mode = 3 else: command_mode = 1 powerFloat = utils.encode_ieee( powerReal) # Converting power to ieee float32 #powerFloat = utils.encode_ieee(power) # Converting power to ieee float32 if self.tcpClient.is_open(): #print 'TCP battery Opened!' # Setting time self.tcpClient.write_multiple_registers( self.addr_time, [self.timeBatt & 0xffff, (self.timeBatt & 0xffff0000) >> 16]) # Setting mode self.tcpClient.write_single_register(self.addr_command, command_mode) # Setting cosphi #print "writing cosphi" #regs_cosphi = self.writeCosPhi(valCosPhi=phi) regs_cosphi = self.writeCosPhi(valCosPhi=cosPhi) #print "regs_cosphi: ", regs_cosphi if regs_cosphi == False: return -1 # Setting power if (command_mode == 4): regs_disPower = self.tcpClient.write_multiple_registers( self.addr_disPower, [powerFloat & 0xffff, (powerFloat & 0xffff0000) >> 16]) if (str(regs_disPower) != "True"): # Check if write function worked return 0 else: return float(time.time()) elif (command_mode == 3): regs_chaPower = self.tcpClient.write_multiple_registers( self.addr_chaPower, [powerFloat & 0xffff, (powerFloat & 0xffff0000) >> 16]) if (str(regs_chaPower) != "True"): # Check if write function worked return 0 else: return float(time.time()) else: return 0 else: #self.logger.debug('tcpClient is not open') self.tcpClient.open() #print 'Returning batt...' return -1 def battery_thread(self, q_batt): self.logger.info('Battery Thread called') print 'BATTERY THREAD...' print "battery thread" state = "OFF" fct = "url" # Which function to call, url or realtime battval = 0 cosphi = 1.0 while True: if not q_batt.empty(): print "q_battery empty" try: queue_param = q_batt.get(True, 1) state = queue_param[0] # State: CHARGING, DISCHARGING, OFF fct = queue_param[1] # Function: url, realtime battval = queue_param[2] cosphi = queue_param[3] q_batt.task_done() print "Queue battery: ", queue_param except Exception as exc: self.logger.exception(exc) client.captureException() if fct == "url": print "url" batt = self.urlBased(19, state, battval, cosphi) if batt == -1: try: batt = self.urlBased(19, state, battval, cosphi) print "Called tcp" except Exception as exc: self.logger.exception(exc) client.captureException() else: print "else RT" batt = self.realtime(battval) if batt == -1: try: batt = self.realtime(battval) except Exception as exc: self.logger.exception(exc) client.captureException() def battery_act(self, q_batt): self.logger.info('Battery Thread called') print 'BATTERY THREAD...' print "battery_act" state = q_batt[0] fct = q_batt[1] # Which function to call, url or realtime battval = q_batt[2] cosphi = q_batt[3] b_id = q_batt[4] print "q_batt: ", q_batt if fct == "url": batt = self.urlBased(b_id, state, battval, cosphi) if batt == -1: try: batt = self.urlBased(b_id, state, battval, cosphi) print "SUCCEED" except Exception as exc: self.logger.exception(exc) client.captureException() else: print "RT" batt = self.realtime(battval) if batt == -1: try: batt = self.realtime(battval) except Exception as exc: self.logger.exception(exc) client.captureException() def readSOE(self, ): self.logger.info('readSOE called') addr = 62852 # Modbus address of SOE if self.tcpClient.is_open(): try: resp = self.tcpClient.read_holding_registers( addr, 2) # Reading 2 registers, int16 Lh = hex(resp[0]) Mh = hex(resp[1]) Sh = Mh[2:] + Lh[2:] val = struct.unpack('f', struct.pack('i', int( Sh, 16))) # Converting from hex to float return val[0] except Exception as exc: self.logger.exception(exc) client.captureException() else: self.tcpClient.open() return -1 def readDC(self, ): self.logger.info('readSOE called') addrI = 62834 # Modbus address of I_DC addrV = 62832 # Modbus address of V_DC addrSOE = 62852 # Modbus address of SOE addr = [addrI, addrV, addrSOE] vals_dc = [] self.realtime(-1500) for i in addr: if self.tcpClient.is_open(): print "TCP client open" try: resp = self.tcpClient.read_holding_registers( i, 2) # Reading 2 registers, int16 Lh = hex(resp[0]) Mh = hex(resp[1]) Sh = Mh[2:] + Lh[2:] print 'Sh: ', Sh val = val = struct.unpack( '!f', Sh.decode('hex')) # Converting from hex to float vals_dc.append(val[0]) except Exception as exc: print 'error in: ', i self.logger.exception(exc) client.captureException() else: self.tcpClient.open() return -1 vals_dc.append(datetime.now()) return vals_dc def readCosPhi(self): self.logger.info('readCosPhi called') addr = 61706 # Modbus address of FixedCosPhi if self.tcpClient.is_open(): try: resp = self.tcpClient.read_holding_registers( addr, 2) # Reading 2 registers, int16 Lh = hex(resp[0]) Mh = hex(resp[1]) if Lh[2:] == '0': Sh = Mh[2:] + '0000' else: Sh = Mh[2:] + Lh[2:] val = struct.unpack( '!f', Sh.decode('hex')) # Converting from hex to float return val[0] except Exception as exc: self.logger.exception(exc) client.captureException() return -9 else: self.tcpClient.open() return -9 # cannot be -1 as cosPhi can be thos number def writeCosPhi(self, valCosPhi=1.0, test=False): #self.logger.info('writeCosPhi called') addr = 61706 # Modbus address of FixedCosPhi if test: # Check to see if this function is going to be used for testing or just writing to register if self.tcpClient.is_open(): try: data_conv = utils.encode_ieee(valCosPhi) regs_data = self.tcpClient.write_multiple_registers( addr, [data_conv & 0xffff, (data_conv & 0xffff0000) >> 16]) return str(regs_data) except Exception as exc: self.logger.exception(exc) client.captureException() return False else: self.tcpClient.open() return False else: try: data_conv = utils.encode_ieee(valCosPhi) regs_data = self.tcpClient.write_multiple_registers( addr, [data_conv & 0xffff, (data_conv & 0xffff0000) >> 16]) return str(regs_data) except Exception as exc: self.logger.exception(exc) client.captureException() return False
import sys from math import * from multiprocessing import * from mpu6050_process_1 import MPU6050_Process_1 from mpu6050_process_2 import MPU6050_Process_2 from pyModbusTCP.client import ModbusClient with Manager() as manager: # Open a modbus client try: c = ModbusClient(host="140.116.82.50", port=7654) except ValueError: print("Error with host or port params") c.open() is_ok = c.write_single_register(0, 1) if not is_ok: print("open error") c.open() def exit_handler(): is_ok = c.write_multiple_registers(0, [0, 0, 0, 0, 0]) c.close() # registing exit handler atexit.register(exit_handler) # data sampling period interval = 120 sleep_time = 1 / interval i = 0
class ClientGUI: def __init__(self): self.lock = RLock() self.calibgui = None self.client = ModbusClient() self.register_values_widgets = {} self.counter = 1 self.find_thread = None self.obj_data = None self.stop_signal = False self.__build_ui() def run_ui(self): self.root.mainloop() def __build_ui(self): # ui hierarchy: # #root # connectframe # connectlabel # connectbutton # snapshotbutton # calibbuton # mainframe # registerframe # reglabel # registergridframe # ... # outputframe # outputlabel # outputtext root = Tk() self.root = root root.wm_title("RemoteSurf Modbus Client") root.protocol("WM_DELETE_WINDOW", self.__delete_window) self.font = tkFont.Font(root = root, family = "Helvetica", size = 12) connectframe = Frame(root) connectbutton = Button(connectframe, text = "Connect", command = self.__connectbutton_click) connectlabel = Label(connectframe, text = "Not connected.") calibbutton = Button(connectframe, text = "Calibrate", command = self.__calibbutton_click) homebutton = Button(connectframe, text = "Home", command = self.__homebutton_click) findbutton = Button(connectframe, text = "Find", command = self.__findbutton_click) mainframe = Frame(root) registerframe = Frame(mainframe) reglabel = Label(registerframe, text = "Set registers") registergridframe = Frame(registerframe) # outputframe = Frame(mainframe) # outputlabel = Label(outputframe, text = "Output") # vscrollbar = Scrollbar(outputframe) # hscrollbar = Scrollbar(outputframe) # outputtext = ThreadSafeConsole(outputframe, root, vscrollbar, font = self.font, wrap = NONE) connectframe.pack(side = TOP, fill = X) connectlabel.pack(side = BOTTOM, anchor = W) homebutton.pack(side = RIGHT) findbutton.pack(side = RIGHT) calibbutton.pack(side = RIGHT) connectbutton.pack(side = RIGHT) mainframe.pack(side = BOTTOM, fill = BOTH, expand = YES) registerframe.pack(side = TOP, expand = YES, anchor = W) # outputframe.pack(side = BOTTOM, fill = BOTH, expand = YES) reglabel.pack(side = TOP, anchor = CENTER) registergridframe.pack(side = BOTTOM, anchor = W) # registerframe.config(bg = "cyan") # mainframe.config(bg = "pink") # registergridframe.config(bg = "red") registergridframe.columnconfigure(0, weight = 1) registergridframe.columnconfigure(1, weight = 1) registergridframe.columnconfigure(2, weight = 1) registergridframe.columnconfigure(3, weight = 1) self.x_pad = 10 registergrid_widgets = [] titles = ["Address", "Label", "Value", ""] col = 0 for title in titles: title_label = Label(registergridframe, text = title) title_label.grid(row = 0, column = col, padx = self.x_pad) registergrid_widgets.append(title_label) col += 1 registers_data = [(500, "x"), (501, "y"), (502, "z"), (503, "A"), (504, "B"), (505, "C"), ] for i in range(len(registers_data)): reg_data = registers_data[i] row = i + 1 self.__add_register(registergridframe, reg_data, row, registergrid_widgets) # hscrollbar.config(orient = HORIZONTAL, command = outputtext.xview) # hscrollbar.pack(side = BOTTOM, fill = X) # outputtext.config(state = DISABLED, yscrollcommand = vscrollbar.set, xscrollcommand = hscrollbar.set) #must change to NORMAL before writing text programmatically # outputtext.pack(side = LEFT, fill = BOTH, expand = YES, padx = x_padding, pady = y_padding) # vscrollbar.config(command = outputtext.yview) # vscrollbar.pack(side = RIGHT, fill = Y) self.connectframe = connectframe self.connectlabel = connectlabel self.connectbutton = connectbutton self.mainframe = mainframe self.registerframe = registerframe self.reglabel = reglabel self.registergridframe = registergridframe self.calibbutton = calibbutton # self.outputframe = outputframe # self.outputlabel = outputlabel # self.vscrollbar = vscrollbar # self.hscrollbar = hscrollbar # self.outputtext = outputtext root.update() w, h = root.winfo_width(), root.winfo_height() root.minsize(w, h) x, y = MAINFRAME_POS root.geometry('%dx%d+%d+%d' % (w, h, x, y)) def __homebutton_click(self): values = { 500: 300, 501: 0, 502: 500, 503: 180, 504: 0, 505: 180, } self.set_values(values, go_to_value = False) def __add_register(self, master, data, row, widget_list): regaddresslabel = Label(master, text=str(data[0])) regaddresslabel.grid(row=row, column=0) reglabellabel = Label(master, text=data[1]) reglabellabel.grid(row=row, column=1) regvalueentry = AccessibleEntry(master, justify = RIGHT) regvalueentry.set("0") regvalueentry.grid(row=row, column=2, padx=self.x_pad) regsetbtn = Button(master, text="Set", command = self.__setbutton_click) regsetbtn.grid(row=row, column=3) widget_list.append(regaddresslabel) widget_list.append(reglabellabel) widget_list.append(regvalueentry) widget_list.append(regsetbtn) self.register_values_widgets[data[0]] = (0, regvalueentry) def __calibbutton_click(self): if not self.calibgui: self.calibgui = CalibGUI(self) def __findbutton_click(self): if self.find_thread is None: self.find_thread = Thread(target=self.__find_object) self.find_thread.start() def __find_object(self): import DataCache as DC from glob import glob from os.path import join import numpy as np from SFMSolver import SFMSolver, find_ext_params import Utils print "FINDING" np.set_printoptions(precision=3, suppress=True) files_dir = "out/2017_3_8__14_51_22/" files = glob(join(files_dir, "*.jpg")) masks = [] for f in files: m = f.replace(".jpg", "_mask.png") masks.append(m) sfm = SFMSolver(files, masks) if self.obj_data is None: imgs, kpts, points, data = sfm.calc_data_from_files_triang_simple() self.obj_data = imgs, kpts, points, data else: imgs, kpts, points, data = self.obj_data arr_calib = DC.getData("out/%s/arrangement_calib.p" % ARRANGEMENT_CALIB_DIR) ttc = arr_calib["ttc"] tor = arr_calib["tor"] if "cam_mtx" in arr_calib: print "camMtx, distcoeffs load" Utils.camMtx = arr_calib["cam_mtx"] Utils.dist_coeffs = arr_calib["dist_coeffs"] if self.stop_signal: self.stop_signal = False return for point in FIND_POINTS: values = { 500: point[0], 501: point[1], 502: point[2], 503: point[3], 504: point[4], 505: point[5], } print "set_values call" self.set_values(values, True) print "set_values return" time.sleep(0.5) CamGrabber.capture_if_no_chessboard = True CamGrabber.capture = True time.sleep(0.5) if self.stop_signal: self.stop_signal = False return find_dir = logger.outputdir files = glob("%s/*.jpg" % find_dir) print files # files_dir = "out/2017_4_5__15_57_20/" # files = glob(join(files_dir, "*.jpg")) files.sort() files = files[-len(FIND_POINTS):] results = [] for f in files: res = find_ext_params(f, imgs, kpts, points, data, tor, ttc) results.append(res) if self.stop_signal: self.stop_signal = False return for i in range(len(results)): print i, results[i] write_log((i, results[i])) result = max(results, key=lambda x: x[2]) write_log(result) values = { 500: int(result[0][0] * 10), 501: int(result[0][1] * 10), 502: int(result[0][2] * 10) + 200, 503: int(result[1][2]), 504: int(result[1][1]), 505: int(result[1][0]), } print "num inl: ", result[2] pprint(values) self.set_values(values, go_to_value=False) self.find_thread = None def __connectbutton_click(self): if self.client.is_open(): self.client.close() else: self.client.host(SERVER_HOST) self.client.port(SERVER_PORT) if self.client.open(): write_log("Connection established") self.refresh_values() self.read_robot_pos() else: write_log("ERROR: Connecting failed") self.__update_gui() def read_robot_pos(self): write_log("Reading robot position:") posdict = {} for i in range(1000, 1006): if self.client.is_open(): with self.lock: real_val_uint = self.client.read_input_registers(i)[0] real_val_holding_uint = self.client.read_holding_registers(i)[0] assert real_val_uint == real_val_holding_uint real_val_int = uintToInt16(real_val_uint) posdict[i] = real_val_int write_log("%d, %d" % (i, real_val_int)) else: write_log("ERROR: Read could not be completed, client not connected.") self.__update_gui() break write_log("Read done.") return posdict def refresh_values(self): for address in self.register_values_widgets: if self.client.is_open(): value, widget = self.register_values_widgets[address] with self.lock: real_val_uint = self.client.read_input_registers(address)[0] real_val_holding_uint = self.client.read_holding_registers(address)[0] assert real_val_uint == real_val_holding_uint real_val_int = uintToInt16(real_val_uint) widget.set(str(real_val_int)) self.register_values_widgets[address] = (real_val_int, widget) else: write_log("ERROR: Read could not be completed, client not connected.") self.__update_gui() break write_log("Refresh done.") return self.register_values_widgets def __update_gui(self): if self.client.is_open(): self.connectlabel.config(text = "Connected to: %s:%d" % (SERVER_HOST, SERVER_PORT)) self.connectbutton.config(text = "Disconnect") else: self.connectbutton.config(text = "Connect") self.connectlabel.config(text = "Not connected.") self.root.update() def __print_memory(self): self.refresh_values() write_log("Memory dump:") write_log("------------") for address in self.register_values_widgets: val, widget = self.register_values_widgets[address] write_log("%d, %d" % (address, val)) write_log("------------") def __setbutton_click(self, wait = False): if not self.client.is_open(): write_log("ERROR: Not connected to client") return # writing message counter retval = self.__write_register(COUNTER_REGISTER_OUT, self.counter) if not retval: self.__update_gui() return # writing registers for address in self.register_values_widgets: value, widget = self.register_values_widgets[address] widgetvalue_int = None try: widgetvalue_int = int(widget.get()) except ValueError: write_log("ERROR: Wrong input format in value entry for address: %d" % address) continue if value == widgetvalue_int: continue retval = self.__write_register(address, widgetvalue_int) if retval: self.register_values_widgets[address] = (widgetvalue_int, widget) else: self.__update_gui() self.refresh_values() # message counter wait if wait: global break_wait while not break_wait: with self.lock: counter = self.client.read_input_registers(COUNTER_REGISTER_IN)[0] if counter == self.counter: break time.sleep(0.1) break_wait = False # counter increment self.counter = (self.counter + 1) % 20 if PRINT_ALL_MEMORY_ON_WRITE: self.__print_memory() self.read_robot_pos() def __write_register(self, address, value): if not (-32768 <= value <= 32767): write_log("ERROR: -32768 <= value <= 32767 is false for address: %d" % address) return False widgetvalue_uint = intToUint16(value) if self.client.is_open(): with self.lock: retval = self.client.write_single_register(address, widgetvalue_uint) if retval: write_log("Register written. Address: %d, value: %d" % (address, value)) return True else: write_log("ERROR: Write failed. Address: %d, value: %d" % (address, value)) else: write_log("ERROR: client not connected.") return False def set_values(self, values, wait = True, go_to_value = True): """ :param values: dictionary of { address : value} both int :return: """ for address in values: if address not in self.register_values_widgets: continue val, widget = self.register_values_widgets[address] widget.set(str(values[address])) if go_to_value: self.__setbutton_click(wait) def __delete_window(self): CamGrabber.exit = True self.stop_signal = True self.client.close() self.root.quit()