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 ModbusModule(): def __init__(self, io_module_name, ip): logger.debug('Creating new controller with name {} and address {}.'.format(io_module_name, ip)) self.io_module_name = io_module_name self.ip_address = ip self.controller_type = CONTROLLER_TYPE.Modbus # build connection object self.client = ModbusClient(ip, port=config.DEFAULT_MODBUS_PORT) self.client.connect() def __del__(self): self.client.close() def __str__(self): return 'Controller "{}" at address {}'.format(self.io_module_name, self.ip_address) def get_bit(self, address): try: result = self.client.read_coils(address) bit_value = result.bits[0] except ConnectionException: logger.error('Could not connect to Modbus module "{}"!' .format(self.io_module_name)) bit_value = False return bit_value def set_bit(self, address, value): try: self.client.write_coil(address, value) except ConnectionException: logger.error('Could not connect to Modbus module "{}"!' .format(self.io_module_name))
def setDeviceStatus(self, postmsg): setDeviceStatusResult = True try: client = ModbusTcpClient(self.get_variable('address'),port=502) client.connect() if (self.get_variable('model')=='VC1000'): if 'heat_setpoint' in postmsg.keys(): client.write_register(6,int(self.far2cel(float(postmsg.get('heat_setpoint')))*100.0),unit=self.get_variable('slave_id')) if 'cool_setpoint' in postmsg.keys(): client.write_register(6,int(self.far2cel(float(postmsg.get('cool_setpoint')))*100.0),unit=self.get_variable('slave_id')) if 'flap_override' in postmsg.keys(): if postmsg.get('flap_override') == 'ON' or postmsg.get('flap_override') == True: client.write_register(159,1,unit=self.get_variable('slave_id')) elif postmsg.get('flap_override') == 'OFF' or postmsg.get('flap_override') == False: client.write_register(159,0,unit=self.get_variable('slave_id')) if 'flap_position' in postmsg.keys(): client.write_register(160,int(postmsg.get('flap_position')),unit=self.get_variable('slave_id')) elif (self.get_variable('model')=='M1000'): if 'heat_setpoint' in postmsg.keys(): client.write_register(187,int(self.far2cel(float(postmsg.get('heat_setpoint')))*100.0),unit=self.get_variable('slave_id')) if 'cool_setpoint' in postmsg.keys(): client.write_register(188,int(self.far2cel(float(postmsg.get('cool_setpoint')))*100.0),unit=self.get_variable('slave_id')) if 'outside_damper_position' in postmsg.keys(): client.write_register(274,int(postmsg.get('outside_damper_position')),unit=self.get_variable('slave_id')) if 'bypass_damper_position' in postmsg.keys(): client.write_register(275,int(postmsg.get('bypass_damper_position')),unit=self.get_variable('slave_id')) if 'fan_status' in postmsg.keys(): if postmsg.get('fan_status') == 'ON' or postmsg.get('fan_status') == True: client.write_register(130,2,unit=self.get_variable('slave_id')) elif postmsg.get('fan_status') == 'OFF' or postmsg.get('fan_status') == False: client.write_register(130,1,unit=self.get_variable('slave_id')) if 'cooling_status' in postmsg.keys(): if postmsg.get('cooling_status') == 'ON': client.write_registers(124,[1,2,2,2],unit=self.get_variable('slave_id')) elif postmsg.get('cooling_status') == 'OFF': client.write_registers(124,[0,1,1,1],unit=self.get_variable('slave_id')) if 'cooling_mode' in postmsg.keys(): if postmsg.get('cooling_mode') == 'None': client.write_register(10,0,unit=self.get_variable('slave_id')) elif postmsg.get('cooling_mode') == 'STG1': client.write_register(10,1,unit=self.get_variable('slave_id')) elif postmsg.get('cooling_mode') == 'STG2': client.write_register(10,2,unit=self.get_variable('slave_id')) elif postmsg.get('cooling_mode') == 'STG3': client.write_register(10,3,unit=self.get_variable('slave_id')) elif postmsg.get('cooling_mode') == 'STG4': client.write_register(10,4,unit=self.get_variable('slave_id')) if 'heating' in postmsg.keys(): client.write_register(129,int(postmsg.get('heating')),unit=self.get_variable('slave_id')) client.close() except: try: client.close() except: print('Modbus TCP client was not built successfully at the beginning') setDeviceStatusResult=False return setDeviceStatusResult
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)};
def wren_gw_modbus_write(config, value): ''' write a value to the peer. @param value a number in the string type. ''' try: m = ModbusTcpClient(host=config['node'], port=config['port']) # XXX # ModbusTcpClient.connect() does not look to do connect(2) actually. m.connect() unit = 0xff if config.has_key('unit_id'): unit = config['unit_id'] # send data result = False if config['table'] == 'HoldingRegister': result = m.write_register(config['address'], int(value), unit=unit) if result.value == int(value): result = True # close it. m.close() return {"status":True, "value":str(value)}; except Exception as e: return {"status":False, "value":str(e)};
def _run_single_client(client_id, host, port, units, results, N, delay, warmup, table): _log.info('Client %d connecting to %s (%s)', client_id, host, port) client = ModbusClient(host, port=port) client.connect() _log.info('Client %d connected to %s (%s)', client_id, host, port) measurements = [] errors = [] for i in xrange(N): if N >= 1000 and i % (N/10) == 0 and i > 0: _log.info('Client %d %.0f%% complete', client_id, 100.0*i/N) try: m = _make_random_request(client, units, table) if i >= warmup or N <= warmup: if i == warmup: _log.info('Client %d warmup complete.', client_id) measurements.append(m) except jem_exceptions.JemException, e: errors.append(e) _log.warn('Client %d received error response: %s', client_id, e) except Exception, e: from pymodbus import exceptions as es _log.error("Caught other exception: %s" % str(e)) _log.error("Is instance: %s", isinstance(e, es.ModbusException))
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 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]
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 testTcpClientConnect(self): ''' Test the tcp client connection method''' with patch.object(socket, 'create_connection') as mock_method: mock_method.return_value = object() client = ModbusTcpClient() self.assertTrue(client.connect()) with patch.object(socket, 'create_connection') as mock_method: mock_method.side_effect = socket.error() client = ModbusTcpClient() self.assertFalse(client.connect())
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 create_sunspec_sync_client(host): """ A quick helper method to create a sunspec client. :param host: The host to connect to :returns: an initialized SunspecClient """ modbus = ModbusTcpClient(host) modbus.connect() client = SunspecClient(modbus) client.initialize() return client
def main(host, port, delay, unit, table_num): client = ModbusClient(host, port=port) client.connect() min_response_time = 100 max_response_time = 0 sum_response_time = 0 N = 0 register_widths = diris_registers.TABLES[table_num-1].copy() register_labels = DEMO_REGISTERS.copy() registers = dict((addr, register_widths[addr]) \ for addr in DEMO_REGISTERS.keys() \ if addr in register_widths) label_width = max([len(label) for label in DEMO_REGISTERS.values()]) + 1 while True: start = time.time() try: response = modbus.read_registers(client, registers=registers, unit=unit) except exceptions.ModbusExceptionResponse, e: response=None response_time = time.time() - start os.system('clear') print "Request Times:" min_response_time = min(min_response_time, response_time) max_response_time = max(max_response_time, response_time) sum_response_time += response_time N += 1 print "Min".rjust(label_width) + ": " + str(min_response_time) print "Max".rjust(label_width) + ": " + str(max_response_time) print "Avg".rjust(label_width) + ": " + str(sum_response_time/N) print "Response Values:" for addr in sorted(registers.keys()): if response is None: break print (u"{label:>" + str(label_width) + u"s}: {value:f}").format( label=register_labels[addr], value=response.read_register(addr)) print time.sleep(delay)
class TcpRtuChannel(BaseChannel): def __init__(self, network, channel_name, channel_protocol, channel_params, manager, channel_type): self.server = channel_params.get("server", "") self.port = channel_params.get("port", "") self.modbus_client = None BaseChannel.__init__(self, network, channel_name, channel_protocol, channel_params, manager, channel_type) def run(self): self.modbus_client = ModbusTcpClient(host=self.server, port=self.port) try: self.modbus_client.connect() logger.debug("连接服务器成功.") except Exception, e: logger.error("连接服务器失败,错误信息:%r." % e)
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 scan(): parser = argparse.ArgumentParser(description = "Write all holding registries on 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 writer. Defaults to 1", type=int, metavar="START", default=1) parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) args = parser.parse_args() try: ip = args.ip except IndexError: print "ERROR: No target given\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 for addr in range(args.start_address, args.end_address): hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 results.append(addr) # if it fails, hr.function = 144 (0x90), cf modbus doc client.close() print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) print 'Writing was successful on these %d addresses:' % len(results) print results
def connect_modbus(modbus_ip, modbus_port): try: client = ModbusClient(modbus_ip, port=modbus_port) except: return None if client.connect(): return client return None
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))
class TcpRtuChannel(BaseChannel): def __init__(self, channel_params, devices_file_name, protocol, mqtt_client, network_name): BaseChannel.__init__(self, channel_params, devices_file_name, protocol, mqtt_client, network_name) # 配置项 self.server = channel_params.get("server", "") self.port = channel_params.get("port", 0) self.protocol.set_device_info(self.server, self.port) # 通信对象 self.modbus_client = None @staticmethod def check_config(channel_params): if "server" not in channel_params or "port" not in channel_params: return False return BaseChannel.check_config(channel_params) def run(self): # 首先上报设备数据 for device_id in self.devices_info_dict: device_info = self.devices_info_dict[device_id] device_msg = { "device_id": device_info["device_id"], "device_type": device_info["device_type"], "device_addr": device_info["device_addr"], "device_port": device_info["device_port"], "protocol": self.protocol.protocol_type, "data": "" } self.mqtt_client.publish_data(device_msg) # 创建连接 self.modbus_client = ModbusTcpClient(host=self.server, port=self.port) try: self.modbus_client.connect() logger.debug("连接服务器成功.") except Exception, e: logger.error("连接服务器失败,错误信息:%r." % e) self.modbus_client = None return while True: # 该线程保持空转 time.sleep(5)
def modbus_poller(id, stop_event, config): log = logging.getLogger("worker-" + str(id)) log.setLevel(logging.DEBUG) client = ModbusClient(host=config["address"], port=config["port"]) client.connect() log.info("Worker started") t_max = -1 while not stop_event.is_set(): log.info("Poller turn") t0 = time() address = 0 for i in poll_range(config["num_controls"], config["chunk_size"]): result = client.read_input_registers(address=address, count=i, unit=1) address += i if result is not None: if result.function_code >= 0x80 and result.function_code != 132: log.warn("Server returned error!") print result stop_event.set() break elif result.function_code == 132: print "Server fault: " + str(result) sleep(1) break t = time() - t0 log.info("Request took " + str(t) + " s") if t > t_max: t_max = t sleep(config["thread"]["interval"]) log.info("Worker shutting down") log.info("Max worker process time: " + str(t_max)) client.close()
def main(argv): syntax = os.path.basename(__file__) + " -p <first port> -n <number of servers> -i <ip:first port of pump server>" tcp_port = 502 inj_tcp = "localhost:502" no_server = 1 try: opts = getopt.getopt(argv, "hp:n:i:", ["port=", "noserver=","injport="])[0] except getopt.GetoptError: print syntax sys.exit(1) if len(opts) < 1: print syntax sys.exit(2) for opt, arg in opts: if opt == '-h': print syntax sys.exit() elif opt in ("-i", "--injport"): inj_tcp = arg elif opt in ("-p", "--port"): tcp_port = int(arg) elif opt in ("-n", "--noserver"): no_server = int(arg) port = tcp_port context_list = [] identity_list = [] address_list = [] splitted = inj_tcp.split(":") ip_pump = splitted[0] port_pump = int(splitted[1]) p_prev_client = None for srv in range(no_server): p_client = ModbusClient(ip_pump, port=port_pump) ret = p_client.connect() if ret: log.info("connection ok on {0}:{1}".format(ip_pump,port_pump)) p_client.close() else: p_client = p_prev_client log.info("Keep the previous pump on {0}:{1}".format(ip_pump,port_pump-1)) port_pump += 1 address_list.append(("127.0.0.1", port)) port += 1 context = context_factory() context_list.append(context) identity_list.append(identity_factory()) time = 1 # 1 seconds delay loop = LoopingCall(f=updating_writer, a=(context,srv,p_client)) p_prev_client = p_client loop.start(time, now=False) # initially delay by time StartMultipleTcpServers(context_list, identity_list, address_list)
def sample(): points=init() print 'all points:',points map=mapping() print 'mapping:',map if not points: logger.error("there is no valid record in [%s]." %CONFIG_FILE) thread.start_new_thread(mail_notify, (3600*12,)) while True: try: # -- connect to the server -- client = ModbusClient(HOST,port=PORT,framer=ModbusFramer) client.connect() print 'connection ok!' # -- current time-- now=time.localtime() dt="%s-%s-%s %s:%s:%s" %now[:6] # -- read all points -- recordlist=[] # id,value,time for p in points: record=read(client,p) if record: _id= record[0] if map[_id]: mem=map[_id],record[1],dt recordlist.append(mem) print 'recordlist',recordlist # -- insert all recordlist -- if recordlist: service=UploadService(URL_PREFIX_POST,URL_PREFIX_GET) r1=service.insert(recordlist) r2=service.update(recordlist) r3=storage(DB_FILE,recordlist) #print r1,r2,r3 logger.info("OK!") except Exception,e: logger.error('error:%s' %e) finally:
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 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()
class ControlLink(object): def __init__(self, host, port=Defaults.Port): self.conn = ModbusTcpClient(host, port) if not self.conn.connect(): raise RuntimeError('Could not connect to host %s port %d' % (host, port)) def read(self, offset): # Adjust offset due to weirdness. offset -= 40000 # Create request. assert offset is not None assert offset >= 0 req = ReadInputRegistersRequest(offset, 1) assert req is not None # Execute and return response. res = self.conn.execute(req) assert res is not None # Extract single value from response. values = res.registers assert values is not None assert len(values) == 1 return long(values[0]) def write(self, offset, value): # Adjust offset due to weirdness. offset -= 40000 # Create request. assert offset is not None assert offset >= 0 assert value is not None req = WriteSingleRegisterRequest(offset, value) # Execute and return response. res = self.conn.execute(req) assert res is not None assert res.value is not None nvalue = res.value if nvalue != value: report('address %d, wrote %d, returned %d' % (offset, value, nvalue)) return nvalue
def write_register(slave_addr, slave_port, reg_addr, reg_val): # Call modbustcp client to write 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 reply = client.write_register(address=reg_addr, value=reg_val, unit=1) client.close() if reply == None: print "No reply while writing Modbus register" return if reply.function_code != 6: print "Writing Modbus register returned wrong function code" return
def testBasicSyncTcpClient(self): ''' Test the basic methods for the tcp sync client''' # receive/send client = ModbusTcpClient() client.socket = mockSocket() self.assertEqual(0, client._send(None)) self.assertEqual(1, client._send('\x00')) self.assertEqual('\x00', client._recv(1)) # connect/disconnect self.assertTrue(client.connect()) client.close() # already closed socket client.socket = False client.close() self.assertEqual("127.0.0.1:502", str(client))
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]
class ModbusDevice: # ModbusDevice # i - IP address # p - Modbus port # f - framer # t - timeout #def __init__(self, i, p, f, t): def __init__(self, i, p): self.ip = i self.port = p self.framer = ModbusFramer self.timeout = 1 self.rKeys = [] self.rValues = [] self.rAddress = [] self.rIndex = [] self.errors = [] self.errFlag = False # False = no errors, True = we had errors # Create the client try: if(LOG_LEVEL >= LOG_DEBUG): print "modbus client" self.client = ModbusClient(self.ip, self.port) #self.client = ModbusClient(self.ip, self.port, self.framer, self.timeout) #self.client = ModbusClient(self.ip, self.port, timeout=10) if(LOG_LEVEL >= LOG_DEBUG): print "modbus client connect" rc = self.client.connect() if(rc == False): self.errFlag = True self.errors.append(str()) print "modbus connect returned ", rc else: if(LOG_LEVEL >= LOG_DEBUG): print "modbus connect finished" except Exception, e: print "modbus device initialization exception ", e self.errors.append(str(e)) self.errFlag = True
class MainWindow(QMainWindow): i = 0 def __init__(self, parent=None): super(MainWindow, self).__init__(parent) # scroll area Widget contents - layout self.scrollLayout = QFormLayout() self.scrollLayout.setContentsMargins(0, 0, 0, 0) # scroll area Widget contents self.scrollWidget = QWidget() self.scrollWidget.setLayout(self.scrollLayout) # scroll area self.scrollArea = QScrollArea() self.scrollArea.setWidgetResizable(True) self.scrollArea.setWidget(self.scrollWidget) # main layout self.mainLayout = QVBoxLayout() self.mainLayout.setSpacing(0) # add all main to the main vLayout self.mainLayout.addWidget(self.scrollArea) # central Widget self.centralWidget = QWidget() self.centralWidget.setLayout(self.mainLayout) # set central Widget self.setCentralWidget(self.centralWidget) try: self._bus = ModbusTcpClient('wechsler.panda.frm2') self._bus.connect() self._sync() print("PLC conforms to spec %.4f" % self.ReadFloat(0)) except Exception: print("Modbus failed, using demo mode!") self._bus = None self._sync() widgets = [] widgets.append(WriteWord(self, 'last_liftpos', addr=58 / 2)) widgets.append(ReadWord(self, 'analog1', addr=92 / 2)) widgets.append(ReadWord(self, 'analog2', addr=96 / 2)) widgets.append(AnalogInput(self, 'liftpos_analog', addr=146 / 2)) widgets.append(DiscreteInput(self, 'lift_sw', addr=68 / 2)) widgets.append(LIFT(self, 'lift', 104 / 2)) widgets.append(WriteWord(self, 'last_magpos', addr=60 / 2)) widgets.append(DiscreteInput(self, 'magazin_sw', addr=72 / 2)) widgets.append(MAGAZIN(self, 'magazin', addr=110 / 2)) widgets.append(DiscreteInput(self, 'magazin_occ_sw', addr=84 / 2)) widgets.append(DiscreteInput(self, 'magazin_occ', addr=88 / 2)) widgets.append(DiscreteInput(self, 'liftclamp_sw', addr=76 / 2)) widgets.append(CLAMP(self, 'liftclamp', addr=116 / 2)) widgets.append(DiscreteInput(self, 'magazinclamp_sw', addr=80 / 2)) widgets.append(CLAMP(self, 'magazinclamp', addr=122 / 2)) widgets.append(CLAMP(self, 'tableclamp', addr=128 / 2)) widgets.append(CLAMP(self, 'inhibit_relay', addr=134 / 2)) widgets.append(WriteWord(self, 'enable_word', addr=150 / 2)) widgets.append(DiscreteInput(self, 'spare inputs', addr=100 / 2)) widgets.append(DiscreteOutput(self, 'spare outputs', addr=140 / 2)) widgets.append(ReadWord(self, 'cycle_counter', addr=152 / 2)) for w in widgets: self.addWidget(w) self.widgets = widgets self.startTimer(225) # in ms ! def ReadWord(self, addr): return self._registers[int(addr)] def WriteWord(self, addr, value): if self._bus: self._bus.write_register(int(addr | 0x4000), int(value)) self._sync() def ReadDWord(self, addr): return unpack( '<I', pack('<HH', self._registers[int(addr)], self._registers[int(addr) + 1])) def WriteDWord(self, addr, value): if self._bus: low, high = unpack('<HH', pack('<I', int(value))) self._bus.write_registers(int(addr | 0x4000), [low, high]) self._sync() def ReadFloat(self, addr): return unpack( '<f', pack('<HH', self._registers[int(addr) + 1], self._registers[int(addr)])) def WriteFloat(self, addr, value): if self._bus: low, high = unpack('<HH', pack('<f', float(value))) self._bus.write_registers(int(addr | 0x4000), [high, low]) self._sync() def _sync(self): if self._bus: self._registers = self._bus.read_holding_registers(0x4000, 77).registers[:] else: self._registers = [self.i + i for i in range(77)] self.i += 1 def timerEvent(self, event): # pylint: disable=R0915 self._sync() for w in self.widgets: w._update() return def addWidget(self, which): which.setContentsMargins(10, 0, 0, 0) self.scrollLayout.addRow(which) l = QFrame() l.setLineWidth(1) # l.setMidLineWidth(4) l.setFrameShape(QFrame.HLine) l.setContentsMargins(10, 0, 10, 0) self.scrollLayout.addRow(l)
def read_modbus_from_tcp_port(conf_file, modbus_registers): log.info("Read modbus config from yaml file") modbus_conf = read_modbus_conf(conf_file) slaveAddr = modbus_conf['slaveaddr'] # ip du slave Modbus tcpport = modbus_conf['tcpport'] # port std modbus TCP log.info("Read modbus registers list from yaml file") input_regs = read_modbus_registers(modbus_registers) log.info("Build registers list") regs_list = build_registers_list(input_regs) payload = {} #---------------------------------------------------------------------------# # instanciating the approriate modbus client #---------------------------------------------------------------------------# client = ModbusClient(slaveAddr, port=tcpport) #client = ModbusClient(method='ascii', port=port, timeout=1) #client = ModbusClient(method='rtu', port='/dev/ttyp0', timeout=1) log.info("Connecting to Modbus slave") connect_ok = client.connect() if connect_ok: #---------------------------------------------------------------------------# # reading all registers and building payload #---------------------------------------------------------------------------# log.info("Read all input registers in sequence") errCnt = 0 regCnt = 0 timestamp = str(time.time()) for reg in regs_list: try: rr = client.read_input_registers(reg, 1, unit=1) message = { 'register_name': input_regs[regCnt]['name'], 'register_alias': input_regs[regCnt]['alias'], 'register_address': input_regs[regCnt]['address'], 'register_value': rr.registers, 'timestamp': timestamp } payload.update({str(regCnt):message}) regCnt += 1 except: errCnt += 1 tb = traceback.format_exc() log.debug("!pymodbus:\terrCnt: %s; last tb: %s" % (errCnt, tb)) finally: # close the client client.close() else: payload = 'Failed to connect to Modbus slave over TCP' log.error(payload) return payload
class SolarEdge: model = "SolarEdge" stopbits = 1 parity = "N" baud = 115200 wordorder = Endian.Big def __init__( self, host=False, port=False, device=False, stopbits=False, parity=False, baud=False, timeout=TIMEOUT, retries=RETRIES, unit=UNIT, parent=False ): if parent: self.client = parent.client self.mode = parent.mode self.timeout = parent.timeout self.retries = parent.retries if unit: self.unit = unit else: self.unit = parent.unit if self.mode is connectionType.RTU: self.device = parent.device self.stopbits = parent.stopbits self.parity = parent.parity self.baud = parent.baud elif self.mode is connectionType.TCP: self.host = parent.host self.port = parent.port else: raise NotImplementedError(self.mode) else: self.host = host self.port = port self.device = device if stopbits: self.stopbits = stopbits if (parity and parity.upper() in ["N", "E", "O"]): self.parity = parity.upper() else: self.parity = False if baud: self.baud = baud self.timeout = timeout self.retries = retries self.unit = unit if device: self.mode = connectionType.RTU self.client = ModbusSerialClient( method="rtu", port=self.device, stopbits=self.stopbits, parity=self.parity, baudrate=self.baud, timeout=self.timeout) else: self.mode = connectionType.TCP self.client = ModbusTcpClient( host=self.host, port=self.port, timeout=self.timeout ) def __repr__(self): if self.mode == connectionType.RTU: return f"{self.model}({self.device}, {self.mode}: stopbits={self.stopbits}, parity={self.parity}, baud={self.baud}, timeout={self.timeout}, retries={self.retries}, unit={hex(self.unit)})" elif self.mode == connectionType.TCP: return f"{self.model}({self.host}:{self.port}, {self.mode}: timeout={self.timeout}, retries={self.retries}, unit={hex(self.unit)})" else: return f"<{self.__class__.__module__}.{self.__class__.__name__} object at {hex(id(self))}>" def _read_holding_registers(self, address, length): for i in range(self.retries): if not self.connected(): self.connect() time.sleep(0.1) continue result = self.client.read_holding_registers(address, length, unit=self.unit) if not isinstance(result, ReadHoldingRegistersResponse): continue if len(result.registers) != length: continue return BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=Endian.Big, wordorder=self.wordorder) return None def _decode_value(self, data, length, dtype, vtype): try: if dtype == registerDataType.UINT16: decoded = data.decode_16bit_uint() elif (dtype == registerDataType.UINT32 or dtype == registerDataType.ACC32): decoded = data.decode_32bit_uint() elif dtype == registerDataType.UINT64: decoded = data.decode_64bit_uint() elif dtype == registerDataType.INT16: decoded = data.decode_16bit_int() elif (dtype == registerDataType.FLOAT32 or dtype == registerDataType.SEFLOAT): decoded = data.decode_32bit_float() elif dtype == registerDataType.STRING: decoded = data.decode_string(length * 2).decode(encoding="utf-8", errors="ignore").replace("\x00", "").rstrip() else: raise NotImplementedError(dtype) if decoded == SUNSPEC_NOTIMPLEMENTED[dtype.name]: return vtype(False) else: return vtype(decoded) except NotImplementedError: raise def _read(self, value): address, length, rtype, dtype, vtype, label, fmt, batch = value try: if rtype == registerType.INPUT: return self._decode_value(self._read_input_registers(address, length), length, dtype, vtype) elif rtype == registerType.HOLDING: return self._decode_value(self._read_holding_registers(address, length), length, dtype, vtype) else: raise NotImplementedError(rtype) except NotImplementedError: raise except AttributeError: return False def _read_all(self, values, rtype): addr_min = False addr_max = False for k, v in values.items(): v_addr = v[0] v_length = v[1] if addr_min is False: addr_min = v_addr if addr_max is False: addr_max = v_addr + v_length if v_addr < addr_min: addr_min = v_addr if (v_addr + v_length) > addr_max: addr_max = v_addr + v_length results = {} offset = addr_min length = addr_max - addr_min try: if rtype == registerType.INPUT: data = self._read_input_registers(offset, length) elif rtype == registerType.HOLDING: data = self._read_holding_registers(offset, length) else: raise NotImplementedError(rtype) if not data: return results for k, v in values.items(): address, length, rtype, dtype, vtype, label, fmt, batch = v if address > offset: skip_bytes = address - offset offset += skip_bytes data.skip_bytes(skip_bytes * 2) results[k] = self._decode_value(data, length, dtype, vtype) offset += length except NotImplementedError: raise return results def connect(self): return self.client.connect() def disconnect(self): self.client.close() def connected(self): return self.client.is_socket_open() def read(self, key): if key not in self.registers: raise KeyError(key) return {key: self._read(self.registers[key])} def read_all(self, rtype=registerType.HOLDING): registers = {k: v for k, v in self.registers.items() if (v[2] == rtype)} results = {} for batch in range(1, len(registers)): register_batch = {k: v for k, v in registers.items() if (v[7] == batch)} if not register_batch: break results.update(self._read_all(register_batch, rtype)) return results
#!/usr/bin/python #MTU Server from config import * from pymodbus.client.sync import ModbusTcpClient import time import logging logging.basicConfig() log = logging.getLogger() log.setLevel(logging.INFO) field_client = ModbusTcpClient(FIELD_IP, FIELD_PORT) field_client.connect() isa_client = ModbusTcpClient(OPC1_IP, OPC1_PORT) isa_client.connect() # while 1: # now = time.time() # print (int(now)/60)%60 # if (int(now)/60)%60 == 0: # print "starting connection" # break print "Simulation will start when the time is 0, 25, 50 ,75" to = 0 while 1: toot = int(time.time()) % 100 if to == toot - 1: print toot to = toot # print to if to == 0 or to == 25 or to == 50 or to == 75:
class HMIWindow(Gtk.Window): def initModbus(self): self.modbusClient = ModbusClient(PLANT_IP, port=PLANT_PORT) def resetLabels(self): self.bottlePositionValue.set_markup("<span weight='bold' foreground='gray33'>N/A</span>") self.motorStatusValue.set_markup("<span weight='bold' foreground='gray33'>N/A</span>") self.levelHitValue.set_markup("<span weight='bold' foreground='gray33'>N/A</span>") self.processStatusValue.set_markup("<span weight='bold' foreground='gray33'>N/A</span>") self.nozzleStatusValue.set_markup("<span weight='bold' foreground='gray33'>N/A</span>") self.connectionStatusValue.set_markup("<span weight='bold' foreground='red'>OFFLINE</span>") def __init__(self): Gtk.Window.__init__(self, title="Bottle-filling factory - HMI - VirtuaPlant") self.set_border_width(20) 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='x-large'>Bottle-filling process status</span>") grid.attach(label, 0, elementIndex, 2, 1) elementIndex += 1 # Bottle in position label bottlePositionLabel = Gtk.Label("Bottle in position") bottlePositionValue = Gtk.Label() grid.attach(bottlePositionLabel, 0, elementIndex, 1, 1) grid.attach(bottlePositionValue, 1, elementIndex, 1, 1) elementIndex += 1 # Nozzle status label nozzleStatusLabel = Gtk.Label("Nozzle Status") nozzleStatusValue = Gtk.Label() grid.attach(nozzleStatusLabel, 0, elementIndex, 1, 1) grid.attach(nozzleStatusValue, 1, elementIndex, 1, 1) elementIndex += 1 # Motor status label motorStatusLabel = Gtk.Label("Motor Status") motorStatusValue = Gtk.Label() grid.attach(motorStatusLabel, 0, elementIndex, 1, 1) grid.attach(motorStatusValue, 1, elementIndex, 1, 1) elementIndex += 1 # Level hit label levelHitLabel = Gtk.Label("Level Hit") levelHitValue = Gtk.Label() grid.attach(levelHitLabel, 0, elementIndex, 1, 1) grid.attach(levelHitValue, 1, elementIndex, 1, 1) elementIndex += 1 # Process status processStatusLabel = Gtk.Label("Process Status") processStatusValue = Gtk.Label() grid.attach(processStatusLabel, 0, elementIndex, 1, 1) grid.attach(processStatusValue, 1, elementIndex, 1, 1) elementIndex += 1 # Connection status connectionStatusLabel = Gtk.Label("Connection Status") connectionStatusValue = Gtk.Label() grid.attach(connectionStatusLabel, 0, elementIndex, 1, 1) grid.attach(connectionStatusValue, 1, elementIndex, 1, 1) elementIndex += 1 # Run and Stop buttons runButton = Gtk.Button("Run") stopButton = Gtk.Button("Stop") runButton.connect("clicked", self.setProcess, 1) stopButton.connect("clicked", self.setProcess, 0) grid.attach(runButton, 0, elementIndex, 1, 1) grid.attach(stopButton, 1, elementIndex, 1, 1) elementIndex += 1 IPText = Gtk.Entry() IPText.set_text("%s:%s" % (PLANT_IP, PLANT_PORT)) IPButton = Gtk.Button("APPLY") IPButton.connect("clicked", self.setIPPLC) grid.attach(IPText, 0, elementIndex, 1, 1) grid.attach(IPButton, 1, elementIndex, 1, 1) elementIndex += 1 # VirtuaPlant branding virtuaPlant = Gtk.Label() virtuaPlant.set_markup("<span size='small'>VirtuaPlant - HMI</span>") grid.attach(virtuaPlant, 0, elementIndex, 2, 1) # Attach Value Labels self.IPText = IPText self.processStatusValue = processStatusValue self.connectionStatusValue = connectionStatusValue self.levelHitValue = levelHitValue self.motorStatusValue = motorStatusValue self.bottlePositionValue = bottlePositionValue self.nozzleStatusValue = nozzleStatusValue self.resetLabels() GObject.timeout_add_seconds(MODBUS_SLEEP, self.update_status) def setIPPLC(self, widget): try: address,port = self.IPText.get_text().split(":") self.modbusClient = ModbusClient(address, port) except: pass def setProcess(self, widget, data=None): try: self.modbusClient.write_register(0x10, data) except: pass def update_status(self): try: rr = self.modbusClient.read_holding_registers(1,16) regs = [] if not rr or not rr.registers: raise ConnectionException regs = rr.registers if not regs or len(regs) < 16: raise ConnectionException if regs[1] == 1: self.bottlePositionValue.set_markup("<span weight='bold' foreground='green'>YES</span>") else: self.bottlePositionValue.set_markup("<span weight='bold' foreground='red'>NO</span>") if regs[0] == 1: self.levelHitValue.set_markup("<span weight='bold' foreground='green'>YES</span>") else: self.levelHitValue.set_markup("<span weight='bold' foreground='red'>NO</span>") if regs[2] == 1: self.motorStatusValue.set_markup("<span weight='bold' foreground='green'>ON</span>") else: self.motorStatusValue.set_markup("<span weight='bold' foreground='red'>OFF</span>") if regs[3] == 1: self.nozzleStatusValue.set_markup("<span weight='bold' foreground='green'>OPEN</span>") else: self.nozzleStatusValue.set_markup("<span weight='bold' foreground='red'>CLOSED</span>") if regs[15] == 1: self.processStatusValue.set_markup("<span weight='bold' foreground='green'>RUNNING</span>") else: self.processStatusValue.set_markup("<span weight='bold' foreground='red'>STOPPED</span>") self.connectionStatusValue.set_markup("<span weight='bold' foreground='green'>ONLINE</span>") except ConnectionException: if not self.modbusClient.connect(): self.resetLabels() except: raise finally: return True
class Danbach_AGV(): def __init__(self, lwheel_scale=1.0, rwheel_scale=1.0, ip='192.168.10.30', port=502, timeout=7e-3): self.client = MbClient(ip, port=port, timeout=timeout) self.lwheel_scale = lwheel_scale self.rwheel_scale = rwheel_scale @property def connected(self): return self.client.is_socket_open() def connect(self): self.client.connect() self.client.write_registers(0x1600, [2, 0x0800, 0, 0]) def disconnect(self): self.client.close() def forward(self, distance, speed=DEFAULT_SPEED): if distance == 0 or speed == 0: return l0, r0 = self.__get_wheel_odo__() t0 = time.time() - CMD_PERIOD while True: l, r = self.__get_wheel_odo__() if l >= l0 + distance or r >= r0 + distance: break if time.time() - t0 > CMD_PERIOD: t0 = time.time() if (distance - l + l0 < GUARD_DIST) or (distance - r + r0 < GUARD_DIST): speed = min(speed, GUARD_SPEED) self.__set_wheel__(speed, speed) self.__set_wheel__(0, 0) def back(self, distance, speed=DEFAULT_SPEED): if distance == 0 or speed == 0: return l0, r0 = self.__get_wheel_odo__() t0 = time.time() - CMD_PERIOD while True: l, r = self.__get_wheel_odo__() if l < l0 - distance or r < r0 - distance: break if time.time() - t0 > CMD_PERIOD: t0 = time.time() if (distance - l0 + l < GUARD_DIST) or (distance - r0 + r < GUARD_DIST): speed = min(speed, GUARD_SPEED) self.__set_wheel__(-speed, -speed) self.__set_wheel__(0, 0) def pivot(self, radian, speed=DEFAULT_SPEED): if radian == 0 or speed == 0: return l0, r0 = self.__get_wheel_odo__() t0 = time.time() - CMD_PERIOD while True: l, r = self.__get_wheel_odo__() if abs(abs(l - l0 - r + r0)) / WHEEL_DIST >= abs(radian): break if time.time() - t0 > CMD_PERIOD: if abs(radian) - abs( abs(l - l0 - r + r0)) / WHEEL_DIST < GUARD_RADIAN: speed = min(speed, GUARD_SPEED) t0 = time.time() if radian > 0: self.__set_wheel__(-speed // 2, speed // 2) else: self.__set_wheel__(speed // 2, -speed // 2) self.__set_wheel__(0, 0) def steer(self, radian, direction=1, speed=DEFAULT_SPEED): if radian == 0 or speed == 0: return l0, r0 = self.__get_wheel_odo__() t0 = time.time() - CMD_PERIOD while True: l, r = self.__get_wheel_odo__() if abs((l - l0) - (r - r0)) / WHEEL_DIST >= abs(radian): print((l - l0 - r + r0) / WHEEL_DIST / pi) break if time.time() - t0 > CMD_PERIOD: if abs(radian) - abs((l - l0) - (r - r0)) / WHEEL_DIST < GUARD_RADIAN: speed = GUARD_SPEED t0 = time.time() if radian > 0 and direction == 1: self.__set_wheel__(0, speed) elif radian < 0 and direction == 1: self.__set_wheel__(speed, 0) elif radian > 0 and direction == -1: self.__set_wheel__(0, -speed) else: self.__set_wheel__(-speed, 0) self.__set_wheel__(0, 0) def turn(self, radian, inner_radius, direction=1, speed=DEFAULT_SPEED): self.__set_wheel__(0, 0) def __get_wheel_odo__(self): while True: try: rq = self.client.read_holding_registers(0x41E, 4, unit=1) L_WHEEL = rq.registers[0] * 0x00010000 + rq.registers[1] R_WHEEL = rq.registers[2] * 0x00010000 + rq.registers[3] except: continue break # 2's complement on int_32 L_WHEEL = L_WHEEL - 0x100000000 if (L_WHEEL & 0x80000000) else L_WHEEL R_WHEEL = R_WHEEL - 0x100000000 if (R_WHEEL & 0x80000000) else R_WHEEL return L_WHEEL * 1e-3 * self.lwheel_scale, R_WHEEL * 1e-3 * self.rwheel_scale def __get_wheel_odo_raw__(self): while True: try: rq = self.client.read_holding_registers(0x41E, 4, unit=1) L_WHEEL = rq.registers[0] * 0x00010000 + rq.registers[1] R_WHEEL = rq.registers[2] * 0x00010000 + rq.registers[3] except: continue break # 2's complement on int_32 L_WHEEL = L_WHEEL - 0x100000000 if (L_WHEEL & 0x80000000) else L_WHEEL R_WHEEL = R_WHEEL - 0x100000000 if (R_WHEEL & 0x80000000) else R_WHEEL return L_WHEEL, R_WHEEL def __set_wheel__(self, lspeed, rspeed): if lspeed == 0 and rspeed == 0: rq = self.client.write_registers(0x1620, [0x0002, 0, 0, 0, 0], unit=0x01) lspeed = lspeed + 0x10000 if lspeed < 0 else lspeed rspeed = rspeed + 0x10000 if rspeed < 0 else rspeed rq = self.client.write_registers(0x1620, [0x0001, lspeed, rspeed, 0, 0], unit=0x01) def __set_wheel__(self, lspeed, rspeed): if lspeed == 0 and rspeed == 0: rq = self.client.write_registers(0x1620, [0x0002, 0, 0, 0, 0], unit=0x01) lspeed = lspeed + 0x10000 if lspeed < 0 else lspeed rspeed = rspeed + 0x10000 if rspeed < 0 else rspeed rq = self.client.write_registers(0x1620, [0x0001, lspeed, rspeed, 0, 0], unit=0x01)
def main(): hosts = [ fds.CHARGE_CONTROLLER_IP ] parser = ArgumentParser() parser.add_argument('--dummydata', '-d', action='store_true', default=False, dest='use_dummy_data', help='Use dummy data instead of connect to the modbus or mcu.') parser.add_argument('--address','-a', action='store', dest='charge_controller_ip', help='Set the Modbus IP to connect to the Charge Controller') parser.add_argument('--cycles', '-c', action='store', default=1, dest='cycles', type=int, help='Set the number of cycles') parser.add_argument('--sampling', '-s', action='store', default=2, dest='sampling_rate', type=int, help='Set the delay in seconds between two readings') parser.add_argument('--daemon', '-g', action='store_true', default=False, dest='im_a_daemon', help='The script will be a daemon') parser.add_argument('--version', action='version', version='%(prog)s ' + str(__version__)) results = parser.parse_args() print 'Parsed arguments =========' print "Use dummy data" , results.use_dummy_data print "CC IP " , results.charge_controller_ip print "Cycles " , results.cycles print "Sampling rate " , results.sampling_rate print "Im a f****n deamon " , results.im_a_daemon print '==========================' SAMPLING_RATE = results.sampling_rate MAX_CYCLES = results.cycles DUMMY_DATA = results.use_dummy_data IM_A_DAEMON = results.im_a_daemon if results.charge_controller_ip is not None: hosts = [results.charge_controller_ip] # logging.basicConfig() # log = logging.getLogger('./modbus.error') # log.setLevel(logging.ERROR) client = None # connect to modbus hosts if not DUMMY_DATA: for host in hosts: print "Trying to connect to Modbus IP Host %s ..." % host client = ModbusClient(host, fds.MODBUS_PORT) client.connect() sqlite_file = './data/db_fds_offgridbox-'+ str(datetime.datetime.now().strftime('%Y%m%d-%H:%M:%S')) +'.sqlite' if os.path.isfile(fds.SQLITE_FILENAME): os.rename(fds.SQLITE_FILENAME, sqlite_file) print "File backup in : " + sqlite_file # Connecting to the database file conn = sqlite3.connect(fds.SQLITE_FILENAME) cur = conn.cursor() createDBtables( cur ) i = 0 counter = 0 while i < MAX_CYCLES: # circa un giorno a 30 al minuto ... forse un po d i piu counter = counter + 1 sys.stdout.write("Reading Modbus " + str(counter) + ' :: ' ) chargeControllerData = getChargeControllerData(client) sys.stdout.write('.') relayBoxData = getRelayBoxData(client) sys.stdout.write('.') relayStateData = readRelayState(client) sys.stdout.write('. done! - Reading MCU ') mcuData = getMCUdata(fds.MCU_READ_CMD) sys.stdout.write('. done! - Adding element to db ' ) addDataToDB(conn, chargeControllerData , relayBoxData, relayStateData, mcuData ) print('! ') time.sleep(SAMPLING_RATE) if not IM_A_DAEMON: i = i + 1 cur.execute('SELECT * FROM charge_controller') # print(cur.fetchall()) conn.commit() conn.close()
class FdsChargeController(): comunicationType = "" serialPort = "" ipAddress = "" modbusClient = None isDebug = False client = None def __init__(self, communicationType, port=DEFAULT_C23_RS485, ipAddress=DEFAULT_CHARGE_CONTROLLER_IP, isDebug=False): self.isDebug = isDebug if (communicationType == MODBUS_ETH): self.communicationType = communicationType self.ipAddress = ipAddress logging.debug("FdsChargeController: ETH enabled ") elif (communicationType == MODBUS_RTU): self.communicationType = communicationType self.serialPort = port logging.debug("FdsChargeController: RTU enabled ") else: raise ValueError("Unsupported Modbus Communication Type. Choose MODBUS_RTU or MODBUS_ETH.") def connect(self): if(self.communicationType == MODBUS_ETH): logging.debug("FdsChargeController: connect EHT called") if self.isDebug == False: print("Trying to connect to Modbus IP Host %s ..." % self.ipAddress) self.client = ModbusClient(self.ipAddress, MODBUS_PORT) self.client.connect() elif (self.communicationType == MODBUS_RTU): logging.debug("FdsChargeController: connect RTU called") def getChargeControllerData(self): data = {'type':'chargecontroller'} if self.client != None: try: # read registers. Start at 0 for convenience rr = self.client.read_holding_registers(0,80, unit=CHARGE_CONTROLLER_UNIT) # for all indexes, subtract 1 from what's in the manual V_PU_hi = rr.registers[0] V_PU_lo = rr.registers[1] I_PU_hi = rr.registers[2] I_PU_lo = rr.registers[3] V_PU = float(V_PU_hi) + float(V_PU_lo) I_PU = float(I_PU_hi) + float(I_PU_lo) v_scale = V_PU * 2**(-15) i_scale = I_PU * 2**(-15) p_scale = V_PU * I_PU * 2**(-17) # battery sense voltage, filtered data["battsV"] = rr.registers[24] * v_scale data["battsSensedV"] = rr.registers[26] * v_scale data["battsI"] = rr.registers[28] * i_scale data["arrayV"] = rr.registers[27] * v_scale data["arrayI"] = rr.registers[29] * i_scale data["statenum"] = rr.registers[50] data["hsTemp"] = rr.registers[35] data["rtsTemp"] = rr.registers[36] data["outPower"] = rr.registers[58] * p_scale data["inPower"] = rr.registers[59] * p_scale data["minVb_daily"] = rr.registers[64] * v_scale data["maxVb_daily"] = rr.registers[65] * v_scale data["minTb_daily"] = rr.registers[71] data["maxTb_daily"] = rr.registers[72] data["dipswitches"] = bin(rr.registers[48])[::-1][:-2].zfill(8) #led_state = rr.registers except ModbusIOException as e: logging.error('Charge Controller: modbusIOException') raise e except Exception as e: logging.error('Charge Controller: unpredicted exception') raise e else: data["battsV"] = random.uniform(0, 60) data["battsSensedV"] = random.uniform(0, 60) data["battsI"] = random.uniform(0, 60) data["arrayV"] = random.uniform(0, 60) data["arrayI"] = random.uniform(0, 60) data["statenum"] = random.randint(1, 10) data["hsTemp"] = random.uniform(0, 60) data["rtsTemp"] = random.uniform(0, 60) data["outPower"] = random.uniform(0, 60) data["inPower"] = random.uniform(0, 60) data["minVb_daily"] = random.uniform(0, 60) data["maxVb_daily"] = random.uniform(0, 60) data["minTb_daily"] = random.uniform(0, 60) data["maxTb_daily"] = random.uniform(0, 60) data["dipswitches"] = bin(0x02)[::-1][:-2].zfill(8) return data def getRelayBoxData(self): data = {'type':'relaybox'} if self.client != None: try: # read registers. Start at 0 for convenience rr = self.client.read_holding_registers(0,18, unit=RELAYBOX_UNIT) v_scale = float(78.421 * 2**(-15)) data["adc_vb"] = rr.registers[0] * v_scale data["adc_vch_1"] = rr.registers[1] * v_scale data["adc_vch_2"] = rr.registers[2] * v_scale data["adc_vch_3"] = rr.registers[3] * v_scale data["adc_vch_4"] = rr.registers[4] * v_scale data["t_mod"] = rr.registers[5] data["global_faults"] = rr.registers[6] data["global_alarms"] = rr.registers[7] data["hourmeter_HI"] = rr.registers[8] data["hourmeter_LO"] = rr.registers[9] data["ch_faults_1"] = rr.registers[10] data["ch_faults_2"] = rr.registers[11] data["ch_faults_3"] = rr.registers[12] data["ch_faults_4"] = rr.registers[13] data["ch_alarms_1"] = rr.registers[14] data["ch_alarms_2"] = rr.registers[15] data["ch_alarms_3"] = rr.registers[16] data["ch_alarms_4"] = rr.registers[17] except ModbusIOException as e: logging.error('RelayBoxRead: modbusIOException') raise e except Exception as e: logging.error('RelayBoxRead: unpredicted exception') raise e else: data["adc_vb"] = random.uniform(0, 60) data["adc_vch_1"] = random.uniform(0, 60) data["adc_vch_2"] = random.uniform(0, 60) data["adc_vch_3"] = random.uniform(0, 60) data["adc_vch_4"] = random.uniform(0, 60) data["t_mod"] = random.uniform(0, 60) data["global_faults"] = random.randint(0, 60) data["global_alarms"] = random.randint(0, 60) data["hourmeter_HI"] = random.uniform(0, 60) data["hourmeter_LO"] = random.uniform(0, 60) data["ch_faults_1"] = random.randint(0, 60) data["ch_faults_2"] = random.randint(0, 60) data["ch_faults_3"] = random.randint(0, 60) data["ch_faults_4"] = random.randint(0, 60) data["ch_alarms_1"] = random.randint(0, 60) data["ch_alarms_2"] = random.randint(0, 60) data["ch_alarms_3"] = random.randint(0, 60) data["ch_alarms_4"] = random.randint(0, 60) return data def getRelayBoxState(self): data = {'type':'relayState'} if self.client != None: try: rr = self.client.read_coils(0, 8, unit=RELAYBOX_UNIT) data["relay_1"] = rr.bits[0] data["relay_2"] = rr.bits[1] data["relay_3"] = rr.bits[2] data["relay_4"] = rr.bits[3] data["relay_5"] = rr.bits[4] data["relay_6"] = rr.bits[5] data["relay_7"] = rr.bits[6] data["relay_8"] = rr.bits[7] except ModbusIOException as e: logging.error( 'RelayState: modbusIOException') raise e except Exception as e: logging.error('RelayState: unpredicted exception') raise else: data["relay_1"] = 0x1 data["relay_2"] = 0x1 data["relay_3"] = 0x1 data["relay_4"] = 0x0 data["relay_5"] = 0x0 data["relay_6"] = 0x0 data["relay_7"] = 0x0 data["relay_8"] = 0x0 return data
class Modbus_Driver(object): def __init__(self, config_file, config_section='modbus', **kwargs): # Use a config section if the config file is being shared with other # parts of a project. **kwargs can contain a variable amount of if (isinstance(config_file,str)): with open(config_file) as f: modbusConfig = yaml.safe_load(f) else: modbusConfig = config_file modbus_section = config_section self.BYTE_ORDER_DICT = {} self.WORD_ORDER_DICT = {} self.input_register_dict = {} self.holding_register_dict = {} self.coil_register_dict = {} self.discrete_register_dict = {} self.input_registers = {} self.holding_registers = {} self.coil_registers = {} self.discrete_registers = {} self.MODBUS_TYPE = modbusConfig[modbus_section]['modbus_type'] # Check to see if unit id is a list, if it is then set flag that it is a # list self.UNIT_ID = modbusConfig[modbus_section]['UNIT_ID'] if isinstance(self.UNIT_ID, list): self.UNIT_ID_LIST = self.UNIT_ID #Set default UNIT_ID as first UNIT_ID in list self.UNIT_ID = int(self.UNIT_ID_LIST[0]) else: # Make a unit id list from the non-list definition for compatibility # reasons of previous configs. This also eliminates the possibility # of error in calling get_data_all_devices() on a config with a non # list definition self.UNIT_ID_LIST = [] self.UNIT_ID_LIST.append(self.UNIT_ID) # Start logging if enabled in config self.LOGGING_FLAG = modbusConfig[modbus_section]['enable_logging'] if self.LOGGING_FLAG == False: #Start client logging for trouble shooting logging.basicConfig() log = logging.getLogger() log.setLevel(logging.ERROR) # Start appropriate client based on the type specified in the config if self.MODBUS_TYPE == 'serial': self.METHOD = modbusConfig[modbus_section]['method'] self.SERIAL_PORT = modbusConfig[modbus_section]['serial_port'] self.STOPBITS = modbusConfig[modbus_section]['stopbits'] self.BYTESIZE = modbusConfig[modbus_section]['bytesize'] self.PARITY = modbusConfig[modbus_section]['parity'] self.BAUDRATE = modbusConfig[modbus_section]['baudrate'] elif self.MODBUS_TYPE == 'tcp': self.IP_ADDRESS = modbusConfig[modbus_section]['ip'] self.PORT = modbusConfig[modbus_section]['port'] else: print("Invalid modbus type") exit # Set the byte order as big or little endian if modbusConfig[modbus_section]['byte_order'] == 'big': self.BYTE_ORDER = Endian.Big self.BYTE_ORDER_DICT[self.UNIT_ID] = Endian.Big elif modbusConfig[modbus_section]['byte_order'] == 'little': self.BYTE_ORDER = Endian.Little self.BYTE_ORDER_DICT[self.UNIT_ID] = Endian.Little else: print("invalid byte order") # change to except later exit() # Set the word order as big or little endian if modbusConfig[modbus_section]['word_order'] == 'big': self.WORD_ORDER = Endian.Big self.WORD_ORDER_DICT[self.UNIT_ID] = Endian.Big elif modbusConfig[modbus_section]['word_order'] == 'little': self.WORD_ORDER = Endian.Little self.WORD_ORDER_DICT[self.UNIT_ID] = Endian.Little else: print("invalid byte order") # change to except later exit() # Read in all registers specified in the YAML config self.coil_register_dict = modbusConfig[modbus_section]['coil_registers'] self.discrete_register_dict = modbusConfig[modbus_section]['discrete_registers'] self.holding_register_dict = modbusConfig[modbus_section]['holding_registers'] self.input_register_dict = modbusConfig[modbus_section]['input_registers'] self.coil_registers[self.UNIT_ID] = self.coil_register_dict self.discrete_registers[self.UNIT_ID] = self.discrete_register_dict self.holding_registers[self.UNIT_ID] = self.holding_register_dict self.input_registers[self.UNIT_ID] = self.input_register_dict #print(self.holding_registers) # Add single device that is either specified in config_section parameter # or a single device config file for current_device in self.UNIT_ID_LIST: self.coil_registers[current_device] = self.coil_register_dict self.discrete_registers[current_device] = self.discrete_register_dict self.holding_registers[current_device] = self.holding_register_dict self.input_registers[current_device] = self.input_register_dict # Set the byte order as big or little endian if modbusConfig[modbus_section]['byte_order'] == 'big': self.BYTE_ORDER_DICT[current_device] = Endian.Big elif modbusConfig[modbus_section]['byte_order'] == 'little': self.BYTE_ORDER_DICT[current_device] = Endian.Little else: print("invalid byte order") # change to except later exit() # Set the word order as big or little endian if modbusConfig[modbus_section]['word_order'] == 'big': self.WORD_ORDER_DICT[current_device] = Endian.Big elif modbusConfig[modbus_section]['word_order'] == 'little': self.WORD_ORDER_DICT[current_device] = Endian.Little else: print("invalid word order") # change to except later exit() # Apply register offset if specified self.OFFSET_REGISTERS = modbusConfig[modbus_section]['OFFSET_REGISTERS'] for key in self.holding_register_dict: self.holding_register_dict[key][0] -= self.OFFSET_REGISTERS # Add devices that were specified with **kwargs for device_name, modbus_section in kwargs.items(): # The Device ID is used as the key in a dictionary for all settings # that could potentially differ between devices. Since all of the # functions already have been updated to take in a UNIT_ID this # can be used to retrieve the appropriate setting for the device. # TODO Handle case where the config section has a list of the same # device. current_device = modbusConfig[modbus_section]['UNIT_ID'] #print(type(current_device)) # TODO make this a for loop for each ID #current_device = current_device[0] self.UNIT_ID_LIST.append(int(current_device)) if modbusConfig[modbus_section]['byte_order'] == 'big': self.BYTE_ORDER_DICT[current_device] = Endian.Big elif modbusConfig[modbus_section]['byte_order'] == 'little': self.BYTE_ORDER_DICT[current_device] = Endian.Little # Set the word order as big or little endian if modbusConfig[modbus_section]['word_order'] == 'big': self.WORD_ORDER_DICT[current_device] = Endian.Big elif modbusConfig[modbus_section]['word_order'] == 'little': self.WORD_ORDER_DICT[current_device] = Endian.Little else: print("invalid word order") # change to except later exit() # Read in all registers specified in the YAML config self.coil_register_dict = modbusConfig[modbus_section]['coil_registers'] self.discrete_register_dict = modbusConfig[modbus_section]['discrete_registers'] self.holding_register_dict = modbusConfig[modbus_section]['holding_registers'] self.input_register_dict = modbusConfig[modbus_section]['input_registers'] self.coil_registers[current_device] = self.coil_register_dict self.discrete_registers[current_device] = self.discrete_register_dict self.holding_registers[current_device] = self.holding_register_dict self.input_registers[current_device] = self.input_register_dict #print(self.holding_register_dict) ''' # Read in all registers specified in the YAML config self.coil_registers[current_device] = modbusConfig[modbus_section]['coil_registers'] self.discrete_registers[current_device] = modbusConfig[modbus_section]['discrete_registers'] self.holding_registers[current_device] = modbusConfig[modbus_section]['holding_registers'] self.input_register_dict[current_device] = modbusConfig[modbus_section]['input_registers'] ''' # Apply register offset if specified # TODO fix this for one device as well as multiple """ self.OFFSET_REGISTERS_DICT[current_device] = modbusConfig[modbus_section]['OFFSET_REGISTERS'] for key in self.holding_register_dict: self.holding_register_dict[key][0] -= self.OFFSET_REGISTERS """ #print(self.holding_registers) def initialize_modbus(self): """ initalize correct client according to type specified in config: 'tcp' or 'serial' """ if self.MODBUS_TYPE == 'serial': self.client= ModbusSerialClient( method = self.METHOD, port = self.SERIAL_PORT, stopbits = self.STOPBITS, bytesize = self.BYTESIZE, parity = self.PARITY, baudrate = self.BAUDRATE ) connection = self.client.connect() if self.MODBUS_TYPE == 'tcp': self.client = ModbusTcpClient(self.IP_ADDRESS,port=self.PORT) ''' rr = self.read_register_raw(0x601,1,247) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER, wordorder=self.WORD_ORDER) output = decoder.decode_16bit_int() print(output) ''' #rr = self.read_register_raw(1001,2,7) '''decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER, wordorder=self.WORD_ORDER) ''' def reconnect(self): try: self.client.close() finally: self.initialize_modbus() def write_single_register(self,register,value, unit=None): """ :param register: address of reigster to write :param value: Unsigned short :returns: Status of write """ if (unit is None): unit = self.UNIT_ID response = self.client.write_register(register,value,unit) return response def write_data(self,register,value): response = self.client.write_register(register,value,unit= self.UNIT_ID) return response def write_register(self,register_name,value, unit=None): """ :param register_name: register key from holding register dictionary generated by yaml config :param value: value to write to register :returns: -- Nothing """ # TODO add the ability to discern which settings will be appropriate for # the device that is being written to if (unit is None): unit = self.UNIT_ID ''' builder = BinaryPayloadBuilder(byteorder=self.BYTE_ORDER, wordorder=self.WORD_ORDER_DICT[unit]) ''' builder = BinaryPayloadBuilder(byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) # This will change depending on the device that is being connected # potentially so it has to be correleated to the device ID if (self.holding_register_dict[register_name][1] == '8int'): builder.add_8bit_int(value) elif (self.holding_register_dict[register_name][1] == '8uint'): builder.add_8bit_uint(value) elif (self.holding_register_dict[register_name][1] == '16int'): builder.add_16bit_int(value) elif (self.holding_register_dict[register_name][1] == '16uint'): builder.add_16bit_uint(value) elif (self.holding_register_dict[register_name][1] == '32int'): builder.add_32bit_int(value) elif (self.holding_register_dict[register_name][1] == '32uint'): builder.add_32bit_uint(value) elif (self.holding_register_dict[register_name][1] == '32float'): builder.add_32bit_float(value) elif (self.holding_register_dict[register_name][1] == '64int'): builder.add_64bit_int(value) elif (self.holding_register_dict[register_name][1] == '64uint'): builder.add_64bit_uint(value) elif (self.holding_register_dict[register_name][1] == '64float'): builder.add_64bit_float(value) else: print("Bad type") exit() payload = builder.build() self.client.write_registers(self.holding_register_dict[register_name][0], payload, skip_encode=True, unit = self.UNIT_ID) def write_coil(self,register,value, unit=None): """ :param register_name: register key from holding register dictionary generated by yaml config :param value: value to write to register :returns: """ # TODO mention what type the value needs to be for value if (unit is None): unit = self.UNIT_ID response = self.client.write_coil(register,value,unit) return response def read_coil(self,register, unit=None): """ :param register: coil register address to read :returns: value stored in coil register """ # TODO mention what type the value needs to be for value if (unit is None): unit = self.UNIT_ID rr = self.client.read_coils(register, 1, unit=unit) return rr.bits[0] def read_discrete(self,register,unit=None): """ :param register: discrete register address to read :returns: value stored in coil register """ if (unit is None): unit = self.UNIT_ID rr = self.client.read_discrete_inputs(register, count=1,unit=unit) return rr.bits[0] def read_register_raw(self,register,length, unit=None): """ :param register: base holding register address to read :param length: amount of registers to read to encompass all of the data necessary for the type :returns: A deferred response handle """ if (unit is None): unit = self.UNIT_ID response = self.client.read_holding_registers(register,length,unit=unit) return response def read_input_raw(self,register,length, unit=None): """ :param register: base input register address to read :param length: amount of registers to read to encompass all of the data necessary for the type :returns: A deferred response handle """ if (unit is None): unit = self.UNIT_ID response = self.client.read_input_registers(register,length,unit=unit) return response def decode_register(self,register,type, unit=None): #print(unit) #print(type(unit)) """ :param register: holding register address to retrieve :param type: type to interpret the registers retrieved as :returns: data in the type specified Based on the type provided, this function retrieves the values contained in the register address specfied plus the amount necessary to encompass the the type. For example, if 32int is specified with an address of 200 the registers accessed would be 200 and 201. The types accepted are listed in the table below along with their length | Type | Length (registers) | | ------------- |:------------------:| | ignore | 1 | | 8int | 1 | | 8uint | 1 | | 16int | 1 | | 16uint | 1 | | 32int | 2 | | 32uint | 2 | | 32float | 2 | | 64int | 4 | | 64uint | 4 | | 64float | 4 | """ if (unit is None): unit = self.UNIT_ID #omitting string for now since it requires a specified length if type == '8int': rr = self.read_register_raw(register,1,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_8bit_int() elif type == '8uint': rr = self.read_register_raw(register,1,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_8bit_uint() elif type == '16int': rr = self.read_register_raw(register,1,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_16bit_int() elif type == '16uint': rr = self.read_register_raw(register,1,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_16bit_uint() elif type == '32int': rr = self.read_register_raw(register,2,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_32bit_int() elif type == '32uint': rr = self.read_register_raw(register,2,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_32bit_uint() elif type == '32float': rr = self.read_register_raw(register,2,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_32bit_float() elif type == '64int': rr = self.read_register_raw(register,4,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_64bit_int() elif type == '64uint': rr = self.read_register_raw(register,4,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_64bit_uint() elif type == 'ignore': rr = self.read_register_raw(register,1,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.skip_bytes(8) elif type == '64float': rr = self.read_register_raw(register,4,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_64bit_float() else: print("Wrong type specified") exit() return output def decode_input_register(self,register,type, unit=None): """ :param register: input register address to retrieve :param type: type to interpret the registers retrieved as :returns: data in the type specified Based on the type provided, this function retrieves the values contained in the register address specfied plus the amount necessary to encompass the the type. For example, if 32int is specified with an address of 200 the registers accessed would be 200 and 201. The types accepted are listed in the table below along with their length | Type | Length (registers) | | ------------- |:------------------:| | ignore | 1 | | 8int | 1 | | 8uint | 1 | | 16int | 1 | | 16uint | 1 | | 32int | 2 | | 32uint | 2 | | 32float | 2 | | 64int | 4 | | 64uint | 4 | | 64float | 4 | """ if (unit is None): unit = self.UNIT_ID #omitting string for now since it requires a specified length if type == '8int': rr = self.read_input_raw(register,1,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_8bit_int() elif type == '8uint': rr = self.read_input_raw(register,1,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit][unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_8bit_uint() elif type == '16int': rr = self.read_input_raw(register,1,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_16bit_int() elif type == '16uint': rr = self.read_input_raw(register,1,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_16bit_uint() elif type == '32int': rr = self.read_input_raw(register,2,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_32bit_int() elif type == '32uint': rr = self.read_input_raw(register,2,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_32bit_uint() elif type == '32float': rr = self.read_input_raw(register,2,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_32bit_float() elif type == '64int': rr = self.read_input_raw(register,4,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_64bit_int() elif type == '64uint': rr = self.read_input_raw(register,4,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_64bit_uint() elif type == 'ignore': rr = self.read_input_raw(register,1,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.skip_bytes(8) elif type == '64float': rr = self.read_input_raw(register,4,unit) decoder = BinaryPayloadDecoder.fromRegisters( rr.registers, byteorder=self.BYTE_ORDER_DICT[unit], wordorder=self.WORD_ORDER_DICT[unit]) output = decoder.decode_64bit_float() else: print("Wrong type specified") exit() return output def read_register(self,register_name): response = self.decode_register(self.holding_register_dict[register_name][0], self.holding_register_dict[register_name][1]) return response def read_input_raw(self,register_name): response = self.decode_input_register(self.holding_register_dict[register_name][0], self.holding_register_dict[register_name][1]) return response def get_data(self,unit=None): """ :returns: Dictionary containing the value retrieved for each register contained in the YAML config file, register names cannot be repeated or the register will be overwritten """ output = {} if unit is None: unit = self.UNIT_ID for key in self.coil_registers[unit]: output[key] = self.read_coil(self.coil_registers[unit][key][0],unit) for key in self.discrete_registers[unit]: output[key] = self.read_discrete(self.discrete_registers[unit][key][0],unit) for key in self.input_registers[unit]: output[key] = self.decode_input_register(self.input_registers[unit][key][0],self.input_registers[unit][key][1],unit) for key in self.holding_registers[unit]: if (len(self.holding_registers[unit][key]) == 3): # Check Read/Write Flag if (self.holding_registers[unit][key][2].find('R') != -1): output[key] = self.decode_register(self.holding_registers[unit][key][0],self.holding_registers[unit][key][1],unit) else: # Register list does not contain a Read/Write Flag assume R output[key] = self.decode_register(self.holding_registers[unit][key][0],self.holding_registers[unit][key][1],unit) return output def get_data_all_devices(self): reg_data_dict = {} cnt = 1 for dev_id in self.UNIT_ID_LIST: new_key = str(dev_id) if str(dev_id) in reg_data_dict: new_key = new_key + '_' + str(cnt) cnt += 1 reg_data_dict[new_key] = self.get_data(dev_id) return reg_data_dict def kill_modbus(self): """ Closes connection with Modbus Slave """ self.client.close()
class ModBus_API: def __init__(self, IP_ADDRESS='169.254.167.246'): self.MIN_SIGNED = -2147483648 self.MAX_UNSIGNED = 4294967295 self.COLOR_CONTROL_IP = IP_ADDRESS self.client = None def connect_to_ccgx(self): try: self.client = ModbusClient(self.COLOR_CONTROL_IP, port='502') if(self.client.connect()): print('Successfully connected to: {0}'.format( self.COLOR_CONTROL_IP)) else: print('Error while connecting to: {0}'.format( self.COLOR_CONTROL_IP)) except: print('Error connecting') def read_device_data(self, address, unit, count=1, d_type='int32'): received = self.client.read_input_registers( address=address, count=count, unit=unit) message = BinaryPayloadDecoder.fromRegisters( received.registers, Endian.Big) if d_type == 'int32': interpreted = message.decode_32bit_int() elif d_type == 'uint32': interpreted = message.decode_32bit_uint() elif d_type == 'iunt:64': interpreted = message.decode_64bit_uint() elif d_type == 'str32': interpreted = message.decode_string(32) elif d_type == 'int16': interpreted = message.decode_16bit_int() elif d_type == 'uint16': interpreted = message.decode_16bit_uint() else: # if no data type is defined do raw interpretation of the delivered data interpreted = message.decode_16bit_uint() return interpreted def close(self): self.client.close() def battery_state_map(self, n): n = int(n) if n == 0: return 'idle' elif n == 1: return 'charging' elif n == 2: return 'discharging' def show_data(self): data ={ 'Battery voltage' : self.read_device_data(840, 100, d_type='uint16')/10.0, 'Battery current' : self.read_device_data(841, 100, d_type='int16')/10.0, 'Battery power' : self.read_device_data(842, 100, d_type='int16'), 'Battery state of charge' : self.read_device_data(843, 100, d_type='uint16'), 'Battery state' : self.battery_state_map(self.read_device_data(844, 100, d_type='int16')), 'AC consumption' : self.read_device_data(817, 100, d_type='int16'), 'vebus volt' : float(self.read_device_data(15, 246, d_type='uint16'))/10.0, 'vebus current' : float(self.read_device_data(18, 246, d_type='int16'))/10.0, 'Battery Consumed AH': float(self.read_device_data(845, 100, d_type='uint16'))/-10.0 #'Consumed Amp1': float(self.read_device_data(771, 234, d_type='uint16')) # 'Consumed Amp2': float(self.read_device_data(265, 245, d_type='uint16')) } return data
class PythonDiagnosticProgramm(): #Modbus general def modbusConnectionOpen(self, iPAddress=modbus_ip, port=modbus_port): self.client = ModbusClient( iPAddress, port) # PLC Address and Port; '192.168.000.250' does not work! time.sleep(0.1) return self.client.connect() def modbusConnectionClose(self): self.client.close() #Modbus read def modbusReadOut(self, startAddress=0, numberOfAddresses=2): floatSolutionArray = [] # numberOfAddresses should be not too much time.sleep(0.1) # Can be modified: 0.1 becomes instable # numberOfAddresses*2 because we read 32bit registers result = self.client.read_input_registers(startAddress, numberOfAddresses * 2) decoder = BinaryPayloadDecoder.fromRegisters(result.registers, endian=Endian.Little) decodedAsInt = { i: decoder.decode_32bit_int() for i in range(0, numberOfAddresses) } #convert the received values in floats for m in range(numberOfAddresses): floatSolutionArray.append( (self._intToFloatPLC(decodedAsInt.get(m)))) return floatSolutionArray def modbusReadOutAxis(self, axis): # With 0 there are 31 values to 30 return self.modbusReadOut(axis * 100, 31) def modbusReadOutAll(self): # it reads of every Axis the first 31 Registers floatSolutionArray = np.zeros((5, 31)) for axis in range(0, len(floatSolutionArray)): floatSolutionArray[axis, :] = self.modbusReadOutAxis(axis) # To be sure that it is an Numpy Array return np.array(floatSolutionArray) def modbusReadOutVariableAxisData(self): # Relevant Addressends for the Variable Axis Data Database addressend = [9, 10, 11, 12, 20, 21, 30] sQLArray = np.zeros([5, 7]) floatSolutionArray = self.modbusReadOutAll() for m in range(len(addressend)): sQLArray[:, m] = floatSolutionArray[:, (addressend[m])] return sQLArray #Modbus write def modbusWrite(self, address, value): toChange = self._IEEE754reverse(value) toSend = self._changingTheOrder(toChange) builder = BinaryPayloadBuilder(endian=Endian.Little) # That is because of difficulies with the PLC builder.add_32bit_uint((toSend)) payload = builder.build() #result = client.write_registers(address, payload, skip_encode=True) result = self.client.write_registers(address, payload, skip_encode=True) #SQL #SQL General def sQLConnectionOpen(self, filePath): self.connection = sqlite3.connect(filePath) self.cursor = self.connection.cursor() def sQLConnectionClose(self): self.connection.commit() self.connection.close() #SQL Editing Methods def sQLCommand(self, sql_command): self.cursor.execute(sql_command) self.connection.commit() def sQLReadingTable(self, tableName="VariableAxisData"): self.cursor.execute("SELECT * FROM %s" % tableName) stringList = self.cursor.fetchall() for i in range(len(stringList)): print stringList[i] def sQLCreateTableVariableAxisData(self): sql_command = """ CREATE TABLE VariableAxisData ( Axis Int, X9 float, X10 float, X11 float, X12 float, X20 float, X21 float, X30 float);""" self.cursor.execute(sql_command) def sQLOverwriteVariableAxisData(self): floatSolutionArray = self.modbusReadOutVariableAxisData() for axis in range(len(floatSolutionArray[:, 0])): sql_command = """ DELETE FROM VariableAxisData WHERE Axis=%i;""" % (axis) self.cursor.execute(sql_command) # Insert the new Values sql_command = """ INSERT INTO VariableAxisData VALUES (%i,%f,%f,%f,%f,%f,%f,%f);""" % ( axis, floatSolutionArray[axis][0], floatSolutionArray[axis][1], floatSolutionArray[axis][2], floatSolutionArray[axis][3], floatSolutionArray[axis][4], floatSolutionArray[axis][5], floatSolutionArray[axis][6]) self.cursor.execute(sql_command) # Confirm self.connection.commit() # txt # Private Methodes def _intToFloatPLC(self, decodedAsInt): # Separate the Bytes; Initial order: byte4 | byte3 | byte2 | byte1 byte1 = (decodedAsInt) & (0xFF) byte2 = (decodedAsInt) >> 8 & (0xFF) byte3 = (decodedAsInt) >> 16 & (0xFF) byte4 = (decodedAsInt) >> 24 & (0xFF) # Combine the Bytes correct; Final order: byte3 | byte4 | byte1 | byte2 result = (byte3 << (24)) result = (byte4 << (16)) | result result = (byte1 << (8)) | result result = (byte2) | result # Transform the bitorder in a float # Refering to IEEE 754: # The 23 lowest significant bits mantissa = result & 0x7FFFFF # The next 8 bits exponent = (result >> (23)) & 0xFF # The formula according to IEEE 754: _floatSolution = (1 + ((mantissa) / (math.pow(2, 23)))) * math.pow(2, (exponent - 127)) # The most significant bit defines the sign if ((byte3 & 0x80) == 0x80): #byte3 is the new most significant byte _floatSolution = -_floatSolution # Underflow case: Exception of IEEE 754 if (result == 0): _floatSolution = 0 # round the result _floatSolution = round(_floatSolution, 4) # Print-Function for test issues # print "Address, Decoded: ", address, ", " ,floatSolution, bin(result) # print axis, m # Save the result, it will be overwritten in the next loop return _floatSolution def _changingTheOrder(self, decodedAsInt): # Separate the Bytes; Initial order: byte4 | byte3 | byte2 | byte1 byte1 = (decodedAsInt) & (0xFF) byte2 = (decodedAsInt) >> 8 & (0xFF) byte3 = (decodedAsInt) >> 16 & (0xFF) byte4 = (decodedAsInt) >> 24 & (0xFF) # Combine the Bytes correct; Final order: byte3 | byte4 | byte1 | byte2 result = (byte3 << (24)) result = (byte4 << (16)) | result result = (byte1 << (8)) | result result = (byte2) | result return (result) def _IEEE754reverse(self, valueIntoVR): valueAsInt = np.asarray(abs(valueIntoVR), dtype=np.float32).view(np.int32).item() if (valueIntoVR < 0): valueAsInt = valueAsInt | 0x80000000 return (valueAsInt)
def run_sync_client(): # ------------------------------------------------------------------------# # choose the client you want # ------------------------------------------------------------------------# # make sure to start an implementation to hit against. For this # you can use an existing device, the reference implementation in the tools # directory, or start a pymodbus server. # # If you use the UDP or TCP clients, you can override the framer being used # to use a custom implementation (say RTU over TCP). By default they use # the socket framer:: # # client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer) # # It should be noted that you can supply an ipv4 or an ipv6 host address # for both the UDP and TCP clients. # # There are also other options that can be set on the client that controls # how transactions are performed. The current ones are: # # * retries - Specify how many retries to allow per transaction (default=3) # * retry_on_empty - Is an empty response a retry (default = False) # * source_address - Specifies the TCP source address to bind to # # Here is an example of using these options:: # # client = ModbusClient('localhost', retries=3, retry_on_empty=True) # ------------------------------------------------------------------------# client = ModbusClient('localhost', port=5020) # client = ModbusClient(method='ascii', port='/dev/pts/2', timeout=1) # client = ModbusClient(method='rtu', port='/dev/ttyp0', timeout=1) client.connect() # ------------------------------------------------------------------------# # specify slave to query # ------------------------------------------------------------------------# # The slave to query is specified in an optional parameter for each # individual request. This can be done by specifying the `unit` parameter # which defaults to `0x00` # ----------------------------------------------------------------------- # log.debug("Reading Coils") rr = client.read_coils(1, 1, unit=0x01) print(rr) # ----------------------------------------------------------------------- # # example requests # ----------------------------------------------------------------------- # # simply call the methods that you would like to use. An example session # is displayed below along with some assert checks. Note that some modbus # implementations differentiate holding/input discrete/coils and as such # you will not be able to write to these, therefore the starting values # are not known to these tests. Furthermore, some use the same memory # blocks for the two sets, so a change to one is a change to the other. # Keep both of these cases in mind when testing as the following will # _only_ pass with the supplied async modbus server (script supplied). # ----------------------------------------------------------------------- # log.debug("Write to a Coil and read back") rq = client.write_coil(0, True, unit=UNIT) rr = client.read_coils(0, 1, unit=UNIT) assert (rq.function_code < 0x80) # test that we are not an error assert (rr.bits[0] == True) # test the expected value log.debug("Write to multiple coils and read back- test 1") rq = client.write_coils(1, [True] * 8, unit=UNIT) assert (rq.function_code < 0x80) # test that we are not an error rr = client.read_coils(1, 21, unit=UNIT) assert (rr.function_code < 0x80) # test that we are not an error resp = [True] * 21 # If the returned output quantity is not a multiple of eight, # the remaining bits in the final data byte will be padded with zeros # (toward the high order end of the byte). resp.extend([False] * 3) assert (rr.bits == resp) # test the expected value log.debug("Write to multiple coils and read back - test 2") rq = client.write_coils(1, [False] * 8, unit=UNIT) rr = client.read_coils(1, 8, unit=UNIT) assert (rq.function_code < 0x80) # test that we are not an error assert (rr.bits == [False] * 8) # test the expected value log.debug("Read discrete inputs") rr = client.read_discrete_inputs(0, 8, unit=UNIT) assert (rq.function_code < 0x80) # test that we are not an error log.debug("Write to a holding register and read back") rq = client.write_register(1, 10, unit=UNIT) rr = client.read_holding_registers(1, 1, unit=UNIT) assert (rq.function_code < 0x80) # test that we are not an error assert (rr.registers[0] == 10) # test the expected value log.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 (rq.function_code < 0x80) # test that we are not an error assert (rr.registers == [10] * 8) # test the expected value log.debug("Read input registers") rr = client.read_input_registers(1, 8, unit=UNIT) assert (rq.function_code < 0x80) # test that we are not an error arguments = { 'read_address': 1, 'read_count': 8, 'write_address': 1, 'write_registers': [20] * 8, } log.debug("Read write registeres simulataneously") rq = client.readwrite_registers(unit=UNIT, **arguments) rr = client.read_holding_registers(1, 8, unit=UNIT) assert (rq.function_code < 0x80) # test that we are not an error assert (rq.registers == [20] * 8) # test the expected value assert (rr.registers == [20] * 8) # test the expected value # ----------------------------------------------------------------------- # # close the client # ----------------------------------------------------------------------- # client.close()
def env_modbus2mongodb_next(): try: t = time() DBclient = MongoClient('mongodb://192.168.1.10/', username='******', password='******', authSource='admin', serverSelectionTimeoutMS=1000) # try: # 数据库连接测试 # # The ismaster command is cheap and does not require auth. # DBclient.admin.command('ismaster') # except ConnectionFailure as e: # Exception # DBclient.close() # log.error(e) # # print("Server not available") # return db = DBclient['sensor_management'] # collection = db['environment'] collection = db['data_test_1117'] # data_all = [] for bus in range(1, 12): client = ModbusClient(ads.conn[bus - 1][0], port=ads.conn[bus - 1][1], timeout=1, framer=ModbusFramer) is_connected = client.connect() if not is_connected: # modbus连接失败 data_db = { 'name': '{:0>2d}xxxx'.format(bus), 'err': 'Modbus Connect Failed', 'datetime': datetime.now() } result = collection.insert_one(data_db) client.close() sleep(1) continue for box in range(ads.busBox[bus - 1], ads.busBox[bus]): # 云盒编号(0开始) sleep(1) rr = client.read_holding_registers(ads.rgs, ads.len_data, unit=box + 1) if not hasattr(rr, 'registers'): # 无返回数据 data_db = { 'name': '{:0>2d}{:0>2d}xx'.format(bus, box + 1), 'message': rr.message, 'err': 'No Data Return', 'datetime': datetime.now() } result = collection.insert_one(data_db) continue data_modbus = rr.registers for i in range(ads.box_num[box][0]): # 二合一编号(0开始) pos_two = ads.two_start + ads.two_len * i # print('two', data_modbus[pos_two + ads.pos_name], (box+1) * 256 + i+1) if data_modbus[pos_two + ads.pos_name] == ( box + 1) * 256 + ads.two_start + i + 1: data_db = { 'name': '{:0>2d}{:0>2d}{:0>2d}'.format( bus, box + 1, ads.two_start + i + 1), 'two_in_one': { ads.two_type[j]: data_modbus[pos_two + ads.pos_data + j] * ads.two_carry[j] for j in range(2) }, 'datetime': datetime.now() } else: data_db = { 'name': '{:0>2d}{:0>2d}{:0>2d}'.format( bus, box + 1, ads.two_start + i + 1), 'data': data_modbus, 'err': 'Unexpected Data Received', 'datetime': datetime.now() } result = collection.insert_one(data_db) # data_all.append(data_db) for i in range(ads.box_num[box][1]): # 六合一编号 pos_six = ads.six_start * ads.two_len + ads.six_len * i # print('six', data_modbus[pos_six + ads.pos_name], (box+1) * 256 + ads.six_start+i + ads.six_bios+1) if data_modbus[pos_six + ads.pos_name] == ( box + 1) * 256 + ads.six_start + i + ads.six_bios + 1: data_db = { 'name': '{:0>2d}{:0>2d}{:0>2d}'.format( bus, box + 1, ads.six_start + i + 1), 'six_in_one': { ads.six_type[j]: data_modbus[pos_six + ads.pos_data + j] * ads.six_carry[j] for j in range(6) }, 'datetime': datetime.now() } else: data_db = { 'name': '{:0>2d}{:0>2d}{:0>2d}'.format( bus, box + 1, ads.six_start + i + 1), 'data': data_modbus, 'err': 'Unexpected Data Received', 'datetime': datetime.now() } result = collection.insert_one(data_db) # data_all.append(data_db) client.close() # DBclient.close() except ConnectionFailure as e: log.error(e) except Exception as e: # log.exception(e) # client.close() # DBclient.close() log.error(e) # log.info('Time Consuming: ' + str(time() - t)) return finally: DBclient.close() log.info('Time Consuming: ' + str(time() - t))
class ClientEngine(): def __init__(self, **kwargs): self.callback = kwargs.get('callback', None) self.svrIp = kwargs.get('svrIp', None) self.svrPort = kwargs.get('svrPort', None) self.mbFramer = kwargs.get('mbFramer', None) self.client = ModbusClient(self.svrIp, port=self.svrPort, framer=self.mbFramer, timeout=1) self.stopper = threading.Event() self.queue_req = queue.LifoQueue() def start(self): self.th = threading.Thread(target=self.worker) self.th.start() self.stopper.clear() self.queue_req.join() def parse_response(self, resp, response_callback): if hasattr(resp, 'function_code'): if resp.function_code in [0x01, 0x02, 0x03, 0x04]: response_callback(self, resp.registers) elif resp.function_code in [0x06, 0x10]: response_callback(self) def worker(self): while not self.stopper.is_set(): try: if self.client.connect(): while not self.queue_req.empty(): request, args, callback = self.queue_req.get() self.parse_response(request(**args), callback) self.queue_req.task_done() time.sleep(0.1) else: self.callback.on_connection_lost(self) except: print sys.exc_info() def _get_request_from_queue(self): if not self.queue_req.empty(): request, args, callback = self.queue_req.get() self.parse_response(request(**args), callback) def read_reg(self, offset, len, response_callback): req = (self.client.read_holding_registers, { 'address': offset, 'count': len, 'unit': 0x01 }, response_callback) self.queue_req.put(req) def write_reg(self, reg_no, val, response_callback): req = (self.client.write_register, { 'address': reg_no, 'value': val, 'unit': 0x01 }, response_callback) self.queue_req.put(req) def stop(self): self.client.close() self.stopper.set() self.th.join()
def env_modbus2mongodb(): try: t = time() DBclient = MongoClient('mongodb://192.168.1.10/', username='******', password='******', authSource='admin') db = DBclient['sensor_management'] # collection = db['environment'] collection = db['data_test_1117'] # data_all = [] for bus in range(1, 12): client = ModbusClient(ads.conn[bus - 1][0], port=ads.conn[bus - 1][1], timeout=1, framer=ModbusFramer) client.connect() for box in range(ads.busBox[bus - 1], ads.busBox[bus]): # 云盒编号(0开始) sleep(1) rr = client.read_holding_registers(ads.rgs, ads.len_data, unit=box + 1) if not hasattr(rr, 'registers'): data_db = { 'name': '{:0>2d}{:0>2d}xx'.format(bus, box + 1), 'message': rr.message, 'err': 'No Data Return', 'datetime': datetime.now() } result = collection.insert_one(data_db) continue data_modbus = rr.registers for i in range(ads.box_num[box][0]): # 二合一编号(0开始) pos_two = ads.two_start + ads.two_len * i # print('two', data_modbus[pos_two + ads.pos_name], (box+1) * 256 + i+1) if data_modbus[pos_two + ads.pos_name] == ( box + 1) * 256 + ads.two_start + i + 1: data_db = { 'name': '{:0>2d}{:0>2d}{:0>2d}'.format( bus, box + 1, ads.two_start + i + 1), 'two_in_one': { ads.two_type[j]: data_modbus[pos_two + ads.pos_data + j] * ads.two_carry[j] for j in range(2) }, 'datetime': datetime.now() } else: data_db = { 'name': '{:0>2d}{:0>2d}{:0>2d}'.format( bus, box + 1, ads.two_start + i + 1), 'data': data_modbus, 'err': 'Unexpected Data Received', 'datetime': datetime.now() } result = collection.insert_one(data_db) # data_all.append(data_db) for i in range(ads.box_num[box][1]): # 六合一编号 pos_six = ads.six_start * ads.two_len + ads.six_len * i # print('six', data_modbus[pos_six + ads.pos_name], (box+1) * 256 + ads.six_start+i + ads.six_bios+1) if data_modbus[pos_six + ads.pos_name] == ( box + 1) * 256 + ads.six_start + i + ads.six_bios + 1: data_db = { 'name': '{:0>2d}{:0>2d}{:0>2d}'.format( bus, box + 1, ads.six_start + i + 1), 'six_in_one': { ads.six_type[j]: data_modbus[pos_six + ads.pos_data + j] * ads.six_carry[j] for j in range(6) }, 'datetime': datetime.now() } else: data_db = { 'name': '{:0>2d}{:0>2d}{:0>2d}'.format( bus, box + 1, ads.six_start + i + 1), 'data': data_modbus, 'err': 'Unexpected Data Received', 'datetime': datetime.now() } result = collection.insert_one(data_db) # data_all.append(data_db) # await asyncio.sleep(1) client.close() DBclient.close() log.info('Time Consuming: ' + str(time() - t)) except Exception as e: # log.exception(e) client.close() DBclient.close() log.error(e) log.info('Time Consuming: ' + str(time() - t))
class KSEM: def __init__(self, ip): self.client = ModbusTcpClient(ip, port="502") self.client.connect() def ReadUInt32(self,addr): data=self.client.read_holding_registers(addr, 2, unit=71) UInt32register = BinaryPayloadDecoder.fromRegisters(data.registers, byteorder=Endian.Big, wordorder=Endian.Big) 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.Big) result = Int32register.decode_32bit_int() 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.Big) result = UInt64register.decode_64bit_uint() return(result) def write(self, filename, value): # print(filename + ": " + str(value)) f = open(filename, 'w') f.write(str(value)) f.close def run(self): voltage1 = self.ReadUInt32(62) * 0.001 self.write('/var/www/html/openWB/ramdisk/evuv1', voltage1) voltage2 = self.ReadUInt32(102) * 0.001 self.write('/var/www/html/openWB/ramdisk/evuv2', voltage2) voltage3 = self.ReadUInt32(142) * 0.001 self.write('/var/www/html/openWB/ramdisk/evuv3', voltage3) bezugkwh = self.ReadUInt64(512) * 0.1 * 0.001 self.write('/var/www/html/openWB/ramdisk/bezugkwh', bezugkwh) bezugw1p = self.ReadUInt32(40) * 0.1 bezugw1m = self.ReadUInt32(42) * 0.1 bezugw1 = bezugw1p if bezugw1p >= bezugw1m else -bezugw1m self.write('/var/www/html/openWB/ramdisk/bezugw1', bezugw1) bezugw2p = self.ReadUInt32(80) * 0.1 bezugw2m = self.ReadUInt32(82) * 0.1 bezugw2 = bezugw2p if bezugw2p >= bezugw2m else -bezugw2m self.write('/var/www/html/openWB/ramdisk/bezugw2', bezugw2) bezugw3p = self.ReadUInt32(120) * 0.1 bezugw3m = self.ReadUInt32(122) * 0.1 bezugw3 = bezugw3p if bezugw3p >= bezugw3m else -bezugw3m self.write('/var/www/html/openWB/ramdisk/bezugw3', bezugw3) bezuga1 = self.ReadUInt32(60) * 0.001 self.write('/var/www/html/openWB/ramdisk/bezuga1', bezuga1) bezuga2 = self.ReadUInt32(100) * 0.001 self.write('/var/www/html/openWB/ramdisk/bezuga2', bezuga2) bezuga3 = self.ReadUInt32(140) * 0.001 self.write('/var/www/html/openWB/ramdisk/bezuga3', bezuga3) wattbezugp = self.ReadUInt32(0) * 0.1 wattbezugm = self.ReadUInt32(2) * 0.1 wattbezug = wattbezugp if wattbezugp >= wattbezugm else -wattbezugm finalwattbezug = int(wattbezug) self.write('/var/www/html/openWB/ramdisk/wattbezug', finalwattbezug) einspeisungkwh = self.ReadUInt64(516) * 0.1 * 0.001 self.write('/var/www/html/openWB/ramdisk/einspeisungkwh', einspeisungkwh) evuhz = self.ReadUInt32(26) * 0.001 self.write('/var/www/html/openWB/ramdisk/evuhz', evuhz) evupf1 = self.ReadInt32(64) * 0.001 self.write('/var/www/html/openWB/ramdisk/evupf1', evupf1) evupf2 = self.ReadInt32(104) * 0.001 self.write('/var/www/html/openWB/ramdisk/evupf2', evupf2) evupf3 = self.ReadInt32(144) * 0.001 self.write('/var/www/html/openWB/ramdisk/evupf3', evupf3)
host = '192.168.30.150' port = '502' client1 = ModbusTcpClient(host, port) host2 = '192.168.30.177' client2 = ModbusTcpClient(host2, port) while True: check = ping_reboot() ##LS-001 # host = '192.168.30.150' # port = '502' # client = ModbusTcpClient(host, port) client1.connect() reg_data = [] print 'client connection-------------------- ', client1.connect() for i in range(0, a): if i in [1, 27, 28, 29, 30]: read_holding_register(client1, 'int32', i) elif i in [2, 3, 17, 26]: read_holding_register(client1, 'int64', i) elif i in [31]: read_holding_register(client1, 'uint32', i) else: read_holding_register(client1, 'float32', i)
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
#!/usr/bin/python3 from pymodbus.client.sync import ModbusTcpClient import time import sys # Simulation eines PLCs (Siemens S7-1200) der die gewünschten Werte in einer Frequenz von 0,5Hz (2s) setzt modbus_ip = '10.0.0.42' register_values = [1, 1234, 56] client = ModbusTcpClient(modbus_ip) if not client.connect(): print("Der Modbus Server läuft nicht.") sys.exit(1) while True: client.write_registers(0, register_values) print("[PLC]: Setze die Werte {} auf Register 1 bis 3".format( register_values)) time.sleep(2)
#!/usr/bin/env python from pymodbus.client.sync import ModbusTcpClient as ModbusClient from pymodbus.transaction import ModbusRtuFramer import pymodbus import serial from pymodbus.pdu import ModbusRequest import logging FORMAT = ('%(asctime)-15s %(threadName)-15s ' '%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') logging.basicConfig(format=FORMAT) log = logging.getLogger() log.setLevel(logging.DEBUG) import paho.mqtt.client as mqtt import paho.mqtt.publish as publish import json, time import inspect client1 = ModbusClient('192.168.1.10', port=502, framer=ModbusRtuFramer) client1.connect() # client1.read_holding_registers(A, B , unit=C) #where A=Address of register(s), B=register number, unit=slave id rr0 = client1.read_holding_registers(1, 1, unit=1) print(rr0.registers)
def poll(self): types = { 'b': 1, 'B': 1, 'h': 1, 'H': 1, 'i': 2, 'I': 2, 'q': 4, 'Q': 4, 'f': 2, 'd': 4, 's': 0, 'c': 1 } measures = {} client = ModbusTcpClient(host=self.host, port=self.port, retries=self.retries, backoff=self.backoff, timeout=self.timeout, retry_on_empty=True, retry_on_invalid=True) if not client.connect(): logger.error("Cannot connect to bridge %s" % (self.host)) return None ut = time.time() for row in self.mapping: (name, descr, unit, datatype, rw, scale, offset, register) = row register = int(register) scale = float(scale) offset = float(offset) length = types.get(datatype) string = re.match(r'^s(\d*)$', datatype) if string: length = int(string.group(1)) >> 1 try: endian = Endian.Little if length >= 2: endian = Endian.Big result = client.read_holding_registers(register - 1, length, unit=self.slaveid) except ConnectionException as e: logger.error( "Error reading bridge %s slave %d register %d: %s" % (self.host, self.slaveid, register, str(e))) client.close() return None if type(result) == ExceptionResponse: logger.error( "Error reading bridge %s slave %d register %d: %s" % (self.host, self.slaveid, register, result)) client.close() return None if result.isError(): logger.error("Error reading bridge %s slave %d register %d" % (self.host, self.slaveid, register)) client.close() return None if datatype in ['h', 'H', 'i', 'I' ] and result.registers[0] == 0x8000: continue try: if string: value = decoder.decode_string(255).decode() measures[name] = value logger.debug( 'Modbus bridge: %s slave %s register %s (%s) value: %s' % (self.host, self.slaveid, register, name, value)) continue decoder = BinaryPayloadDecoder.fromRegisters( result.registers, byteorder=Endian.Big, wordorder=endian) if datatype == 'b': value = decoder.decode_8bit_int() if datatype == 'B': value = decoder.decode_8bit_uint() if datatype == 'h': value = decoder.decode_16bit_int() if datatype == 'H': value = decoder.decode_16bit_uint() if datatype == 'i': value = decoder.decode_32bit_int() if datatype == 'I': value = decoder.decode_32bit_uint() if datatype == 'q': value = decoder.decode_64bit_int() if datatype == 'Q': value = decoder.decode_64bit_uint() if datatype == 'f': value = decoder.decode_32bit_float() if datatype == 'd': value = decoder.decode_64bit_float() except (AttributeError, ValueError, struct.error): logger.error("Error reading bridge %s slave %d register %d" % (self.host, self.slaveid, register)) client.close() return None if math.isnan(value): continue measures[name] = round(value * scale, 8) + offset logger.debug( 'Modbus bridge: %s slave: %s register: %s (%s) value: %s %s' % (self.host, self.slaveid, register, name, measures[name], unit)) client.close() data = { 'ts': ut, 'client_id': self.clientid, 'device_id': self.deviceid, 'measures': measures } print(data) return data
parser.add_argument( '--op', required=True, choices=['r', 'w'], help='op type.') parser.add_argument( '--val', type=int, help='Wrtite value.') args = parser.parse_args() try: results = None if client.connect() == False: print("[ERROR] failed to connect.") sys.exit(0) if args.op == 'w': if args.fun == 'hr': rq = client.write_register(args.adr, args.val, unit=args.id) elif args.fun == 'co': rq = client.write_coil(args.adr, args.val, unit=args.id) print "Write function return code : " + str(rq.function_code) else : if args.fun == 'hr': rr = client.read_holding_registers(args.adr, args.qty, unit=args.id) if rr != None: results = rr.registers elif args.fun == 'ri':
from pymodbus.client.sync import ModbusTcpClient import timeit client = ModbusTcpClient('127.0.0.1', 5020) client.connect() def write(c): c.write_coil(1, False) c.read_coils(1, 1) print timeit.timeit(lambda: write(client), number=100) #result = client.read_coils(1,1) #print result.bits[0] client.close()
class SDM: model = "SDM" stopbits = 1 parity = "N" baud = 38400 registers = {} def __init__( self, host=False, port=False, device=False, stopbits=False, parity=False, baud=False, timeout=TIMEOUT, retries=RETRIES, unit=UNIT, parent=False ): if parent: self.client = parent.client self.mode = parent.mode self.timeout = parent.timeout self.retries = parent.retries if unit: self.unit = unit else: self.unit = parent.unit if self.mode is connectionType.RTU: self.device = parent.device self.stopbits = parent.stopbits self.parity = parent.parity self.baud = parent.baud elif self.mode is connectionType.TCP: self.host = parent.host self.port = parent.port else: raise NotImplementedError(self.mode) else: self.host = host self.port = port self.device = device if stopbits: self.stopbits = stopbits if (parity and parity.upper() in ["N", "E", "O"]): self.parity = parity.upper() else: self.parity = False if baud: self.baud = baud self.timeout = timeout self.retries = retries self.unit = unit if device: self.mode = connectionType.RTU self.client = ModbusSerialClient( method="rtu", port=self.device, stopbits=self.stopbits, parity=self.parity, baudrate=self.baud, timeout=self.timeout) else: self.mode = connectionType.TCP self.client = ModbusTcpClient( host=self.host, port=self.port, timeout=self.timeout ) def __repr__(self): if self.mode == connectionType.RTU: return f"{self.model}({self.device}, {self.mode}: stopbits={self.stopbits}, parity={self.parity}, baud={self.baud}, timeout={self.timeout}, retries={self.retries}, unit={hex(self.unit)})" elif self.mode == connectionType.TCP: return f"{self.model}({self.host}:{self.port}, {self.mode}: timeout={self.timeout}, retries={self.retries}, unit={hex(self.unit)})" else: return f"<{self.__class__.__module__}.{self.__class__.__name__} object at {hex(id(self))}>" def _read_input_registers(self, address, length): for i in range(self.retries): if not self.connected(): self.connect() time.sleep(0.1) continue result = self.client.read_input_registers(address=address, count=length, unit=self.unit) if not isinstance(result, ReadInputRegistersResponse): continue if len(result.registers) != length: continue return BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=Endian.Big, wordorder=Endian.Big) return None def _read_holding_registers(self, address, length): for i in range(self.retries): if not self.connected(): self.connect() time.sleep(0.1) continue result = self.client.read_holding_registers(address=address, count=length, unit=self.unit) if not isinstance(result, ReadHoldingRegistersResponse): continue if len(result.registers) != length: continue return BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=Endian.Big, wordorder=Endian.Big) return None def _write_holding_register(self, address, value): return self.client.write_registers(address=address, values=value, unit=self.unit) def _encode_value(self, data, dtype): builder = BinaryPayloadBuilder(byteorder=Endian.Big, wordorder=Endian.Big) try: if dtype == registerDataType.FLOAT32: builder.add_32bit_float(data) else: raise NotImplementedError(dtype) except NotImplementedError: raise return builder.to_registers() def _decode_value(self, data, length, dtype, vtype): try: if dtype == registerDataType.FLOAT32: return vtype(data.decode_32bit_float()) else: raise NotImplementedError(dtype) except NotImplementedError: raise def _read(self, value): address, length, rtype, dtype, vtype, label, fmt, batch = value try: if rtype == registerType.INPUT: return self._decode_value(self._read_input_registers(address, length), length, dtype, vtype) elif rtype == registerType.HOLDING: return self._decode_value(self._read_holding_registers(address, length), length, dtype, vtype) else: raise NotImplementedError(rtype) except NotImplementedError: raise def _read_all(self, values, rtype): addr_min = False addr_max = False for k, v in values.items(): v_addr = v[0] v_length = v[1] if addr_min is False: addr_min = v_addr if addr_max is False: addr_max = v_addr + v_length if v_addr < addr_min: addr_min = v_addr if (v_addr + v_length) > addr_max: addr_max = v_addr + v_length results = {} offset = addr_min length = addr_max - addr_min try: if rtype == registerType.INPUT: data = self._read_input_registers(offset, length) elif rtype == registerType.HOLDING: data = self._read_holding_registers(offset, length) else: raise NotImplementedError(rtype) if not data: return results for k, v in values.items(): address, length, rtype, dtype, vtype, label, fmt, batch = v if address > offset: skip_bytes = address - offset offset += skip_bytes data.skip_bytes(skip_bytes * 2) results[k] = self._decode_value(data, length, dtype, vtype) offset += length except NotImplementedError: raise return results def _write(self, value, data): address, length, rtype, dtype, vtype, label, fmt, batch = value try: if rtype == registerType.HOLDING: return self._write_holding_register(address, self._encode_value(data, dtype)) else: raise NotImplementedError(rtype) except NotImplementedError: raise def connect(self): return self.client.connect() def disconnect(self): self.client.close() def connected(self): return self.client.is_socket_open() def read(self, key): if key not in self.registers: raise KeyError(key) return self._read(self.registers[key]) def write(self, key, data): if key not in self.registers: raise KeyError(key) return self._write(self.registers[key], data) def read_all(self, rtype=registerType.INPUT): registers = {k: v for k, v in self.registers.items() if (v[2] == rtype)} results = {} for batch in range(1, len(registers)): register_batch = {k: v for k, v in registers.items() if (v[7] == batch)} if not register_batch: break results.update(self._read_all(register_batch, rtype)) return results
#!/usr/bin/python import sys import os import time import getopt import socket import ConfigParser import struct import binascii from pymodbus.constants import Endian from pymodbus.payload import BinaryPayloadDecoder ipaddress = str(sys.argv[1]) from pymodbus.client.sync import ModbusTcpClient client = ModbusTcpClient(ipaddress, port=502) connection = client.connect() #grid power resp = client.read_holding_registers(2600, 1, unit=30) decoder = BinaryPayloadDecoder.fromRegisters(resp.registers, byteorder=Endian.Big, wordorder=Endian.Big) w1 = str(decoder.decode_16bit_int()) resp = client.read_holding_registers(2601, 1, unit=30) decoder = BinaryPayloadDecoder.fromRegisters(resp.registers, byteorder=Endian.Big, wordorder=Endian.Big) w2 = str(decoder.decode_16bit_int()) resp = client.read_holding_registers(2602, 1, unit=30) decoder = BinaryPayloadDecoder.fromRegisters(resp.registers, byteorder=Endian.Big, wordorder=Endian.Big)
class VisualizerApp(Ui_MainWindow): def __init__(self, main_window): self.setupUi(main_window) self.connect_slots() self.init_poll_table() self.update_poll_table_column_headers() self.configure_modbus_client() self.connected = False def connect_slots(self): self.singlePollPushButton.clicked.connect(self.single_poll) self.startRegisterSpinBox.valueChanged.connect( self.update_poll_table_column_headers) def init_poll_table(self): """ Initialize the table with QTableWidgetItem objects that are empty strings. """ num_rows = self.pollTable.rowCount() num_cols = self.pollTable.columnCount() for j in range(num_cols): for i in range(num_rows): self.pollTable.setItem(i, j, QTableWidgetItem("")) def update_poll_table_column_headers(self): self.clear_poll_table() # Avoids confusion start = self.startRegisterSpinBox.value() num_cols = self.pollTable.columnCount() num_rows = self.pollTable.rowCount() for i in range(num_cols): self.pollTable.horizontalHeaderItem(i).setText( str(start + i * num_rows)) def clear_poll_table(self): num_rows = self.pollTable.rowCount() num_cols = self.pollTable.columnCount() for j in range(num_cols): for i in range(num_rows): self.pollTable.item(i, j).setText("") def write_poll_table(self, data): self.clear_poll_table() num_rows = self.pollTable.rowCount() cur_col = 0 for i, datum in enumerate(data): self.pollTable.item(i % 10, cur_col).setText(str(datum)) #self.pollTable.setItem(i % 10, cur_col, QTableWidgetItem(str(datum))) if (i + 1) % num_rows == 0: cur_col += 1 def configure_modbus_client(self): tcp_mode = self.tcpRadioButton.isChecked() rtu_mode = self.rtuRadioButton.isChecked() if rtu_mode: pass elif tcp_mode: host = self.tcpHostLineEdit.text() port = self.tcpPortLineEdit.text() self.client = ModbusTcpClient(host, port) self.connected = self.client.connect() if not self.connected: self.write_console("Could not connect.") else: self.write_console("Connection Successful.") def single_poll(self): data = self.poll_modbus_data() self.write_poll_table(data) if data: self.write_console("Poll Successful") def poll_modbus_data(self): self.configure_modbus_client() if not self.connected: return [] start = self.startRegisterSpinBox.value() length = self.numberOfRegistersSpinBox.value() register_type = self.registerTypeComboBox.currentText() if register_type == "Coils": rr = self.client.read_coils(start, length) data = rr.bits[:length] elif register_type == "Discrete Inputs": rr = self.client.read_discrete_inputs(start, length) data = rr.bits[:length] elif register_type == "Input Registers": rr = self.client.read_input_registers(start, length) data = rr.registers elif register_type == "Holding Registers": rr = self.client.read_holding_registers(start, length) data = rr.registers else: self.write_console("Unknown Register Type.") data = [] return data def write_console(self, msg): self.consoleLineEdit.setText(msg) def exit(self): QApplication.quit()
async def main(): if simulation==1: if ((GOVtotal+27)<(GOVsolicitado)): timeStamp = datetime.now() print(timeStamp) minutoActual=timeStamp.minute if 'minutoPasado' in locals(): print(minutoActual) print(minutoPasado) if (minutoActual-minutoPasado >= ventana): print('almacenar') minutoPasado=minutoActual else: print('no almacenar') else: print('inicio almacenar') minutoPasado=minutoActual flujoTR = flujoPreset + randrange(-3,3) GOVcomponente = GOVcomponente + flujoTR*(tiempoMuestreo/60) GOVtotal = GOVcomponente GSV = GOVtotal * factor time.sleep(tiempoMuestreo) #Esto lo modifiqué con mis variables servidor_driver_ucl = { "timestamp": listToString(timeStamp), "data": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", "config": { "version": 0.1, "tipo": "driver_ucl_rt", }, "ucl":{ "config": { "version": 0.1, "tipo": "ucl", "id_instrumentacion": "23", "nombre": "UCL 01", "producto1": "regular", "producto2": "premium" }, "servidor": { "online": True, }, "online_status": { "estado_en_espera": False, "estado_en_uso": True, }, "data_orden":{ "id_orden_actual": "23", "cantidad_programada": str(GOVsolicitado), "cantidad_componente": str(GOVcomponente), "cantidad_cargada": str(GOVtotal), "cantidad_restante": str(GOVtotal-GOVsolicitado), "cantidad_gsv": str(GSV), "unidad": "l", "producto": producto } }, "mdp":{ "config": { "version": 0.1, "tipo": "mdp", "id_instrumentacion": "23", }, "servidor": { "online": True, }, "online_status": { "estado_en_espera": False, "estado_en_uso": True }, "data": { "flujo": formato_flujo(str(flujoTR.registers[0])), "flujoPreset": str(flujoPreset.registers[0]), "unidad": "l/min", } }, "rtd":{ "config": { "version": 0.1, "tipo": "rtd", "id_instrumentacion": "26", }, "servidor": { "online": True, }, "online_status": { "estado_sensando": True }, "data": { "temperatura": formato_temperatura(str((temperaturaTRrgl.registers[0]/100)+(temperaturaTRprm.registers[0]/100))), "temperaturaAvg": str(temperaturaAvg.registers[0]), "unidad": "c", } }, "baumanometro":{ "config": { "version": 0.1, "tipo": "baumanometro", "id_instrumentacion": "36", }, "servidor": { "online": True, }, "online_status": { "estado_sensando": True }, "data": { "presion": str(presionTR.registers[0]), "presionPreset": str(presionPreset.registers[0]), "unidad": "kPa", } }, "densimetro":{ "config": { "version": 0.1, "tipo": "densimetro", "id_instrumentacion": "37", }, "servidor": { "online": True, }, "online_status": { "estado_sensando": True }, "data": { "densidadTR": str(densidadTR.registers[0]), "densidadComponent": str(densidadComponent.registers[0]), "unidad": "Kg m^3", } }, "caudalimetro":{ "config": { "version": 0.1, "tipo": "caudalimetro", "id_instrumentacion": "38", }, "servidor": { "online": True, }, "online_status": { "estado_sensando": True }, "data": { "masaTR": str(masaTR.registers[0]), "unidad": "s/u", } }, "bsw":{ "config": { "version": 0.1, "tipo": "bsw", "id_instrumentacion": "39", }, "servidor": { "online": True, }, "online_status": { "estado_sensando": True }, "data": { "BSWTR": str(BSWTR.registers[0]), "unidad": "s/u", } }, "gravidad":{ "config": { "version": 0.1, "tipo": "gravidad", "id_instrumentacion": "40", }, "servidor": { "online": True, }, "online_status": { "estado_sensando": True }, "data": { "gravidadTR": str(gravidadTR.registers[0]), "unidad": "s/u", } }, "kFactor":{ "config": { "version": 0.1, "tipo": "kFactor", "id_instrumentacion": "26", }, "servidor": { "online": True, }, "online_status": { "estado_sensando": True }, "data": { "kFactor": str(kFactor.registers[0]), "unidad": "adimensional", } }, "vcf":{ "config": { "version": 0.1, "tipo": "vcf", "id_instrumentacion": "12", }, "servidor": { "online": True, }, "data": { "estado_abierta": False, } }, # "vcf_descarga": { # "config": { # "version": 0.1, # "tipo": "vcf", # "id_instrumentacion": "12", # }, # "servidor": { # "online": True, # }, # "data": { # "estado_abierta": True, # } # }, "valvula_de_tanques":[ { "config": { "version": 0.1, "tipo": "vcf", "id_instrumentacion": "12", "producto": "regular" }, "servidor": { "online": True, }, "data": { "estado_abierta": True, } }, { "config": { "version": 0.1, "tipo": "vcf", "id": "12", "producto": "premium" }, "servidor": { "online": True, }, "data": { "estado_abierta": True, } }, # { # "config": { # "version": 0.1, # "tipo": "vcf", # "id": "12", # "producto": "diesel" # }, # "servidor": { # "online": True, # }, # "data": { # "estado_abierta": True, # } # } ], "permisivo_tierra":{ "config": { "version": 0.1, "tipo": "permisivo", "id_instrumentacion": "12", }, "servidor": { "online": True, }, "data": { "estado_activado": True, } }, "permisivo_sobrellenado":{ "config": { "version": 0.1, "tipo": "permisivo", "id_instrumentacion": "12", }, "servidor": { "online": True, }, "data": { "estado_activado": True, } } } json_txt = json.dumps( servidor_driver_ucl) print(json_txt) await conn.write_message(json_txt) await asyncio.sleep(0.5) else: try: conn = await websocket_connect(url) client=ModbusTcpClient('192.168.0.200') #client.connect() while 1: """ if client.connect(): #Fecha y hora timeStamp=client.read_holding_registers(0x0023,12,unit=1) #5.2.1. Preset quantity in whole units GOVsolicitado=client.read_holding_registers(4036,2,unit=1) #5.2.10. Component delivered gross quantity in whole units GOVcomponente=client.read_holding_registers(4372,2,unit=1) #5.2.8. Meter delivered gross quantity in whole units GOVtotal=client.read_holding_registers(4192,2,unit=1) #5.2.11. Component delivered net quantity in whole units GSV=client.read_holding_registers(4564,2,unit=1) #5.2.7. Preset gross flow rate in whole units flujoPreset=client.read_holding_registers(4180,2,unit=1) #5.2.9. Meter gross flow rate in whole units flujoTR=client.read_holding_registers(4312,2,unit=1) #5.2.13. Component batch average pressure in tenths or hundredths presionPreset=client.read_holding_registers(4948,2,unit=1) #5.2.16. Component current pressure in hundredths presionTR=client.read_holding_registers(4948,2,unit=1) #5.2.17. Component current density in tenths densidadTR=client.read_holding_registers(5716,2,unit=1) #5.2.14. Component batch average density/relative density/gravity densidadComponent=client.read_holding_registers(5140,2,unit=1) #5.2.15. Component current temp in hundredths temperaturaTRrgl=client.read_holding_registers(5332,2,unit=1) temperaturaTRprm=client.read_holding_registers(5334,2,unit=1) #5.2.4. Preset batch average temp in tenths or hundredths temperaturaAvg=client.read_holding_registers(4108,2,unit=1) #5.2.22. Component current mass delivered masaTR=client.read_holding_registers(6868,2,unit=1) #5.2.20. Component current BSW hund BSWTR=client.read_holding_registers(6484,2,unit=1) #5.2.22. Component current API gravity tenths gravidadTR=client.read_holding_registers(6676,2,unit=1) #Meter k-factor kFactor=client.read_holding_registers(1770,2,unit=1) if temperaturaTRprm.registers[0]!=0: producto="premium" else: producto="regular" else: timeStamp.registers[0]=[0,0] GOVsolicitado.registers[0]=0 GOVcomponente.registers[0]=0 GOVtotal.registers[0]=0 GSV.registers[0]=0 flujoPreset.registers[0]=0 flujoTR.registers[0]=0 presionPreset.registers[0]=0 presionTR.registers[0]=0 densidadTR.registers[0]=0 densidadComponent.registers[0]=0 temperaturaTRrgl.registers[0]=0 temperaturaTRprm.registers[0]=0 temperaturaAvg.registers[0]=0 masaTR.registers[0]=0 BSWTR.registers[0]=0 gravidadTR.registers[0]=0 kFactor.registers[0]=0 producto="regular" """ client.connect() #Fecha y hora timeStamp=client.read_holding_registers(0x0023,12,unit=1) #5.2.1. Preset quantity in whole units GOVsolicitado=client.read_holding_registers(4036,2,unit=1) #5.2.10. Component delivered gross quantity in whole units GOVcomponente=client.read_holding_registers(4372,2,unit=1) #5.2.8. Meter delivered gross quantity in whole units GOVtotal=client.read_holding_registers(4192,2,unit=1) #5.2.11. Component delivered net quantity in whole units GSV=client.read_holding_registers(4564,2,unit=1) #5.2.7. Preset gross flow rate in whole units flujoPreset=client.read_holding_registers(4180,2,unit=1) #5.2.9. Meter gross flow rate in whole units flujoTR=client.read_holding_registers(4312,2,unit=1) #5.2.13. Component batch average pressure in tenths or hundredths presionPreset=client.read_holding_registers(4948,2,unit=1) #5.2.16. Component current pressure in hundredths presionTR=client.read_holding_registers(4948,2,unit=1) #5.2.17. Component current density in tenths densidadTR=client.read_holding_registers(5716,2,unit=1) #5.2.14. Component batch average density/relative density/gravity densidadComponent=client.read_holding_registers(5140,2,unit=1) #5.2.15. Component current temp in hundredths temperaturaTRrgl=client.read_holding_registers(5332,2,unit=1) temperaturaTRprm=client.read_holding_registers(5334,2,unit=1) #5.2.4. Preset batch average temp in tenths or hundredths temperaturaAvg=client.read_holding_registers(4108,2,unit=1) #5.2.22. Component current mass delivered masaTR=client.read_holding_registers(6868,2,unit=1) #5.2.20. Component current BSW hund BSWTR=client.read_holding_registers(6484,2,unit=1) #5.2.22. Component current API gravity tenths gravidadTR=client.read_holding_registers(6676,2,unit=1) #Meter k-factor kFactor=client.read_holding_registers(1770,2,unit=1) if temperaturaTRprm.registers[0]!=0: producto="premium" else: producto="regular" #Esto lo modifiqué con mis variables servidor_driver_ucl = { "timestamp": listToString(timeStamp.registers), "data": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", "config": { "version": 0.1, "tipo": "driver_ucl_rt", }, "ucl":{ "config": { "version": 0.1, "tipo": "ucl", "id_instrumentacion": "23", "nombre": "UCL 01", "producto1": "regular", "producto2": "premium" }, "servidor": { "online": True, }, "online_status": { "estado_en_espera": False, "estado_en_uso": True, }, "data_orden":{ "id_orden_actual": "23", "cantidad_programada": str(GOVsolicitado.registers[0]), "cantidad_componente": str(GOVcomponente.registers[0]), "cantidad_cargada": str(GOVtotal.registers[0]), "cantidad_restante": str(GOVtotal.registers[0]-GOVsolicitado.registers[0]), "cantidad_gsv": str(GSV.registers[0]), "unidad": "l", "producto": producto } }, "mdp":{ "config": { "version": 0.1, "tipo": "mdp", "id_instrumentacion": "23", }, "servidor": { "online": True, }, "online_status": { "estado_en_espera": False, "estado_en_uso": True }, "data": { "flujo": formato_flujo(str(flujoTR.registers[0])), "flujoPreset": str(flujoPreset.registers[0]), "unidad": "l/min", } }, "rtd":{ "config": { "version": 0.1, "tipo": "rtd", "id_instrumentacion": "26", }, "servidor": { "online": True, }, "online_status": { "estado_sensando": True }, "data": { "temperatura": formato_temperatura(str((temperaturaTRrgl.registers[0]/100)+(temperaturaTRprm.registers[0]/100))), "temperaturaAvg": str(temperaturaAvg.registers[0]), "unidad": "c", } }, "baumanometro":{ "config": { "version": 0.1, "tipo": "baumanometro", "id_instrumentacion": "36", }, "servidor": { "online": True, }, "online_status": { "estado_sensando": True }, "data": { "presion": str(presionTR.registers[0]), "presionPreset": str(presionPreset.registers[0]), "unidad": "kPa", } }, "densimetro":{ "config": { "version": 0.1, "tipo": "densimetro", "id_instrumentacion": "37", }, "servidor": { "online": True, }, "online_status": { "estado_sensando": True }, "data": { "densidadTR": str(densidadTR.registers[0]), "densidadComponent": str(densidadComponent.registers[0]), "unidad": "Kg m^3", } }, "caudalimetro":{ "config": { "version": 0.1, "tipo": "caudalimetro", "id_instrumentacion": "38", }, "servidor": { "online": True, }, "online_status": { "estado_sensando": True }, "data": { "masaTR": str(masaTR.registers[0]), "unidad": "s/u", } }, "bsw":{ "config": { "version": 0.1, "tipo": "bsw", "id_instrumentacion": "39", }, "servidor": { "online": True, }, "online_status": { "estado_sensando": True }, "data": { "BSWTR": str(BSWTR.registers[0]), "unidad": "s/u", } }, "gravidad":{ "config": { "version": 0.1, "tipo": "gravidad", "id_instrumentacion": "40", }, "servidor": { "online": True, }, "online_status": { "estado_sensando": True }, "data": { "gravidadTR": str(gravidadTR.registers[0]), "unidad": "s/u", } }, "kFactor":{ "config": { "version": 0.1, "tipo": "kFactor", "id_instrumentacion": "26", }, "servidor": { "online": True, }, "online_status": { "estado_sensando": True }, "data": { "kFactor": str(kFactor.registers[0]), "unidad": "adimensional", } }, "vcf":{ "config": { "version": 0.1, "tipo": "vcf", "id_instrumentacion": "12", }, "servidor": { "online": True, }, "data": { "estado_abierta": False, } }, # "vcf_descarga": { # "config": { # "version": 0.1, # "tipo": "vcf", # "id_instrumentacion": "12", # }, # "servidor": { # "online": True, # }, # "data": { # "estado_abierta": True, # } # }, "valvula_de_tanques":[ { "config": { "version": 0.1, "tipo": "vcf", "id_instrumentacion": "12", "producto": "regular" }, "servidor": { "online": True, }, "data": { "estado_abierta": True, } }, { "config": { "version": 0.1, "tipo": "vcf", "id": "12", "producto": "premium" }, "servidor": { "online": True, }, "data": { "estado_abierta": True, } }, # { # "config": { # "version": 0.1, # "tipo": "vcf", # "id": "12", # "producto": "diesel" # }, # "servidor": { # "online": True, # }, # "data": { # "estado_abierta": True, # } # } ], "permisivo_tierra":{ "config": { "version": 0.1, "tipo": "permisivo", "id_instrumentacion": "12", }, "servidor": { "online": True, }, "data": { "estado_activado": True, } }, "permisivo_sobrellenado":{ "config": { "version": 0.1, "tipo": "permisivo", "id_instrumentacion": "12", }, "servidor": { "online": True, }, "data": { "estado_activado": True, } } } json_txt = json.dumps( servidor_driver_ucl) await conn.write_message(json_txt) await asyncio.sleep(0.5) client.close() except ConnectionRefusedError: print('error: ConnectionRefusedError') sys.exit(1) except TimeoutError: print('error: TimeoutError') sys.exit(1) print('done') sys.exit(0)
class TPLC: def __init__(self): super().__init__() IP = "192.168.137.62" PORT = 502 self.Client = ModbusTcpClient(IP, port=PORT) self.Connected = self.Client.connect() print("TPLC connected: " + str(self.Connected)) self.nRTD = 8 self.RTD = [0.] * self.nRTD self.RTD_setting = [0.] * self.nRTD self.nAttribute = [0.] * self.nRTD # self.PT80 = 0. # self.FlowValve = 0. # self.BottomChillerSetpoint = 0. # self.BottomChillerTemp = 0. # self.BottomChillerState = 0 # self.BottomChillerPowerReset = 0 # self.TopChillerSetpoint = 0. # self.TopChillerTemp = 0. # self.TopChillerState = 0 # self.CameraChillerSetpoint = 0. # self.CameraChillerTemp = 0. # self.CameraChillerState = 0 # self.WaterChillerSetpoint = 0. # self.WaterChillerTemp = 0. # self.WaterChillerPressure = 0. # self.WaterChillerState = 0 # self.InnerPower = 0. # self.OuterClosePower = 0. # self.OuterFarPower = 0. # self.FreonPower = 0. # self.ColdRegionSetpoint = 0. # self.HotRegionSetpoint = 0. # self.HotRegionP = 0. # self.HotRegionI = 0. # self.HotRegionD = 0. # self.ColdRegionP = 0. # self.ColdRegionI = 0. # self.ColdRegionD = 0. # self.HotRegionPIDState = 0 # self.ClodRegionPIDState = 0 # self.Camera0Temp = 0. # self.Camera0Humidity = 0. # self.Camera0AirTemp = 0. # self.Camera1Temp = 0. # self.Camera1Humidity = 0. # self.Camera1AirTemp = 0. # self.Camera2Temp = 0. # self.Camera2Humidity = 0. # self.Camera2AirTemp = 0. # self.Camera3Temp = 0. # self.Camera3Humidity = 0. # self.Camera3AirTemp = 0. # self.WaterFlow = 0. # self.WaterTemp = 0. # self.WaterConductivityBefore = 0. # self.WaterConductivityAfter = 0. # self.WaterPressure = 0. # self.WaterLevel = 0. # self.WaterPrimingPower = 0 # self.WaterPrimingStatus = 0 # self.BeetleStatus = 0 self.LiveCounter = 0 self.NewData_Display = False self.NewData_Database = False def __del__(self): self.Client.close() def ReadAll(self): if self.Connected: # Reading all the RTDs Raw = self.Client.read_holding_registers(38000, count=self.nRTD * 2, unit=0x01) # RTD_setting = self.Client.read_holding_registers(18002, count=1, unit=0x01) for i in range(0, self.nRTD): self.RTD[i] = round( struct.unpack( "<f", struct.pack("<HH", Raw.getRegister((2 * i) + 1), Raw.getRegister(2 * i)))[0], 3) # print("Updating TPLC", i, "RTD",self.RTD[i]) Attribute = [0.] * self.nRTD for i in range(0, self.nRTD): Attribute[i] = self.Client.read_holding_registers(18000 + i * 8, count=1, unit=0x01) self.nAttribute[i] = hex(Attribute[i].getRegister(0)) # print("Attributes", self.nAttribute) # PT80 (Cold Vacuum Conduit Pressure) # Raw = self.Client.read_holding_registers(0xA0, count = 2, unit = 0x01) # self.PT80 = round(struct.unpack("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 7) # # Flow valve # Raw = self.Client.read_holding_registers(0x, count = 2, unit = 0x01) # self.FlowValve = round(struct.unpack("<f", struct.pack("<HH", Raw.getRegister(1), # Raw.getRegister(0)))[0], 0) # Bottom chiller # Raw = self.Client.read_holding_registers(0xA8, count = 4, unit = 0x01) # self.BottomChillerSetpoint = round(struct.unpack("<f", struct.pack # ("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 1) # self.BottomChillerTemp = round(struct.unpack("<f", struct.pack # ("<HH", Raw.getRegister(3), Raw.getRegister(2)))[0], 2) # Raw = self.Client.read_coils(0x10, count = 1, unit = 0x01) # self.BottomChillerState = Raw.bits[0] # self.BottomChillerPowerReset = Raw.bits[0] # Top chiller # Raw = self.Client.read_holding_registers(0xB0, count = 4, unit = 0x01) # self.TopChillerSetpoint = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 1) # self.TopChillerTemp = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(3), Raw.getRegister(2)))[0], 2) # Raw = self.Client.read_coils(0x13, count = 1, unit = 0x01) # self.TopChillerState = Raw.bits[0] # Camera chiller # Raw = self.Client.read_holding_registers(0xBA, count = 4, unit = 0x01) # self.CameraChillerSetpoint = round(struct.unpack("<f", struct.pack # ("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 1) # self.CameraChillerTemp = round(struct.unpack("<f", struct.pack # ("<HH", Raw.getRegister(3), Raw.getRegister(2)))[0], 2) # Raw = self.Client.read_coils(0x15, count = 1, unit = 0x01) # self.CameraChillerState = Raw.bits[0] # Water chiller # Raw = self.Client.read_holding_registers(0xC4, count = 4, unit = 0x01) # self.WaterChillerSetpoint = round(struct.unpack("<f", struct.pack # ("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 1) # self.WaterChillerTemp = round(struct.unpack("<f", struct.pack # ("<HH", Raw.getRegister(3), Raw.getRegister(2)))[0], 2) # self.WaterChillerPressure = round(struct.unpack("<f", struct.pack # ("<HH", Raw.getRegister(3), Raw.getRegister(2)))[0], 2) # Raw = self.Client.read_coils(0x17, count = 1, unit = 0x01) # self.WaterChillerState = Raw.bits[0] # Heaters # Raw = self.Client.read_holding_registers(0xC8, count = 8, unit = 0x01) # self.InnerPower = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 1) # self.OuterClosePower = round(struct.unpack("<f", struct.pack # ("<HH", Raw.getRegister(3), Raw.getRegister(2)))[0], 1) # self.OuterFarPower = round(struct.unpack("<f", struct.pack # ("<HH", Raw.getRegister(5), Raw.getRegister(4)))[0], 1) # self.FreonPower = round(struct.unpack("<f", struct.pack # ("<HH", Raw.getRegister(7), Raw.getRegister(6)))[0], 1) # Hot/cold region # Raw = self.Client.read_holding_registers(0xD0, count = 4, unit = 0x01) # self.ColdRegionSetpoint = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 1) # self.HotRegionSetpoint = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(3), Raw.getRegister(2)))[0], 1) # self.HotRegionP = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(3), Raw.getRegister(2)))[0], 2) # self.HotRegionI = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(3), Raw.getRegister(2)))[0], 2) # self.HotRegionD = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(3), Raw.getRegister(2)))[0], 2) # self.ColdRegionP = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(3), Raw.getRegister(2)))[0], 2) # self.ColdRegionI = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(3), Raw.getRegister(2)))[0], 2) # self.ColdRegionD = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(3), Raw.getRegister(2)))[0], 2) # Raw = self.Client.read_coils(0x19, count = 1, unit = 0x01) # self.HotRegionPIDState = Raw.bits[0] # self.ClodRegionPIDState = Raw.bits[0] # Cameras # Raw = self.Client.read_holding_registers(0x, count = 24, unit = 0x01) # self.Camera0Temp = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 2) # self.Camera0Humidity = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 1) # self.Camera0AirTemp = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 2) # self.Camera1Temp = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 2) # self.Camera1Humidity = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 1) # self.Camera1AirTemp = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 2) # self.Camera2Temp = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 2) # self.Camera2Humidity = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 1) # self.Camera2AirTemp = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 2) # self.Camera3Temp = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 2) # self.Camera3Humidity = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 1) # self.Camera3AirTemp = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 2) # Water system # Raw = self.Client.read_holding_registers(0x, count = 12, unit = 0x01) # self.WaterFlow = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 2) # self.WaterTemp = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 2) # self.WaterConductivityBefore = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 2) # self.WaterConductivityAfter = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 2) # self.WaterPressure = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 2) # self.WaterLevel = round(struct.unpack # ("<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 2) # Raw = self.Client.read_coils(0x, count = 1, unit = 0x01) # self.WaterPrimingPower = Raw.bits[0] # self.WaterPrimingStatus = Raw.bits[1] # self.BeetleStatus = Raw.bits[2] # PLC Raw = self.Client.read_holding_registers(0x3E9, count=1, unit=0x01) self.LiveCounter = Raw.getRegister(0) self.NewData_Display = True self.NewData_Database = True return 0 else: return 1 def SaveSetting(self): self.WriteBool(0x0, 0, 1) return 0 # There is no way to know if it worked... Cross your fingers! def SetFlowValve(self, value): return self.WriteFloat(0x0, value) def SetBottomChillerSetpoint(self, value): return self.WriteFloat(0x0, value) def SetBottomChillerState(self, State): if State == "Off": value = 0 elif State == "On": value = 1 else: print("State is either on or off in string format.") value = None return self.WriteBool(0x0, 0, value) def SetBottomChillerPowerReset(self, State): if State == "Off": value = 0 elif State == "On": value = 1 else: print("State is either on or off in string format.") value = None return self.WriteBool(0x0, 0, value) def SetTopChillerSetpoint(self, value): return self.WriteFloat(0x0, value) def SetTopChillerState(self, State): if State == "Off": value = 0 elif State == "On": value = 1 else: print("State is either on or off in string format.") value = None return self.WriteBool(0x0, 0, value) def SetCameraChillerSetpoint(self, value): return self.WriteFloat(0x0, value) def SetCameraChillerState(self, State): if State == "Off": value = 0 elif State == "On": value = 1 else: print("State is either on or off in string format.") value = None return self.WriteBool(0x0, 0, value) def SetWaterChillerSetpoint(self, value): return self.WriteFloat(0x0, value) def SetWaterChillerState(self, State): if State == "Off": value = 0 elif State == "On": value = 1 else: print("State is either on or off in string format.") value = None return self.WriteBool(0x0, 0, value) def SetInnerPower(self, value): return self.WriteFloat(0x0, value) def SetOuterClosePower(self, value): return self.WriteFloat(0x0, value) def SetOuterFarPower(self, value): return self.WriteFloat(0x0, value) def SetFreonPower(self, value): return self.WriteFloat(0x0, value) def SetInnerPowerState(self, State): if State == "Off": self.WriteBool(0x0, 0, 1) elif State == "On": self.WriteBool(0x0, 0, 1) return 0 # There is no way to know if it worked... Cross your fingers! def SetOuterClosePowerState(self, State): if State == "Off": self.WriteBool(0x0, 0, 1) elif State == "On": self.WriteBool(0x0, 0, 1) return 0 # There is no way to know if it worked... Cross your fingers! def SetOuterFarPowerState(self, State): if State == "Off": self.WriteBool(0x0, 0, 1) elif State == "On": self.WriteBool(0x0, 0, 1) return 0 # There is no way to know if it worked... Cross your fingers! def SetFreonPowerState(self, State): if State == "Off": self.WriteBool(0x0, 0, 1) elif State == "On": self.WriteBool(0x0, 0, 1) return 0 # There is no way to know if it worked... Cross your fingers! def SetColdRegionSetpoint(self, value): return self.WriteFloat(0x0, value) def SetHotRegionSetpoint(self, value): return self.WriteFloat(0x0, value) def SetHotRegionP(self, value): return self.WriteFloat(0x0, value) def SetHotRegionI(self, value): return self.WriteFloat(0x0, value) def SetHotRegionD(self, value): return self.WriteFloat(0x0, value) def SetColdRegionP(self, value): return self.WriteFloat(0x0, value) def SetColdRegionI(self, value): return self.WriteFloat(0x0, value) def SetColdRegionD(self, value): return self.WriteFloat(0x0, value) def SetHotRegionPIDMode(self, Mode): if Mode == "Manual": value = 0 elif Mode == "Auto": value = 1 else: print("State is either on or off in string format.") value = None return self.WriteBool(0x0, 0, value) def SetColdRegionPIDMode(self, Mode): if Mode == "Manual": value = 0 elif Mode == "Auto": value = 1 else: print("State is either on or off in string format.") value = None return self.WriteBool(0x0, 0, value) def SetWaterPrimingPower(self, State): if State == "Off": value = 0 elif State == "On": value = 1 else: print("State is either on or off in string format.") value = None return self.WriteBool(0x0, 0, value) def WriteFloat(self, Address, value): if self.Connected: value = round(value, 3) Dummy = self.Client.write_register(Address, struct.unpack( "<HH", struct.pack("<f", value))[1], unit=0x01) Dummy = self.Client.write_register(Address + 1, struct.unpack( "<HH", struct.pack("<f", value))[0], unit=0x01) time.sleep(1) Raw = self.Client.read_holding_registers(Address, count=2, unit=0x01) rvalue = round( struct.unpack( "<f", struct.pack("<HH", Raw.getRegister(1), Raw.getRegister(0)))[0], 3) if value == rvalue: return 0 else: return 2 else: return 1 def WriteBool(self, Address, Bit, value): if self.Connected: Raw = self.Client.read_coils(Address, count=Bit, unit=0x01) Raw.bits[Bit] = value Dummy = self.Client.write_coil(Address, Raw, unit=0x01) time.sleep(1) Raw = self.Client.read_coils(Address, count=Bit, unit=0x01) rvalue = Raw.bits[Bit] if value == rvalue: return 0 else: return 2 else: return 1
class SolaredgeModbusHub: """Thread safe wrapper class for pymodbus.""" def __init__( self, hass, name, host, port, scan_interval, read_meter1=False, read_meter2=False, read_meter3=False, ): """Initialize the Modbus hub.""" self._hass = hass self._client = ModbusTcpClient(host=host, port=port) self._lock = threading.Lock() self._name = name self.read_meter1 = read_meter1 self.read_meter2 = read_meter2 self.read_meter3 = read_meter3 self._scan_interval = timedelta(seconds=scan_interval) self._unsub_interval_method = None self._sensors = [] self.data = {} @callback def async_add_solaredge_sensor(self, update_callback): """Listen for data updates.""" # This is the first sensor, set up interval. if not self._sensors: self.connect() self._unsub_interval_method = async_track_time_interval( self._hass, self.async_refresh_modbus_data, self._scan_interval ) self._sensors.append(update_callback) @callback def async_remove_solaredge_sensor(self, update_callback): """Remove data update.""" self._sensors.remove(update_callback) if not self._sensors: """stop the interval timer upon removal of last sensor""" self._unsub_interval_method() self._unsub_interval_method = None self.close() async def async_refresh_modbus_data(self, _now: Optional[int] = None) -> None: """Time to update.""" if not self._sensors: return update_result = self.read_modbus_data() if update_result: for update_callback in self._sensors: update_callback() @property def name(self): """Return the name of this hub.""" return self._name def close(self): """Disconnect client.""" with self._lock: self._client.close() def connect(self): """Connect client.""" with self._lock: self._client.connect() def read_holding_registers(self, unit, address, count): """Read holding registers.""" with self._lock: kwargs = {"unit": unit} if unit else {} return self._client.read_holding_registers(address, count, **kwargs) def calculate_value(self, value, sf): return value * 10 ** sf def read_modbus_data_stub(self): return ( self.read_modbus_data_inverter_stub() and self.read_modbus_data_meter1_stub() and self.read_modbus_data_meter2_stub() and self.read_modbus_data_meter3_stub() ) def read_modbus_data(self): return ( self.read_modbus_data_inverter() and self.read_modbus_data_meter1() and self.read_modbus_data_meter2() and self.read_modbus_data_meter3() ) def read_modbus_data_inverter_stub(self): self.data["accurrent"] = 1 self.data["accurrenta"] = 1 self.data["accurrentb"] = 1 self.data["accurrentc"] = 1 self.data["acvoltageab"] = 1 self.data["acvoltagebc"] = 1 self.data["acvoltageca"] = 1 self.data["acvoltagean"] = 1 self.data["acvoltagebn"] = 1 self.data["acvoltagecn"] = 1 self.data["acpower"] = 1 self.data["acfreq"] = 1 self.data["acva"] = 1 self.data["acvar"] = 1 self.data["acpf"] = 1 self.data["acenergy"] = 1 self.data["dccurrent"] = 1 self.data["dcvoltage"] = 1 self.data["dcpower"] = 1 self.data["tempsink"] = 1 self.data["status"] = 1 self.data["statusvendor"] = 1 return True def read_modbus_data_meter1_stub(self): return self.read_modbus_data_meter_stub("m1_") def read_modbus_data_meter2_stub(self): return self.read_modbus_data_meter_stub("m2_") def read_modbus_data_meter3_stub(self): return self.read_modbus_data_meter_stub("m3_") def read_modbus_data_meter_stub(self, meter_prefix): self.data[meter_prefix + "accurrent"] = 2 self.data[meter_prefix + "accurrenta"] = 2 self.data[meter_prefix + "accurrentb"] = 2 self.data[meter_prefix + "accurrentc"] = 2 self.data[meter_prefix + "acvoltageln"] = 2 self.data[meter_prefix + "acvoltagean"] = 2 self.data[meter_prefix + "acvoltagebn"] = 2 self.data[meter_prefix + "acvoltagecn"] = 2 self.data[meter_prefix + "acvoltagell"] = 2 self.data[meter_prefix + "acvoltageab"] = 2 self.data[meter_prefix + "acvoltagebc"] = 2 self.data[meter_prefix + "acvoltageca"] = 2 self.data[meter_prefix + "acfreq"] = 2 self.data[meter_prefix + "acpower"] = 2 self.data[meter_prefix + "acpowera"] = 2 self.data[meter_prefix + "acpowerb"] = 2 self.data[meter_prefix + "acpowerc"] = 2 self.data[meter_prefix + "acva"] = 2 self.data[meter_prefix + "acvaa"] = 2 self.data[meter_prefix + "acvab"] = 2 self.data[meter_prefix + "acvac"] = 2 self.data[meter_prefix + "acvar"] = 2 self.data[meter_prefix + "acvara"] = 2 self.data[meter_prefix + "acvarb"] = 2 self.data[meter_prefix + "acvarc"] = 2 self.data[meter_prefix + "acpf"] = 2 self.data[meter_prefix + "acpfa"] = 2 self.data[meter_prefix + "acpfb"] = 2 self.data[meter_prefix + "acpfc"] = 2 self.data[meter_prefix + "exported"] = 2 self.data[meter_prefix + "exporteda"] = 2 self.data[meter_prefix + "exportedb"] = 2 self.data[meter_prefix + "exportedc"] = 2 self.data[meter_prefix + "imported"] = 2 self.data[meter_prefix + "importeda"] = 2 self.data[meter_prefix + "importedb"] = 2 self.data[meter_prefix + "importedc"] = 2 self.data[meter_prefix + "exportedva"] = 2 self.data[meter_prefix + "exportedvaa"] = 2 self.data[meter_prefix + "exportedvab"] = 2 self.data[meter_prefix + "exportedvac"] = 2 self.data[meter_prefix + "importedva"] = 2 self.data[meter_prefix + "importedvaa"] = 2 self.data[meter_prefix + "importedvab"] = 2 self.data[meter_prefix + "importedvac"] = 2 self.data[meter_prefix + "importvarhq1"] = 2 self.data[meter_prefix + "importvarhq1a"] = 2 self.data[meter_prefix + "importvarhq1b"] = 2 self.data[meter_prefix + "importvarhq1c"] = 2 self.data[meter_prefix + "importvarhq2"] = 2 self.data[meter_prefix + "importvarhq2a"] = 2 self.data[meter_prefix + "importvarhq2b"] = 2 self.data[meter_prefix + "importvarhq2c"] = 2 self.data[meter_prefix + "importvarhq3"] = 2 self.data[meter_prefix + "importvarhq3a"] = 2 self.data[meter_prefix + "importvarhq3b"] = 2 self.data[meter_prefix + "importvarhq3c"] = 2 self.data[meter_prefix + "importvarhq4"] = 2 self.data[meter_prefix + "importvarhq4a"] = 2 self.data[meter_prefix + "importvarhq4b"] = 2 self.data[meter_prefix + "importvarhq4c"] = 2 return True def read_modbus_data_meter1(self): if not self.read_meter1: return True else: return self.read_modbus_data_meter("m1_", 40190) def read_modbus_data_meter2(self): if not self.read_meter2: return True else: return self.read_modbus_data_meter("m2_", 40364) def read_modbus_data_meter3(self): if not self.read_meter3: return True else: return self.read_modbus_data_meter("m3_", 40539) def read_modbus_data_meter(self, meter_prefix, start_address): """start reading meter data """ meter_data = self.read_holding_registers( unit=1, address=start_address, count=103 ) if not meter_data.isError(): decoder = BinaryPayloadDecoder.fromRegisters( meter_data.registers, byteorder=Endian.Big ) accurrent = decoder.decode_16bit_int() accurrenta = decoder.decode_16bit_int() accurrentb = decoder.decode_16bit_int() accurrentc = decoder.decode_16bit_int() accurrentsf = decoder.decode_16bit_int() accurrent = self.calculate_value(accurrent, accurrentsf) accurrenta = self.calculate_value(accurrenta, accurrentsf) accurrentb = self.calculate_value(accurrentb, accurrentsf) accurrentc = self.calculate_value(accurrentc, accurrentsf) self.data[meter_prefix + "accurrent"] = round(accurrent, abs(accurrentsf)) self.data[meter_prefix + "accurrenta"] = round(accurrenta, abs(accurrentsf)) self.data[meter_prefix + "accurrentb"] = round(accurrentb, abs(accurrentsf)) self.data[meter_prefix + "accurrentc"] = round(accurrentc, abs(accurrentsf)) acvoltageln = decoder.decode_16bit_int() acvoltagean = decoder.decode_16bit_int() acvoltagebn = decoder.decode_16bit_int() acvoltagecn = decoder.decode_16bit_int() acvoltagell = decoder.decode_16bit_int() acvoltageab = decoder.decode_16bit_int() acvoltagebc = decoder.decode_16bit_int() acvoltageca = decoder.decode_16bit_int() acvoltagesf = decoder.decode_16bit_int() acvoltageln = self.calculate_value(acvoltageln, acvoltagesf) acvoltagean = self.calculate_value(acvoltagean, acvoltagesf) acvoltagebn = self.calculate_value(acvoltagebn, acvoltagesf) acvoltagecn = self.calculate_value(acvoltagecn, acvoltagesf) acvoltagell = self.calculate_value(acvoltagell, acvoltagesf) acvoltageab = self.calculate_value(acvoltageab, acvoltagesf) acvoltagebc = self.calculate_value(acvoltagebc, acvoltagesf) acvoltageca = self.calculate_value(acvoltageca, acvoltagesf) self.data[meter_prefix + "acvoltageln"] = round( acvoltageln, abs(acvoltagesf) ) self.data[meter_prefix + "acvoltagean"] = round( acvoltagean, abs(acvoltagesf) ) self.data[meter_prefix + "acvoltagebn"] = round( acvoltagebn, abs(acvoltagesf) ) self.data[meter_prefix + "acvoltagecn"] = round( acvoltagecn, abs(acvoltagesf) ) self.data[meter_prefix + "acvoltagell"] = round( acvoltagell, abs(acvoltagesf) ) self.data[meter_prefix + "acvoltageab"] = round( acvoltageab, abs(acvoltagesf) ) self.data[meter_prefix + "acvoltagebc"] = round( acvoltagebc, abs(acvoltagesf) ) self.data[meter_prefix + "acvoltageca"] = round( acvoltageca, abs(acvoltagesf) ) acfreq = decoder.decode_16bit_int() acfreqsf = decoder.decode_16bit_int() acfreq = self.calculate_value(acfreq, acfreqsf) self.data[meter_prefix + "acfreq"] = round(acfreq, abs(acfreqsf)) acpower = decoder.decode_16bit_int() acpowera = decoder.decode_16bit_int() acpowerb = decoder.decode_16bit_int() acpowerc = decoder.decode_16bit_int() acpowersf = decoder.decode_16bit_int() acpower = self.calculate_value(acpower, acpowersf) acpowera = self.calculate_value(acpowera, acpowersf) acpowerb = self.calculate_value(acpowerb, acpowersf) acpowerc = self.calculate_value(acpowerc, acpowersf) self.data[meter_prefix + "acpower"] = round(acpower, abs(acpowersf)) self.data[meter_prefix + "acpowera"] = round(acpowera, abs(acpowersf)) self.data[meter_prefix + "acpowerb"] = round(acpowerb, abs(acpowersf)) self.data[meter_prefix + "acpowerc"] = round(acpowerc, abs(acpowersf)) acva = decoder.decode_16bit_int() acvaa = decoder.decode_16bit_int() acvab = decoder.decode_16bit_int() acvac = decoder.decode_16bit_int() acvasf = decoder.decode_16bit_int() acva = self.calculate_value(acva, acvasf) acvaa = self.calculate_value(acvaa, acvasf) acvab = self.calculate_value(acvab, acvasf) acvac = self.calculate_value(acvac, acvasf) self.data[meter_prefix + "acva"] = round(acva, abs(acvasf)) self.data[meter_prefix + "acvaa"] = round(acvaa, abs(acvasf)) self.data[meter_prefix + "acvab"] = round(acvab, abs(acvasf)) self.data[meter_prefix + "acvac"] = round(acvac, abs(acvasf)) acvar = decoder.decode_16bit_int() acvara = decoder.decode_16bit_int() acvarb = decoder.decode_16bit_int() acvarc = decoder.decode_16bit_int() acvarsf = decoder.decode_16bit_int() acvar = self.calculate_value(acvar, acvarsf) acvara = self.calculate_value(acvara, acvarsf) acvarb = self.calculate_value(acvarb, acvarsf) acvarc = self.calculate_value(acvarc, acvarsf) self.data[meter_prefix + "acvar"] = round(acvar, abs(acvarsf)) self.data[meter_prefix + "acvara"] = round(acvara, abs(acvarsf)) self.data[meter_prefix + "acvarb"] = round(acvarb, abs(acvarsf)) self.data[meter_prefix + "acvarc"] = round(acvarc, abs(acvarsf)) acpf = decoder.decode_16bit_int() acpfa = decoder.decode_16bit_int() acpfb = decoder.decode_16bit_int() acpfc = decoder.decode_16bit_int() acpfsf = decoder.decode_16bit_int() acpf = self.calculate_value(acpf, acpfsf) acpfa = self.calculate_value(acpfa, acpfsf) acpfb = self.calculate_value(acpfb, acpfsf) acpfc = self.calculate_value(acpfc, acpfsf) self.data[meter_prefix + "acpf"] = round(acpf, abs(acpfsf)) self.data[meter_prefix + "acpfa"] = round(acpfa, abs(acpfsf)) self.data[meter_prefix + "acpfb"] = round(acpfb, abs(acpfsf)) self.data[meter_prefix + "acpfc"] = round(acpfc, abs(acpfsf)) exported = decoder.decode_32bit_uint() exporteda = decoder.decode_32bit_uint() exportedb = decoder.decode_32bit_uint() exportedc = decoder.decode_32bit_uint() imported = decoder.decode_32bit_uint() importeda = decoder.decode_32bit_uint() importedb = decoder.decode_32bit_uint() importedc = decoder.decode_32bit_uint() energywsf = decoder.decode_16bit_int() exported = self.calculate_value(exported, energywsf) exporteda = self.calculate_value(exporteda, energywsf) exportedb = self.calculate_value(exportedb, energywsf) exportedc = self.calculate_value(exportedc, energywsf) imported = self.calculate_value(imported, energywsf) importeda = self.calculate_value(importeda, energywsf) importedb = self.calculate_value(importedb, energywsf) importedc = self.calculate_value(importedc, energywsf) self.data[meter_prefix + "exported"] = round(exported * 0.001, 3) self.data[meter_prefix + "exporteda"] = round(exporteda * 0.001, 3) self.data[meter_prefix + "exportedb"] = round(exportedb * 0.001, 3) self.data[meter_prefix + "exportedc"] = round(exportedc * 0.001, 3) self.data[meter_prefix + "imported"] = round(imported * 0.001, 3) self.data[meter_prefix + "importeda"] = round(importeda * 0.001, 3) self.data[meter_prefix + "importedb"] = round(importedb * 0.001, 3) self.data[meter_prefix + "importedc"] = round(importedc * 0.001, 3) exportedva = decoder.decode_32bit_uint() exportedvaa = decoder.decode_32bit_uint() exportedvab = decoder.decode_32bit_uint() exportedvac = decoder.decode_32bit_uint() importedva = decoder.decode_32bit_uint() importedvaa = decoder.decode_32bit_uint() importedvab = decoder.decode_32bit_uint() importedvac = decoder.decode_32bit_uint() energyvasf = decoder.decode_16bit_int() exportedva = self.calculate_value(exportedva, energyvasf) exportedvaa = self.calculate_value(exportedvaa, energyvasf) exportedvab = self.calculate_value(exportedvab, energyvasf) exportedvac = self.calculate_value(exportedvac, energyvasf) importedva = self.calculate_value(importedva, energyvasf) importedvaa = self.calculate_value(importedvaa, energyvasf) importedvab = self.calculate_value(importedvab, energyvasf) importedvac = self.calculate_value(importedvac, energyvasf) self.data[meter_prefix + "exportedva"] = round(exportedva, abs(energyvasf)) self.data[meter_prefix + "exportedvaa"] = round( exportedvaa, abs(energyvasf) ) self.data[meter_prefix + "exportedvab"] = round( exportedvab, abs(energyvasf) ) self.data[meter_prefix + "exportedvac"] = round( exportedvac, abs(energyvasf) ) self.data[meter_prefix + "importedva"] = round(importedva, abs(energyvasf)) self.data[meter_prefix + "importedvaa"] = round( importedvaa, abs(energyvasf) ) self.data[meter_prefix + "importedvab"] = round( importedvab, abs(energyvasf) ) self.data[meter_prefix + "importedvac"] = round( importedvac, abs(energyvasf) ) importvarhq1 = decoder.decode_32bit_uint() importvarhq1a = decoder.decode_32bit_uint() importvarhq1b = decoder.decode_32bit_uint() importvarhq1c = decoder.decode_32bit_uint() importvarhq2 = decoder.decode_32bit_uint() importvarhq2a = decoder.decode_32bit_uint() importvarhq2b = decoder.decode_32bit_uint() importvarhq2c = decoder.decode_32bit_uint() importvarhq3 = decoder.decode_32bit_uint() importvarhq3a = decoder.decode_32bit_uint() importvarhq3b = decoder.decode_32bit_uint() importvarhq3c = decoder.decode_32bit_uint() importvarhq4 = decoder.decode_32bit_uint() importvarhq4a = decoder.decode_32bit_uint() importvarhq4b = decoder.decode_32bit_uint() importvarhq4c = decoder.decode_32bit_uint() energyvarsf = decoder.decode_16bit_int() importvarhq1 = self.calculate_value(importvarhq1, energyvarsf) importvarhq1a = self.calculate_value(importvarhq1a, energyvarsf) importvarhq1b = self.calculate_value(importvarhq1b, energyvarsf) importvarhq1c = self.calculate_value(importvarhq1c, energyvarsf) importvarhq2 = self.calculate_value(importvarhq2, energyvarsf) importvarhq2a = self.calculate_value(importvarhq2a, energyvarsf) importvarhq2b = self.calculate_value(importvarhq2b, energyvarsf) importvarhq2c = self.calculate_value(importvarhq2c, energyvarsf) importvarhq3 = self.calculate_value(importvarhq3, energyvarsf) importvarhq3a = self.calculate_value(importvarhq3a, energyvarsf) importvarhq3b = self.calculate_value(importvarhq3b, energyvarsf) importvarhq3c = self.calculate_value(importvarhq3c, energyvarsf) importvarhq4 = self.calculate_value(importvarhq4, energyvarsf) importvarhq4a = self.calculate_value(importvarhq4a, energyvarsf) importvarhq4b = self.calculate_value(importvarhq4b, energyvarsf) importvarhq4c = self.calculate_value(importvarhq4c, energyvarsf) self.data[meter_prefix + "importvarhq1"] = round( importvarhq1, abs(energyvarsf) ) self.data[meter_prefix + "importvarhq1a"] = round( importvarhq1a, abs(energyvarsf) ) self.data[meter_prefix + "importvarhq1b"] = round( importvarhq1b, abs(energyvarsf) ) self.data[meter_prefix + "importvarhq1c"] = round( importvarhq1c, abs(energyvarsf) ) self.data[meter_prefix + "importvarhq2"] = round( importvarhq2, abs(energyvarsf) ) self.data[meter_prefix + "importvarhq2a"] = round( importvarhq2a, abs(energyvarsf) ) self.data[meter_prefix + "importvarhq2b"] = round( importvarhq2b, abs(energyvarsf) ) self.data[meter_prefix + "importvarhq2c"] = round( importvarhq2c, abs(energyvarsf) ) self.data[meter_prefix + "importvarhq3"] = round( importvarhq3, abs(energyvarsf) ) self.data[meter_prefix + "importvarhq3a"] = round( importvarhq3a, abs(energyvarsf) ) self.data[meter_prefix + "importvarhq3b"] = round( importvarhq3b, abs(energyvarsf) ) self.data[meter_prefix + "importvarhq3c"] = round( importvarhq3c, abs(energyvarsf) ) self.data[meter_prefix + "importvarhq4"] = round( importvarhq4, abs(energyvarsf) ) self.data[meter_prefix + "importvarhq4a"] = round( importvarhq4a, abs(energyvarsf) ) self.data[meter_prefix + "importvarhq4b"] = round( importvarhq4b, abs(energyvarsf) ) self.data[meter_prefix + "importvarhq4c"] = round( importvarhq4c, abs(energyvarsf) ) return True else: return False def read_modbus_data_inverter(self): inverter_data = self.read_holding_registers(unit=1, address=40071, count=38) if not inverter_data.isError(): decoder = BinaryPayloadDecoder.fromRegisters( inverter_data.registers, byteorder=Endian.Big ) accurrent = decoder.decode_16bit_uint() accurrenta = decoder.decode_16bit_uint() accurrentb = decoder.decode_16bit_uint() accurrentc = decoder.decode_16bit_uint() accurrentsf = decoder.decode_16bit_int() accurrent = self.calculate_value(accurrent, accurrentsf) accurrenta = self.calculate_value(accurrenta, accurrentsf) accurrentb = self.calculate_value(accurrentb, accurrentsf) accurrentc = self.calculate_value(accurrentc, accurrentsf) self.data["accurrent"] = round(accurrent, abs(accurrentsf)) self.data["accurrenta"] = round(accurrenta, abs(accurrentsf)) self.data["accurrentb"] = round(accurrentb, abs(accurrentsf)) self.data["accurrentc"] = round(accurrentc, abs(accurrentsf)) acvoltageab = decoder.decode_16bit_uint() acvoltagebc = decoder.decode_16bit_uint() acvoltageca = decoder.decode_16bit_uint() acvoltagean = decoder.decode_16bit_uint() acvoltagebn = decoder.decode_16bit_uint() acvoltagecn = decoder.decode_16bit_uint() acvoltagesf = decoder.decode_16bit_int() acvoltageab = self.calculate_value(acvoltageab, acvoltagesf) acvoltagebc = self.calculate_value(acvoltagebc, acvoltagesf) acvoltageca = self.calculate_value(acvoltageca, acvoltagesf) acvoltagean = self.calculate_value(acvoltagean, acvoltagesf) acvoltagebn = self.calculate_value(acvoltagebn, acvoltagesf) acvoltagecn = self.calculate_value(acvoltagecn, acvoltagesf) self.data["acvoltageab"] = round(acvoltageab, abs(acvoltagesf)) self.data["acvoltagebc"] = round(acvoltagebc, abs(acvoltagesf)) self.data["acvoltageca"] = round(acvoltageca, abs(acvoltagesf)) self.data["acvoltagean"] = round(acvoltagean, abs(acvoltagesf)) self.data["acvoltagebn"] = round(acvoltagebn, abs(acvoltagesf)) self.data["acvoltagecn"] = round(acvoltagecn, abs(acvoltagesf)) acpower = decoder.decode_16bit_int() acpowersf = decoder.decode_16bit_int() acpower = self.calculate_value(acpower, acpowersf) self.data["acpower"] = round(acpower, abs(acpowersf)) acfreq = decoder.decode_16bit_uint() acfreqsf = decoder.decode_16bit_int() acfreq = self.calculate_value(acfreq, acfreqsf) self.data["acfreq"] = round(acfreq, abs(acfreqsf)) acva = decoder.decode_16bit_int() acvasf = decoder.decode_16bit_int() acva = self.calculate_value(acva, acvasf) self.data["acva"] = round(acva, abs(acvasf)) acvar = decoder.decode_16bit_int() acvarsf = decoder.decode_16bit_int() acvar = self.calculate_value(acvar, acvarsf) self.data["acvar"] = round(acvar, abs(acvarsf)) acpf = decoder.decode_16bit_int() acpfsf = decoder.decode_16bit_int() acpf = self.calculate_value(acpf, acpfsf) self.data["acpf"] = round(acpf, abs(acpfsf)) acenergy = decoder.decode_32bit_uint() acenergysf = decoder.decode_16bit_uint() acenergy = self.calculate_value(acenergy, acenergysf) self.data["acenergy"] = round(acenergy * 0.001, 3) dccurrent = decoder.decode_16bit_uint() dccurrentsf = decoder.decode_16bit_int() dccurrent = self.calculate_value(dccurrent, dccurrentsf) self.data["dccurrent"] = round(dccurrent, abs(dccurrentsf)) dcvoltage = decoder.decode_16bit_uint() dcvoltagesf = decoder.decode_16bit_int() dcvoltage = self.calculate_value(dcvoltage, dcvoltagesf) self.data["dcvoltage"] = round(dcvoltage, abs(dcvoltagesf)) dcpower = decoder.decode_16bit_int() dcpowersf = decoder.decode_16bit_int() dcpower = self.calculate_value(dcpower, dcpowersf) self.data["dcpower"] = round(dcpower, abs(dcpowersf)) # skip register decoder.skip_bytes(2) tempsink = decoder.decode_16bit_int() # skip 2 registers decoder.skip_bytes(4) tempsf = decoder.decode_16bit_int() tempsink = self.calculate_value(tempsink, tempsf) self.data["tempsink"] = round(tempsink, abs(tempsf)) status = decoder.decode_16bit_int() self.data["status"] = status statusvendor = decoder.decode_16bit_int() self.data["statusvendor"] = statusvendor return True else: return False
from pymodbus.client.sync import ModbusTcpClient as ModbusClient # ---------------------------------------------------------------------------# # configure the client logging # ---------------------------------------------------------------------------# import logging logging.basicConfig() log = logging.getLogger() log.setLevel(logging.INFO) # ---------------------------------------------------------------------------# # We are going to use a simple client to send our requests # ---------------------------------------------------------------------------# client = ModbusClient("127.0.0.1") 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 # - an 8 bit int 0x12 # - an 8 bit bitstring [0,1,0,1,1,0,1,0] # ---------------------------------------------------------------------------# builder = BinaryPayloadBuilder(endian=Endian.Little)
class Drive: client = None queue = [] def __init__(self, sensors): self.sensors = sensors self.connect_modbus() def connect_modbus(self): try: self.client = ModbusClient(HOST, port=PORT) print("Opening modbus connection...") self.client.connect() print("Connection opened") except ConnectionException: print("Impossible to connect") def close_modbus(self): print("Closing modbus connection...") self.client.close() print("Connection closed") def add_vehicle(self, vehicle): self.queue.append(vehicle) def read_registers(self, sc): if self.client.is_socket_open(): t = time.time_ns() regs = self.client.read_input_registers(0,1) if isinstance(regs, ReadInputRegistersResponse) and regs: registers = regs.registers if (isinstance(registers, list) and len(registers) > 0): inputs = self.pad_inputs(self.hex_to_binary(registers[0])) inputs = self.parse_input_status(inputs) if len(inputs): for sensor in self.sensors: if sensor.input < len(inputs): updated = sensor.update_state(inputs[sensor.input], t) if updated: self.send_message(sensor, t) try: sc.enter(0.5, 1, self.read_registers, (sc, )) except: print("stop") else: print("Connection to address '" + HOST + "' could not be made") def hex_to_binary(self, hex_code): bin_code = bin(hex_code)[2:] padding = (4 - len(bin_code) % 4) % 4 return '0' * padding + bin_code def pad_inputs(self, inputs): return inputs.zfill(8) def parse_input_status(self, inputs): inputs = inputs[::-1] coils = [] for i in range(len(inputs)): coils.append(inputs[i] == '1') return coils def send_message(self, sensor, timestamp): t = time.localtime(timestamp / 1000000000) print("[" + time.strftime("%m/%d/%Y %H:%M:%S", t) + "] : Detection on channel (" + str(sensor.input) + ") : " + sensor.get_readable_state())