def scan(): parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") parser.add_argument("ip", help="IP address of the slave") parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) args = parser.parse_args() try: ip = args.ip except IndexError: print "ERROR: No target to scan\n\n" parser.print_help() exit() # ip address format verification if not validate_ipv4(ip): print "ERROR: IP address is invalid\n\n" parser.print_help() exit() print 'Connecting to %s...' % ip, # connect to modbus slave client = ModbusTcpClient(ip, args.port) client.connect() if client.socket == None: print "ERROR: Could not connect to %s." %ip exit() print ' Connected.' # TODO add ETA mechanism results = {} addr = 1 registers_tested = args.end_address - args.start_address + 1 if registers_tested == 1: hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) if hr.function_code == 3: # if we succeed reading stuff results[addr] = hr.registers[0] # if it fails, hr.function = 131 (0x83), cf modbus doc else: for addr in range(args.start_address, args.end_address): hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) if hr.function_code == 3: # if we succeed reading stuff results[addr] = hr.registers[0] # if it fails, hr.function = 131 (0x83), cf modbus doc client.close() print 'Register scanning is finished (%d registers were tried)' % (registers_tested) # sorting dict for printing ordered_results = collections.OrderedDict(sorted(results.items())) for addr, value in ordered_results.iteritems(): print 'Addr {0} \t{1}'.format(addr,value)
class UEMD(object): def __init__(self, host: str, port: int = 502, timeout: int = 3): self.client = ModbusTcpClient(host=host, port=port, timeout=timeout) def is_connectable(self): ret = self.client.connect() self.client.close() return ret def show(self): print(self.client) r = self.client.read_holding_registers(0, count=2) print(r.registers) def get_data(self): # print(self.is_connectable()) result = self.client.read_holding_registers(0, count=2) decoder = BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=Endian.Little, wordorder=Endian.Little) return decoder.decode_32bit_float() def __del__(self): self.client.close()
class SmaModbus(Log): """ Communicates via modbus to SMA PV invertes """ _unit_id: int = -1 def __init__(self, host: str, port: int = 502): super().__init__() self._client = ModbusTcpClient(host, port) def connect(self): self._client.connect() # Ask for unit ID reply = self._client.read_holding_registers(42109, 4, unit=1) self._unit_id = reply.registers[3] def close(self): self._client.close() def read(self, reg: Register) -> ValueWithUnit: value = u32( self._client.read_holding_registers(reg.id, 2, unit=self._unit_id)) if value == 0xffffffff or value == 0x80000000: # Use 0 as a more sane "not available" value value = 0 return ValueWithUnit(value, reg.unit)
class TestMbTcpClass0(unittest.TestCase): read_values = range(0xAA50, 0xAA60) write_values = range(0xBB50, 0xBB60) def setUp(self): self.client = ModbusTcpClient(SERVER_HOST) self.client.connect() def tearDown(self): self.client.close() def test_read_holding_registers(self): rv = self.client.read_holding_registers(0, 16) self.assertEqual(rv.function_code, 0x03) self.assertEqual(rv.registers, self.read_values) def test_read_holding_registers_exception(self): rv = self.client.read_holding_registers(16, 1) self.assertEqual(rv.function_code, 0x83) self.assertEqual(rv.exception_code, 0x02) def test_write_holding_registers(self): rq = self.client.write_registers(0, self.write_values) self.assertEqual(rq.function_code, 0x10) rr = self.client.read_holding_registers(0, 16) self.assertEqual(rr.registers, self.write_values) rq = self.client.write_registers(0, self.read_values) self.assertEqual(rq.function_code, 0x10) def test_write_holding_registers_exception(self): rq = self.client.write_registers(16, [0x00]) self.assertEqual(rq.function_code, 0x90) self.assertEqual(rq.exception_code, 0x02)
class TestMbTcpClass0(unittest.TestCase): read_values = range(0xAA50, 0xAA60) write_values = range(0xBB50, 0xBB60) def setUp(self): self.client = ModbusTcpClient(SERVER_HOST) self.client.connect() def tearDown(self): self.client.close() def test_read_holding_registers(self): rv = self.client.read_holding_registers(0, 16) self.assertEqual(rv.function_code, 0x03) self.assertEqual(rv.registers, self.read_values) def test_read_holding_registers_exception(self): rv = self.client.read_holding_registers(16, 1) self.assertEqual(rv.function_code, 0x83) self.assertEqual(rv.exception_code, 0x02) def test_write_holding_registers(self): rq = self.client.write_registers(0, self.write_values) self.assertEqual(rq.function_code, 0x10) rr = self.client.read_holding_registers(0, 16) self.assertEqual(rr.registers, self.write_values) rq = self.client.write_registers(0, self.read_values) self.assertEqual(rq.function_code, 0x10) def test_write_holding_registers_exception(self): rq = self.client.write_registers(16, [0x00]) self.assertEqual(rq.function_code, 0x90) self.assertEqual(rq.exception_code, 0x02)
def run(self): client = Client(self.url, port=self.port) client.connect() registers = [] count = self.count readCount = 0 try: while count > 0: if count > 125: rr = client.read_holding_registers(self.address + readCount - 1, 125, unit=self.unit) count -= 125 readCount += 125 else: rr = client.read_holding_registers(self.address + readCount - 1, count, unit=self.unit) count = 0 readCount += count registers = registers + rr.registers client.close() return registers except: return []
def run(self): VEBUS_FIRST_ADDRESS = 3 VEBUS_LAST_ADDRESS = 59 VEBUS_NUM_ADDRESSES = VEBUS_LAST_ADDRESS - VEBUS_FIRST_ADDRESS VEBUS_INPUT_POWER_PHASE_1 = 12 - 3 #(Register 12, aber wir fangen ja erst bei Reg.3 an...) VEBUS_STATE_OF_CHARGE = 30 - 3 GRID_FIRST_ADDRESS = 2600 #Reg. 2600 - 2602 sind die drei Phasen am Übergabezähler GRID_NUM_ADDRESSES = 3 UID_VEBUS = 246 UID_GRID = 30 wechselrichter = ModbusTcpClient(self.ip, self.port) wechselrichter.connect() while True: vebus = wechselrichter.read_holding_registers(VEBUS_FIRST_ADDRESS, VEBUS_NUM_ADDRESSES, unit=UID_VEBUS) grid = wechselrichter.read_holding_registers(GRID_FIRST_ADDRESS, GRID_NUM_ADDRESSES, unit=UID_GRID) vebus_register = vebus.registers grid_register = grid.registers self.soc = vebus_register[VEBUS_STATE_OF_CHARGE] / 10 self.pac = self.correct_power_value( vebus_register[VEBUS_INPUT_POWER_PHASE_1]) * 10 self.pgrid1 = self.correct_power_value(grid_register[0]) self.pgrid2 = self.correct_power_value(grid_register[1]) self.pgrid3 = self.correct_power_value(grid_register[2]) self.checked = True time.sleep(self.interval)
class ModbusUtility(): def __init__(self, ip): self.modcli = ModbusTcpClient(ip) @staticmethod def getReg(reg, index=0): # Registers are stored without decimal points. Their values represent # the number multiplied by 100 so we undo that to get the real value # We assume desired register is first element, pass in optional index to change return (float(reg[index]) / 100) @staticmethod def setReg(data): # Since register data is stored without decimals and multiplied by 100 that is # what we supply return (int(data * 100)) def PrintAllRegisters(self): print("Printing registers...") for key in REG_DICT.keys(): data = self.ReadRegister(key) print("Register [{}]: {}".format(key, data)) def ReadRegister(self, name): t = REG_DICT[name]["type"] # Current register type o = REG_DICT[name]["offset"] # Current register offset s = REG_DICT[name]["size"] # Current register size in bytes. # If the size is greater the 2 bytes unpack it like it is a float. # Really we should also check that this is a float but it doesn't matter since # our system only has 3 registers that are 4 bytes long and they are all floats if (s > 2): data = self.modcli.read_holding_registers(o, s, unit=1).registers reg = struct.unpack( ">f", data[0].to_bytes(2, "big") + data[2].to_bytes(2, "big")) return (reg[0]) data = self.modcli.read_holding_registers(o, 1, unit=1) return (self.getReg(data.registers)) def WriteRegister(self, name, num): o = REG_DICT[name]["offset"] # Current register offset s = REG_DICT[name]["size"] / 2 # Current register size if (s > 1): data = struct.unpack("HH", struct.pack("=f", num)) # Sending these backwards is a concious decision. Unpack always returns # them in 'backwards' order. self.modcli.write_registers(o, data[1]) self.modcli.write_registers(o + 1, data[0]) else: data = num self.modcli.write_registers(o, self.setReg(data))
def main(protocol): global messageCounter global hub_manager try: print("\nPython %s\n" % sys.version) print("IoT Hub Client for Python") hub_manager = HubManager(protocol) print("Starting the IoT Hub Python sample using protocol %s..." % hub_manager.client_protocol) while True: time.sleep(POLLINGfrequency) modbusclient = ModbusClient(POLLINGHost, port=502) try: modbusclient.connect() messageToSend = {} messageToSend['POLLINGHost'] = POLLINGHost messageToSend['dateTime'] = str(datetime.datetime.now()) messageToSend[ 'Las Vegas'] = modbusclient.read_holding_registers( 0, 1, unit=0x01).registers[0] messageToSend[ 'Stockholm'] = modbusclient.read_holding_registers( 1, 1, unit=0x01).registers[0] messageToSend[ 'Wadi Halfa'] = modbusclient.read_holding_registers( 2, 1, unit=0x01).registers[0] messageToSend[ 'MSFT Stock'] = modbusclient.read_holding_registers( 3, 1, unit=0x01).registers[0] messageToSend[ 'HPE Stock'] = modbusclient.read_holding_registers( 4, 1, unit=0x01).registers[0] IoTmessageToSend = IoTHubMessage( bytearray(json.dumps(messageToSend), 'utf8')) hub_manager.forward_event_to_output("output1", IoTmessageToSend, messageCounter) messageCounter += 1 except Exception: errorMessage = "{\"error\":\"" + str(sys.exc_info()[0]) + "\"}" IoTmessageToSend = IoTHubMessage( bytearray(errorMessage, 'utf8')) hub_manager.forward_event_to_output("output1", IoTmessageToSend, messageCounter) messageCounter += 1 modbusclient.close() except IoTHubError as iothub_error: print("Unexpected error %s from IoTHub" % iothub_error) return except KeyboardInterrupt: print("IoTHubModuleClient sample stopped")
def retrieve_file(Filename, starting, filesize): MAX_FILE_SIZE = 2047 blocksize = 64 #print (filesize) if ((starting + int(filesize) < MAX_FILE_SIZE) & (get_IP() != "")): write_screen("Reading file from PLC...") client = ModbusClient(get_IP(), DPORT) client.connect() f = open(Filename, "wb") while (starting < filesize): if ((filesize // 2) - starting >= blocksize): #print ("Leemos "+str(blocksize)+" words desde "+str(starting)+" para llegar a "+str(filesize//2)) #leemos 64 enteros, 128 bytes response = client.read_holding_registers(starting, blocksize, unit=0x01) dot() else: # print ("Leemos "+str(filesize//2-starting)+" words desde "+str(starting)+" para llegar a "+str(filesize//2)) response = client.read_holding_registers( starting, (filesize // 2) - starting + 2, unit=0x01) starting = filesize + 1 bytes = [] regs = [] if response: for regnum in range(1, len(response.registers) + 1): regs.append(response.registers[regnum - 1]) if ((starting > filesize) & (regnum == len(response.registers))): print(response.registers[regnum - 2]) bytes.append(response.registers[regnum - 1] % 256) else: bytes.append(response.registers[regnum - 1] // 256) bytes.append(response.registers[regnum - 1] % 256) #Last word is only 1 byte long... #print (regnum) #bytes.append(response.registers[regnum]%256) else: print("Error: could not read any register from PLC") f.write(bytearray(bytes)) starting += 64 f.close() client.close() write_screen("\n" + str(filesize) + " bytes recovered from PLC") else: print("Error: File does NOT exist. Exiting")
class CSpot(): # CSpot: class used to read a spot modbus register def __init__(self, config): self.host = config[ 'HOST'] #use the host ip address defined in etc/config (default is '10.1.10.50') timeout = int(config['CONN_TIMEOUT_S'] ) #define a connection timeout (not currently used) #self.modBusRegToRead = int(config['READ_MODBUS_REG']) self.config = config # make the config accessabile def ReadRegister(self, nReadings, sampleInteveralMs, address): self.client = ModbusTcpClient( self.host) # use ModbusTcpClient from pymodbus #Method to read nReadings of a single modbus regeister at a sample interval sampleInteveralMs #Uses a pause of sampleInterval rather than re-sampling #Make an array for the the NReadings of values read from the register allValues = np.ones(nReadings) allValues = allValues * np.NAN t = TicToc() t.tic() #Start timer registerValue = np.NAN #bug fix - read a registor once, to set the correct registor address request = self.client.read_holding_registers(address, 1) registerValue = request.registers registerValue = np.NAN for k in range(0, nReadings): try: #address = int(self.config['READ_MODBUS_REG']) request = self.client.read_holding_registers(address, 1) registerValue = request.registers except: registerValue = np.NAN # return Nan if the register can't be read #print(registerValue) #print(type(registerValue)) #print(allValues) #exit(0) allValues[k] = registerValue[0] time.sleep( sampleInteveralMs / 1e3 ) #pause before next reading. NB we are consitently sampling the same phase of the chopper #Return the array of nReadings of a single modbus register and the time taken to acquire. elapsedTime = t.tocvalue() time.sleep(1) #Dwell to allow return of reponse self.client.close() return allValues, elapsedTime
class modbus: def __init__(self, IP): # Class Variablen self._IP = IP self._client = '' # Plenticore als Modbus Client einrichten self._client = ModbusTcpClient(self._IP, port=1502) # self._wr.client.connect() def ReadRegister(self, address, count=1, **kwargs): return self._client.read_holding_registers(address, count, **kwargs) def ReadUInt16(self, addr): data = self._client.read_holding_registers(addr, 1, unit=71) UInt16register = BinaryPayloadDecoder.fromRegisters( data.registers, byteorder=Endian.Big, wordorder=Endian.Little) result = UInt16register.decode_16bit_uint() return (result) def ReadInt16(self, addr): data = self._client.read_holding_registers(addr, 1, unit=71) Int16register = BinaryPayloadDecoder.fromRegisters( data.registers, byteorder=Endian.Big, wordorder=Endian.Little) result = Int16register.decode_16bit_int() return (result) def ReadUInt32(self, addr): data = self._client.read_holding_registers(addr, 2, unit=71) UInt32register = BinaryPayloadDecoder.fromRegisters( data.registers, byteorder=Endian.Big, wordorder=Endian.Little) result = UInt32register.decode_32bit_uint() return (result) def ReadInt32(self, addr): data = self._client.read_holding_registers(addr, 2, unit=71) Int32register = BinaryPayloadDecoder.fromRegisters( data.registers, byteorder=Endian.Big, wordorder=Endian.Little) result = Int32register.decode_32bit_int() return (result) def ReadFloat32(self, addr): data = self._client.read_holding_registers(addr, 2, unit=71) Float32register = BinaryPayloadDecoder.fromRegisters( data.registers, byteorder=Endian.Big, wordorder=Endian.Little) result = Float32register.decode_32bit_float() return (result) def ReadUInt64(self, addr): data = self._client.read_holding_registers(addr, 4, unit=71) UInt64register = BinaryPayloadDecoder.fromRegisters( data.registers, byteorder=Endian.Big, wordorder=Endian.Little) result = UInt64register.decode_64bit_uint() return (result) def ReadString(self, addr): data = self._client.read_holding_registers(addr, 8, unit=71) Stringregister = BinaryPayloadDecoder.fromRegisters( data.registers, byteorder=Endian.Big, wordorder=Endian.Little) result = Stringregister.decode_string(8) return (result)
def getPortNo(type, ipaddress): slaveid = 1 file_path = '/var/www/html/openWB/ramdisk/solaredgeport_' + str(type) # ModBus is configured to listen on port 502 or 1502, actual port is autodetected and cache in ramdisk port = 0 # port not defined ramdiskInitialized = False # assume ramdisk cache is not set if os.path.isfile(file_path): with open(file_path, 'r') as f: try: data = f.read() (ipaddr, port) = data.split(':') if (ipaddress == ipaddr): ramdiskInitialized = True return port else: print('changed ip addr, old: %s, new: %s' % (ipaddr, ipaddress)) os.remove(file_path) except: pass # ramdisk file does not exist, proceed with autodetection port = 502 # try port 502 first client = ModbusTcpClient(ipaddress, port=port) try: resp = client.read_holding_registers(40000, 1, unit=slaveid) if resp.registers[0] == 21365: if not ramdiskInitialized: # if we reach this line, we were able to read ModBus registers # ramdisk is not set, so persist port value now for next time with open(file_path, 'w') as f: f.write(ipaddress + ':' + str(port)) return port # we were unable to read registers from port 502 so try 1502 next except ConnectionException: port = 1502 client.port = port try: resp = client.read_holding_registers(40000, 1, unit=slaveid) if resp.registers[0] == 21365: # now it worked, persist port number in ramdisk if not ramdiskInitialized: with open(file_path, 'w') as f: f.write(ipaddress + ':' + str(port)) return port except: # no connection, remove cache file if any if os.path.isfile(file_path): os.remove(file_path) return port
def loop_process(): # Main Process err_count = 0 registre_count = 10 while True: sleep(1) try: client = ModbusTcpClient(modbus_server_ip, modbus_server_port) # read registers CAPT1 = client.read_holding_registers(0, 1, unit=UNIT).registers[0] CAPT2 = client.read_holding_registers(1, 1, unit=UNIT).registers[0] M_UP = client.read_holding_registers(2, 1, unit=UNIT).registers[0] M_DOWN = client.read_holding_registers(3, 1, unit=UNIT).registers[0] C_UP = client.read_holding_registers(4, 1, unit=UNIT).registers[0] C_DOWN = client.read_holding_registers(5, 1, unit=UNIT).registers[0] C_STOP = client.read_holding_registers(6, 1, unit=UNIT).registers[0] LIGHT1 = client.read_holding_registers(7, 1, unit=UNIT).registers[0] LIGHT2 = client.read_holding_registers(8, 1, unit=UNIT).registers[0] # process LIGHT1 = CAPT1 LIGHT2 = CAPT2 # Moteur up = M_UP = (not M_DOWN) and (not CAPT1) and (not C_STOP) and (C_UP or M_UP) M_DOWN = (not M_UP) and (CAPT2) and (not C_STOP) and (C_DOWN or M_DOWN) # C_* are just buttons C_UP = 0 C_DOWN = 0 C_STOP = 0 # CAPT1 & CAPT2 are updated by the PHP script itself # save registers client.write_register(0, CAPT1, unit=UNIT) client.write_register(1, CAPT2, unit=UNIT) client.write_register(2, M_UP, unit=UNIT) client.write_register(3, M_DOWN, unit=UNIT) client.write_register(4, C_UP, unit=UNIT) client.write_register(5, C_DOWN, unit=UNIT) client.write_register(6, C_STOP, unit=UNIT) client.write_register(7, LIGHT1, unit=UNIT) client.write_register(8, LIGHT2, unit=UNIT) except Exception as err: print '[error] %s' % err err_count += 1 if err_count == 5: print '[error] 5 errors happened in the process ! exiting...' sys.exit(1)
class OpenPlcModbus: def __init__(self): self.plc = ModbusClient('localhost', port=502) def get_counter_value(self): request = self.plc.read_holding_registers(1024, 1) value = request.registers[0] return value def get_motor_status(self): request = self.plc.read_coils(0, 1) status = request.bits[0] return status def turn_on(self, action): if action: self.plc.write_coil(1, True) else: self.plc.write_coil(1, False) def turn_off(self, action): if action: self.plc.write_coil(2, True) else: self.plc.write_coil(2, False) def close(self): self.plc.close()
def wren_gw_modbus_read(config): ''' read a value from the peer. @param config the configuration in the key/value type. ''' try: m = ModbusTcpClient(host=config['node'], port=config['port']) m.connect() unit = 0xff if config.has_key('unit_id'): unit = config['unit_id'] # sed data value = None if config['table'] == 'InputRegister': result = m.read_input_registers(config['address'], 1, unit=unit) if result: value = result.registers[config['address']] if config['table'] == 'HoldingRegister': result = m.read_holding_registers(config['address'], 1, unit=unit) if result: value = result.registers[config['address']] # close it. m.close() return {"status":True, "value":str(value)}; except Exception as e: return {"status":False, "value":str(e)};
class TestMbTcpClass1(unittest.TestCase): read_values = range(0xAA50, 0xAA60) write_values = range(0xBB50, 0xBB60) def setUp(self): self.client = ModbusTcpClient(SERVER_HOST) self.client.connect() def tearDown(self): self.client.close() def test_write_single_holding_register(self): rq = self.client.write_register(8, 0xCC) self.assertEqual(rq.function_code, 0x06) rr = self.client.read_holding_registers(8, 1) self.assertEqual(rr.registers[0], 0xCC) rq = self.client.write_register(16, 0x00) self.assertEqual(rq.function_code, 0x86) rq = self.client.write_register(8, 0xAA58) def test_write_coil(self): rq = self.client.write_coil(0, True) self.assertEqual(rq.function_code, 0x05) rq = self.client.write_coil(0, False) self.assertEqual(rq.function_code, 0x05) rq = self.client.write_coil(256, False) self.assertEqual(rq.function_code, 0x85) def test_read_coil(self): coil_read_values = [True, False, True, False, False, True, False, False]
def read_registers(self, slave): # Carefully measured artificial pause to make sure everything is processed time.sleep(0.02) try: if type(slave.slave_id) is int: # logging.debug(f'++ Requesting data from {slave.slave_id}') response = self.serialModbus.read_holding_registers( 0, slave.reg_count, unit=slave.slave_id) else: # logging.debug(f'++ Requesting data from {slave.slave_id}') tcp_modbus = ModbusTcpClient(slave.slave_id) tcp_modbus.connect() response = tcp_modbus.read_holding_registers( 0, slave.reg_count) if issubclass(type(response), ModbusException): raise response # logging.debug(f'++ Got data from {slave.slave_id}') return response except (IndexError, struct.error, ModbusException, ConnectionException) as e: logging.exception(e, exc_info=False) slave.errors += 1 return None
def get_values(address,port): client = ModbusTcpClient(str(address), int(port)) succeed = client.connect() if succeed: result = client.read_holding_registers(address=0,count=15,unit=1) result2 = client.read_coils(address=0,count=15,unit=1) client.close() results = {} for r in range(0,15): register = result.registers[r] results["r"+str(r)] = str(register)+"%" coil = result2.bits[r] if coil: coil='ON' else: coil='OFF' results["c"+str(r)] = coil #print(results) return jsonify(results) else: return render_template('index.html', error="Modbus slave is disconnected")
def reader(): c = ModbusTcpClient(host="localhost", port=502) if not c.is_socket_open() and not c.connect(): print("unable to connect to host") if not c.is_socket_open(): return None holdingRegisters = c.read_holding_registers(1, 4) if holdingRegisters.isError(): print('Error reading registers') return None # Imagine we've "energy" value in position 1 with two words energy = ( holdingRegisters.registers[0] << 16) | holdingRegisters.registers[1] # Imagine we've "power" value in position 3 with two words power = ( holdingRegisters.registers[2] << 16) | holdingRegisters.registers[3] out = {"energy": energy, "power": power} print(out) return json.dumps(out)
class Koyo: def __init__(self, ip_address): self.ip_address = ip_address self._koyo = ModbusClient(ip_address) print("Connected:", self._koyo.connect()) if self._koyo.connect(): self._getversions() self._get_device_info() def _getversions(self): data = self._koyo.read_input_registers(17500, 6) self.os_version = '.'.join(map(str, data.registers[0:3])) self.boot_version = '.'.join(map(str, data.registers[3:6])) def _get_device_info(self): data = self._koyo.read_input_registers(17510, 19) self.device_version = data.registers[0] self.family = data.registers[1] def disconnect(self): self._koyo.close() def read_register(self, x): read = self._koyo.read_holding_registers(x, count=1, unit=1) return read.registers[0]
def run_sync_client(): """ Main loop for Modbus communication """ # Define client connection client = ModbusClient('localhost', port=5020, framer=ModbusFramer) client.connect() # Specify target device log.debug("Reading Coils") rr = client.read_holding_registers(0, 7, unit=UNIT) log.debug(rr.registers) log.debug(rr.registers[0]) decoder = BinaryPayloadDecoder.fromRegisters(rr.registers, byteorder=Endian.Big) decoded = OrderedDict([ ('value', decoder.decode_32bit_float()), ('qualityId', decoder.decode_16bit_uint()), ('unitId', decoder.decode_16bit_float()), ('paramId', decoder.decode_16bit_uint()), ('sentinel', decoder.decode_32bit_float()) ]) for name, value in iteritems(decoded): log.debug(name) log.debug(value) # Close Client client.close()
def main( host, port, address, write=None, unit=1 ): # NOTE: the unit is like an identifier for the slave; it corresponds to the identifier for a store client = ModbusTcpClient(host, port=port) client.connect() if write != None: value = write logger.debug(f"Writing value {value} to address {address}") rq = client.write_register(address, value, unit=unit) assert (not rq.isError()) # test that we are not an error rr = client.read_holding_registers(address, 1, unit=unit) logger.info(f"Value at address {address} is {rr.registers[0]}") #assert(rr.registers[0] == 11) # test the expected value # logger.debug("Write to multiple holding registers and read back") # rq = client.write_registers(1, [10]*8, unit=UNIT) # rr = client.read_holding_registers(1, 8, unit=UNIT) # assert(not rq.isError()) # test that we are not an error # assert(rr.registers == [10]*8) # test the expected value client.close()
def read_holding_regs(): form = ReusableForm(request.form) print form.errors if request.method == 'POST': ip = request.form['ip'] port = request.form['port'] address = request.form['address'] value = request.form['value'] unitId = request.form['unitId'] print ip, " ", port, " ", address host = ip port = int(port) client = ModbusTcpClient(host, port) client.connect() rr = client.read_holding_registers(int(address), int(value), unit=int(unitId)) assert (rr.function_code < 0x80) # test that we are not an error print(rr) print(str(rr.registers)) if form.validate(): flash(str(rr.registers)) else: flash("Error") return render_template('read-hold-regs.html', form=form)
def Get_Modbus_Value(Sensors,IP,Address,RegisterID,RegisterAddr,RegisterLength,RegisterType,RegisterPeriod,P): try: result=[] for i in range (0,len(Sensors)): mclient = ModbusTcpClient(IP[i]) mclient.connect() for j in range(0,len(RegisterID[i])): if(datetime.now()>=P[i][j]): P[i][j] = P[i][j] + timedelta(seconds=RegisterPeriod[i][j]) data = mclient.read_holding_registers(RegisterAddr[i][j],RegisterLength[i][j], unit=Address[i]) reg = data.registers decoder = BinaryPayloadDecoder.fromRegisters(reg,byteorder=Endian.Big,wordorder=Endian.Little) if(RegisterType[i][j] == 1): reg = float('{0:.2f}'.format(decoder.decode_16bit_uint())) elif (RegisterType[i][j]==2): reg = float('{0:.2f}'.format(decoder.decode_32bit_uint())) elif (RegisterType[i][j]==3): reg = float('{0:.2f}'.format(decoder.decode_16bit_int())) elif (RegisterType[i][j]==4): reg = float('{0:.2f}'.format(decoder.decode_32bit_int())) elif (RegisterType[i][j]==5): reg = float('{0:.2f}'.format(decoder.decode_32bit_float())) result.append(reg) return result,P except ReturnError: print("Could not read modbus values from sensors",Sensors)
class TestMbTcpClass1(unittest.TestCase): read_values = range(0xAA50, 0xAA60) write_values = range(0xBB50, 0xBB60) def setUp(self): self.client = ModbusTcpClient(SERVER_HOST) self.client.connect() def tearDown(self): self.client.close() def test_write_single_holding_register(self): rq = self.client.write_register(8, 0xCC) self.assertEqual(rq.function_code, 0x06) rr = self.client.read_holding_registers(8, 1) self.assertEqual(rr.registers[0], 0xCC) rq = self.client.write_register(16, 0x00) self.assertEqual(rq.function_code, 0x86) rq = self.client.write_register(8, 0xAA58) def test_write_coil(self): rq = self.client.write_coil(0, True) self.assertEqual(rq.function_code, 0x05) rq = self.client.write_coil(0, False) self.assertEqual(rq.function_code, 0x05) rq = self.client.write_coil(256, False) self.assertEqual(rq.function_code, 0x85) def test_read_coil(self): coil_read_values = [ True, False, True, False, False, True, False, False ]
def readMBholdingregisters(clientIP, register, number=1): from pymodbus.client.sync import ModbusTcpClient, ConnectionException client = ModbusTcpClient(clientIP) values = [] try: rawresult = client.read_holding_registers(register, number) except ConnectionException: # print('we were unable to connect to the host') statuscode = 7 else: # print(rawresult) try: resultregisters = rawresult.registers except AttributeError: statuscode = rawresult.exception_code else: statuscode = 0 values = resultregisters client.close() result = { 'message': messagefrommbstatuscode(statuscode), 'statuscode': statuscode, 'values': values } return result
def read_holding_registers(self, command): parser = argument_parser() command = 'read_holding_register ' + command spec = parser.parse_args(command.split()) response = _ModbusClient.read_holding_registers( self, spec.address, spec.count, unit=spec.unit_id) return response
def loop_process(): # Main Process (template = flip-flop) err_count = 0 registre_count = 10 while True: sleep(1) try: client = ModbusTcpClient(modbus_server_ip, modbus_server_port) coils = client.read_coils(0, count=registre_count, unit=UNIT) coils = coils.bits[:registre_count] # flipping booleans from list coils coils = [not i for i in coils] client.write_coils(0, coils) registers = client.read_holding_registers(0, count=registre_count, unit=UNIT) registers = registers.registers[:registre_count] registers = [i + 1 for i in registers] client.write_registers(0, registers, unit=UNIT) updateGPIO(coils, registers) except Exception as err: print('[error] %s' % err) err_count += 1 if err_count == 5: print('[error] 5 errors happened in the process ! exiting...') sys.exit(1)
class ModbusConnection(object): _max_retries_read = 10 _max_retries_write = 3 @property def max_retries_read(self): return self._max_retries_read @property def max_retries_write(self): return self._max_retries_write @property def client_address(self): return self.client.host @property def client_port(self): return str(self.client.port) def __init__(self, client_address, client_port): self.client = ModbusClient(host = client_address, port = int(client_port)) self.connect_to_client() def __del__(self): self.disconnect_from_client() def connect_to_client(self): self.client.connect() def disconnect_from_client(self): self.client.close() def read_input_registers(self, address, count, unit): k = 0 while k < self.max_retries_read: try: return self.client.read_input_registers(address = address, count = count, unit = unit).registers except: k += 1 sleep(1.5) def read_holding_registers(self, address, count, unit): k = 0 while k < self.max_retries_read: try: return self.client.read_holding_registers(address = address, count = count, unit = unit).registers except: k += 1 sleep(1.5) def write_register(self, address, unit, value): k = 0 while k < self.max_retries_write: try: return self.client.write_register(address = address, unit = unit, value = value) except: k += 1 sleep(1.5)
def getModbusData(modeAwake, classicHost, classicPort): global isConnected, modbusClient try: if not isConnected: log.debug("Opening the modbus Connection") if modbusClient is None: modbusClient = ModbusClient(host=classicHost, port=classicPort) #Test for succesful connect, if not, log error and mark modbusConnected = False modbusClient.connect() result = modbusClient.read_holding_registers(4163, 2, unit=10) if result.isError(): # close the client log.error("MODBUS isError H:{} P:{}".format(classicHost, classicPort)) modbusClient.close() isConnected = False return {} isConnected = True theData = {} #Read in all the registers at one time theData[4100] = getRegisters(theClient=modbusClient,addr=4100,count=44) theData[4360] = getRegisters(theClient=modbusClient,addr=4360,count=22) theData[4163] = getRegisters(theClient=modbusClient,addr=4163,count=2) theData[4209] = getRegisters(theClient=modbusClient,addr=4209,count=4) theData[4243] = getRegisters(theClient=modbusClient,addr=4243,count=32) theData[16386]= getRegisters(theClient=modbusClient,addr=16386,count=4) #If we are snoozing, then give up the connection #log.debug("modeAwake:{}".format(modeAwake)) if not modeAwake : log.debug("Closing the modbus Connection, we are in Snooze mode") modbusClient.close() isConnected = False except: # Catch all modbus excpetions e = sys.exc_info()[0] log.error("MODBUS Error H:{} P:{} e:{}".format(classicHost, classicPort, e)) try: modbusClient.close() isConnected = False except: log.error("MODBUS Error on close H:{} P:{}".format(classicHost, classicPort)) return {} log.debug("Got data from Classic at {}:{}".format(classicHost,classicPort)) #Iterate over them and get the decoded data all into one dict decoded = {} for index in theData: decoded = {**dict(decoded), **dict(doDecode(index, getDataDecoder(theData[index])))} return decoded
class PLC: # Method: Constructor # Description: Initializes the PLC device # Arguments: self: Initialized PLC object # a: String IP address of HMI # p: Integer port number to communicate with the HMI # i: Float Initial value of PLC device # t: List of float Threshold value at which the device will fail # v: Integer Variance value # Returns: PLC object of initialized PLC Device def __init__(self, a, p, s): print "Client IP: %s Port: %s" % (a, p) self.client = ModbusTcpClient(a, port=p) self.status_reg_num = s # Method: Connect # Description: Connects PLC device with HMI # Arguments: self: Initialized PLC object # Returns: Void def connect(self): connected = False while not connected: try: connected = self.client.connect() except Exception as e: print "Connection Error %s" % e time.sleep(30) # Method: Disconnect # Description: Disconnects PLC device from HMI # Arguments: self: Initialized PLC object # Returns: Void def disconnect(self): self.client.close() sys.exit(0) # Method: Read Register # Description: Modbus Read register request # Arguments: Reg: Modbus connection between PLC device and HMI Server # ID: integer id number of device # Returns: Integer value of register requested def read_reg(self, reg_num): return int( self.client.read_holding_registers(int(reg_num)).registers[0]) # Method: Write Register # Description: Modbus Write register request # Arguments: Reg: Modbus connection between PLC device and HMI Server # ID: integer id number of device # Value: integer value to write to register # Returns: void def write_reg(self, reg_num, value): print "Reg Num: %s Value: %s" % (reg_num, value) self.client.write_register(reg_num, value) def status(self): return False if hex(self.read_reg( self.status_reg_num)) == "0xffff" else True
class Plc: def __init__(self,ip = "", port = ""): self.ip = ip self.port = port self.device = None self.connected = False def connect(self,ui=None): try: self.device = ModbusTcpClient(self.ip, self.port) self.device.connect() tc_values = self.device.read_holding_registers(40, 10, unit=0) assert(tcValues.function_code < 0x80) self.connected = True if ui: ui.plc_connection_button.setStyleSheet("background-color: rgb(78, 154, 6)") ui.plc_connection_button.setText(f"CONNECTED TO \nPLC") return 0 except Exception as error: if ui: ui.plc_connection_button.setStyleSheet("background-color: rgb(255, 85, 0)") ui.plc_connection_button.setText(f"NOT CONNECTED TO \nPLC...") self.connected = False #print("Connection to PLC error : ", error) return 1 def measure(self,ui = None, simu_mode=False): ''' Measure and return teperature values in a tuple ''' if not simu_mode: try: if not self.connected: self.connect() tc_values = self.device.read_holding_registers(40, 10, unit=0) assert(tc_values.function_code < 0x80) # test that there is not an error return [temperature for temp in tc_values] except Exception as error: print("Couldn't get temperatures : ", error) return [i*2 for i in range(10)] else: print(f"simu_mode is {simu_mode}") return [i*2 for i in range(10)]
def readModbus(host, port, address, registers, roundingFactor): client = ModbusTcpClient(host, port) metrics = client.read_holding_registers(address, registers, unit=0x1) result = [] for res in metrics.registers: result.append(round(res * roundingFactor, 2)) client.close() return result
def get_temp(self, addr): # connect to modbus slave try: client = ModbusClient(addr, port=502) client.connect() rr = client.read_holding_registers(0x00,1,unit=1) temp = rr.registers[0] return temp except: # if unable to connect, return None log_stuff("Unable to connect to " + self.addr) return None
def main(): # connect to modbus slave client = ModbusClient(args.slave_addr, port=502) client.connect() try: while True: # get value of holding registers (first has the temperature value) rr = client.read_holding_registers(0x00,1,unit=1) temp = rr.registers[0] enable_light(temp) time.sleep(3) except KeyboardInterrupt: subprocess.call(['gpio', 'write', '0', '0']) subprocess.call(['gpio', 'write', '1', '0']) print "Exiting..."
def search(): client = ModbusClient(HOST,port=PORT,framer=ModbusFramer) if not client.connect(): logger.error("cannot connect to [%s:%d]." %(HOST,PORT)) n=0 while n<247: rr=client.read_holding_registers(address=0x015e,count=2,unit=n) assert(rr.function_code < 0x80) if rr: print n else: print 'fail',n n=n+1 client.close() #search()
def get_modbus(properties): try: print "Performing an action which may throw an exception." client = ModbusClient(properties['ip'], port=502) client.connect() log.debug(properties['registers']) log.debug(properties['coils']) modbus_values = {} # Get holding registers values modbus_registers = {} for i in properties['registers']: register_start_nb = i.split('-')[0] register_end_nb = i.split('-')[1] log.debug('Register start number : %s' % register_start_nb) log.debug('Register end number : %s' % register_end_nb) register_count = int(register_end_nb) - int(register_start_nb) log.debug('Number of registers to read : %s' % register_count) rr = client.read_holding_registers(int(register_start_nb),register_count, unit=0x01) modbus_registers[register_start_nb] = rr.registers log.debug('Registers values : %s' % rr.registers) # Get coils values modbus_coils = {} for i in properties['coils']: coil_start_nb = i.split('-')[0] coil_end_nb = i.split('-')[1] log.debug('Coil start number : ' + register_start_nb) log.debug('Coil end number : ' + register_end_nb) coil_count = int(coil_end_nb) - int(coil_start_nb) log.debug('Number of coils to read : ' + str(coil_count)) rr = client.read_coils(int(coil_start_nb),coil_count, unit=0x01) modbus_coils[coil_start_nb] = rr.bits log.debug('Coils values : ' + str(rr.bits)) log.debug('Modbus coils values : ' + str(modbus_coils)) client.close() modbus_values['registers'] = modbus_registers modbus_values['coils'] = modbus_coils log.debug(str(modbus_values)) return modbus_values except Exception, error: log.debug('Error connecting to %s' % properties['ip']) log.debug(str(error))
def single_client_test(host, cycles): ''' Performs a single threaded test of a synchronous client against the specified host :param host: The host to connect to :param cycles: The number of iterations to perform ''' logger = log_to_stderr() logger.setLevel(logging.DEBUG) logger.debug("starting worker: %d" % os.getpid()) try: count = 0 client = ModbusTcpClient(host) while count < cycles: result = client.read_holding_registers(10, 1).getRegister(0) count += 1 except: logger.exception("failed to run test successfully") logger.debug("finished worker: %d" % os.getpid())
def read_register(slave_addr, slave_port, reg_addr): # Call modbustcp client to read current register value client = ModbusTcpClient(host=slave_addr, port=slave_port) if client.connect() == False: print "Connection to Modbus slave %s:%d failed" %(slave_addr, slave_port) return None reply = client.read_holding_registers(address=reg_addr, unit=1) client.close() if reply == None: print "No reply while reading Modbus register" return None if reply.function_code != 3: print "Reading Modbus register returned wrong function code" return None return reply.registers[0]
def readMBholdingregisters(clientIP, register, number=1): from pymodbus.client.sync import ModbusTcpClient, ConnectionException client = ModbusTcpClient(clientIP) values = [] try: rawresult = client.read_holding_registers(register, number) except ConnectionException: # print('we were unable to connect to the host') statuscode = 7 else: # print(rawresult) try: resultregisters = rawresult.registers except AttributeError: statuscode = rawresult.exception_code else: statuscode = 0 values = resultregisters client.close() result = {'message': messagefrommbstatuscode(statuscode), 'statuscode': statuscode, 'values':values} return result
class SchneiderOTBSwitch(ChimeraObject, Switch): __config__ = {"device": None, "output": 6, # Which output to switch on/off "switch_timeout": None, # Maximum number of seconds to wait for state change } def __init__(self): super(SchneiderOTBSwitch, self).__init__() def __start__(self): self.client = ModbusTcpClient(self["device"]) def _getOTBstate(self): return self.client.read_holding_registers(100).getRegister(0) def _setOTBstate(self, state): self.client.write_register(100, state) return True def switchOn(self): if not self.isSwitchedOn(): if self._setOTBstate(self._getOTBstate() + (1 << self['output'])): self.switchedOn() return True else: return False def switchOff(self): if self.isSwitchedOn(): if self._setOTBstate(self._getOTBstate() - (1 << self['output'])): self.switchedOff() return True else: return False def isSwitchedOn(self): return self._getOTBstate() & 1 << self['output'] != 0
rr = client.read_coils(1,1) assert(rq.function_code < 0x80) # test that we are not an error assert(rr.bits[0] == True) # test the expected value rq = client.write_coils(1, [True]*8) rr = client.read_coils(1,8) assert(rq.function_code < 0x80) # test that we are not an error assert(rr.bits == [True]*8) # test the expected value rq = client.write_coils(1, [False]*8) rr = client.read_discrete_inputs(1,8) assert(rq.function_code < 0x80) # test that we are not an error assert(rr.bits == [True]*8) # test the expected value rq = client.write_register(1, 10) rr = client.read_holding_registers(1,1) assert(rq.function_code < 0x80) # test that we are not an error assert(rr.registers[0] == 10) # test the expected value rq = client.write_registers(1, [10]*8) rr = client.read_input_registers(1,8) assert(rq.function_code < 0x80) # test that we are not an error assert(rr.registers == [17]*8) # test the expected value arguments = { 'read_address': 1, 'read_count': 8, 'write_address': 1, 'write_registers': [20]*8, } rq = client.readwrite_registers(**arguments)
The following is an quick performance check of the synchronous modbus client. ''' #---------------------------------------------------------------------------# # import the necessary modules #---------------------------------------------------------------------------# from pymodbus.client.sync import ModbusTcpClient from time import time #---------------------------------------------------------------------------# # initialize the test #---------------------------------------------------------------------------# client = ModbusTcpClient('127.0.0.1') count = 0 start = time() iterations = 10000 #---------------------------------------------------------------------------# # perform the test #---------------------------------------------------------------------------# while count < iterations: result = client.read_holding_registers(10, 1, 0).getRegister(0) count += 1 #---------------------------------------------------------------------------# # check our results #---------------------------------------------------------------------------# stop = time() print "%d requests/second" % ((1.0 * count) / (stop - start))
class Handler(object): def __init__(self,a,a2,canvas, samples_no=1): self.btnLog = builder.get_object("btnLog") self.txtCommentBuffer = builder.get_object("txtCommentBuffer") self.dlgComments = builder.get_object("dlgComments") self.samples_no = samples_no self.loop_no = 0 self.volume = 0 self.elapsed = 0 self.lastTick = None self.thisTick = None self.loop = None self.listP1 = [] self.reg104_1 = None self.low1, self.high1 = a_low, a_high # danzi.tn@20160728 current as nanoampere nA - analogic values self.low2, self.high2 = a_low, a_high # danzi.tn@20160728 current as nanoampere nA - analogic values self.low_p1, self.high_p1 = p_low, p_high # danzi.tn@20160728 pressure range (P in bar/10) self.low_q1, self.high_q1 = q_low, q_high # danzi.tn@20160728 flow-rate range (Q in lit/min/10) self.low_p2, self.high_p2 = p_low, p_high # danzi.tn@20160728 pressure range (P in bar/10) self.low_q2, self.high_q2 = q_low, q_high # danzi.tn@20160728 flow-rate range (Q in lit/min/10) self.p1_fit = np.polyfit([self.low1, self.high1],[self.low_p1, self.high_p1],1) self.p1_func = np.poly1d(self.p1_fit) # Conversion from current (mA) to flow-rate (lit/min) self.q1_fit = np.polyfit([self.low1, self.high1],[self.low_q1, self.high_q1],1) self.q1_func = np.poly1d(self.q1_fit) self.p2_fit = np.polyfit([self.low2, self.high2],[self.low_p2, self.high_p2],1) self.p2_func = np.poly1d(self.p2_fit) # Conversion from current (mA) to flow-rate (lit/min) self.q2_fit = np.polyfit([self.low2, self.high2],[self.low_q2, self.high_q2],1) self.q2_func = np.poly1d(self.q2_fit) self.ret_m1 = False self.ret_m2 = False self.ret_p = False self.afigure = a self.afigure2 = a2 self.afigure3 = a3 self.canvas = canvas self._bufsize = x_size self.databuffer_p1 = collections.deque([0.0]*self._bufsize, self._bufsize) self.databuffer_p2 = collections.deque([0.0]*self._bufsize, self._bufsize) self.databuffer_q1 = collections.deque([0.0]*self._bufsize, self._bufsize) self.databuffer_q2 = collections.deque([0.0]*self._bufsize, self._bufsize) self.databuffer_q_max = collections.deque([0.0]*self._bufsize, self._bufsize) self.databuffer_q_out = collections.deque([0.0]*self._bufsize, self._bufsize) self.x = range(x_size) self.line_p1, = self.afigure3.plot(self.x, self.databuffer_p1,"b-", label='P1(An./Eng.)') self.line_p2, = self.afigure.plot(self.x, self.databuffer_p2,"m-", label='Pmax') self.line_q2, = self.afigure.plot(self.x, self.databuffer_q2,"g-", label='Pout') self.line_q1, = self.afigure3.plot(self.x, self.databuffer_q1,"r-", label='Q1(An./Eng.)') self.line_qmax, = self.afigure2.plot(self.x, self.databuffer_q1,"y-", label='Qmax') self.line_qout, = self.afigure2.plot(self.x, self.databuffer_q1,"k-", label='Qout') h1, l1 = a.get_legend_handles_labels() h2, l2 = a2.get_legend_handles_labels() h3, l3 = a3.get_legend_handles_labels() self.afigure.legend(h1+h2+h3, l1+l2+l3, loc=2, ncol=3, fontsize=10) self.pmax = 0 self.qmax = 0 self.blogFile = False self.oneLogged = False self.pipeLength = 0.0 self.pipeDiam = 0.0 self.pipeType = "ND" self.mixType = "ND" self.mixDensity = 0.0 self.staticHead = 0.0 self.treeview2 = builder.get_object("treeview2") self.p_count = 0 renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn("Name", renderer, text=0) self.treeview2.append_column(column) renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn("Description", renderer, text=1) self.treeview2.append_column(column) renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn("Value", renderer, text=2) self.treeview2.append_column(column) self.adjustPMax = builder.get_object("adjustment1") self.adjustQMax = builder.get_object("adjustment2") self.txtMongoConnection = builder.get_object("txtMongoConnection") self.lstPumps = builder.get_object("lstPumps") self.lstMan1 = builder.get_object("lstMan1") self.lstMan2 = builder.get_object("lstMan2") self.lblDbMesg = builder.get_object("lblDbMesg") self.btnFolder = builder.get_object("btnFolder") self.txtOutFolder = builder.get_object("txtOutFolder") self.chkAnalogic = builder.get_object("chkAnalogic") self.btnFolder.connect("clicked", self.on_btnFolder_clicked) self.time = datetime.datetime.utcnow() self.sMongoDbConnection = "" self.mongo_CLI = None self.mongodb = None self.outputFolder = None self.export_csv_path = None self.lblAnalyzed = builder.get_object("lblAnalyzed") self.parentWindow = builder.get_object("windowMain") if smtConfig.has_option('Mongodb','Connectionstring'): self.txtMongoConnection.set_text(smtConfig.get('Mongodb', 'Connectionstring')) def on_btnFolder_clicked(self, widget): dialog = Gtk.FileChooserDialog("Please choose an output folder", self.parentWindow, buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,"Select", Gtk.ResponseType.OK)) dialog.set_action(Gtk.FileChooserAction.SELECT_FOLDER) dialog.set_default_size(600, 400) response = dialog.run() if response == Gtk.ResponseType.OK: print("Select clicked") print("Folder selected: " + dialog.get_filename()) self.outputFolder = dialog.get_filename() self.export_csv_path = os.path.join(self.outputFolder,"test_{0}.csv".format(datetime.datetime.utcnow().strftime("%Y%m%d%H%M%S"))) self.txtOutFolder.set_text( dialog.get_filename()) if not smtConfig.has_section('Output'): smtConfig.add_section('Output') smtConfig.set('Output', 'Folder', self.outputFolder) with open(sCFGName, 'wb') as configfile: smtConfig.write(configfile) elif response == Gtk.ResponseType.CANCEL: print("Cancel clicked") dialog.destroy() def on_txtMongoConnection_changed(self,txtEdit): pass def on_btnDatabase_clicked(self,btn): self.sMongoDbConnection = self.txtMongoConnection.get_text() splitted = self.sMongoDbConnection.split("@") mongo_database = splitted[0] splitted = splitted[1].split(":") mongo_host = splitted[0] mongo_port = splitted[1] self.mongo_CLI = MongoClient(mongo_host, int(mongo_port)) self.mongodb = self.mongo_CLI[mongo_database] self.lstPumps.clear() self.lstMan2.clear() self.lstMan1.clear() projs =[] self.lblDbMesg.set_label("") try: projs = list(self.mongodb.projects.find({})) except pyErrors.ServerSelectionTimeoutError as timeouterr: self.lblDbMesg.set_label(str(timeouterr)) logApp.debug("Database error = {0}".format(str(timeouterr))) if len(projs) > 0: if not smtConfig.has_section('Mongodb'): smtConfig.add_section('Mongodb') smtConfig.set('Mongodb', 'Connectionstring', self.sMongoDbConnection) with open(sCFGName, 'wb') as configfile: smtConfig.write(configfile) gePumps = self.mongodb.groutingequipments.find({"type":"P"}) geManifolds = self.mongodb.groutingequipments.find({"type":"M"}) for p in gePumps: self.lstPumps.append([p["ipAddress"], int(p["TCPPort"]),"{0}.{1}({2}:{3})".format(p["type"],p["code"],p["ipAddress"],p["TCPPort"])]) for p in geManifolds: self.lstMan2.append([p["ipAddress"], int(p["TCPPort"]),"{0}.{1}({2}:{3})".format(p["type"],p["code"],p["ipAddress"],p["TCPPort"])]) self.lstMan1.append([p["ipAddress"], int(p["TCPPort"]),"{0}.{1}({2}:{3})".format(p["type"],p["code"],p["ipAddress"],p["TCPPort"])]) btn.set_label("DB Connected") logApp.debug("Database Connected") else: btn.set_label("DB Connect") self.lblDbMesg.set_label("Database {0} is empty".format(mongo_database)) logApp.debug("Database {0} is empty".format(mongo_database)) def on_cmbPumps_changed(self,cmb): tree_iter = cmb.get_active_iter() if tree_iter != None: model = cmb.get_model() ip = model[tree_iter][0] port = model[tree_iter][1] builder.get_object("txtIPPump").set_text(ip) builder.get_object("txtPortPump").set_text(str(port)) def on_cmbMan1_changed(self,cmb): tree_iter = cmb.get_active_iter() if tree_iter != None: model = cmb.get_model() ip = model[tree_iter][0] port = model[tree_iter][1] builder.get_object("txtIP1").set_text(ip) builder.get_object("txtPort1").set_text(str(port)) def on_cmbMan2_changed(self,cmb): tree_iter = cmb.get_active_iter() if tree_iter != None: model = cmb.get_model() ip = model[tree_iter][0] port = model[tree_iter][1] builder.get_object("txtIP2").set_text(ip) builder.get_object("txtPort2").set_text(str(port)) def logging_data(self, a): self.loop_no += 1 builder.get_object("levelbar1").set_value(len(self.listP1)%60+1) # print "1.1 {0}".format(t1) txtPout = a[11] txtQout = a[12] aIN1 = a[2] aIN2 = a[3] aIN1ENG = a[4] aIN2ENG = a[5] pDeltaPump = a[8] qDeltaPump = a[9] # print "1.2 {0}".format(t1) # QUI CAPITA Unhandled error in Deferred quando si perde la connessione- provare un try except e saltare il campione try: okC1 = self.client_1.connect() if okC1: rr1 = self.client_1.read_holding_registers(0,48) else: logApp.error("logging_data connection to manifold 1 failed") aIN1.set_text("CONNECTION ERROR") aIN2.set_text("CONNECTION ERROR") aIN1ENG.set_text("CONNECTION ERROR") aIN2ENG.set_text("CONNECTION ERROR") return False except: logApp.error("Unhandled error in Deferred - logging_data connection to manifold 1 failed") print "1.3 {0}".format(t1) aIN1.set_text("Unhandled ERROR") aIN2.set_text("Unhandled ERROR") aIN1ENG.set_text("Unhandled ERROR") aIN2ENG.set_text("Unhandled ERROR") return False # logApp.debug("logging_data 3 read_holding_registers 2 ok") # print "3 {0}".format(t1) self.client_1.close() if rr1.registers[test_reg_no] == test_value_1 or rr1.registers[test_reg_no] == test_value_2: # Manifold 1 p_mA1 = rr1.registers[4-1] q_mA1 = rr1.registers[6-1] q_Sign = 0 if rr1.registers[test_reg_no] == test_value_2: q_Sign = rr1.registers[12-1] # save value into databuffer for iprog in range(12): logApp.info("Manifold registers[{0}] = {1}".format(iprog+1, rr1.registers[iprog])) t1=datetime.datetime.utcnow() # logApp.debug("logging_data 1") dt_seconds = (t1-self.time).seconds # convert ANALOGIC to Digital p_Eng1 = self.p1_func(p_mA1) q_Eng1 = self.q1_func(q_mA1) if q_Sign: q_Eng1 = -1.*q_Eng1 pEng1Display = p_Eng1/10. qEng1Display = q_Eng1/10. self.thisTick = datetime.datetime.utcnow() dV = 0.0 if self.lastTick: dT = self.thisTick - self.lastTick self.elapsed = dT.total_seconds() dV = qEng1Display / 60 * self.elapsed self.volume += dV #print "total_seconds = " , dT.total_seconds() #print "qEng1Display = " , qEng1Display #print "dV = " , dV #print "volume = ", self.volume builder.get_object("txtVolume").set_text("{0:.2f} lit".format(self.volume)) self.lastTick = self.thisTick # display del valore analogico se chkAnalogic è selezionato if self.chkAnalogic.get_active(): self.databuffer_p1.append( p_mA1 ) self.afigure3.set_ylim(a_low, a_high) self.afigure3.set_ylabel('Voltage (mV)') else: self.databuffer_p1.append( pEng1Display ) self.afigure3.set_ylim(-10, 80) self.afigure3.set_ylabel('Eng Values') self.line_p1.set_ydata(self.databuffer_p1) # display del valore analogico se chkAnalogic è selezionato if self.chkAnalogic.get_active(): self.databuffer_q1.append( q_mA1 ) else: self.databuffer_q1.append( qEng1Display ) self.line_q1.set_ydata(self.databuffer_q1) self.listP1.append(p_Eng1/10.) aIN1.set_text(str(p_mA1)) aIN2.set_text(str(q_mA1)) aIN1ENG.set_text("{0} bar".format(pEng1Display )) aIN2ENG.set_text("{0} lit/min".format(qEng1Display)) # INIETTORE #print "4 {0}".format(t1) if self.client_p: rr_p = self.client_p.read_holding_registers(500,100,unit=1) # print "5 {0}".format(t1) txtPout.set_text("{0} bar".format(rr_p.registers[16])) txtQout.set_text("{0} s/min {1:.2f} l/min".format(rr_p.registers[20], litCiclo*rr_p.registers[20] )) self.pmax = rr_p.registers[60] self.qmax = rr_p.registers[62] self.adjustPMax.set_value(float(self.pmax) ) self.adjustQMax.set_value(float(self.qmax)) builder.get_object("txtPmax").set_text("{0} bar".format(rr_p.registers[60])) builder.get_object("txtQmax").set_text("{0} s/min {1:.2f} l/min".format(rr_p.registers[62], litCiclo*rr_p.registers[62])) self.pDeltaP = self.pmax - rr_p.registers[16] self.qDeltaP = self.qmax - rr_p.registers[20] self.databuffer_q_max.append(self.qmax*litCiclo) self.databuffer_q_out.append(rr_p.registers[20]*litCiclo) self.databuffer_q2.append(rr_p.registers[16] ) self.databuffer_p2.append( self.pmax ) self.line_p2.set_ydata(self.databuffer_p2) self.line_q2.set_ydata(self.databuffer_q2) self.line_qout.set_ydata(self.databuffer_q_out) self.line_qmax.set_ydata(self.databuffer_q_max) pDeltaPump.set_text("{0} bar".format(self.pDeltaP )) qDeltaPump.set_text("{0} s/min {1:.2f} l/min".format(self.qDeltaP, self.qDeltaP*litCiclo )) self.p_count += 1 rr_p.registers[50] = self.p_count self.client_p.write_registers(500,rr_p.registers,unit=1) self.afigure.relim() self.afigure.autoscale_view(False, False, True) self.afigure2.relim() self.afigure2.autoscale_view(False, False, True) self.afigure3.relim() self.afigure3.autoscale_view(False, False, True) self.canvas.draw() if self.blogFile: self.oneLogged = True # TODO btnLog set label # time now - before self.btnLog.set_label("{0}".format(datetime.timedelta(seconds =dt_seconds))) log.info("%d;%f;%d;%f;%f;%f" % (p_mA1, p_Eng1, q_mA1, q_Sign, q_Eng1,self.elapsed,self.volume)) # print "6 {0}".format(t1) logApp.debug("logging_data terminated successfully") else: logApp.error( "error on test data {0}-{1} vs {2}".format(test_value_1,test_value_2,rr1.registers[test_reg_no])) return False return True def onDeleteWindow(self, *args): Gtk.main_quit(*args) def testConnection1(self, button): lblTest1 = builder.get_object("lblTest1") manifold_host_1 = builder.get_object("txtIP1").get_text() manifold_port_1 = int(builder.get_object("txtPort1").get_text()) self.client_1 = ModbusClient(manifold_host_1, port=manifold_port_1) self.ret_m1=self.client_1.connect() lblTest1.set_text(str(self.ret_m1)) if not smtConfig.has_section('Manifold_1'): smtConfig.add_section('Manifold_1') if self.ret_m1: logApp.debug("connection to manifold #1 ({0}:{1}) succedeed".format(manifold_host_1,manifold_port_1)) rr1_103 = self.client_1.read_holding_registers(103,10) self.reg104_1 = tuple(rr1_103.registers ) builder.get_object("switchMain").set_sensitive(True) smtConfig.set('Manifold_1', 'host', manifold_host_1) smtConfig.set('Manifold_1', 'port', manifold_port_1) with open(sCFGName, 'wb') as configfile: smtConfig.write(configfile) else: logApp.debug("connection to manifold #1 ({0}:{1}) failed".format(manifold_host_1,manifold_port_1)) self.client_1.close() def on_btnConnectPump_clicked(self, button): lblTestPump = builder.get_object("lblTestPump") pump_host = builder.get_object("txtIPPump").get_text() pump_port = int(builder.get_object("txtPortPump").get_text()) self.client_p = ModbusClient(pump_host, port=pump_port) self.ret_p=self.client_p.connect() lblTestPump.set_text(str(self.ret_p)) if not smtConfig.has_section('Pump'): smtConfig.add_section('Pump') if self.ret_p: builder.get_object("btnShow").set_sensitive(True) logApp.debug("connection to Pump ({0}:{1}) succedeed".format(pump_host,pump_port)) self.checkPump(self.client_p) smtConfig.set('Pump', 'host', pump_host) smtConfig.set('Pump', 'port', pump_port) with open(sCFGName, 'wb') as configfile: smtConfig.write(configfile) else: builder.get_object("btnShow").set_sensitive(False) logApp.debug("connection to Pump ({0}:{1}) failed".format(pump_host,pump_port)) self.client_p.close() def checkPump(self,client_p): self.p_count += 1 rq = client_p.write_register(550,self.p_count,unit=1) if rq.function_code < 0x80: rr_p = client_p.read_holding_registers(500,100,unit=1) if len(rr_p.registers)==100 and rr_p.registers[0]==self.p_count: decoder = BinaryPayloadDecoder.fromRegisters(rr_p.registers[2:7],endian=Endian.Little) # 502 bits_502 = decoder.decode_bits() bits_502 += decoder.decode_bits() # 503 bits_503 = decoder.decode_bits() bits_503 += decoder.decode_bits() # 504 bits_504 = decoder.decode_bits() bits_504 += decoder.decode_bits() # 505 bits_505 = decoder.decode_bits() bits_505 += decoder.decode_bits() # 506 bits_506 = decoder.decode_bits() bits_506 += decoder.decode_bits() if bits_502[7]: builder.get_object("switchPumpStatus").set_active(True) else: builder.get_object("switchPumpStatus").set_active(False) if bits_502[4] == False and bits_502[10] == True: builder.get_object("switchPumpStatus").set_sensitive(True) else: builder.get_object("switchPumpStatus").set_sensitive(False) self.setPumpFlowAndPressure() def on_btnOpenFile_clicked(self,button): #os.system() subprocess.call(["libreoffice",self.export_csv_path]) def setPumpFlowAndPressure(self): if self.ret_p: rr_p = self.client_p.read_holding_registers(500,100,unit=1) self.p_count += 1 rr_p.registers[50] = self.p_count rr_p.registers[60] = int(self.pmax) rr_p.registers[62] = int(self.qmax) rr_p = self.client_p.write_registers(500,rr_p.registers,unit=1) def on_btnOff_clicked(self,button): print("Closing application") logApp.debug("HDLF GUI CLOSING") Gtk.main_quit() def storeHDLF(self): self.pipeLength = float(builder.get_object("txtPipeLenght").get_text()) self.pipeDiam = float(builder.get_object("txtPipeDiam").get_text()) self.pipeType = builder.get_object("txtPipeType").get_text() self.mixType = builder.get_object("txtMixType").get_text() self.mixDensity = float(builder.get_object("txtMixDensity").get_text()) self.staticHead = float(builder.get_object("txtStaticHead").get_text()) if not smtConfig.has_section('HeadLossFactor'): smtConfig.add_section('HeadLossFactor') smtConfig.set('HeadLossFactor', 'pipeLength', self.pipeLength) smtConfig.set('HeadLossFactor', 'pipeDiam', self.pipeDiam) smtConfig.set('HeadLossFactor', 'pipeType', self.pipeType) smtConfig.set('HeadLossFactor', 'mixType', self.mixType) smtConfig.set('HeadLossFactor', 'mixDensity', self.mixDensity) smtConfig.set('HeadLossFactor', 'staticHead', self.staticHead) with open(sCFGName, 'wb') as configfile: smtConfig.write(configfile) def on_btnLog_toggled(self,button): if button.get_active(): self.time = datetime.datetime.utcnow() self.blogFile = True self.volume = 0 self.elapsed = 0 else: self.blogFile = False builder.get_object("btnLog").set_label("Log Data") def on_switchPumpStatus_state_set(self, switch,gparam): self.ret_p=self.client_p.connect() rr = self.client_p.read_holding_registers(500,100,unit=1) # conversione in bit array da 552 decoder = BinaryPayloadDecoder.fromRegisters(rr.registers[52:53],endian=Endian.Little) bits_552 = decoder.decode_bits() bits_552 += decoder.decode_bits() decoder = BinaryPayloadDecoder.fromRegisters(rr.registers[2:7],endian=Endian.Little) # 502 bits_502 = decoder.decode_bits() bits_502 += decoder.decode_bits() # 503 bits_503 = decoder.decode_bits() bits_503 += decoder.decode_bits() # 504 bits_504 = decoder.decode_bits() bits_504 += decoder.decode_bits() # 505 bits_505 = decoder.decode_bits() bits_505 += decoder.decode_bits() # 506 bits_506 = decoder.decode_bits() bits_506 += decoder.decode_bits() bSendCommand = False if switch.get_active(): # %MW552:X2 START INIET. DA REMOTO bSendCommand = not bits_502[7] bits_552[2] = True bits_552[3] = False bits_552[14] = True else: # %MW552:X2 STOP INIET. DA REMOTO bSendCommand = bits_502[7] bits_552[2] = False bits_552[3] = True bits_552[14] = False builder = BinaryPayloadBuilder(endian=Endian.Little) # builder.add_bits(bits_502) builder.add_bits(bits_552) reg_552 = builder.to_registers() rr.registers[52:53] = reg_552 self.p_count += 1 rr.registers[50] = self.p_count if bSendCommand: self.client_p.write_registers(500, rr.registers,unit=1) self.client_p.close() def on_btnShow_clicked(self,button): # show dlgRegistries self.lstDialog = builder.get_object("dlgRegistries") self.liststore = builder.get_object("liststore1") if not self.ret_p: self.ret_p = self.client_p.connect() if self.ret_p: self.liststore.clear() rr = self.client_p.read_holding_registers(500,100,unit=1) for idx in [0,2,4,6,12,13,14,15,16,20,50,52,60,62]: if idx in (2,4,6,52): decoder = BinaryPayloadDecoder.fromRegisters(rr.registers[idx:idx+1],endian=Endian.Little) bits = decoder.decode_bits() bits += decoder.decode_bits() for ib, b in enumerate(bits): if b: sCode = "%MW5{0:02d}:X{1}".format(idx,ib) self.liststore.append([sCode,reg_descr[sCode], str( b ) ]) else: sCode = "%MW5{0:02d}".format(idx) self.liststore.append([sCode, reg_descr[sCode], str( rr.registers[idx]) ]) response = self.lstDialog.run() self.lstDialog.hide() def on_btnOk_clicked(self,button): self.lstDialog.close() def on_btnOKComments_clicked(self, button): self.dlgComments.close() def on_btnComments_clicked(self, button): # self.parentWindow response = self.dlgComments.run() self.dlgComments.hide() def on_btnVolume_clicked(self, button): self.volume = 0 self.elapsed = 0 def on_chkAnalogic_toggled(self,chk): if chk.get_active(): logApp.info( "on_chkAnalogic_toggled toggled Active" ) # else: logApp.info( "on_chkAnalogic_toggled toggled Inactive" ) def on_spinPMax_value_changed(self,spin): self.pmax = int(spin.get_value()) self.setPumpFlowAndPressure() def on_spinQMax_value_changed(self,spin): self.qmax = int(spin.get_value()) self.setPumpFlowAndPressure() def on_switchMain_activate(self, switch,gparam): self.lblAnalyzed.set_label("...") if switch.get_active(): self.listP1 = [] self.export_csv_path = os.path.join(self.outputFolder,"test_{0}.csv".format(datetime.datetime.utcnow().strftime("%Y%m%d%H%M%S"))) file_handler = logging.handlers.RotatingFileHandler(self.export_csv_path, maxBytes=5000000,backupCount=5) file_handler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s;%(message)s') file_handler.setFormatter(formatter) if len(log.handlers) > 0: log.handlers[0] = file_handler else: log.addHandler(file_handler) log.info("p_mA1;p_Eng1;q_mA1;q_Sign;q_Eng1;elapsed;volume") self.client_1 = ModbusClient(manifold_host_1, port=manifold_port_1) self.client_p = None if self.ret_p: self.client_p = ModbusClient(pump_host, port=pump_port) #self.client_1.connect() self.ret_p = self.client_p.connect() time.sleep(1.5) print "start connection with Pump" time_delay = 1./float(self.samples_no) # 1 seconds delay self.loop = LoopingCall(f=self.logging_data, a=(self.client_1,None, builder.get_object("txtAIN1"),builder.get_object("txtAIN2"),builder.get_object("txtAIN1ENG"),builder.get_object("txtAIN2ENG"),None,None,builder.get_object("txtAIN1ENG2"),builder.get_object("txtAIN2ENG2"),self.client_p,builder.get_object("txtPout"),builder.get_object("txtQout"))) print "LoopingCall created" self.loop.start(time_delay, now=False) # initially delay by time print "loop started" builder.get_object("txtFilePath").set_text("") builder.get_object("btnOpenFile").set_sensitive(False) builder.get_object("btnOff").set_sensitive(False) # self.ani = animation.FuncAnimation(self.figure, self.update_plot, interval = 1000) else: self.loop.stop() time.sleep(1) #self.client_1.close() if self.ret_p: self.client_p.close() print "stop connection with Pump" time.sleep(1) builder.get_object("txtFilePath").set_text(self.export_csv_path) builder.get_object("btnOpenFile").set_sensitive(True) builder.get_object("btnOff").set_sensitive(True)
class ModbusFB(FunctionalBlock): DP_01 = dict(name="reg_1", access="input", dptId="7.xxx", default=0) DP_02 = dict(name="reg_2", access="input", dptId="7.xxx", default=0) DP_03 = dict(name="reg_3", access="output", dptId="7.xxx", default=0) GO_01 = dict(dp="reg_1", flags="CRWU", priority="low") GO_02 = dict(dp="reg_2", flags="CRWU", priority="low") GO_03 = dict(dp="reg_3", flags="CWTU", priority="low") DESC = "Modbus FB" def init(self): self._client = ModbusTcpClient(host=settings.MODBUS_HOST, port=settings.MODBUS_PORT) def _read(self, register): """ @param register: name of the variable to read @type register: int @return: register value @rtype: int """ self._client.connect() try: result = self._client.read_holding_registers(register, 1, unit=settings.MODBUS_UNIT) value = result.registers[0] return value finally: self._client.close() def _write(self, register, value): """ @param var: name of the variable to read @type var: str """ self._client.connect() try: self._client.write_register(register, value, unit=settings.MODBUS_UNIT) finally: self._client.close() @notify.datapoint(dp="reg_1", condition="change") @notify.datapoint(dp="reg_2", condition="change") @notify.datapoint(dp="reg_3", condition="change") def RegisterStateChanged(self, event): """ Method called when any of the 'reg_x' Datapoint change """ logger.debug("%s: event=%s" % (self.name, repr(event))) dpName = event['dp'] newValue = event['newValue'] oldValue = event['oldValue'] logger.info("%s: '%s' value changed from %s to %s" % (self.name, dpName, oldValue, newValue)) # Send new register value to modbus client self._write(config.KNX_TO_MODBUS[dpName], newValue) @schedule.every(seconds=settings.MODBUS_REFRESH_RATE) def modbusRefresh(self): """ Read modbus output registers """ for register, dp in config.MODBUS_TO_KNX.items(): value = self._read(register) self.dp[dp].value = value
while (not connected): resp = client.connect() if (resp == False): sys.exit(1); #time.sleep(10) else: connected = 1 count = count + 1 def close(): global client client.close() #main, pymodbus cant read more then 123 addresses at a time rq = client.read_holding_registers(4100,120) for x in range(0,120): reg= 4100 + x + 1 val = rq.registers[x] print(str(reg)+" "+str(val)) rq = client.read_holding_registers(4220,120) for x in range(0,120): reg= 4220 + x + 1 val = rq.registers[x] print(str(reg)+" "+str(val)) rq = client.read_holding_registers(16384,6) for x in range(0,6): reg= 16385 + x + 1 val = rq.registers[x]
logging.basicConfig() log = logging.getLogger() log.setLevel(logging.DEBUG) host='25.7.11.1' port=502 sleep_time=0.2;#in sec try: print'Открываем соединение...' client = ModbusClient(host, port); print'Подключились к хосту',host client.connect(); print'Установили соединение' start_address = 0x00; regs=2; for i in range(2): print "."*20,"we are going to read now" rq = client.read_holding_registers(start_address,regs,unit=1) print print "MY OUTPUT:",i, rq.registers rq.registers[1]=rq.registers[1]+1; sleep(sleep_time) print "."*20,"we are going to write now" client.write_register(1,rq.registers[1],unit=1) print sleep(sleep_time) except: print'ошибка!' else: print'Всё хорошо.'
#!/usr/bin/env python from pymodbus.client.sync import ModbusTcpClient as ModbusClient from pymodbus.transaction import ModbusRtuFramer as ModbusFramer import time client=ModbusClient('192.168.0.125',port=502,framer=ModbusFramer) connexion=client.connect() print connexion cnt=4 #nombre de registre rr=client.read_holding_registers(0,cnt,unit=0x01) time.sleep(2) print rr #tab=[] #for i in range(0,cnt): # tab.append(rr.getRegister(i)) #print tab #act = tab[0]+0.01*tab[1] #react = tab[2]+0.01*tab[3] #print 'Active energy: %10.2f' %act #print 'Reactive energy: %10.2f' %react client.close()
# -*- coding: utf-8 -*- #!/usr/bin/env python from pymodbus.client.sync import ModbusTcpClient as ModbusClient # INIETTORE pump_host = '10.243.37.106' # 10.243.37.xx pump_port = 502 # 502 client = ModbusClient(pump_host, port=pump_port) ret_p=client.connect() assert(ret_p==True) default_550 = 2 rq = client.write_register(550,default_550,unit=1) assert(rq.function_code < 0x80) rr_p = client.read_holding_registers(500,100,unit=1) assert(len(rr_p.registers)==100) for idx, r in enumerate(rr_p.registers): print "MW5{0:02d}={1}".format(idx,r) print rr_p.registers[0] assert(rr_p.registers[0]==default_550) # registro 500 contiene quanto settato in 550 print "Pump register 500 = {0}".format(rr_p.registers[0]) client.close() # CAVALLETTO 1 manifold_host = '10.243.37.8' # 10.243.37.xx manifold_port = 502 # 502 client = ModbusClient(manifold_host, port=manifold_port) ret_m=client.connect() assert(ret_m==True) rr_m = client.read_holding_registers(0,48) assert(len(rr_m.registers)==48) assert(rr_m.registers[0]==0x5200) print "Manifold 1 first register {0}".format(rr_m.registers[0]) sIPAddr = "%d.%d.%d.%d" % tuple(rr_m.registers[32-1:36-1])
import logging logging.basicConfig() log = logging.getLogger() log.setLevel(logging.DEBUG) # test connettività host = '127.0.0.1' port = 5020 test_reg_no = 0 # test the expected value (Machine ID, defaukt is 0x5100) test_value = 0x5100 # 20736 starting_register = 40001 client = ModbusClient(host, port=port) try: client.connect() log.info("Connessione Modbus TCP a {0}:{1} effettuata".format(host,port)) # scegliere registro e assert da verificare rr = client.read_holding_registers(starting_register,10) if isinstance(rr ,ExceptionResponse): log.error("Errore su read_holding_registers {0}: {1}".format(starting_register,rr)) else: log.info("{1} Regsitri letti {0}".format(rr.registers,len(rr.registers))) if rr.registers[test_reg_no] == test_value: log.info("OK - Su registro {0} il valore {1} == {2}".format(test_reg_no,rr.registers[test_reg_no],test_value)) else: log.error("Errore su registro {0}, valore {1} != {2}".format(test_reg_no,rr.registers[test_reg_no],test_value)) client.close() log.info("Chiusa la connessione Modbus TCP a {0}:{1}".format(host,port)) except ConnectionException as cex: log.error("Errore connessione Modbus TCP {1}:{2}. {0}".format(cex,host,port)) exit(-99)
class modbus(): #################################################################################################### # # # # # #################################################################################################### def __init__(self, smarthome, device='', timeout=None, port=502, cycle=5, pe_adress = 0, pe_length= 0, pa_adress= 0, pa_length= 0): ##Initialdaten aus Plugin.conf self._sh = smarthome self._items = {} self.timeout = float(timeout) self.device = str(device) self.port = int(port) self.cycle = int(cycle) #Inputs self.pe_adress = int(pe_adress) self.pe_lenght = int(pe_length) #Outputs self.pa_adress = int(pa_adress) self.pa_lenght = int(pa_length) ###################################### self._db = {}##ausgangsbytes self._db['in'] = {} self._db['out'] = {} #1: bool 0...1 #5: 8-bit signed value 0...255 #5.001: 8-bit unsigned value 0...100 #6: 8-bit signed value -128...127 #7: 16-bit unsigned value 0...65535 #8: 16-bit signed value -32768...32767 #9: floating point -671088,64 - 670760,96 self._db['dpt'] = {1:1, 5:8, 5.001:8, 6:8, 7:16, 8:16}##dpt und länge in bits self.init_read = 0 self._lock = threading.Lock() self.connected = False logger.info('Initialising Modbus TCP PLUGIN###############################################') smarthome.connections.monitor(self) def run(self):##plugin starten self.alive = True self._sh.scheduler.add('Modbus', self.refresh, cycle=self.cycle) logger.info('MODBUS: Started!') def stop(self):##plugin stoppen self.alive = False self._socket.close() logger.info('MODBUS: Stopped!') def parse_logic(self, logic):##nicht benoetigt pass def connect(self): #Verbinden/socket oeffnen self._lock.acquire() target = None try: if self.device is not None: self._modbuspy = ModbusTcpClient(self.device, self.port) self._modbuspy.connect() except Exception as e: logger.error('MODBUS: Could not connect to {}: {}'.format(self.device, e)) self._lock.release() return else: logger.info('MODBUS: Connected to {}'.format(self.device)) self.connected = True self._lock.release() def disconnect(self): #Verbindung trennen/socket schließen if self.connected: try: if self_socket is not None: client.close() except: pass logger.info('MODBUS: Disconnected!') self.connected = False self._target = None #################################################################################################### #HAUPTFUNKTION(main) #Funktion wird zyklisch von Smarthome aufgerufen: # # # #################################################################################################### def refresh(self): logger.debug('MODBUS cycle started########################################################') if self.connected: if self.init_read == 0: #1 start Ausgangsregister lesen self.read('out') self.init_read = 1 pprint(self._db) start = time.time() werte = self.read() self.write() cycletime = time.time() - start logger.debug("Modbus cycle takes {0} seconds".format(cycletime)) else: self.connect()#neu pass #################################################################################################### #Items beim start überprüfen, auf modbus_on = 1 #Items Namen (gads) und Bytes werden peb und pab zugeordnet #Bits werden in Bytes einsortiert # # #################################################################################################### def parse_item(self, item): if 'modbus_on' in item.conf: byte = int(item.conf['modbus_byte']) if 'modbus_bit' in item.conf: bit = int(item.conf['modbus_bit']) else: bit = None ##Daten zusammenstellen daten = [] daten.append(bit) #0 if 'modbus_dpt' in item.conf: daten.append(item.conf['modbus_dpt']) #1 daten.append(item()) #2 else: #oder daten.append(1) #1 daten.append(bool(item())) #2 daten.append(item) #3 #pprint(daten) #datensatz pro item ##Unterscheidung in in/outputs if self.pe_adress <= byte <= (self.pe_adress+self.pe_lenght): ##INPUTS if not byte in self._db['in'].keys(): self._db['in'][byte] = [] self._db['in'][byte].append(daten) elif self.pa_adress <= byte <= (self.pa_adress+self.pa_lenght): ##OUTPUTS if byte not in self._db['out'].keys(): self._db['out'][byte] = [] self._db['out'][byte].append(daten) return None #################################################################################################### ##Item hat sich verändert, wird von Smarthome aufgerufen, bei item(name, caller...) ##self._DB updaten! # # # #################################################################################################### def update_item(self, item, caller=None, source=None, dest=None): if caller == 'modbus': pass #################################################################################################### #AusgangsWORTe an Steuerung schreiben # # # # #################################################################################################### def write(self): try: lb = 00000000 hb = 00000000 #### byte besteht immer aus 16 bits for byte in self._db['out']: for bit in sorted(self._db['out'][byte]): if bit in self._db['out'][byte]: bitpos = bit[0] #startbit/bitposition des binärwertes type = bit[1] value = bit[2] name = bit[3] bit[2] = bit[3]() ##aktueller wert des items abrufen und value updaten! builder = BinaryPayloadBuilder(endian=Endian.Little) ##unterscheidung dateityp if type == '5' or type == '5.001' or type == '6' : ##8bit uint / int length = 8 if bitpos < 8: #lb lb = value else: #hb hb = value if type == '5': builder.add_8bit_uint(lb) builder.add_8bit_uint(hb) #logger.debug('MODBUS: 8bit uint {0} ; {1}'.format(lb,hb)) elif type == '5.001': ##0-100 in 0-255 umwandeln! #print(dpts.en5001(lb)) #print(dpts.en5001(hb)) lb = self.de5001(lb) hb = self.de5001(hb) #print("lb geschrieben", lb ) #print("hb geschrieben", hb ) builder.add_8bit_uint(lb) builder.add_8bit_uint(hb) #logger.debug('MODBUS: 8bit uint {0} ; {1}'.format(lb,hb)) elif type == '6': if lb > 127: lb = 127 elif lb < -128: lb = -128 if hb > 127: hb = 127 elif hb < -128: hb = -128 builder.add_8bit_int(lb) builder.add_8bit_int(hb) #logger.debug('MODBUS: 8bit int {0} ; {1}'.format(lb.hb)) elif type == '7' or type == '8': #16bit uint / int length = 16 if type == '7': #0...65535 builder.add_16bit_uint(value) #logger.debug('MODBUS: 16bit uint {0} '.format(value)) else: #-32768...32767 builder.add_16bit_int(value) #logger.debug('MODBUS: 16bit int {0}'.format(value)) elif type == '1': length = 1 #nur pro byte einmal die bits wandeln if bitpos < 8: #lb lb = lb | int(value) << bitpos #logger.debug('MODBUS: 8bit int{0}'.format(lb)) else: #hb hb = hb | int(value) << bitpos #logger.debug('MODBUS: 8bit int{0}'.format(hb)) builder.add_8bit_uint(lb) builder.add_8bit_uint(hb) payload = builder.build() logger.debug('MODBUS: write to PLC: WORD {0} set to {1} '.format(byte,payload)) self._modbuspy.write_registers(byte, payload, skip_encode=True) builder.reset() except Exception as e: logger.error('MODBUS: Could not write an OutWord, because {}'.format(e)) self._lock.release() return None #################################################################################################### #Liest komplett angegebenen Speicherbereich aus Steuerung aus und gibt sie in dict zurück! #read = anfangswert, end= länge #Eingangsbereich von Steuerung lesen # # #################################################################################################### def read(self, iO='in'): #print('DATEN VOM BUS LESEN') i = 0 if iO !='in': x = 'out' else: x = 'in' try: for byte in self._db[x]: rr = self._modbuspy.read_holding_registers(byte,2) pprint(rr) decodert2 = BinaryPayloadDecoder.fromRegisters(rr.registers, endian=Endian.Little) ##prüfen welcher dpt typ vorliegt und dann das registerabfrage ergebnis aufdröseln: #->decode_16bit_uint() -> 7 / 8 #->decode_8bit_uint() -> 5 | 5.001 #->decode_8bit_int() -> 6 #->decode_bits() -> 1 for bit in self._db[x][byte]: ##eintraege in dict durchgehen bitpos = bit[0] type = bit[1] name = bit[3] if type == '5' or type == '5.001' or type == '6': ##8bit uint / int length = 8 if type == '6': lb = decodert2.decode_8bit_int() hb = decodert2.decode_8bit_int() elif type == '5' or type == '5.001': lb = decodert2.decode_8bit_uint() hb = decodert2.decode_8bit_uint() if bitpos < 8:#lb value = hb #logger.debug('MODBUS: byte{0} startpos{1} wert (5) {2}'.format(bit, bitpos,value)) else:#hb value = lb #logger.debug('MODBUS: byte{0} startpos{1} wert (5) {2}'.format(bit, bitpos,value)) if type == '5.001': #print('lb/hb Daten gelesen', value) value = self.en5001(value) #logger.debug('MODBUS: byte{0} startpos{1} wert (5.001) {2}'.format(bit, bitpos, value)) elif type == '7' or type == '8': #16bit uint / int length = 16 if type == '7': #0...65535 value = decodert2.decode_16bit_uint() #logger.debug('MODBUS: 16bit uint{0}'.format(value)) else: #-32768...32767 value = decodert2.decode_16bit_int() #logger.debug('MODBUS: 16bit int{0}'.format(value)) elif type == '1': length = 1 hb = decodert2.decode_bits() lb = decodert2.decode_bits() bits = lb+hb value = bits[bitpos] #logger.debug('MODBUS: Bits{0}'.format(bits)) bit[2] = value #zurückspeichern decodert2.reset() ##Debug################################################################################# bit[3](value, caller='modbus') i = i+1 lb = decodert2.decode_bits() hb = decodert2.decode_bits() bits = hb+lb decodert2.reset() logger.debug('MODBUS: read from PLC {0}-{1} {2}'.format(byte, bits, bytes)) except Exception as e: logger.error('MODBUS: Could not read an InputWord, because {}'.format( e)) self._lock.release() return None i = 0 return None #################################################################################################### #wandelt str in binary ohne führendes 0b #und invertiert auf wunsch das Ergebnis! # # # #################################################################################################### def toBinary2(self, n, invert = 1):## byte = '{:08b}'.format(n) i = int(16)-len(byte) ausgabe = "" for x in range(0,i): ausgabe = "0"+ausgabe ausgabe = ausgabe+byte if invert == 1:#invertieren ausgabe = ausgabe[::-1] return ausgabe def toBinary(self, n, invert = 0):## byte = '{:08b}'.format(n) if invert == 1:#invertieren byte = byte[::-1] ausgabe = [] if byte == '00000000': ausgabe.append('00000000') ausgabe.append('00000000') elif byte < '256' : ausgabe.append(byte[0:8]) ausgabe.append('00000000') else: ausgabe.append(byte[0:8]) ausgabe.append(byte[8:17]) return ausgabe def de5001(self, value): #8bit 0-100 auf 0-255 normieren if value > 255: value = 255 elif value < 0: value = 0 return int(round(value*2.55)) def en5001(self, value): #8bit auf 0-100 normieren if value > 255: value = 255 elif value < 0: value = 0 return (round((value/2.55), 2))
#---------------------------------------------------------------------------# # If you need to decode a collection of registers in a weird layout, the # payload decoder can help you as well. # # Here we demonstrate decoding a random register layout, unpacked it looks # like the following: # # - a 8 byte string 'abcdefgh' # - a 32 bit float 22.34 # - a 16 bit unsigned int 0x1234 # - an 8 bit int 0x12 # - an 8 bit bitstring [0,1,0,1,1,0,1,0] #---------------------------------------------------------------------------# address = 0x00 count = 8 result = client.read_holding_registers(address, count, unit=1) decoder = BinaryPayloadDecoder.fromRegisters(result.registers, endian=Endian.Big) decoded = { 'string': decoder.decode_string(8), 'float': decoder.decode_32bit_float(), '16uint': decoder.decode_16bit_uint(), '8int': decoder.decode_8bit_int(), 'bits': decoder.decode_bits(), } print "-" * 60 print "Decoded Data" print "-" * 60 for name, value in decoded.iteritems(): print ("%s\t" % name), value
class clientthreads(threading.Thread): def __init__(self, vnic, ipaddr, port): threading.Thread.__init__(self) self.ipaddr = ipaddr # ip address self.port = port # port address self.vnic = vnic # virtual nic self.mode = "" # server or client self.state = "" # up or down self.dest = "" # destination address for client self.clientstop = threading.Event() self.server = "" self.client = "" self.framer = "" self.vnicm = "" self.runtime= 0 self.delayr = random.uniform(0,5) self.delayw = random.uniform(0,60) self.firstdelay = 0 self.pstart= "" def run(self): self.client = ModbusTcpClient(self.dest, self.port, source_address=(self.ipaddr, 0), retries=1, retry_on_empty=True) if(self.mode=="read"): self.clientintr() elif(self.mode=="write"): self.clientintw() else: print "wrong mode specified" def clientintr(self): # instantiate server stuff while(not self.clientstop.is_set()): if(time.time() - self.pstart > self.runtime): print "stopping" break if(self.firstdelay < 1): print "Start RDelay is: " + str(self.delayr) time.sleep(self.delayr) self.firstdelay = 1 print "Starting Reads" self.clientreads() print "\n\r-----read-----\n\r" print self.dest print time.time() - self.pstart print "------------------\n\r" def clientintw(self): # instantiate server stuff while(not self.clientstop.is_set()): if(time.time() - self.pstart > self.runtime): print "stopping" break if(self.firstdelay < 1): print "Start WDelay is: " + str(self.delayw) time.sleep(self.delayw) self.firstdelay = 1 print "Starting Writes" self.clientwrites() print "\n\r-----write----\n\r" print self.dest print time.time() - self.pstart print "------------------\n\r" def clientreads(self): self.client.read_coils(1, 10) self.client.read_discrete_inputs(1, 10) self.client.read_holding_registers(1, 10) self.client.read_input_registers(1, 10) time.sleep(5) def clientwrites(self): self.client.write_coil(1, True) self.client.write_register(1, 3) self.client.write_coils(1, [True]*10) self.client.write_registers(1, [3]*10) time.sleep(60) def alloc(self): # Allocate ip address if (validateIP(self.ipaddr, self.vnicm)): cmdargs = [self.vnic, self.ipaddr] subprocess.call(["ifconfig"] + cmdargs) else: return 0 def dealloc(self): # De-allocate ip address cmdargs = [self.vnic] subprocess.call(["ifconfig"] + cmdargs + ["down"]) def stop(self): self.clientstop.set() return
class HMIWindow(Gtk.Window): oil_processed_amount = 0 oil_spilled_amount = 0 def initModbus(self): # Create modbus connection to specified address and port self.modbusClient = ModbusClient(args.server_addr, port=5020) # Default values for the HMI labels def resetLabels(self): self.feed_pump_value.set_markup("<span weight='bold' foreground='gray33'>N/A</span>") self.separator_value.set_markup("<span weight='bold' foreground='gray33'>N/A</span>") self.level_switch_value.set_markup("<span weight='bold' foreground='gray33'>N/A</span>") self.process_status_value.set_markup("<span weight='bold' foreground='gray33'>N/A</span>") self.connection_status_value.set_markup("<span weight='bold' foreground='red'>OFFLINE</span>") self.oil_processed_value.set_markup("<span weight='bold' foreground='green'>" + str(self.oil_processed_amount) + " Liters</span>") self.oil_spilled_value.set_markup("<span weight='bold' foreground='red'>" + str(self.oil_spilled_amount) + " Liters</span>") self.outlet_valve_value.set_markup("<span weight='bold' foreground='red'>N/A</span>") self.waste_value.set_markup("<span weight='bold' foreground='red'>N/A</span>") def __init__(self): # Window title Gtk.Window.__init__(self, title="Oil Refinery") self.set_border_width(100) #Create modbus connection self.initModbus() elementIndex = 0 # Grid grid = Gtk.Grid() grid.set_row_spacing(15) grid.set_column_spacing(10) self.add(grid) # Main title label label = Gtk.Label() label.set_markup("<span weight='bold' size='xx-large' color='black'>Crude Oil Pretreatment Unit </span>") grid.attach(label, 4, elementIndex, 4, 1) elementIndex += 1 # Crude Oil Feed Pump feed_pump_label = Gtk.Label("Crude Oil Tank Feed Pump") feed_pump_value = Gtk.Label() feed_pump_start_button = Gtk.Button("START") feed_pump_stop_button = Gtk.Button("STOP") feed_pump_start_button.connect("clicked", self.setPump, 1) feed_pump_stop_button.connect("clicked", self.setPump, 0) grid.attach(feed_pump_label, 4, elementIndex, 1, 1) grid.attach(feed_pump_value, 5, elementIndex, 1, 1) grid.attach(feed_pump_start_button, 6, elementIndex, 1, 1) grid.attach(feed_pump_stop_button, 7, elementIndex, 1, 1) elementIndex += 1 # Level Switch level_switch_label = Gtk.Label("Crude Oil Tank Level Switch") level_switch_value = Gtk.Label() level_switch_start_button = Gtk.Button("ON") level_switch_stop_button = Gtk.Button("OFF") level_switch_start_button.connect("clicked", self.setTankLevel, 1) level_switch_stop_button.connect("clicked", self.setTankLevel, 0) grid.attach(level_switch_label, 4, elementIndex, 1, 1) grid.attach(level_switch_value, 5, elementIndex, 1, 1) grid.attach(level_switch_start_button, 6, elementIndex, 1, 1) grid.attach(level_switch_stop_button, 7, elementIndex, 1, 1) elementIndex += 1 #outlet valve outlet_valve_label = Gtk.Label("Outlet Valve") outlet_valve_value = Gtk.Label() outlet_vlave_open_button = Gtk.Button("OPEN") outlet_valve_close_button = Gtk.Button("CLOSE") outlet_vlave_open_button.connect("clicked", self.setOutletValve, 1) outlet_valve_close_button.connect("clicked", self.setOutletValve, 0) grid.attach(outlet_valve_label, 4, elementIndex, 1, 1) grid.attach(outlet_valve_value, 5, elementIndex, 1, 1) grid.attach(outlet_vlave_open_button, 6, elementIndex, 1, 1) grid.attach(outlet_valve_close_button, 7, elementIndex, 1, 1) elementIndex += 1 #Separator Vessel separator_label = Gtk.Label("Separator Vessel Valve") separator_value = Gtk.Label() separator_open_button = Gtk.Button("OPEN") separator_close_button = Gtk.Button("CLOSED") separator_open_button.connect("clicked", self.setSepValve, 1) separator_close_button.connect("clicked", self.setSepValve, 0) grid.attach(separator_label, 4, elementIndex, 1, 1) grid.attach(separator_value, 5, elementIndex, 1, 1) grid.attach(separator_open_button, 6, elementIndex, 1, 1) grid.attach(separator_close_button, 7, elementIndex, 1, 1) elementIndex += 1 #Waste Water Valve waste_label = Gtk.Label("Waste Water Valve") waste_value = Gtk.Label() waste_open_button = Gtk.Button("OPEN") waste_close_button = Gtk.Button("CLOSED") waste_open_button.connect("clicked", self.setWasteValve, 1) waste_close_button.connect("clicked", self.setWasteValve, 0) grid.attach(waste_label, 4, elementIndex, 1, 1) grid.attach(waste_value, 5, elementIndex, 1, 1) grid.attach(waste_open_button, 6, elementIndex, 1, 1) grid.attach(waste_close_button, 7, elementIndex, 1, 1) elementIndex += 1 # Process status process_status_label = Gtk.Label("Process Status") process_status_value = Gtk.Label() grid.attach(process_status_label, 4, elementIndex, 1, 1) grid.attach(process_status_value, 5, elementIndex, 1, 1) elementIndex += 1 # Connection status connection_status_label = Gtk.Label("Connection Status") connection_status_value = Gtk.Label() grid.attach(connection_status_label, 4, elementIndex, 1, 1) grid.attach(connection_status_value, 5, elementIndex, 1, 1) elementIndex += 1 # Oil Processed Status oil_processed_label = Gtk.Label("Oil Processed Status") oil_processed_value = Gtk.Label() grid.attach(oil_processed_label, 4, elementIndex, 1, 1) grid.attach(oil_processed_value, 5, elementIndex, 1, 1) elementIndex += 1 # Oil Spilled Status oil_spilled_label = Gtk.Label("Oil Spilled Status") oil_spilled_value = Gtk.Label() grid.attach(oil_spilled_label, 4, elementIndex, 1, 1) grid.attach(oil_spilled_value, 5, elementIndex, 1, 1) elementIndex += 1 # Oil Refienery branding virtual_refinery = Gtk.Label() virtual_refinery.set_markup("<span size='small'>Crude Oil Pretreatment Unit - HMI</span>") grid.attach(virtual_refinery, 4, elementIndex, 2, 1) # Attach Value Labels self.feed_pump_value = feed_pump_value self.process_status_value = process_status_value self.connection_status_value = connection_status_value self.separator_value = separator_value self.level_switch_value = level_switch_value self.oil_processed_value = oil_processed_value self.oil_spilled_value = oil_spilled_value self.outlet_valve_value = outlet_valve_value self.waste_value = waste_value # Set default label values self.resetLabels() GObject.timeout_add_seconds(MODBUS_SLEEP, self.update_status) # Control the feed pump register values def setPump(self, widget, data=None): try: self.modbusClient.write_register(0x01, data) except: pass # Control the tank level register values def setTankLevel(self, widget, data=None): try: self.modbusClient.write_register(0x02, data) except: pass # Control the separator vessel level register values def setSepValve(self, widget, data=None): try: self.modbusClient.write_register(0x04, data) except: pass # Control the separator vessel level register values def setWasteValve(self, widget, data=None): try: self.modbusClient.write_register(0x08, data) except: pass def setOutletValve(self, widget, data=None): try: self.modbusClient.write_register(0x03, data) except: pass def update_status(self): try: # Store the registers of the PLC in "rr" rr = self.modbusClient.read_holding_registers(1,16) regs = [] # If we get back a blank response, something happened connecting to the PLC if not rr or not rr.registers: raise ConnectionException # Regs is an iterable list of register key:values regs = rr.registers if not regs or len(regs) < 16: raise ConnectionException # If the feed pump "0x01" is set to 1, then the pump is running if regs[0] == 1: self.feed_pump_value.set_markup("<span weight='bold' foreground='green'>RUNNING</span>") else: self.feed_pump_value.set_markup("<span weight='bold' foreground='red'>STOPPED</span>") # If the level sensor is ON if regs[1] == 1: self.level_switch_value.set_markup("<span weight='bold' foreground='green'>ON</span>") else: self.level_switch_value.set_markup("<span weight='bold' foreground='red'>OFF</span>") # Outlet Valve status if regs[2] == 1: self.outlet_valve_value.set_markup("<span weight='bold' foreground='green'>OPEN</span>") else: self.outlet_valve_value.set_markup("<span weight='bold' foreground='red'>CLOSED</span>") # If the feed pump "0x04" is set to 1, separator valve is open if regs[3] == 1: self.separator_value.set_markup("<span weight='bold' foreground='green'>OPEN</span>") self.process_status_value.set_markup("<span weight='bold' foreground='green'>RUNNING </span>") else: self.separator_value.set_markup("<span weight='bold' foreground='red'>CLOSED</span>") self.process_status_value.set_markup("<span weight='bold' foreground='red'>STOPPED </span>") # Waste Valve status "0x08" if regs[7] == 1: self.waste_value.set_markup("<span weight='bold' foreground='green'>OPEN</span>") else: self.waste_value.set_markup("<span weight='bold' foreground='red'>CLOSED</span>") # If the oil spilled tag gets set, increase the amount of oil we have spilled if regs[5]: self.oil_spilled_value.set_markup("<span weight='bold' foreground='red'>" + str(regs[5]) + " Liters</span>") # If the oil spilled tag gets set, increase the amount of oil we have spilled if regs[6]: self.oil_processed_value.set_markup("<span weight='bold' foreground='green'>" + str(regs[6] + regs[8]) + " Liters</span>") # If we successfully connect, then show that the HMI has contacted the PLC self.connection_status_value.set_markup("<span weight='bold' foreground='green'>ONLINE </span>") except ConnectionException: if not self.modbusClient.connect(): self.resetLabels() except: raise finally: return True
class Handler(object): def __init__(self,a,a2,canvas,loop=None): self.loop = loop self.ret_m1 = False self.afigure = a self.afigure2 = a2 self.canvas = canvas self._bufsize = x_size self.databuffer_p1 = collections.deque([0.0]*self._bufsize, self._bufsize) self.databuffer_p2 = collections.deque([0.0]*self._bufsize, self._bufsize) self.databuffer_r = collections.deque([0.0]*self._bufsize, self._bufsize) self.databuffer_q1 = collections.deque([0.0]*self._bufsize, self._bufsize) self.x = range(x_size) self.line_p1, = self.afigure.plot(self.x, self.databuffer_p1,"b-", label='Pg') self.line_p2, = self.afigure.plot(self.x, self.databuffer_p2,"-", color='#ffa100', label='Pe') self.line_r, = self.afigure.plot(self.x, self.databuffer_r,"r-", label='R') self.line_q1, = self.afigure2.plot(self.x, self.databuffer_q1,"m-", label='Q') h1, l1 = a.get_legend_handles_labels() h2, l2 = a2.get_legend_handles_labels() self.afigure.legend(h1+h2, l1+l2, loc=2, ncol=2, fontsize=10) self.pmax = 0 self.qmax = 0 self.qVmax = 0 self.pR = 0 self.blogFile = False self.oneLogged = False self.pipeLength = 0.0 self.pipeDiam = 0.0 self.pipeType = "ND" self.mixType = "ND" self.mixDensity = 0.0 self.staticHead = 0.0 self.treeview2 = builder.get_object("treeview2") self.p_count = 0 renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn("Name", renderer, text=0) self.treeview2.append_column(column) renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn("Description", renderer, text=1) self.treeview2.append_column(column) renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn("Value", renderer, text=2) self.treeview2.append_column(column) self.adjustPMax = builder.get_object("adjustment1") self.adjustQMax = builder.get_object("adjustment2") self.chkPAna = builder.get_object("chkPAna") self.txtDHLF = builder.get_object("txtDHLF") self.btnAnalyze = builder.get_object("btnAnalyze") self.txtRefPressure = builder.get_object("txtR") self.btnAnalyze.set_sensitive(False) self.time = datetime.datetime.utcnow() self.lastPe = collections.deque(maxlen=designRTW*60) self.lastPg = collections.deque(maxlen=designRTW*60) self.lastQ = collections.deque(maxlen=designRTW*60) self.txtQ2 = builder.get_object("txtQ2") self.txtQ1 = builder.get_object("txtQ1") self.txtK = builder.get_object("txtK") self.txtPoutMax = builder.get_object("txtPoutMax") self.lblOK = builder.get_object("lblOK") self.hdlf_q2 = 0 self.hdlf_q1 = 0 self.hdlf_k = 0 self.designQmin = 0. def logging_data(self, a): self.send_parity() t1=datetime.datetime.utcnow() dt_seconds = (t1-self.time).seconds builder.get_object("levelbar1").set_value(len(listP1)%60+1) client_1 = a[0] client_p = a[8] txtPout = a[9] txtQout = a[10] aIN1 = a[1] aIN2 = a[2] aIN1ENG = a[3] aIN2ENG = a[4] aIN12 = a[5] aIN22 = a[6] aIN1ENG2 = a[7] strR = self.txtRefPressure.get_text() if strR.isdigit(): self.pR = int(strR) else: self.pR = 10 self.txtRefPressure.set_text("10") strR = builder.get_object("txtPipeLenght").get_text() if strR.isdigit(): self.pipeLength = int(strR) else: builder.get_object("txtPipeLenght").set_text(str(self.pipeLength)) self.hdlf_q2 = float(builder.get_object("txtQ2").get_text()) self.hdlf_q1 = float(builder.get_object("txtQ1").get_text()) self.hdlf_k = float(builder.get_object("txtK").get_text()) strR = builder.get_object("txtStaticHead").get_text() try: self.staticHead = float(strR) except ValueError: builder.get_object("txtStaticHead").set_text(str(self.staticHead)) rr1 = client_1.read_holding_registers(0,48) if rr1.registers[test_reg_no] == test_value: p_mA1 = rr1.registers[4-1]# AIN1 pressione in mA in posizione 4 p_Eng1 = int(pEngFunc(p_mA1)) # AIN2 portata in mA in posizione 6 q_mA1 = rr1.registers[6-1] q_Eng1 = int(qEngFunc(q_mA1)) rr1_103 = client_1.read_holding_registers(103,10) reg104_1 = tuple(rr1_103.registers ) p_mA2 = 0 # rr2.registers[4-1]# AIN1 pressione in mA in posizione 4 p_Eng2 = 0 # rr2.registers[5-1] # AIN2 portata in mA in posizione 6 q_mA2 = 0 # rr2.registers[6-1] if p_mA1 <= 4000: p_mA1 = 0 p_Eng1 = 0 if q_mA1 <= 4000: q_mA1 = 0 q_Eng1 = 0 hdlf = (self.hdlf_q2, self.hdlf_q1,self.hdlf_k) self.pDHL = phdlf( q_Eng1/10. ,self.pipeLength, hdlf ) p_Eng2 = p_Eng1 - 10.*self.pDHL + 10.*self.staticHead self.lastQ.append(q_Eng1/10.) self.lastPe.append(p_Eng2/10.) self.lastPg.append(p_Eng1/10.) if len(self.lastPe) == self.lastPe.maxlen: p_mA2 = np.mean(self.lastPe) q_mA2 = np.mean(self.lastQ) pRate = p_mA2/self.pR if q_mA2 <= self.designQmin and p_mA2 >= self.pR: self.lblOK.set_label("OK") else: self.lblOK.set_label("P<R ({0:.2f})".format(pRate)) self.txtDHLF.set_text("{0:.2f}".format(-self.pDHL)) self.databuffer_p1.append( p_Eng1/10. ) self.line_p1.set_ydata(self.databuffer_p1) self.databuffer_p2.append( p_Eng2/10. ) self.line_p2.set_ydata(self.databuffer_p2) self.databuffer_r.append( self.pR ) self.line_r.set_ydata(self.databuffer_r) self.databuffer_q1.append( q_Eng1/10. ) self.line_q1.set_ydata(self.databuffer_q1) self.afigure.relim() self.afigure.autoscale_view(False, False, True) self.afigure2.relim() self.afigure2.autoscale_view(False, False, True) self.canvas.draw() listP1.append(p_Eng1/10.) listP2.append(p_Eng2/10.) aIN1.set_text(str(p_mA1)) aIN2.set_text(str(q_mA1)) aIN1ENG.set_text("{0} bar".format(p_Eng1/10.)) aIN2ENG.set_text("{0} lit/min".format(q_Eng1/10.)) aIN12.set_text("{0:.2f} bar".format(p_mA2)) aIN22.set_text("{0:.2f} lit/min".format(q_mA2)) aIN1ENG2.set_text("{0} bar".format(p_Eng2/10.)) # INIETTORE rr_p = client_p.read_holding_registers(500,100,unit=1) txtPout.set_text("{0} bar".format(rr_p.registers[16])) fPoutMax = self.pR + rr_p.registers[16] - p_Eng2/10. self.txtPoutMax.set_text("{0}".format(int(fPoutMax))) txtQout.set_text("{0} c/min {1:.2f} l/min".format(rr_p.registers[20], litCiclo*rr_p.registers[20] )) self.pmax = rr_p.registers[60] if self.chkPAna.get_active(): self.qmax = rr_p.registers[64] builder.get_object("txtQmax").set_text("{0} V".format(self.qmax)) else: self.qmax = rr_p.registers[62] builder.get_object("txtQmax").set_text("{0} c/min {1:.2f} l/min".format(self.qmax, litCiclo*self.qmax)) # self.qVmax = rr_p.registers[64] builder.get_object("txtPmax").set_text("{0} bar".format(rr_p.registers[60])) # print "P: {0}->{1} \tdP = {4} \t\tQ: {2}->{3} \tn={5} \tavg P1 {6:.2f}({7:.2f}) P2 {8:.2f}({9:.2f})".format(p_Eng1/10.,p_Eng2/10.,q_Eng1/10.,q_Eng2/10.,(p_Eng1-p_Eng2)/10., len(listP1), np.mean(listP1),np.std(listP1),np.mean(listP2),np.std(listP2) ) if self.blogFile: self.oneLogged = True # TODO btnLog set label # time now - before builder.get_object("btnLog").set_label("{0}".format(datetime.timedelta(seconds =dt_seconds))) log.info("%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%f;%f;%s;%s;%f;%f;%f;%d;%d;%d;%d;%f;%f;%f;%f;%f;%f" % (self.pR, p_mA1, p_Eng1, q_mA1, q_Eng1,reg104_1[0] ,reg104_1[1] ,reg104_1[2] , reg104_1[3],reg104_1[6] ,reg104_1[7] ,reg104_1[8] , reg104_1[9],p_mA2, p_Eng2, q_mA2, self.pipeLength, self.pipeDiam,self.pipeType,self.mixType,self.mixDensity,self.staticHead,self.pDHL, rr_p.registers[16],rr_p.registers[20],self.pmax,self.qmax, self.pmax-rr_p.registers[16], rr_p.registers[16]- p_Eng1/10. , hdlf[0], hdlf[1], hdlf[2],fPoutMax)) else: print "error on test data {0} vs {1} or {0} vs {2}".format(test_value,rr1.registers[test_reg_no],rr2.registers[test_reg_no]) def onDeleteWindow(self, *args): Gtk.main_quit(*args) def testConnection1(self, button): lblTest1 = builder.get_object("lblTest1") manifold_host_1 = builder.get_object("txtIP1").get_text() manifold_port_1 = int(builder.get_object("txtPort1").get_text()) client_1 = ModbusClient(manifold_host_1, port=manifold_port_1) self.ret_m1=client_1.connect() lblTest1.set_text(str(self.ret_m1)) if not smtConfig.has_section('Manifold_1'): smtConfig.add_section('Manifold_1') if self.ret_m1: builder.get_object("switchMain").set_sensitive(True) smtConfig.set('Manifold_1', 'host', manifold_host_1) smtConfig.set('Manifold_1', 'port', manifold_port_1) with open(sCFGName, 'wb') as configfile: smtConfig.write(configfile) client_1.close() def on_btnConnectPump_clicked(self, button): lblTestPump = builder.get_object("lblTestPump") pump_host = builder.get_object("txtIPPump").get_text() pump_port = int(builder.get_object("txtPortPump").get_text()) self.client_p = ModbusClient(pump_host, port=pump_port) self.ret_p=self.client_p.connect() lblTestPump.set_text(str(self.ret_p)) if not smtConfig.has_section('Pump'): smtConfig.add_section('Pump') if self.ret_p: self.checkPump(self.client_p) smtConfig.set('Pump', 'host', pump_host) smtConfig.set('Pump', 'port', pump_port) with open(sCFGName, 'wb') as configfile: smtConfig.write(configfile) self.client_p.close() def checkPump(self,client_p): rr = client_p.read_holding_registers(500,100,unit=1) # conversione in bit array da 552 decoder = BinaryPayloadDecoder.fromRegisters(rr.registers[52:53],endian=Endian.Little) bits_552 = decoder.decode_bits() bits_552 += decoder.decode_bits() bits_552[10] = True b_builder = BinaryPayloadBuilder(endian=Endian.Little) b_builder.add_bits(bits_552) reg_552 = b_builder.to_registers() rr.registers[52:53] = reg_552 for it in range(10): self.p_count += 1 rr.registers[50] = self.p_count rq = client_p.write_registers(500, rr.registers,unit=1) if rq.function_code < 0x80: rr_p = client_p.read_holding_registers(500,100,unit=1) if len(rr_p.registers)==100 and rr_p.registers[0]==self.p_count: decoder = BinaryPayloadDecoder.fromRegisters(rr_p.registers[2:7],endian=Endian.Little) # 502 bits_502 = decoder.decode_bits() bits_502 += decoder.decode_bits() # 503 bits_503 = decoder.decode_bits() bits_503 += decoder.decode_bits() # 504 bits_504 = decoder.decode_bits() bits_504 += decoder.decode_bits() # 505 bits_505 = decoder.decode_bits() bits_505 += decoder.decode_bits() # 506 bits_506 = decoder.decode_bits() bits_506 += decoder.decode_bits() if bits_502[7]: builder.get_object("switchPumpStatus").set_active(True) else: builder.get_object("switchPumpStatus").set_active(False) if bits_502[4] == False and bits_502[10] == True: builder.get_object("switchPumpStatus").set_sensitive(True) else: builder.get_object("switchPumpStatus").set_sensitive(False) else: print "errore checkPump %d" % self.p_count bits_552[10] = False print str(bits_552) b_builder = BinaryPayloadBuilder(endian=Endian.Little) b_builder.add_bits(bits_552) reg_552_2 = b_builder.to_registers() rr.registers[52:53] = reg_552_2 rq = client_p.write_registers(500, rr.registers,unit=1) if rq.function_code < 0x80: pass else: print "checkPump terminato con scrittura KO" def on_btnOpenFile_clicked(self,button): #os.system() subprocess.call(["libreoffice",export_csv_path]) def on_btnGetPump_clicked(self,button): self.adjustPMax.set_value(float(self.pmax) ) self.adjustQMax.set_value(float(self.qmax)) def send_parity(self): self.p_count += 1 rr_p = self.client_p.write_registers(550,self.p_count,unit=1) def on_btnSetPump_clicked(self,button): rr_p = self.client_p.read_holding_registers(500,100,unit=1) decoder = BinaryPayloadDecoder.fromRegisters(rr_p.registers[52:53],endian=Endian.Little) bits_552 = decoder.decode_bits() bits_552 += decoder.decode_bits() self.pmax = self.adjustPMax.get_value() _qmax = self.adjustQMax.get_value() self.p_count += 1 rr_p.registers[50] = self.p_count rr_p.registers[60] = int(self.pmax) if self.chkPAna.get_active(): self.qmax = getFlowRateAsVolts(_qmax) v = getVoltsFromFlowRate(self.qmax) print "_qmax => {0} self.qmax => {1} c => {2}".format(_qmax, self.qmax, v) rr_p.registers[64] = self.qmax rr_p.registers[62] = int(_qmax/litCiclo) bits_552[12] = True else: self.qmax = _qmax rr_p.registers[62] = int(self.qmax) rr_p.registers[64] = cicli_volt[int(self.qmax)] bits_552[12] = False b_builder = BinaryPayloadBuilder(endian=Endian.Little) # builder.add_bits(bits_502) b_builder.add_bits(bits_552) reg_552 = b_builder.to_registers() rr_p.registers[52:53] = reg_552 rr_p = self.client_p.write_registers(500,rr_p.registers,unit=1) def on_btnOff_clicked(self,button): print("Closing application") Gtk.main_quit() def on_btnLog_toggled(self,button): if button.get_active(): self.time = datetime.datetime.utcnow() self.blogFile = True else: self.blogFile = False builder.get_object("btnLog").set_label("Log Data") def readDataSetupConfig(self): self.pipeLength = float(builder.get_object("txtPipeLenght").get_text()) self.pipeDiam = float(builder.get_object("txtPipeDiam").get_text()) self.pipeType = builder.get_object("txtPipeType").get_text() self.mixType = builder.get_object("txtMixType").get_text() self.mixDensity = float(builder.get_object("txtMixDensity").get_text()) self.staticHead = float(builder.get_object("txtStaticHead").get_text()) self.hdlf_q2 = float(builder.get_object("txtQ2").get_text()) self.hdlf_q1 = float(builder.get_object("txtQ1").get_text()) self.hdlf_k = float(builder.get_object("txtK").get_text()) self.pR = int(builder.get_object("txtR").get_text()) self.designQmin = int(builder.get_object("txtQmin").get_text()) designRTW = int(builder.get_object("txtRefTime").get_text()) if designRTW*60 != self.lastPe.maxlen: print "resize RTW from {0} to {1}".format(self.lastPe.maxlen, designRTW*60) self.lastPe = collections.deque(self.lastPe, maxlen=designRTW*60) self.lastPg = collections.deque(self.lastPg, maxlen=designRTW*60) self.lastQ = collections.deque(self.lastQ, maxlen=designRTW*60) if not smtConfig.has_section('HeadLossFactor'): smtConfig.add_section('HeadLossFactor') smtConfig.set('HeadLossFactor', 'pipeLength', self.pipeLength) smtConfig.set('HeadLossFactor', 'pipeDiam', self.pipeDiam) smtConfig.set('HeadLossFactor', 'pipeType', self.pipeType) smtConfig.set('HeadLossFactor', 'mixType', self.mixType) smtConfig.set('HeadLossFactor', 'mixDensity', self.mixDensity) smtConfig.set('HeadLossFactor', 'staticHead', self.staticHead) smtConfig.set('HeadLossFactor', 'Q2', self.hdlf_q2) smtConfig.set('HeadLossFactor', 'Q1', self.hdlf_q1) smtConfig.set('HeadLossFactor', 'K', self.hdlf_k) if not smtConfig.has_section('Design'): smtConfig.add_section('Design') smtConfig.set('Design', 'R', self.pR) smtConfig.set('Design', 'Qmin', self.designQmin) smtConfig.set('Design', 'RTW', designRTW) with open(sCFGName, 'wb') as configfile: smtConfig.write(configfile) def on_switchPumpStatus_state_set(self, switch,gparam): self.ret_p=self.client_p.connect() rr = self.client_p.read_holding_registers(500,100,unit=1) # conversione in bit array da 552 decoder = BinaryPayloadDecoder.fromRegisters(rr.registers[52:53],endian=Endian.Little) bits_552 = decoder.decode_bits() bits_552 += decoder.decode_bits() decoder = BinaryPayloadDecoder.fromRegisters(rr.registers[2:7],endian=Endian.Little) # 502 bits_502 = decoder.decode_bits() bits_502 += decoder.decode_bits() # 503 bits_503 = decoder.decode_bits() bits_503 += decoder.decode_bits() # 504 bits_504 = decoder.decode_bits() bits_504 += decoder.decode_bits() # 505 bits_505 = decoder.decode_bits() bits_505 += decoder.decode_bits() # 506 bits_506 = decoder.decode_bits() bits_506 += decoder.decode_bits() bSendCommand = False if switch.get_active(): # %MW552:X2 START INIET. DA REMOTO bSendCommand = not bits_502[7] bits_552[2] = True bits_552[3] = False bits_552[14] = True else: # %MW552:X2 STOP INIET. DA REMOTO bSendCommand = bits_502[7] bits_552[2] = False bits_552[3] = True bits_552[14] = False builder = BinaryPayloadBuilder(endian=Endian.Little) # builder.add_bits(bits_502) builder.add_bits(bits_552) reg_552 = builder.to_registers() rr.registers[52:53] = reg_552 self.p_count += 1 rr.registers[50] = self.p_count if bSendCommand: self.client_p.write_registers(500, rr.registers,unit=1) if bits_552[2]: bits_552[2] = False builder = BinaryPayloadBuilder(endian=Endian.Little) # builder.add_bits(bits_502) builder.add_bits(bits_552) reg_552 = builder.to_registers() self.client_p.write_register(552, reg_552[0]) print "pulsante rilasciato" self.client_p.close() def on_btnShow_clicked(self,button): # show dlgRegistries self.lstDialog = builder.get_object("dlgRegistries") self.liststore = builder.get_object("liststore1") if self.ret_p: self.liststore.clear() rr = self.client_p.read_holding_registers(500,100,unit=1) for idx in [0,2,4,6,12,13,14,15,16,20,50,52,60,62,64]: if idx in (2,4,6,52): decoder = BinaryPayloadDecoder.fromRegisters(rr.registers[idx:idx+1],endian=Endian.Little) bits = decoder.decode_bits() bits += decoder.decode_bits() for ib, b in enumerate(bits): if b: sCode = "%MW5{0:02d}:X{1}".format(idx,ib) self.liststore.append([sCode,reg_descr[sCode], str( b ) ]) else: sCode = "%MW5{0:02d}".format(idx) self.liststore.append([sCode, reg_descr[sCode], str( rr.registers[idx]) ]) response = self.lstDialog.run() self.lstDialog.hide() def on_btnOk_clicked(self,button): self.lstDialog.close() def on_btnAnalyze_clicked(self,button): with open(export_csv_path, 'rb') as csvfile: template_vars = {} csv_reader = csv.DictReader(csvfile, delimiter=';') csv_list = list(csv_reader) data = [ np.asarray([row["q_Eng1"],row["dPManifold"],row["q_out"],row["dPPump"] , row["p_Eng1"],row["p_Eng2"]], dtype=np.float64) for row in csv_list] x1 = [d[0]/10. for d in data] y1 = [d[1]/10. for d in data] x2 = [d[2]*litCiclo for d in data] y2 = [d[3] for d in data] p1 = [d[4]/10. for d in data] p2 = [d[5]/10. for d in data] dP = [d[4]/10. - d[5]/10. for d in data] # The solution minimizes the squared error fit1_1, res1_1, _, _, _ = np.polyfit(x1, y1,1,full=True) fit1_2, res1_2, _, _, _ = np.polyfit(x1, y1,2,full=True) fit2_1, res2_1, _, _, _ = np.polyfit(x2, y2,1,full=True) fit2_2, res2_2, _, _, _ = np.polyfit(x2, y2,2,full=True) p_func_fit1_1 = np.poly1d(fit1_1) p_func_fit1_2 = np.poly1d(fit1_2) p_func_fit2_1 = np.poly1d(fit2_1) p_func_fit2_2 = np.poly1d(fit2_2) xp = np.linspace(np.min(x1), np.max(x1), 100) fig = plt.figure(figsize=(16, 9), dpi=100) plt.plot(x1, y1, 'b.', label='Samples') plt.plot(xp, p_func_fit1_1(xp), 'r--', label="Linear (e={0:.3f})".format(res1_1[0])) plt.plot(xp, p_func_fit1_2(xp), 'g-', label="Curved (e={0:.3f})".format(res1_2[0])) plt.xlabel('Flow Rate (lit/min)') plt.ylabel('Pressure (bar)') #plt.legend() plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, ncol=3, mode="expand", borderaxespad=0.) plt.grid(True) tex1 = r'$%.3fx^{2}%+.3fx%+.3f$' % tuple(fit1_2) plt.text(int(np.min(x1)),np.max(y1)*0.9, tex1, fontsize=16, va='bottom', color="g") template_vars["fit1_1"] = tuple(fit1_1) template_vars["fit1_2"] = tuple(fit1_2) template_vars["res1_1"] = res1_1 template_vars["res1_2"] = res1_2 imagefname = "hflf_1_{0}.png".format(sDate) imagefpath = os.path.join(sCurrentWorkingdir,"out",imagefname) template_vars["hflf_1"] = imagefpath plt.savefig(imagefpath,format="png", bbox_inches='tight', pad_inches=0) plt.close(fig) xp = np.linspace(np.min(x2), np.max(x2), 100) fig = plt.figure(figsize=(16, 9), dpi=100) plt.plot(x2, y2, 'b.', label='Samples') plt.plot(xp, p_func_fit2_1(xp), 'r--', label='Linear model (e={0:.3f})'.format(res2_1[0])) plt.plot(xp, p_func_fit2_2(xp), 'g-', label='Curved model (e={0:.3f})'.format(res2_2[0])) plt.xlabel('Flow Rate (lit/min)') plt.ylabel('Pressure (bar)') plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, ncol=3, mode="expand", borderaxespad=0.) plt.grid(True) tex1 = r'$%.3fx^{2}%+.3fx%+.3f$' % tuple(fit2_2) plt.text(int(np.min(x2)),np.max(y2)*0.9, tex1, fontsize=16, va='bottom', color="g") imagefname = "hflf_2_{0}.png".format(sDate) imagefpath = os.path.join(sCurrentWorkingdir,"out",imagefname) template_vars["hflf_2"] = imagefpath plt.savefig(imagefpath,format="png", bbox_inches='tight', pad_inches=0) plt.close(fig) # andamento pressione portata nel tempo fig = plt.figure(figsize=(16, 9), dpi=100) t = np.arange(len(p1)) a = fig.add_subplot(212) a.grid(True) for tick in a.xaxis.get_major_ticks(): tick.label.set_fontsize(10) for tick in a.yaxis.get_major_ticks(): tick.label.set_fontsize(10) a.set_xlabel('Time (seconds)') #a.set_ylim(np.min(dP)-2, np.max(dP)+2) a.set_ylim(np.min(p1)-2, np.max(p1)+2) a.set_xlim(0, len(t)+1) a.plot(t, p1, 'bo-', label='P1') a.plot(t, p2, 'ro-', label='P2') a.set_ylabel('Pressure (P bar)', fontsize=10) a.legend(loc=2, ncol=2, fontsize=10) a2 = fig.add_subplot(211) a2.grid(True) for tick in a2.xaxis.get_major_ticks(): tick.label.set_fontsize(10) for tick in a2.yaxis.get_major_ticks(): tick.label.set_fontsize(10) a2.set_xlabel('Time (seconds)') a2.set_ylabel('Flow rate (Q lit/min)', fontsize=10) a2.set_ylim(np.min(x1)-2, np.max(x1)+2) a2.set_xlim(0, len(t)+1) #a.plot(t, dP, 'r-', label='dP') a2.plot(t, x1, 'go-', label='Q') a2.legend(loc=2, ncol=2, fontsize=10) template_vars["t_items"] = list(t) template_vars["q_items"] = list(x1) template_vars["p1_items"] = list(p1) template_vars["p2_items"] = list(p2) template_vars["dp_items"] = list(dP) template_vars["pipeLength"] = self.pipeLength template_vars["pipeDiam"] = self.pipeDiam template_vars["pipeType"] = self.pipeType template_vars["mixType"] = self.mixType template_vars["mixDensity"] = self.mixDensity imagefname = "time_{0}.png".format(sDate) imagefpath = os.path.join(sCurrentWorkingdir,"out",imagefname) template_vars["time"] = imagefpath plt.savefig(imagefpath,format="png", bbox_inches='tight', pad_inches=0) plt.close(fig) template_vars["issue_date"] = datetime.datetime.utcnow().strftime("%Y.%m.%d %H:%M:%S") env = Environment(loader=FileSystemLoader('.')) templateFile = "hdlf_template.html" templateFilePath = os.path.join(sCurrentWorkingdir,"out",templateFile) template = env.get_template(templateFile) html_out = template.render(template_vars) pdffname = "hdlf_{0}.pdf".format(sDate) pdfpath = os.path.join(sCurrentWorkingdir,"out",pdffname) HTML(string=html_out).write_pdf(pdfpath, stylesheets=["typography.css","grid.css"]) def on_switchMain_activate(self, switch,gparam): if switch.get_active(): self.client_1 = ModbusClient(manifold_host_1, port=manifold_port_1) self.client_p = ModbusClient(pump_host, port=pump_port) self.client_1.connect() self.client_p.connect() self.readDataSetupConfig() time.sleep(2) print "start connection" time_delay = 1 # 1 seconds delay self.loop = LoopingCall(f=self.logging_data, a=(self.client_1, builder.get_object("txtAIN1"),builder.get_object("txtAIN2"),builder.get_object("txtAIN1ENG"),builder.get_object("txtAIN2ENG"),builder.get_object("txtAIN12"),builder.get_object("txtAIN22"),builder.get_object("txtAIN1ENG2"),self.client_p,builder.get_object("txtPout"),builder.get_object("txtQout"))) self.loop.start(time_delay, now=False) # initially delay by time builder.get_object("btnOpenFile").set_sensitive(False) builder.get_object("btnOff").set_sensitive(False) self.btnAnalyze.set_sensitive(False) # self.ani = animation.FuncAnimation(self.figure, self.update_plot, interval = 1000) else: self.loop.stop() time.sleep(1) self.client_1.close() self.client_p.close() print "stop connection" time.sleep(2) builder.get_object("txtFilePath").set_text(export_csv_path) builder.get_object("btnOpenFile").set_sensitive(True) builder.get_object("btnOff").set_sensitive(True) if self.oneLogged: self.btnAnalyze.set_sensitive(True)
class InModbus(ApplicationSession): """ Reads the AC-Values of the WAGO 750-494 I/O Clamps every second via Modbus and publishes them to the topic eshl/eshl.wago.v2.readout.meter.494 """ def __init__(self, config=None): ApplicationSession.__init__(self, config) self.pfcIp = '192.168.1.50' self.modbusTcpPort = 502 self.numberOfClamps = 7 self.client = ModbusClient(self.pfcIp, self.modbusTcpPort) self.clamps = [] for i in range(0, self.numberOfClamps): self.clamps.append('Clamp' + str(i + 1)) self.clampsV2 = [] for i in range(0, self.numberOfClamps): if i < 9: self.clampsV2.append('Clamp0' + str(i + 1)) if i >= 9: self.clampsV2.append('Clamp' + str(i + 1)) #============================================================================== # Generates a blank Dataset with the current system timestamp #============================================================================== def blankDataSetGen(self): blankDataset = {'U1' : 'NaN', 'U2' : 'NaN', 'U3' : 'NaN', 'I1' : 'NaN', 'I2' : 'NaN', 'I3' : 'NaN', 'P1' : 'NaN', 'P2' : 'NaN', 'P3' : 'NaN', 'Q1' : 'NaN', 'Q2' : 'NaN', 'Q3' : 'NaN', 'S1' : 'NaN', 'S2' : 'NaN', 'S3' : 'NaN', 'CosPhi1' : 'NaN', 'CosPhi2' : 'NaN', 'CosPhi3' : 'NaN', 'PF1': 'NaN', 'PF2': 'NaN', 'PF3': 'NaN', 'Qua1': 'NaN', 'Qua2': 'NaN', 'Qua3': 'NaN', 'AEI1': 'NaN', 'AED1': 'NaN', 'REI1': 'NaN', 'REC1': 'NaN', 'AEI2': 'NaN', 'AED2': 'NaN', 'REI2': 'NaN', 'REC2': 'NaN', 'AEI3': 'NaN', 'AED3': 'NaN', 'REI3': 'NaN', 'REC3': 'NaN', 'DataValid' : '0', 'TimestampPFC' : 'NaN', 'TimestampSYS' : round(time.time() * 1000) } return blankDataset def requestLoop(self): numberOfRegPerClamp = 74 # max number of holding registers is 125 as the total number of bytes incl. CRC is 256 according to the spec (via 03 command) meterreadings = {} meterreadingsV2 = {} print(time.time()) try: if (self.client.connect() is False): print('not connected') self.client = self.client.connect() print('trying to connecto to ' + str(self.pfcIp)) address = 0 #============================================================================== # Read current timestamp from PFC #============================================================================== timestampSys = round(time.time() * 1000) result2 = self.client.read_holding_registers(timestampPFCRegister, 4) decoder = BinaryPayloadDecoder.fromRegisters(result2.registers, endian=Endian.Little) timestampPFC = decoder.decode_64bit_int() #============================================================================== # Reads the values from modbus registers clamp by clamp # and buffers the results in meterreadings{} # It is not possible to read all registers in one request because of the limitation of the Modbus-Message size to 255kb # When the results of all clamps are buffered, they are published #============================================================================== for x in range(0, len(self.clamps)): result = self.client.read_holding_registers(address, numberOfRegPerClamp) decoder = BinaryPayloadDecoder.fromRegisters(result.registers, endian=Endian.Little) decoded = { 'I1': decoder.decode_32bit_float(), 'I2': decoder.decode_32bit_float(), 'I3': decoder.decode_32bit_float(), 'U1': decoder.decode_32bit_float(), 'U2': decoder.decode_32bit_float(), 'U3': decoder.decode_32bit_float(), 'P1': decoder.decode_32bit_float(), 'P2': decoder.decode_32bit_float(), 'P3': decoder.decode_32bit_float(), 'Q1': decoder.decode_32bit_float(), 'Q2': decoder.decode_32bit_float(), 'Q3': decoder.decode_32bit_float(), 'S1': decoder.decode_32bit_float(), 'S2': decoder.decode_32bit_float(), 'S3': decoder.decode_32bit_float(), 'CosPhi1': decoder.decode_32bit_float(), 'CosPhi2': decoder.decode_32bit_float(), 'CosPhi3': decoder.decode_32bit_float(), 'PF1': decoder.decode_32bit_float(), 'PF2': decoder.decode_32bit_float(), 'PF3': decoder.decode_32bit_float(), 'Qua1': decoder.decode_32bit_float(), 'Qua2': decoder.decode_32bit_float(), 'Qua3': decoder.decode_32bit_float(), 'AEI1': decoder.decode_32bit_float(), 'AED1': decoder.decode_32bit_float(), 'REI1': decoder.decode_32bit_float(), 'REC1': decoder.decode_32bit_float(), 'AEI2': decoder.decode_32bit_float(), 'AED2': decoder.decode_32bit_float(), 'REI2': decoder.decode_32bit_float(), 'REC2': decoder.decode_32bit_float(), 'AEI3': decoder.decode_32bit_float(), 'AED3': decoder.decode_32bit_float(), 'REI3': decoder.decode_32bit_float(), 'REC3': decoder.decode_32bit_float(), 'DataValid' : decoder.decode_32bit_float()} #============================================================================== # standardize both TimestampPFC and TimestampSYS precision to be millisecond #============================================================================== decoded['TimestampPFC'] = str(timestampPFC)[0:13] decoded['TimestampSYS'] = timestampSys #============================================================================== # PFC measures energy values in mWh --> convert to watt-seconds #============================================================================== decoded['AEI1'] = float(decoded['AEI1']) * 3.6 decoded['AED1'] = float(decoded['AED1']) * 3.6 decoded['REI1'] = float(decoded['REI1']) * 3.6 decoded['REC1'] = float(decoded['REC1']) * 3.6 decoded['AEI2'] = float(decoded['AEI2']) * 3.6 decoded['AED2'] = float(decoded['AED2']) * 3.6 decoded['REI2'] = float(decoded['REI2']) * 3.6 decoded['REC2'] = float(decoded['REC2']) * 3.6 decoded['AEI3'] = float(decoded['AEI3']) * 3.6 decoded['AED3'] = float(decoded['AED3']) * 3.6 decoded['REI3'] = float(decoded['REI3']) * 3.6 decoded['REC3'] = float(decoded['REC3']) * 3.6 meterreadingsV2[self.clampsV2[x]] = decoded meterreadings[self.clamps[x]] = decoded address += numberOfRegPerClamp self.publish(u'eshl.wago.v1.readout.wiz.494', json.dumps(meterreadings, sort_keys=True)) self.publish(u'eshl.wago.v2.readout.wiz.494', meterreadingsV2) #============================================================================== # If there is no connection to the pfc-modbus slave or no connection to the pfc at all # the blankDataSet is published #============================================================================== except ConnectionException as connErr: for x in range(0, len(self.clamps)): meterreadings[self.clamps[x]] = self.blankDataSetGen() self.publish(u'eshl.wago.v1.readout.wiz.494', json.dumps(meterreadings, sort_keys=True)) self.publish(u'eshl.wago.v2.readout.wiz.494', meterreadings) sys.__stdout__.write('ConnectionException in-wago-wiz-494' + '\n' + 'Timestamp: ' + str(timestampSys) + ', Errorcode --> ' + str(connErr)) sys.__stdout__.flush() except Exception as err: sys.__stdout__.write('Exception in-wago-wiz-494' + '\n' + 'Timestamp: ' + str(timestampSys) + ', Errorcode --> ' + str(err)) sys.__stdout__.flush() def onJoin(self, details): ApplicationSession.onJoin(self, details) print("session ready") self._loop = task.LoopingCall(self.requestLoop) self._loop.start(1.0) def onLeave(self, details): ApplicationSession.onLeave(self, details) print("leaving") if(hasattr(self, "_loop") and self._loop): self._loop.stop()
def run_binary_payload_ex(): # ----------------------------------------------------------------------- # # We are going to use a simple client to send our requests # ----------------------------------------------------------------------- # client = ModbusClient('127.0.0.1', port=5440) client.connect() # ----------------------------------------------------------------------- # # If you need to build a complex message to send, you can use the payload # builder to simplify the packing logic. # # Here we demonstrate packing a random payload layout, unpacked it looks # like the following: # # - a 8 byte string 'abcdefgh' # - a 32 bit float 22.34 # - a 16 bit unsigned int 0x1234 # - another 16 bit unsigned int 0x5678 # - an 8 bit int 0x12 # - an 8 bit bitstring [0,1,0,1,1,0,1,0] # - an 32 bit uint 0x12345678 # - an 32 bit signed int -0x1234 # - an 64 bit signed int 0x12345678 # The packing can also be applied to the word (wordorder) and bytes in each # word (byteorder) # The wordorder is applicable only for 32 and 64 bit values # Lets say we need to write a value 0x12345678 to a 32 bit register # The following combinations could be used to write the register # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # # Word Order - Big Byte Order - Big # word1 =0x1234 word2 = 0x5678 # Word Order - Big Byte Order - Little # word1 =0x3412 word2 = 0x7856 # Word Order - Little Byte Order - Big # word1 = 0x5678 word2 = 0x1234 # Word Order - Little Byte Order - Little # word1 =0x7856 word2 = 0x3412 # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # # ----------------------------------------------------------------------- # builder = BinaryPayloadBuilder(byteorder=Endian.Little, wordorder=Endian.Big) builder.add_string('abcdefgh') builder.add_32bit_float(22.34) builder.add_16bit_uint(0x1234) builder.add_16bit_uint(0x5678) builder.add_8bit_int(0x12) builder.add_bits([0, 1, 0, 1, 1, 0, 1, 0]) builder.add_32bit_uint(0x12345678) builder.add_32bit_int(-0x1234) builder.add_64bit_int(0x1234567890ABCDEF) payload = builder.build() address = 0 client.write_registers(address, payload, skip_encode=True, unit=1) # ----------------------------------------------------------------------- # # If you need to decode a collection of registers in a weird layout, the # payload decoder can help you as well. # # Here we demonstrate decoding a random register layout, unpacked it looks # like the following: # # - a 8 byte string 'abcdefgh' # - a 32 bit float 22.34 # - a 16 bit unsigned int 0x1234 # - another 16 bit unsigned int which we will ignore # - an 8 bit int 0x12 # - an 8 bit bitstring [0,1,0,1,1,0,1,0] # ----------------------------------------------------------------------- # address = 0x00 count = len(payload) result = client.read_holding_registers(address, count, unit=1) print("-" * 60) print("Registers") print("-" * 60) print(result.registers) print("\n") decoder = BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=Endian.Little, wordorder=Endian.Big) decoded = { 'string': decoder.decode_string(8), 'float': decoder.decode_32bit_float(), '16uint': decoder.decode_16bit_uint(), 'ignored': decoder.skip_bytes(2), '8int': decoder.decode_8bit_int(), 'bits': decoder.decode_bits(), "32uints": decoder.decode_32bit_uint(), "32ints": decoder.decode_32bit_int(), "64ints": decoder.decode_64bit_int(), } print("-" * 60) print("Decoded Data") print("-" * 60) for name, value in iteritems(decoded): print("%s\t" % name, hex(value) if isinstance(value, int) else value) # ----------------------------------------------------------------------- # # close the client # ----------------------------------------------------------------------- # client.close()
topic = "/plc1" try: publish.single(topic, payload, hostname="broker_ip_address", port=1883, retain=False, qos=0) except Exception as err: print "Couldn't publish :" + str(err) pass client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message client.connect("mqtt_broker_ip_address") client.loop_start() while True: rr = client2.read_holding_registers(200, 1, unit=1) rr22 = client2.read_holding_registers(22, 1, unit=1) rr40 = client2.read_holding_registers(40, 1, unit=1) rr41 = client2.read_holding_registers(41, 1, unit=1) rr13 = client2.read_holding_registers(14, 1, unit=1) rr51 = client2.read_holding_registers(51, 1, unit=1) rr61 = client2.read_holding_registers(61, 1, unit=1) result = rr.registers result22 = rr22.registers result40 = rr40.registers result41 = rr41.registers result13 = rr13.registers result51 = rr51.registers result61 = rr61.registers valor = str(result)[1:-1] valor22 = str(result22)[1:-1]