class TestClientServer(unittest.TestCase): def setUp(self): # modbus server self.server = ModbusServer(port=5020, no_block=True) self.server.start() # modbus client self.client = ModbusClient(port=5020) self.client.open() def tearDown(self): self.client.close() def test_read_and_write(self): # word space self.assertEqual(self.client.read_holding_registers(0), [0], 'Default value is 0 when server start') self.assertEqual(self.client.read_input_registers(0), [0], 'Default value is 0 when server start') # single read/write self.assertEqual(self.client.write_single_register(0, 0xffff), True) self.assertEqual(self.client.read_input_registers(0), [0xffff]) # multi-write at max size words_l = [randint(0, 0xffff)] * 0x7b self.assertEqual(self.client.write_multiple_registers(0, words_l), True) self.assertEqual(self.client.read_holding_registers(0, len(words_l)), words_l) self.assertEqual(self.client.read_input_registers(0, len(words_l)), words_l) # write over sized words_l = [randint(0, 0xffff)] * 0x7c self.assertEqual(self.client.write_multiple_registers(0, words_l), None) # bit space self.assertEqual(self.client.read_coils(0), [False], 'Default value is False when server start') self.assertEqual(self.client.read_discrete_inputs(0), [False], 'Default value is False when server start') # single read/write self.assertEqual(self.client.write_single_coil(0, True), True) self.assertEqual(self.client.read_coils(0), [True]) self.assertEqual(self.client.read_discrete_inputs(0), [True]) # multi-write at min size bits_l = [getrandbits(1)] * 0x1 self.assertEqual(self.client.write_multiple_coils(0, bits_l), True) self.assertEqual(self.client.read_coils(0, len(bits_l)), bits_l) self.assertEqual(self.client.read_discrete_inputs(0, len(bits_l)), bits_l) # multi-write at max size bits_l = [getrandbits(1)] * 0x7b0 self.assertEqual(self.client.write_multiple_coils(0, bits_l), True) self.assertEqual(self.client.read_coils(0, len(bits_l)), bits_l) self.assertEqual(self.client.read_discrete_inputs(0, len(bits_l)), bits_l) # multi-write over sized bits_l = [getrandbits(1)] * 0x7b1 self.assertEqual(self.client.write_multiple_coils(0, bits_l), None)
def read_all_tags(self): try: c = ModbusClient(host="192.168.2.11", port=502, debug=False) c.open() for name, tag in self.tag_db.items(): mb0 = tag['modbus_start'] -1 mb1 = tag['modbus_stop'] -1 size = 1+mb1-mb0 #print(name, mb0, mb1, size) #print(tag) if 0 <= mb0 < 100000: val = c.read_coils(mb0)[0] elif 100000 <= mb0 < 200000: val = c.read_discrete_inputs(mb0-100000)[0] elif 300000 <= mb0 < 400000: val = c.read_input_registers(mb0-300000, size) if size == 1: val = val[0] elif size == 2: val = utils.word_list_to_long(val, big_endian=False)[0] elif 400000 <= mb0 < 500000: val = c.read_holding_registers(mb0-400000, size ) if size == 1: val = val[0] elif size == 2: val = utils.word_list_to_long(val, big_endian=False)[0] if tag['dtype'] == 'float32': val = utils.decode_ieee(val) #print(name, val) self.settings[name] = val except Exception as err: print("Error in read_all_tags", err) c.close()
def read_valid_registers(target_ip, port, reg): result = False print(f'\n=====Polling remote server for {reg}:=====') for i in range(start_reg, end_reg): client = ModbusClient(host=target_ip, port=port, auto_open=True, auto_close=True, timeout=10) if reg == "hold": data = client.read_holding_registers(i, 1) if reg == "input": data = client.read_input_registers(i, 1) if reg == "discrete": data = client.read_discrete_inputs(i, 1) if reg == "coil": data = client.read_coils(i, 1) if data: result = True print(f'\nValid Registers {reg} detected at {i} with value {data}') client.close() print('/', end='') sleep(0.1) # return valid_list,data_list,permission_list if result != True: print(f'\n No Valid Registers detected in specified range')
def callback(marker_array, inputs): output_address = inputs[0] input_address = inputs[1] zone_distance = inputs[2] grid_x = inputs[3] #Create a connection with the ADAM-6052 adam = ModbusClient(host="192.168.1.3", port=502, auto_open=True, auto_close=False) #Calculate distance to nearest object distance = 100 for marker in marker_array.markers: xpos = marker.pose.position.x xsize = marker.scale.x #Set distance if new distance is smaller if xpos - float(xsize) / 2 - grid_x < distance: distance = xpos - float(xsize) / 2 - grid_x a = adam.read_discrete_inputs(int(input_address)) #If it is a valid read if type(a) == type([]): #If HIGH if a[0] == 1: rospy.loginfo("System is in reduced distance mode") #If there is an obstruction less than xm detected write pin False if distance <= int(zone_distance): rospy.logwarn("Obstruction has been detected") adam.write_single_coil(int(output_address), False) #If there is an no obstruction less than xm detected write pin False else: rospy.loginfo("No Obsturction has been detected") adam.write_single_coil(int(output_address), True) #If LOW elif a[0] == 0: #If there is an obstruction detected write pin False if len(marker_array.markers) > 0: rospy.logwarn("Obstruction has been detected") adam.write_single_coil(int(output_address), False) #If there is no obstruction detected write pin True else: rospy.loginfo("No Obsturction has been detected") adam.write_single_coil(int(output_address), True) else: rospy.logwarn("Connection to adam failed")
def read_valid_registers(ip_addr,port,reg): valid_list=[] data_list=[] permission_list=[] client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) for i in tqdm(range(1,500)): if reg == "hold": data=client.read_holding_registers(i,1) if reg == "input": data=client.read_input_registers(i,1) if reg == "discrete": data=client.read_discrete_inputs(i,1) if reg == "coil": data=client.read_coils(i,1) if data: valid_list.append(i) data_list.append(data[0]) permission_list.append("Read") client.close() return valid_list,data_list,permission_list
def monitor_register(target_ip, port, address, delay, reg): while True: client = ModbusClient(host=target_ip, port=port, auto_open=True, auto_close=True, timeout=1) if reg == "Holding": data = client.read_holding_registers(address, 1) if reg == "Input": data = client.read_input_registers(address, 1) if reg == "Discrete": data = client.read_discrete_inputs(address, 1) if reg == "Coil": data = client.read_coils(address, 1) if data: print(f'{reg} register at address {address} has value {data}') #print ('.', end='') client.close() sleep(delay)
# TCP auto connect on first modbus request #c = ModbusClient(host="localhost", port=502, auto_open=True) # TCP auto connect on modbus request, close after it #c = ModbusClient(host="127.0.0.1", auto_open=True, auto_close=True) c = ModbusClient() c.host("192.168.58.10") c.port(502) # managing TCP sessions with call to c.open()/c.close() c.open() # to debug the communication #c.debug(True) inputRegD = c.read_discrete_inputs(0, 16) coil = c.read_coils(0, 16) read_holding = c.read_holding_registers(0, 2) inputReg = c.read_input_registers(0, 2) while True: if inputRegD: #print(regs) #print(type(regs)) #print(type(coil)) x = inputRegD[5] print("Read Input: " + str(inputRegD)) print("Read Coils: " + str(coil)) print("Holding Register: " + str(read_holding)) print("Read Input Register: " + str(inputReg))
class ThermiaGenesis: # pylint:disable=too-many-instance-attributes """Main class to perform modbus requests to heat pump.""" def __init__(self, host, port=502, kind='inverter', delay=0.1, max_registers=16): """Initialize.""" self.data = {} self._client = ModbusClient(host, port=port, unit_id=1, auto_open=True) self.firmware = None if(kind == MODEL_MEGA): self.model = "Mega" else: self.model = "Diplomat Inverter" self._host = host self._port = port self._kind = kind self._delay = delay self.MAX_REGISTERS = max_registers _LOGGER.debug("Using host: %s:%d", host, port) async def async_set(self, register, value): # pylint:disable=too-many-branches """Write data to heat pump.""" ret_value = await self._set_data(register, value) self._client.close() async def async_update(self, register_types=REG_TYPES, only_registers = None): # pylint:disable=too-many-branches """Update data from heat pump.""" use_registers = [] if(only_registers != None): #Make sure to sort registers by type and address use_registers = sorted(only_registers, key=(lambda x: f"{REGISTERS[x][KEY_REG_TYPE]}-{REGISTERS[x][KEY_ADDRESS]:03}")) else: use_registers = dict(filter(lambda x: x[1][self._kind], REGISTERS.items())).keys() raw_data = await self._get_data(use_registers) self._client.close() if not raw_data: self.data = {} return {} #_LOGGER.debug("RAW data: %s", raw_data) data = {} try: for i, (name, val) in enumerate(raw_data.items()): data[name] = val self.firmware = f"{self.data[ATTR_INPUT_SOFTWARE_VERSION_MAJOR]}.{self.data[ATTR_INPUT_SOFTWARE_VERSION_MINOR]}.{self.data[ATTR_INPUT_SOFTWARE_VERSION_MICRO]}" _LOGGER.debug("------------- REGISTERS ----------------------") for i, (name, val) in enumerate(self.data.items()): _LOGGER.debug(f"{REGISTERS[name][KEY_ADDRESS]}\t{val}\t{name}") except AttributeError as err: _LOGGER.debug("Incomplete data from modbus.") _LOGGER.debug(err) except KeyError as err: _LOGGER.debug("Incomplete data from modbus.") _LOGGER.debug(err) except TypeError as err: _LOGGER.debug("Incomplete data from modbus.") _LOGGER.debug(err) self.data = data return data @property def available(self): """Return True is data is available.""" return bool(self.data) async def _set_data(self, register, value): meta = REGISTERS[register] regtype = meta[KEY_REG_TYPE] address = meta[KEY_ADDRESS] scale = meta[KEY_SCALE] await asyncio.sleep(self._delay) try: if(regtype == REG_COIL): _LOGGER.debug(f"Set {regtype} register at {address} value {value} ({value})") self._client.write_single_coil(address, value) elif(regtype == REG_HOLDING): converted_value = int(value * scale) if(meta[KEY_DATATYPE] == TYPE_INT): converted_value = num_to_bin(converted_value) _LOGGER.debug(f"Set {regtype} register at {address} value {converted_value} ({value}) {scale}") self._client.write_single_register(address, converted_value) else: raise "This register can not be changed" except Exception as e: _LOGGER.error(f'exception: {e}') print(traceback.format_exc()) return value async def _get_data(self, registers): """Retreive data from heat pump.""" raw_data = {} #Split into requests that reads up to self.MAX_REGISTERS within REGISTER_RANGES (register blocks) for the requested registers first_chunk_address = 0 current_type = None chunks = [] chunk = None for name in registers: meta = REGISTERS[name] if(name == ATTR_HOLDING_FIXED_SYSTEM_SUPPLY_SET_POINT): #This will give an errror unless coil 42 is True, so skip if we don't know this or if it's false enableAttr = ATTR_COIL_ENABLE_FIXED_SYSTEM_SUPPLY_SET_POINT if(enableAttr not in raw_data and enableAttr not in self.data): _LOGGER.debug(f"Will not read {name} since we don't know if {ATTR_COIL_ENABLE_FIXED_SYSTEM_SUPPLY_SET_POINT} is set, include this register in the request to read this") continue if(not raw_data[ATTR_COIL_ENABLE_FIXED_SYSTEM_SUPPLY_SET_POINT] and not self.data[ATTR_COIL_ENABLE_FIXED_SYSTEM_SUPPLY_SET_POINT]): _LOGGER.debug(f"Will not read {name} since {ATTR_COIL_ENABLE_FIXED_SYSTEM_SUPPLY_SET_POINT} is False which disables this register") continue reg_address = meta[KEY_ADDRESS] if(chunk == None #First iteration or chunk[KEY_REG_TYPE] != meta[KEY_REG_TYPE] #New register type or (reg_address - chunk['start']) >= self.MAX_REGISTERS #Exceeds max number of registers per request or reg_address > chunk['range_end']): #Address belongs to another register block if(chunk != None): chunks.append(chunk) start = meta[KEY_ADDRESS] chunk = { KEY_REG_TYPE: meta[KEY_REG_TYPE], 'start': start, 'slots': { name: 0 } } if(meta[KEY_DATATYPE] == TYPE_LONG): chunk['end'] = start + 1 else: chunk['end'] = start in_range = list(filter(lambda x: x[0] <= start and x[1] >= start, REGISTER_RANGES[self._kind][meta[KEY_REG_TYPE]])) chunk['range_end'] = in_range[0][1] else: chunk['slots'][name] = reg_address - start if(meta[KEY_DATATYPE] == TYPE_LONG): chunk['end'] = reg_address + 1 else: chunk['end'] = reg_address if(chunk != None): chunks.append(chunk) _LOGGER.info(f"Will make {len(chunks)} requests to read {len(registers)} registers") #print(f"Will make {len(chunks)} requests to read {len(registers)} registers") try: for chunk in chunks: await asyncio.sleep(self._delay) start_address = chunk['start'] length = chunk['end'] - chunk['start'] + 1 regtype = chunk[KEY_REG_TYPE] _LOGGER.debug(f"Reading {regtype} {start_address} length {length}") read_data = None if(regtype == REG_COIL): read_data = self._client.read_coils(start_address, length) elif(regtype == REG_DISCRETE_INPUT): read_data = self._client.read_discrete_inputs(start_address, length) elif(regtype == REG_INPUT): read_data = self._client.read_input_registers(start_address, length) elif(regtype == REG_HOLDING): read_data = self._client.read_holding_registers(start_address, length) if read_data: for i, (name, address) in enumerate(chunk['slots'].items()): info = REGISTERS[name] datatype = info[KEY_DATATYPE] scale = info[KEY_SCALE] val = read_data[address] if(datatype == TYPE_LONG): regs = read_data[address:(address+2)] val = word_list_to_long(regs)[0] elif(datatype == TYPE_INT): if(val == 32767): val = 0 if(val > 32767): val = val - 65536 elif(datatype == TYPE_STATUS): status_str = "OFF" if val == 1: status_str = "Manual Operation" elif val == 2: status_str = "Defrost" elif val == 3: status_str = "Hot water" elif val == 4: status_str = "Heat" elif val == 5: status_str = "Cool" elif val == 6: status_str = "Pool" elif val == 7: status_str = "Anti legionella" elif val == 98: status_str = "Standby" elif val == 99: status_str = "No demand" val = status_str if(scale != 1): val = val / scale raw_data[name] = val else: if self._client.last_error() > 0: _LOGGER.error(f'error {self._client.last_error()}') raise Exception(f"Failed to read {regtype} {start_address} length {length}", self._client.last_error()) #for regtype in register_types: # last_chunk_address = 0 # values = [] # for chunk in REGISTER_RANGES[self._kind][regtype]: # await asyncio.sleep(self._delay) # start_address = chunk[0] # length = chunk[1] - start_address # #Insert 0 if there is a gap # values.extend([0] * (start_address - last_chunk_address)) # _LOGGER.debug(f"Reading {regtype} {start_address} length {length}") # read_data = None # if(regtype == REG_COIL): # read_data = self._client.read_coils(start_address, length) # elif(regtype == REG_DISCRETE_INPUT): # read_data = self._client.read_discrete_inputs(start_address, length) # elif(regtype == REG_INPUT): # read_data = self._client.read_input_registers(start_address, length) # elif(regtype == REG_HOLDING): # read_data = self._client.read_holding_registers(start_address, length) # if read_data: # values.extend(read_data) # else: # if self._client.last_error() > 0: # print(f'error {self._client.last_error()}') # _LOGGER.error(f'error {self._client.last_error()}') # raise Exception(f"Failed to read {regtype} {start_address} length {length}", self._client.last_error()) # last_chunk_address = chunk[1] # raw_data[regtype] = values except Exception as e: _LOGGER.error(f'exception: {e}') print(traceback.format_exc()) return raw_data
def get_points(conn, devices): for device in devices: try: cur = conn.cursor() #Get IP Address and port from database cur.execute("SELECT ip, port FROM device WHERE devID = ?", (device, )) request = cur.fetchone() ip = request[0] port = request[1] client = ModbusClient() client.host(ip) client.port(port) client_connected = True if (client.is_open() == False): if (client.open() == False): print("Unable to connect to " + ip + ":" + str(port)) client_connected = False if (client_connected == True): cur.execute( "SELECT name, address, type, pointID, mult_factor FROM device_points WHERE devID = ? AND deleted = 0", (device, )) rows = cur.fetchall() for row in rows: if (row[2] == "dig_in"): req = client.read_discrete_inputs(int(row[1]), 1) datetime_str = datetime.now().strftime( "%Y-%m-%d %H:%M:%S.%f") point_ID = row[3] value = req[0] * row[4] print(datetime_str + " | " + str(point_ID) + " | " + str(value)) cur.execute("INSERT INTO point_data VALUES (?, ?, ?)", (datetime_str, point_ID, value)) #print("Value for point " + row[0] + ": " + str(req) + datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) if (row[2] == "dig_out"): req = client.read_coils(int(row[1]), 1) datetime_str = datetime.now().strftime( "%Y-%m-%d %H:%M:%S.%f") point_ID = row[3] value = req[0] * row[4] error_code = 0 print(datetime_str + " | " + str(point_ID) + " | " + str(value)) cur.execute("INSERT INTO point_data VALUES (?, ?, ?)", (datetime_str, point_ID, value)) #print("Value for point " + row[0] + ": " + str(req) + datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) if (row[2] == "an_in"): req = client.read_input_registers(int(row[1]), 1) datetime_str = datetime.now().strftime( "%Y-%m-%d %H:%M:%S.%f") point_ID = row[3] value = req[0] * row[4] error_code = 0 print(datetime_str + " | " + str(point_ID) + " | " + str(value)) cur.execute("INSERT INTO point_data VALUES (?, ?, ?)", (datetime_str, point_ID, value)) #print("Value for point " + row[0] + ": " + str(req) + datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) if (row[2] == "an_out"): req = client.read_holding_registers(int(row[1]), 1) datetime_str = datetime.now().strftime( "%Y-%m-%d %H:%M:%S.%f") point_ID = row[3] value = req[0] * row[4] error_code = 0 print(datetime_str + " | " + str(point_ID) + " | " + str(value)) cur.execute("INSERT INTO point_data VALUES (?, ?, ?)", (datetime_str, point_ID, value)) #print("Value for point " + row[0] + ": " + str(req) + datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) print("\n") conn.commit() cur.close() client.close() except Error as e: print(e) conn.close() database = "./database/SCADADB.db" conn = create_connection(database)
class ET7000: ranges = { 0x00: { 'min': -0.015, 'max': 0.015, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0x01: { 'min': -0.05, 'max': 0.05, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0x02: { 'min': -0.1, 'max': 0.1, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0x03: { 'min': -0.5, 'max': 0.5, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0x04: { 'min': -1., 'max': 1., 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0x05: { 'min': -2.5, 'max': 2.5, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0x06: { 'min': -20.0e-3, 'max': 20.0e-3, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'A' }, 0x07: { 'units': 'A', 'min': 4.0e-3, 'min_code': 0x0000, 'max_code': 0xffff, 'max': 20.0e-3 }, 0x08: { 'units': 'V', 'min': -10., 'max': 10., 'min_code': 0x8000, 'max_code': 0x7fff, }, 0x09: { 'units': 'V', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -5., 'max': 5. }, 0x0A: { 'units': 'V', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -1., 'max': 1. }, 0x0B: { 'units': 'V', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -.5, 'max': .5 }, 0x0C: { 'units': 'V', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -.15, 'max': .15 }, 0x0D: { 'min': -20.0e-3, 'max': 20.0e-3, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'A' }, 0x0E: { 'units': 'degC', 'min_code': 0xdca2, 'max_code': 0x7fff, 'min': -210.0, 'max': 760.0 }, 0x0F: { 'units': 'degC', 'min_code': 0xe6d0, 'max_code': 0x7fff, 'min': -270.0, 'max': 1372.0 }, 0x10: { 'units': 'degC', 'min_code': 0xa99a, 'max_code': 0x7fff, 'min': -270.0, 'max': 400.0 }, 0x11: { 'units': 'degC', 'min_code': 0xdd71, 'max_code': 0x7fff, 'min': -270.0, 'max': 1000.0 }, 0x12: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 1768.0 }, 0x13: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 1768.0 }, 0x14: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 1820.0 }, 0x15: { 'units': 'degC', 'min_code': 0xe56b, 'max_code': 0x7fff, 'min': -270.0, 'max': 1300.0 }, 0x16: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 2320.0 }, 0x17: { 'units': 'degC', 'min_code': 0xe000, 'max_code': 0x7fff, 'min': -200.0, 'max': 800.0 }, 0x18: { 'units': 'degC', 'min_code': 0x8000, 'max_code': 0x4000, 'min': -200.0, 'max': 100.0 }, 0x19: { 'units': 'degC', 'min_code': 0xe38e, 'max_code': 0xffff, 'min': -200.0, 'max': 900.0 }, 0x1A: { 'min': 0.0, 'max': 20.0e-3, 'min_code': 0x0000, 'max_code': 0xffff, 'units': 'A' }, 0x20: { 'units': 'degC', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -100.0, 'max': 100.0 }, 0x21: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 100.0 }, 0x22: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 200.0 }, 0x23: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 600.0 }, 0x24: { 'units': 'degC', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -100.0, 'max': 100.0 }, 0x25: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 100.0 }, 0x26: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 200.0 }, 0x27: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 600.0 }, 0x28: { 'units': 'degC', 'min_code': 0x999a, 'max_code': 0x7fff, 'min': -80.0, 'max': 100.0 }, 0x29: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 100.0 }, 0x2A: { 'units': 'degC', 'min_code': 0xd556, 'max_code': 0x7fff, 'min': -200.0, 'max': 600.0 }, 0x2B: { 'units': 'degC', 'min_code': 0xeeef, 'max_code': 0x7fff, 'min': -20.0, 'max': 150.0 }, 0x2C: { 'units': 'degC', 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 200.0 }, 0x2D: { 'units': 'degC', 'min_code': 0xeeef, 'max_code': 0x7fff, 'min': -20.0, 'max': 150.0 }, 0x2E: { 'units': 'degC', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -200.0, 'max': 200.0 }, 0x2F: { 'units': 'degC', 'min_code': 0x8000, 'max_code': 0x7fff, 'min': -200.0, 'max': 200.0 }, 0x80: { 'units': 'degC', 'min_code': 0xd556, 'max_code': 0x7fff, 'min': -200.0, 'max': 600.0 }, 0x81: { 'units': 'degC', 'min_code': 0xd556, 'max_code': 0x7fff, 'min': -200.0, 'max': 600.0 }, 0x82: { 'units': 'degC', 'min_code': 0xd556, 'max_code': 0x7fff, 'min': -50.0, 'max': 150.0 }, 0x83: { 'min_code': 0xd556, 'max_code': 0x7fff, 'units': 'degC', 'min': -60.0, 'max': 180.0 }, 0x30: { 'min_code': 0x0000, 'max_code': 0xffff, 'min': 0.0, 'max': 20.0e-3, 'units': 'A' }, 0x31: { 'min_code': 0x0000, 'max_code': 0xffff, 'min': 4.0e-3, 'max': 20.0e-3, 'units': 'A' }, 0x32: { 'min_code': 0x0000, 'max_code': 0x7fff, 'min': 0.0, 'max': 10.0, 'units': 'V' }, 0x33: { 'min': -10.0, 'max': 10.0, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0x34: { 'min': 0.0, 'max': 5.0, 'min_code': 0x0000, 'max_code': 0x7fff, 'units': 'V' }, 0x35: { 'min': -5.0, 'max': 5.0, 'min_code': 0x8000, 'max_code': 0x7fff, 'units': 'V' }, 0xff: { 'min': 0, 'max': 0xffff, 'min_code': 0x0000, 'max_code': 0xffff, 'units': '?' } } devices = {0x7015: {}, 0x7016: {}, 0x7018: {}, 0x7060: {}, 0x7026: {}} @staticmethod def range(r): if r in ET7000.ranges: return (ET7000.ranges[r]) return ET7000.ranges[0xff] # default conversion from quanta to real units @staticmethod def convert(b, amin, amax): b = float(b) # обрабатывается 2 случая - минимум нулевой или больше 0 if amin >= 0 and amax > 0: return amin + (amax - amin) * b / 0xffff # и минимум и максимум разного знака if amin < 0 and amax > 0: range = max(-amin, amax) if b <= 0x7fff: return range * b / 0x7fff else: return range * (0x8000 - b) / 0x8000 # в других случаях ошибка return float('nan') @staticmethod def ai_convert_function(r): v_min = 0 v_max = 0xffff c_min = 0 c_max = 0xffff try: v_min = ET7000.ranges[r]['min'] v_max = ET7000.ranges[r]['max'] c_min = ET7000.ranges[r]['min_code'] c_max = ET7000.ranges[r]['max_code'] except: pass if c_min < c_max: k = (v_max - v_min) / (c_max - c_min) b = v_min - k * c_min return lambda x: k * x + b k_max = v_max / c_max k_min = v_min / (0x10000 - c_min) #return lambda x: (x < 0x8000) * k_max * x + (x >= 0x8000) * k_min * (0x10000 - x) return lambda x: k_max * x if x < 0x8000 else k_min * (0x10000 - x) @staticmethod def ao_convert_function(r): v_min = 0 v_max = 0xffff c_min = 0 c_max = 0xffff try: v_min = ET7000.ranges[r]['min'] v_max = ET7000.ranges[r]['max'] c_min = ET7000.ranges[r]['min_code'] c_max = ET7000.ranges[r]['max_code'] except: pass #print(hex(r), v_min, v_max, c_min, c_max) if c_min < c_max: k = (c_max - c_min) / (v_max - v_min) b = c_min - k * v_min return lambda x: int(k * x + b) k_max = c_max / v_max k_min = (0xffff - c_min) / v_min #return lambda x: int((x >= 0) * k_max * x + (x < 0) * (0xffff - k_min * x)) return lambda x: int(k_max * x) if (x >= 0) else int(0xffff - k_min * x ) @staticmethod def convert_to_raw(v, amin, amax): v = float(v) # обрабатывается 2 случая - минимум нулевой или больше 0 if amin >= 0 and amax > 0: return int((v - amin) / (amax - amin) * 0xffff) # и минимум и максимум разного знака if amin < 0 and amax > 0: if v >= 0.0: return int(v * 0x7fff / amax) else: return int(0x8000 - v / amax * 0x7fff) # в других случаях ошибка return 0 def __init__(self, host, port=502, timeout=0.15, logger=None): self.host = host self.port = port # logger confid if logger is None: logger = logging.getLogger(__name__) self.logger = logger # default device type self._name = 0 self.type = '0000' # default ai self.AI_n = 0 self.AI_masks = [] self.AI_ranges = [] self.AI_min = [] self.AI_max = [] self.AI_units = [] self.AI_raw = [] self.AI_values = [] # default ao self.AO_n = 0 self.AO_masks = [] self.AO_ranges = [] self.AO_min = [] self.AO_max = [] self.AO_units = [] self.AO_raw = [] self.AO_values = [] self.AO_write_raw = [] self.AO_write_values = [] self.AO_write_result = False # default di self.DI_n = 0 self.DI_values = [] # default do self.DO_n = 0 self.DO_values = [] # modbus client self._client = ModbusClient(host, port, auto_open=True, auto_close=True, timeout=timeout) status = self._client.open() if not status: self.logger.error('ET7000 device at %s is offline' % host) return # read module name self._name = self.read_module_name() self.type = hex(self._name).replace('0x', '') if self._name not in ET7000.devices: self.logger.warning( 'ET7000 device type %s probably not supported' % hex(self._name)) # ai self.AI_n = self.read_AI_n() self.AI_masks = [False] * self.AI_n self.AI_ranges = [0xff] * self.AI_n self.AI_raw = [0] * self.AI_n self.AI_values = [float('nan')] * self.AI_n self.AI_units = [''] * self.AI_n self.read_AI_masks() self.read_AI_ranges() self.AI_convert = [lambda x: x] * self.AI_n for n in range(self.AI_n): r = self.AI_ranges[n] self.AI_units[n] = ET7000.ranges[r]['units'] self.AI_convert[n] = ET7000.ai_convert_function(r) # ao self.AO_n = self.read_AO_n() self.AO_masks = [True] * self.AO_n self.read_AO_masks() self.AO_ranges = [0xff] * self.AO_n self.AO_raw = [0] * self.AO_n self.AO_values = [float('nan')] * self.AO_n self.AO_write_values = [float('nan')] * self.AO_n self.AO_units = [''] * self.AO_n self.AO_write = [0] * self.AO_n self.AO_write_raw = [0] * self.AO_n self.read_AO_ranges() self.AO_convert = [lambda x: x] * self.AI_n self.AO_convert_write = [lambda x: 0] * self.AI_n for n in range(self.AO_n): r = self.AO_ranges[n] self.AO_units[n] = ET7000.ranges[r]['units'] self.AO_convert[n] = ET7000.ai_convert_function( r) # !!! ai_convert for reading self.AO_convert_write[n] = ET7000.ao_convert_function( r) # !!! ao_convert for writing # di self.DI_n = self.read_DI_n() self.DI_values = [False] * self.DI_n # do self.DO_n = self.read_DO_n() self.DO_values = [False] * self.DO_n self.DO_write = [False] * self.DO_n def read_module_name(self): regs = self._client.read_holding_registers(559, 1) if regs and regs[0] != 0: return regs[0] regs = self._client.read_holding_registers(260, 1) if regs: return regs[0] return 0 # AI functions def read_AI_n(self): regs = self._client.read_input_registers(320, 1) if regs and regs[0] != 0: return regs[0] regs = self._client.read_input_registers(120, 1) if regs: return regs[0] return 0 def read_AI_masks(self): coils = self._client.read_coils(595, self.AI_n) if coils and len(coils) == self.AI_n: self.AI_masks = coils return coils def read_AI_ranges(self): regs = self._client.read_holding_registers(427, self.AI_n) if regs and len(regs) == self.AI_n: self.AI_ranges = regs return regs def read_AI_raw(self, channel=None): if channel is None: n = self.AI_n channel = 0 else: n = 1 regs = self._client.read_input_registers(0 + channel, n) if regs and len(regs) == n: self.AI_raw[channel:channel + n] = regs if n == 1: return regs[0] return regs def convert_AI(self): for k in range(self.AI_n): if self.AI_masks[k]: self.AI_values[k] = self.AI_convert[k](self.AI_raw[k]) else: self.AI_values[k] = float('nan') return self.AI_values def read_AI(self, channel=None): if channel is None: self.read_AI_raw() self.convert_AI() return self.AI_values return self.read_AI_channel(channel) def read_AI_channel(self, k: int): v = float('nan') if self.AI_masks[k]: regs = self._client.read_input_registers(0 + k, 1) if regs: self.AI_raw[k] = regs[0] v = self.AI_convert[k](regs[0]) self.AI_values[k] = v return v # AO functions def read_AO_n(self): regs = self._client.read_input_registers(330, 1) if regs and regs[0] != 0: return regs[0] regs = self._client.read_input_registers(130, 1) if regs: return regs[0] return 0 def read_AO_masks(self): return self.AO_masks def read_AO_ranges(self): regs = self._client.read_holding_registers(459, self.AO_n) if regs and len(regs) == self.AO_n: self.AO_ranges = regs return regs def read_AO_raw(self, channel=None): if channel is None: n = self.AO_n channel = 0 else: n = 1 regs = self._client.read_holding_registers(0 + channel, n) if regs and len(regs) == n: self.AO_raw[channel:channel + n] = regs if n == 1: return regs[0] return regs def write_AO_raw(self, regs): result = self._client.write_multiple_registers(0, regs) self.AO_write_result = result if len(regs) == self.AO_n: self.AO_write_raw = regs return result def convert_AO(self): raw = self.AO_raw for k in range(self.AO_n): self.AO_values[k] = self.AO_convert[k](raw[k]) return self.AO_values def convert_to_raw_AO(self, values=None): if values is None: values = self.AO_write_values answer = [] for k in range(len(values)): answer.append(self.AO_convert_write[k](values[k])) return answer def read_AO(self): self.AO_raw = self.read_AO_raw() self.convert_AO() return self.AO_values def read_AO_channel(self, k: int): v = float('nan') if self.AO_masks[k]: regs = self._client.read_holding_registers(0 + k, 1) if regs: v = self.AO_convert[k](regs[0]) self.AO_values[k] = v return v def write_AO(self, values): self.AO_write_values = values regs = ET7000.convert_to_raw_AO(values) result = self.write_AO_raw(regs) return result def write_AO_channel(self, k: int, value): raw = self.AO_convert_write[k](value) result = self._client.write_single_register(0 + k, raw) self.AO_write_result = result if result: self.AO_write_values[k] = value self.AO_write_raw[k] = raw pass return result # DI functions def read_DI_n(self): regs = self._client.read_input_registers(300, 1) if regs and regs[0] != 0: return regs[0] regs = self._client.read_input_registers(100, 1) if regs: return regs[0] return 0 def read_DI(self): regs = self._client.read_discrete_inputs(0, self.DI_n) if regs: self.DI_values = regs return self.DI_values def read_DI_channel(self, k: int): reg = self._client.read_discrete_inputs(0 + k, 1) if reg: self.DI_values[k] = reg[0] return reg[0] return None # DO functions def read_DO_n(self): self.DO_time = time.time() regs = self._client.read_input_registers(310, 1) if regs and regs[0] != 0: return regs[0] regs = self._client.read_input_registers(110, 1) if regs: return regs[0] return 0 def read_DO(self): regs = self._client.read_coils(0, self.DI_n) if regs: self.DI_values = regs return self.DI_values def read_DO_channel(self, k: int): reg = self._client.read_coils(0 + k, 1) if reg: self.DO_values[k] = reg[0] return reg[0] return None def write_DO(self, values): self.DO_write = values self.DO_write_result = self._client.write_multiple_coils(0, values) return self.DO_write_result def write_DO_channel(self, k: int, value: bool): result = self._client.write_single_coil(0 + k, value) self.DO_write_result = result if result: self.DO_write[k] = value return result
class TestClientServer(unittest.TestCase): port = 5020 def setUp(self): # modbus server self.server = ModbusServer(port=TestClientServer.port, no_block=True) self.server.start() # modbus client self.client = ModbusClient(port=TestClientServer.port) self.client.open() # to prevent address taken errors TestClientServer.port += 1 def tearDown(self): self.client.close() @repeat def test_word_init(self): # word space self.assertEqual(self.client.read_holding_registers(0), [0], 'Default value is 0 when server start') self.assertEqual(self.client.read_input_registers(0), [0], 'Default value is 0 when server start') @repeat def test_word_single(self): # single read/write self.assertEqual(self.client.write_single_register(0, 0xffff), True) self.assertEqual(self.client.read_input_registers(0), [0xffff]) @repeat def test_word_multi(self): # multi-write at max size words_l = [randint(0, 0xffff)] * 0x7b self.assertEqual(self.client.write_multiple_registers(0, words_l), True) self.assertEqual(self.client.read_holding_registers(0, len(words_l)), words_l) self.assertEqual(self.client.read_input_registers(0, len(words_l)), words_l) @repeat def test_word_oversize(self): # write over sized words_l = [randint(0, 0xffff)] * 0x7c self.assertEqual(self.client.write_multiple_registers(0, words_l), None) @repeat def test_bit_init(self): # bit space self.assertEqual(self.client.read_coils(0), [False], 'Default value is False when server start') self.assertEqual(self.client.read_discrete_inputs(0), [False], 'Default value is False when server start') @repeat def test_bit_single(self): # single read/write self.assertEqual(self.client.write_single_coil(0, True), True) self.assertEqual(self.client.read_coils(0), [True]) self.assertEqual(self.client.read_discrete_inputs(0), [True]) @repeat def test_bit_multi_min(self): # multi-write at min size bits_l = [getrandbits(1)] * 0x1 self.assertEqual(self.client.write_multiple_coils(0, bits_l), True) self.assertEqual(self.client.read_coils(0, len(bits_l)), bits_l) self.assertEqual(self.client.read_discrete_inputs(0, len(bits_l)), bits_l) @repeat def test_bit_multi_max(self): # multi-write at max size bits_l = [getrandbits(1)] * 0x7b0 self.assertEqual(self.client.write_multiple_coils(0, bits_l), True) self.assertEqual(self.client.read_coils(0, len(bits_l)), bits_l) self.assertEqual(self.client.read_discrete_inputs(0, len(bits_l)), bits_l) @repeat def test_bit_multi_oversize(self): # multi-write over sized bits_l = [getrandbits(1)] * 0x7b1 self.assertEqual(self.client.write_multiple_coils(0, bits_l), None)
while True: if not c.is_open(): logger.error("not open") time.sleep(2) continue # 写 coils c.write_single_coil(1, coil_value) logger.debug(f"写 coil,值为 {coil_value}") coil_value = not coil_value time.sleep(1) # 读 discrete_inputs inputs = c.read_discrete_inputs(1) if inputs is None: logger.error("读 discrete_inputs 失败") time.sleep(2) continue logger.debug(f"读 discrete_input,值为 {inputs[0]}") # 写 holding_registers c.write_single_register(1, holding_reg_value) logger.debug(f"写 holding_register,值为 {holding_reg_value}") holding_reg_value = (holding_reg_value + 1) % range_value time.sleep(1) # 读 input_register regs = c.read_input_registers(1)
class LightController(): """Class to control lights of a single controller""" toggle_time = config.toggle_time def __init__(self, host): self.client = ModbusClient(host=host, auto_open=True, auto_close=False) #self.client.debug(True) logger.info("Connecting to %s", self.client.host()) status = self.check_status() if status & 1<<15: # Watchdog ellapsed, try to reset logger.info("Resetting watchdog") self.client.write_single_register(0x1121, 0xbecf) self.client.write_single_register(0x1121, 0xaffe) # Disable the watchdog, if enabled watchdog_timeout = self.client.read_holding_registers(0x1120)[0] if watchdog_timeout > 0: logger.debug("Watchdog timeout: %d", watchdog_timeout) logger.info("Disabling watchdog") self.client.write_single_register(0x1120, 0) (self.num_outputs, self.num_inputs) = self.client.read_holding_registers(0x1012, 2) logger.info("Number of outputs: %d", self.num_outputs) logger.info("Number of inputs: %d", self.num_inputs) self.client.close() # We use auto close for all subsequent calls after initialization self.client.auto_close(True) def check_status(self): """Read buscoupler status from the module""" buscoupler_status = self.client.read_holding_registers(0x100c)[0] if buscoupler_status & 1<<0: logger.error("Bus terminal error") if buscoupler_status & 1<<1: logger.error("Bus coupler configuration error") if buscoupler_status & 1<<15: logger.error("Fieldbus error, watchdog timer elapsed") return buscoupler_status def inputs(self): """Read input status from module""" inputs = self.client.read_discrete_inputs(0, self.num_inputs) logger.debug("Inputs: %s", "".join(map(lambda c: '1' if c else '0', inputs))) return inputs def outputs(self): """Read output status from module""" coils = self.client.read_coils(0, self.num_outputs) logger.debug("Outputs: %s", "".join(map(lambda c: '1' if c else '0', coils))) return coils def toggle(self, bit_addr): """Toggle a impulse relay connected to a single output""" logger.info("Toggling %d on %s", bit_addr, self.client.host()) self.client.auto_close(False) self.client.write_single_coil(bit_addr, True) logger.debug("On %d", bit_addr) time.sleep(self.toggle_time) self.client.write_single_coil(bit_addr, False) logger.debug("Off %d", bit_addr) self.client.close() self.client.auto_close(True)
#print(regs) #print(regs2) try: for j in range(0, 10): print(i * 10 + j, ",cois status,", regs2[j]) except: print(i * 10, ",") print("") print("") print("") print("") for i in range(0, 1000): regs2 = _modbusClient.read_discrete_inputs(i * 10, 10) #print(i*10,"") #print(regs) #print(regs2) try: for j in range(0, 10): print(i * 10 + j, ",input status,", regs2[j]) except: print(i * 10, ",") print("") print("") for i in range(0, 1000): regs = _modbusClient.read_holding_registers(i * 10, 10)
class Beckhoff(Adapter): """Beckhoff Modbus/TCP bus coupler (e.g. BK9000)""" def __init__(self, ip_address): super(Beckhoff, self).__init__(ip_address) self.mb_client = ModbusClient(host=ip_address, timeout=5) def start(self): while True: self.mb_client.open() if self.mb_client.is_open(): break print 'Unable to connect to Beckhoff rack at {}; retrying...'.format( self.ip_address) sleep(1) def stop(self): self.mb_client.close() def read_all(self): # print 'Read inputs' if self.d_ins: data = self.mb_client.read_discrete_inputs( self.d_in_range[0], self.d_in_range[1] - self.d_in_range[0] + 1) if not data: raise ConnectionError('No data received for DIns') i0 = self.d_in_range[ 0] # Starting index for looking up values from the data list for d in self.d_ins.values(): d.val = data[d.address - i0] if self.a_ins: # print '\tRead input registers', self.a_in_range[0], self.a_in_range[1] - self.a_in_range[0] + 1 data = self.mb_client.read_input_registers( self.a_in_range[0], self.a_in_range[1] - self.a_in_range[0] + 1) if not data: raise ConnectionError('No data received from AIns') i0 = self.a_in_range[ 0] # Starting index for looking up values from the data list for d in self.a_ins.values(): d.status = data[d.address - i0] d.val = data[d.address - i0 + 1] def write_all(self): # print 'Write outputs' if self.d_outs: data = [] for i in xrange(self.d_out_range[0], self.d_out_range[1] + 1): try: data.append(self.d_outs[i].raw) except KeyError: data.append(0) # Default value self.mb_client.write_multiple_coils(self.d_out_range[0], data) if self.a_outs: data = [] for d in self.a_outs.values(): data.append(0) data.append(d.raw) # Only write to low words self.mb_client.write_multiple_registers(self.a_out_range[0], data)
if not c.is_open(): if not c.open(): print("unable to connect to " + client_host + ":" + str(client_port)) def int32_to_int8(n): mask = (1 << 16) - 1 return [(n >> k) & mask for k in range(0, 32, 16)] var_int = utils.encode_ieee(7.5) print(var_int) sonuc=int32_to_int8(var_int) print(sonuc) if c.is_open(): # read 10 registers at address 0, store result in regs list print(var_int) c.write_single_register(0,5) c.write_multiple_registers(1,sonuc) regs = c.read_holding_registers(0,100) # if success display registers if regs: print("reg ad #0 to 9: " , regs) bits = c.read_discrete_inputs(0, 16) # if success display registers if bits: print("bit ad #0 to 9: " + str(bits))
if c.is_open(): is_ok = c.write_multiple_coils(addr, coil_bits_write) if not is_ok: print('Dummy') print("bit #" + str(addr) + ": unable to write " + str(toggle)) print('numCoilsTest = ' + str(numCoilsTest), end='\r') break #time.sleep(1) # if open() is ok, read coils (modbus function 0x01) addr = 72 if c.is_open(): # read 10 bits at address 0, store result in regs list coil_bits_read.clear() #coil_bits_read = c.read_coils(addr, numCoilsTest) coil_bits_read = c.read_discrete_inputs(addr, numCoilsTest) # if success display registers if not coil_bits_read: print('Dummy') print("bit ad #0 to : " + str(numCoilsTest) + str(coil_bits_read)) break # compare written with read bits info #print(coil_bits_read) for i in range(0, numCoilsTest): if i == 23: continue if coil_bits_read[i] != coil_bits_write[i]: print('Error in comparision at Coil ' + str(i)) print("Written = " + str(coil_bits_write[i]) + " :: Read :" +
class ConveyorNode(object): __reg_A_servo_on = 0 __reg_A_command = 1 __reg_A_velocity = 2 __reg_B_servo_on = 3 __reg_B_command = 4 __reg_B_velocity = 5 def __init__(self): rospy.init_node("conveyor_node") rospy.loginfo("Starting ConveyorNode as conveyor_node.") host = rospy.get_param("~host", default="10.42.0.21") port = rospy.get_param("~port", default=502) publish_rate = rospy.get_param("~rate", default=20) self.ratio_vel_A = rospy.get_param("~ratio_vel_A", default="1") self.ratio_vel_B = rospy.get_param("~ratio_vel_B", default="1") self.ratio_cmd_A = rospy.get_param("~ratio_cmd_A", default="1") self.ratio_cmd_B = rospy.get_param("~ratio_cmd_B", default="1") self.min_vel = rospy.get_param("~min_vel", default="-0.2") self.max_vel = rospy.get_param("~max_vel", default="0.2") self.rate = rospy.Rate(publish_rate) rospy.Subscriber("conveyorA/command", Float32, self.set_velocityA) # unit [m/s] self.stateA_pub = rospy.Publisher("conveyorA/state", conveyor, queue_size=1) # state of conveyor rospy.Subscriber("conveyorB/command", Float32, self.set_velocityB) # unit [m/s] self.stateB_pub = rospy.Publisher("conveyorB/state", conveyor, queue_size=1) # state of conveyor self.stateA_msg = conveyor() self.stateA_msg.target_vel = 0.0 self.stateA_msg.current_vel = 0.0 self.stateB_msg = conveyor() self.stateB_msg.target_vel = 0.0 self.stateB_msg.current_vel = 0.0 self.__timeout_timeA = time.time() self.__timeout_timeB = time.time() try: self.client = ModbusClient(host, port, auto_open=True) rospy.loginfo("Setup complete") except ValueError: rospy.logerr("Error with conveyor Host or Port params") self.__register_data = None self.__input_data = None @staticmethod def clamp(n, minn, maxn): return max(min(maxn, n), minn) @staticmethod def map_velocity_to_value(velocity): # value = (velocity/0.05*100*2*math.pi*60)/500 velocity = (velocity * 60) / (0.052 * 2 * math.pi * 4) value = int(velocity / 10.0 * 27648.0) return utils.get_2comp(value) & 0xFFFF @staticmethod def map_value_to_velocity(value): voltage = float(utils.get_2comp(value)) / 27648.0 * 10.0 velocity = voltage * 4.0 * 2.0 * math.pi * 0.052 / 60.0 return velocity def set_velocityA(self, msg): self.stateA_msg.target_vel = self.clamp(msg.data, self.min_vel, self.max_vel) # [m/s] self.__timeout_timeA = time.time() def set_velocityB(self, msg): self.stateB_msg.target_vel = self.clamp(msg.data, self.min_vel, self.max_vel) # [m/s] self.__timeout_timeB = time.time() def run(self): while not rospy.is_shutdown(): try: self.__input_data = self.client.read_discrete_inputs(0, 6) self.stateA_msg.sensor_1 = self.__input_data[0] self.stateA_msg.sensor_2 = self.__input_data[1] self.stateA_msg.sensor_3 = self.__input_data[2] self.stateB_msg.sensor_1 = self.__input_data[3] self.stateB_msg.sensor_2 = self.__input_data[4] self.stateB_msg.sensor_3 = self.__input_data[5] self.__register_data = self.client.read_holding_registers(0, 6) if time.time() - self.__timeout_timeA > 1.0: self.stateA_msg.target_vel = 0 self.client.write_single_register(self.__reg_A_servo_on, 0) else: value = self.map_velocity_to_value( self.stateA_msg.target_vel) * self.ratio_cmd_A self.client.write_single_register(self.__reg_A_servo_on, 1) self.client.write_single_register(self.__reg_A_command, value) if time.time() - self.__timeout_timeB > 1.0: self.stateB_msg.target_vel = 0 self.client.write_single_register(self.__reg_B_servo_on, 0) else: value = self.map_velocity_to_value( self.stateB_msg.target_vel) * self.ratio_cmd_B self.client.write_single_register(self.__reg_B_servo_on, 1) self.client.write_single_register(self.__reg_B_command, value) velocity = self.map_value_to_velocity( self.__register_data[self.__reg_A_velocity]) self.stateA_msg.current_vel = velocity * self.ratio_vel_A velocity = self.map_value_to_velocity( self.__register_data[self.__reg_B_velocity]) self.stateB_msg.current_vel = velocity * self.ratio_vel_B self.stateA_pub.publish(self.stateA_msg) self.stateB_pub.publish(self.stateB_msg) except Exception as e: rospy.logerr(e) self.rate.sleep()
def onHeartbeat(self): Domoticz.Debug("onHeartbeat called") try: client = ModbusClient(host=self.TCP_IP, port=int(self.TCP_PORT), unit_id=int(1), auto_open=True, auto_close=True, timeout=2) except: Domoticz.Error("Can not connect to Modbus TCP/IP: " + self.TCP_IP + ":" + self.TCP_PORT) try: c207 = BinaryPayloadDecoder.fromRegisters( client.read_coils(207, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() c211 = BinaryPayloadDecoder.fromRegisters( client.read_coils(211, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() c902 = BinaryPayloadDecoder.fromRegisters( client.read_coils(902, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() c1200 = BinaryPayloadDecoder.fromRegisters( client.read_coils(1200, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() #Domoticz.Debug("Modbus response: v='" + str(i201) + "'") except: Domoticz.Error( "Modbus TCP/IP communication error (input registers). Check it out!" ) try: i200 = BinaryPayloadDecoder.fromRegisters( client.read_input_registers(200, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() i201 = BinaryPayloadDecoder.fromRegisters( client.read_input_registers(201, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() i203 = BinaryPayloadDecoder.fromRegisters( client.read_input_registers(203, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() i204 = BinaryPayloadDecoder.fromRegisters( client.read_input_registers(204, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() i205 = BinaryPayloadDecoder.fromRegisters( client.read_input_registers(205, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() i206 = BinaryPayloadDecoder.fromRegisters( client.read_input_registers(206, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() #Domoticz.Debug("Modbus response: v='" + str(i201) + "'") except: Domoticz.Error( "Modbus TCP/IP communication error (input registers). Check it out!" ) try: d200 = BinaryPayloadDecoder.fromRegisters( client.read_discrete_inputs(200, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() d201 = BinaryPayloadDecoder.fromRegisters( client.read_discrete_inputs(201, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() d202 = BinaryPayloadDecoder.fromRegisters( client.read_discrete_inputs(202, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() d203 = BinaryPayloadDecoder.fromRegisters( client.read_discrete_inputs(203, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() #Domoticz.Debug("Modbus response: v='" + str(i201) + "'") except: Domoticz.Error( "Modbus TCP/IP communication error (discrete inputs). Check it out!" ) try: v1000 = BinaryPayloadDecoder.fromRegisters( client.read_holding_registers(1000, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() v1001 = BinaryPayloadDecoder.fromRegisters( client.read_holding_registers(1001, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() #v1008 = BinaryPayloadDecoder.fromRegisters(client.read_holding_registers(1008, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() #v1009 = BinaryPayloadDecoder.fromRegisters(client.read_holding_registers(1009, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() #v1012 = BinaryPayloadDecoder.fromRegisters(client.read_holding_registers(1012, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() #v1013 = BinaryPayloadDecoder.fromRegisters(client.read_holding_registers(1013, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() v1015 = BinaryPayloadDecoder.fromRegisters( client.read_holding_registers(1015, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() v1016 = BinaryPayloadDecoder.fromRegisters( client.read_holding_registers(1016, 1), byteorder=Endian.Big, wordorder=Endian.Big).decode_16bit_int() #Domoticz.Debug("Modbus response: v='" + str(v1015) + "'") except: Domoticz.Error( "Modbus TCP/IP communication error (holding registers). Check it out!" ) # == Temperatures Devices[self.uTU1].Update(0, str(i200 / 10)) Devices[self.uTU2].Update(0, str(i201 / 10)) Devices[self.uTEa].Update(0, str(i203 / 10)) Devices[self.uTEb].Update(0, str(i204 / 10)) # == IN1 & IN2 # I00205 Stav vstupu IN1 (0-10V): Analogový vstup: U= DATA/1000, Kontaktní vstup: rozepnuto ~ 3350 až 3450, sepnuto ~ do 20 # I00206 Stav vstupu IN2 (0-10V): Analogový vstup: U= DATA/1000, Kontaktní vstup: rozepnuto ~ 3350 až 3450, sepnuto ~ do 20 # kontakt: Statuses: Open: nValue = 1, Closed: nValue = 0 if self.uIN1 in Devices: if self.atreaIN1type == "Contact": Devices[self.uIN1].Update(int(not (i205 <= 50)), "") elif Devices[self.uIN1].Type == 81: # Humidity_status can be one of: # 0=Normal 45~50, 55~60 # 1=Comfortable 50~55 # 2=Dry <45 # 3=Wet >60 if i205 < 4500: humstat = 2 elif i205 > 6000: humstat = 3 elif i205 >= 5000 and i205 <= 5500: humstat = 1 else: humstat = 0 Devices[self.uIN1].Update(int(i205 / 100), str(humstat)) else: Devices[self.uIN1].Update(int(i205 / 100), str(i205 / 100)) if self.uIN2 in Devices: if self.atreaIN2type == "Contact": Devices[self.uIN2].Update(int(not (i206 <= 50)), "") elif Devices[self.uIN2].Type == 81: if i206 < 4500: humstat = 2 elif i206 > 6000: humstat = 3 elif i206 >= 5000 and i206 <= 5500: humstat = 1 else: humstat = 0 Devices[self.uIN2].Update(int(i206 / 100), str(humstat)) else: Devices[self.uIN2].Update(int(i206 / 100), str(i206 / 100)) # == D1 & D2 & D3 & D4 # D00200 Stav vstupu D1 : 0/1 : Vypnuto/Zapnuto # D00201 Stav vstupu D2 : 0/1 : Vypnuto/Zapnuto # D00202 Stav vstupu D3 : 0/1 : Vypnuto/Zapnuto # D00203 Stav vstupu D4 : 0/1 : Vypnuto/Zapnuto if self.uD1 in Devices: Devices[self.uD1].Update(int(d200 == 1), "") if self.uD2 in Devices: Devices[self.uD2].Update(int(d201 == 1), "") if self.uD3 in Devices: Devices[self.uD3].Update(int(d202 == 1), "") if self.uD4 in Devices: Devices[self.uD4].Update(int(d203 == 1), "") # == ZVT # C00207 0 = ZVT if self.uZVT in Devices: Devices[self.uZVT].Update(int(c207 == 0), "") # == Bypass # C00211 1 = Bypass flap if self.uBypass in Devices: Devices[self.uBypass].Update(int(c211 == 1), "") # == Heating season # C01200 1 = heating, 0 = non-heating if self.uHeatingSeason in Devices: Devices[self.uHeatingSeason].Update(int(c1200 == 1), "") # == Nightly Cooling # C00902 0 = recuperation, 1 = cooling if self.uNightlyCooling in Devices: Devices[self.uNightlyCooling].Update(int(c902 == 1), "") # == ControlMode if v1015 == 2 or v1016 == 2: Devices[self.uControlMode].Update(1, str(30)) elif v1015 == 1 or v1016 == 1: Devices[self.uControlMode].Update(0, str(10)) else: Devices[self.uControlMode].Update(0, str(20)) # == PowerReq # H01009 Nastavení požadovaného výkonu, pokud H01016=1, 0 = Vyp, 12=12%,..., 100 = 100% # H01013 Nastavení požadovaného výkonu, pokud H01016=0/2, 0 = Vyp, 12=12%,..., 100 = 100% #if (v1016 == 1): Devices[self.uPowerReq].Update(int(int(v1009) >= 10), str(self._powerPercentToDomoticzValue(v1009))) #elif (v1016 == 2): Devices[self.uPowerReq].Update(int(int(v1013) >= 10), str(self._powerPercentToDomoticzValue(v1013))) #elif (v1016 == 0): Devices[self.uPowerReq].Update(int(int(v1001) >= 10), str(self._powerPercentToDomoticzValue(v1001))) # == PowerCur # "0|60|90|120|150|180|240|300" Devices[self.uPowerCur].Update( int(int(v1001) >= 10), str(self._powerPercentToDomoticzValue(v1001))) # == ModeReq "Vypnuto | Periodické větrání | Větrání" # H01008 Nastavení požadovaného režimu, pokud H01015=1, 0 = Periodické větrání, 1 = Větrání # H01012 Nastavení požadovaného režimu, pokud H01015= 0/2, 0 = Vypnuto, 1 = Periodické větrání, 2 = Větrání #if (v1015 == 1): # if v1008 == 0: Devices[self.uModeReq].Update(1, str(10)) # elif v1008 == 1: Devices[self.uModeReq].Update(1, str(20)) #elif (v1015 == 2): # if v1012 == 0: Devices[self.uModeReq].Update(1, str(10)) # elif v1012 == 1: Devices[self.uModeReq].Update(1, str(20)) #elif (v1015 == 0): # if v1000 == 0: Devices[self.uModeReq].Update(1, str(10)) # elif v1000 == 1: Devices[self.uModeReq].Update(1, str(20)) # == ModeCur # "|Periodické větrání|Větrání|Čidlo vlhkosti|IN2|D1|D2|Koupelny+WC|Odsavač kuchyň|Náběh|Doběh|Odmrazování rekuperátoru" if (v1000 == 0): Devices[self.uModeCur].Update(int(int(v1001) >= 10), str(10)) elif (v1000 == 1): Devices[self.uModeCur].Update(int(int(v1001) >= 10), str(20)) elif (v1000 == 10): Devices[self.uModeCur].Update(1, str(30)) elif (v1000 == 11): Devices[self.uModeCur].Update(1, str(40)) elif (v1000 == 12): Devices[self.uModeCur].Update(1, str(50)) elif (v1000 == 13): Devices[self.uModeCur].Update(1, str(60)) elif (v1000 == 14): Devices[self.uModeCur].Update(1, str(70)) elif (v1000 == 15): Devices[self.uModeCur].Update(1, str(80)) elif (v1000 == 20): Devices[self.uModeCur].Update(1, str(90)) elif (v1000 == 21): Devices[self.uModeCur].Update(1, str(100)) elif (v1000 == 22): Devices[self.uModeCur].Update(1, str(110)) # == Filter alarm from XML via HTTP try: bChangedFilter = True timeOfChange = 0 xml = xmltodict.parse( requests.get("http://" + str(self.TCP_IP) + "/config/alarms.xml").content) for i in xml['root']['errors']['i']: if int(i['@i']) == 100: bChangedFilter = int(i['@p']) == 1 timeOfChange = i['@t'] dtOfChange = datetime.fromtimestamp(int(timeOfChange)) if bChangedFilter: Devices[self.uAlarmFilter].Update( 1, self._("Filter last changed") + ": " + str(dtOfChange)) else: Devices[self.uAlarmFilter].Update( 4, self._("Filter to change since") + ": " + str(dtOfChange)) except: Domoticz.Error( "Failed to get or process XML via HTML to get state of filter alarm." ) return
mqttc.on_subscribe = on_subscribe # Uncomment to enable debug messages #mqttc.on_log = on_log is_mqttConnect = connect_to_MQTT() mqttc.loop_start() mqttc.subscribe("modbus/holding") while True: #Read the first 8 inputs via Modbus regs = c.read_discrete_inputs(0, 8) toBroker = "{" print(is_mqttConnect) if (is_mqttConnect == 0) : if regs: #print(f"Send to Broker ", json.dumps(convert(regs))) for idx, reg in enumerate(regs): if reg == False: toBroker += "0" else: toBroker += "1" if idx < 7: toBroker += ","
c = ModbusClient() if not c.host(host_client): print("host error") if not c.port(502): print("port error") # Автоматическое соединение TCP по запросу Modbus, закрытие после него\TCP auto connect on modbus request, close after it c = ModbusClient(host=host_client, auto_open=True, auto_close=True) while True: if c.is_open(): # считываем регистры установки\read setup registers in_regs_read = c.read_input_registers(0, 51) hl_regs_read = c.read_holding_registers(0, 3) coil_regs_read = c.read_coils(0, 25) dis_in_regs = c.read_discrete_inputs(0, 72) # присвоить переменным значение\assign variables a value CL_POWER, CL_TIMER, CL_WEEK, CL_Boost_MODE, CL_FPLC_MODE, CL_IntRH_CTRL, CL_ExtRH_CTRL, CL_IntCO2_CTRL, CL_ExtCO2_CTRL, CL_IntPM2_5_CTRL, CL_ExtPM2_5_CTRL, CL_IntVOC_CTRL, CL_ExtVOC_CTRL, CL_BoostSWITCH_CTRL, CL_FplcSWITCH_CTRL, CL_FireALARM_CTRL, CL_10V_SENSOR_CTRL, CL_RESET_FILTER_TIMER, CL_RESET_ALARM, CL_RESTORE_FACTORY, CL_CLOUD_CTRL, CL_MinSuAirOutTEMP_CTRL, CL_WaterPRESS_CTRL, CL_WaterFLOW_CTRL, CL_WaterHeaterAutoRestart = coil_regs_read IR_CurSelTEMP, IR_CurTEMP_SuAirIn, IR_CurTEMP_SuAirOut, IR_CurTEMP_ExAirIn, IR_CurTEMP_ExAirOut, unknown6in, unknown7in, IR_CurTEMP_Ext, IR_CurTEMP_Water, IR_CurVBAT, IR_CurRH_Int, IR_CurRH_Ext, IR_CurCO2_Int, IR_CurCO2_Ext, IR_CurPM2_5_Int, IR_CurPM2_5_Ext, IR_CurVOC_Int, IR_CurVOC_Ext, IR_Cur10V_SENSOR, IR_CurSuAirFLOW, IR_CurExAirFLOW, IR_CurSuPRESS, IR_CurExPRESS, IR_SuRPM, IR_ExRPM, unknown26in, IR_CurTIMER_TIME, unknown28in, IR_CurFILTER_TIMER, unknown30in, IR_TotalWorkingTime, IR_StateFILTER, IR_CurWeekSpeed, IR_CurWeekSetTemp, unknown35in, unknown36in, IR_VerMAIN_FMW, IR_DeviceTYPE, IR_ALARM, IR_RH_U, IR_CO2_U, IR_PM2_5_U, IR_VOC_U, IR_PreHeater_U, IR_MainHeater_U, IR_BPS_ROTOR_U, IR_KKB_U, IR_ReturnWater_U, IR_SuAirOutSetTemp, IR_WaterStandbySetTemp, IR_WaterStartSetTemp = in_regs_read DI_CurBoostSWITCH, DI_CurFplcSWITCH, DI_CurFireALARM, DI_StatusRH, DI_StatusCO2, DI_StatusPM2_5, DI_StatusVOC, DI_StatusHEATER, DI_StatusCOOLER, DI_StatusFanBLOWING, DI_CurPreHeaterThermostat, DI_CurMainHeaterThermostat, DI_CurSuFilterPRESS, DI_CurExFilterPRESS, DI_CurWaterPRESS, DI_CurWaterFLOW, DI_CurSuFanPRESS, DI_CurExFanPRESS, DI_WaterPreheatingStatus, DI_AlarmCODE0, DI_AlarmCODE1, DI_AlarmCODE2, DI_AlarmCODE3, DI_AlarmCODE4, DI_AlarmCODE5, DI_AlarmCODE6, DI_AlarmCODE7, DI_AlarmCODE8, DI_AlarmCODE9, DI_AlarmCODE10, DI_AlarmCODE11, DI_AlarmCODE12, DI_AlarmCODE13, DI_AlarmCODE14, DI_AlarmCODE15, DI_AlarmCODE16, DI_AlarmCODE17, DI_AlarmCODE18, DI_AlarmCODE19, DI_AlarmCODE20, DI_AlarmCODE21, DI_AlarmCODE22, DI_AlarmCODE23, DI_AlarmCODE24, DI_AlarmCODE25, DI_AlarmCODE26, DI_AlarmCODE27, DI_AlarmCODE28, DI_AlarmCODE29, DI_AlarmCODE30, DI_AlarmCODE31, DI_AlarmCODE32, DI_AlarmCODE33, DI_AlarmCODE34, DI_AlarmCODE35, DI_AlarmCODE36, DI_AlarmCODE37, DI_AlarmCODE38, DI_AlarmCODE39, DI_AlarmCODE40, DI_AlarmCODE41, DI_AlarmCODE42, DI_AlarmCODE43, DI_AlarmCODE44, DI_AlarmCODE45, DI_AlarmCODE46, DI_AlarmCODE47, DI_AlarmCODE48, DI_AlarmCODE49, DI_AlarmCODE50, DI_AlarmCODE51, DI_AlarmCODE52 = dis_in_regs HR_VENTILATION_MODE, HR_MaxSPEED_MODE, HR_SPEED_MODE = hl_regs_read print("Время", real_time) print("Время", type(real_time)) # тест списков :) # print("количество значений списка переменних", len(other)) print("количество значений списка регистров", type(hl_regs_read)) print(CL_POWER) print(IR_CurSelTEMP) print(DI_StatusHEATER) print(HR_SPEED_MODE) else:
class Device(): def __init__(self, host, port, timeout, byteorder=BE): # big_endian : Byte order of the device memory structure # True >> big endian # False >> little endian if byteorder == BE: self.big_endian=True else: self.big_endian=False self.dev = ModbusClient() self.dev.host(host) self.dev.port(port) self.dev.timeout(timeout) self.dev.open() #self.dev.debug = True #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ READ METHODS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# #Method to read binary variable def read_bits(self, VarNameList, AddressList, functioncode=2): # Arguments: # VarNameList : list of variable name # AddressList : list of variable register address in decimal (relative address) # functioncode : functioncode for modbus reading operation # 1 >> for Discrete Output (Coils) # 2 >> for Discrete Input # Return : dictionary of variable name and its value self.values = [] if functioncode == 1: for address in AddressList: self.values.extend(self.dev.read_coils(address[0], len(address))) elif functioncode == 2: for address in AddressList: self.values.extend(self.dev.read_discrete_inputs(address[0], len(address))) self.Result = dict(zip(VarNameList, self.values)) return self.Result #Method to read INT16 or UINT16 variable def read_INT16(self, VarNameList, AddressList, MultiplierList, signed=False, roundto=3, functioncode=3): # Arguments: # VarNameList : list of variable name # AddressList : list of variable register address in decimal (relative address) # MultiplierList : list of multiplier # roundto : number of digits after decimal point # any positive integer number >> to limit the number of digits after decimal point # None >> to disable # signed : True >> for signed values # False >> for unsigned values # functioncode : functioncode for modbus reading operation # 3 >> for Holding Register # 4 >> for Input Register # Return : dictionary of variable name and its value self.values = [] if functioncode == 3: for address in AddressList: self.values.extend(self.dev.read_holding_registers(address[0],len(address))) elif functioncode == 4: for address in AddressList: self.values.extend(self.dev.read_input_registers(address[0],len(address))) if signed: self.values = UINT16toINT16(self.values) for i in range(0, len(self.values)): self.values[i] = round(self.values[i]*MultiplierList[i],roundto) self.Result = dict(zip(VarNameList, self.values)) return self.Result #Method to read INT32 or UINT32 variable def read_INT32(self, VarNameList, AddressList, MultiplierList, signed=False, roundto=3, functioncode=3): # Arguments: # VarNameList : list of variable name # AddressList : list of variable register address in decimal (relative address) # MultiplierList : list of multiplier # roundto : number of digits after decimal point # any positive integer number >> to limit the number of digits after decimal point # None >> to disable # signed : True >> for signed values # False >> for unsigned values # functioncode : functioncode for modbus reading operation # 3 >> for Holding Register # 4 >> for Input Register # Return : dictionary of variable name and its value self.values = [] if functioncode == 3: for address in AddressList: self.values.extend(self.dev.read_holding_registers(address[0],len(address))) elif functioncode == 4: for address in AddressList: self.values.extend(self.dev.read_input_registers(address[0],len(address))) self.values = UINT16toINT32(self.values, self.big_endian, signed) for i in range(0, len(self.values)): self.values[i] = round(self.values[i]*MultiplierList[i], roundto) self.Result = dict(zip(VarNameList, self.values)) return self.Result #Method to read INT64 or UINT64 variable def read_INT64(self, VarNameList, AddressList, MultiplierList, signed=False, roundto=3, functioncode=3): # Arguments: # VarNameList : list of variable name # AddressList : list of variable register address in decimal (relative address) # MultiplierList : list of multiplier # roundto : number of digits after decimal point # any positive integer number >> to limit the number of digits after decimal point # None >> to disable # signed : True >> for signed values # False >> for unsigned values # functioncode : functioncode for modbus reading operation # 3 >> for Holding Register # 4 >> for Input Register # Return : dictionary of variable name and its value self.values = [] if functioncode == 3: for address in AddressList: self.values.extend(self.dev.read_holding_registers(address[0],len(address))) elif functioncode == 4: for address in AddressList: self.values.extend(self.dev.read_input_registers(address[0],len(address))) self.values = UINT16toINT64(self.values, self.big_endian, signed) for i in range(0, len(self.values)): self.values[i] = round(self.values[i]*MultiplierList[i], roundto) self.Result = dict(zip(VarNameList, self.values)) return self.Result #Method to read FLOAT16 variable def read_FLOAT16(self, VarNameList, AddressList, MultiplierList, roundto=3, functioncode=3): # Arguments: # VarNameList : list of variable name # AddressList : list of variable register address in decimal (relative address) # MultiplierList : list of multiplier # roundto : number of digits after decimal point # any positive integer number >> to limit the number of digits after decimal point # None >> to disable # functioncode : functioncode for modbus reading operation # 3 >> for Holding Register # 4 >> for Input Register # Return : dictionary of variable name and its value self.values = [] if functioncode == 3: for address in AddressList: self.values.extend(self.dev.read_holding_registers(address[0],len(address))) elif functioncode == 4: for address in AddressList: self.values.extend(self.dev.read_input_registers(address[0],len(address))) self.values = UINT16toFLOAT16(self.values) for i in range(0, len(self.values)): self.values[i] = round(self.values[i]*MultiplierList[i], roundto) self.Result = dict(zip(VarNameList, self.values)) return self.Result #Method to read FLOAT32 variable def read_FLOAT32(self, VarNameList, AddressList, MultiplierList, roundto=3, functioncode=3): # Arguments: # VarNameList : list of variable name # AddressList : list of variable register address in decimal (relative address) # MultiplierList : list of multiplier # roundto : number of digits after decimal point # any positive integer number >> to limit the number of digits after decimal point # None >> to disable # functioncode : functioncode for modbus reading operation # 3 >> for Holding Register # 4 >> for Input Register # Return : dictionary of variable name and its value self.values = [] if functioncode == 3: for address in AddressList: self.values.extend(self.dev.read_holding_registers(address[0],len(address))) elif functioncode == 4: for address in AddressList: self.values.extend(self.dev.read_input_registers(address[0],len(address))) self.values = UINT16toFLOAT32(self.values, self.big_endian) for i in range(0, len(self.values)): self.values[i] = round(self.values[i]*MultiplierList[i], roundto) self.Result = dict(zip(VarNameList, self.values)) return self.Result #Method to read FLOAT64 variable def read_FLOAT64(self, VarNameList, AddressList, MultiplierList, roundto=3, functioncode=3): # Arguments: # VarNameList : list of variable name # AddressList : list of variable register address in decimal (relative address) # MultiplierList : list of multiplier # roundto : number of digits after decimal point # any positive integer number >> to limit the number of digits after decimal point # None >> to disable # functioncode : functioncode for modbus reading operation # 3 >> for Holding Register # 4 >> for Input Register # Return : dictionary of variable name and its value self.values = [] if functioncode == 3: for address in AddressList: self.values.extend(self.dev.read_holding_registers(address[0],len(address))) elif functioncode == 4: for address in AddressList: self.values.extend(self.dev.read_input_registers(address[0],len(address))) self.values = UINT16toFLOAT64(self.values, self.big_endian) for i in range(0, len(self.values)): self.values[i] = round(self.values[i]*MultiplierList[i], roundto) self.Result = dict(zip(VarNameList, self.values)) return self.Result #Method to read STRING variable def read_STRING(self, VarNameList, AddressList, functioncode=3): # Arguments: # VarNameList : list of variable name # AddressList : list of variable register address in decimal (relative address) # functioncode : functioncode for modbus reading operation # 3 >> for Holding Register # 4 >> for Input Register # Return : dictionary of variable name and its value self.values = [] if functioncode == 3: for address in AddressList: _uint16Val = self.dev.read_holding_registers(address[0],len(address)) self.values.append(UINT16toSTRING(_uint16Val, self.big_endian)) elif functioncode == 4: for address in AddressList: _uint16Val = self.dev.read_input_registers(address[0],len(address)) self.values.append(UINT16toSTRING(_uint16Val, self.big_endian)) self.Result = dict(zip(VarNameList, self.values)) return self.Result #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ WRITE METHODS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Method to write binary value on discrete output register (Coil) def write_bit(self, registerAddress, value): # Arguments: # registerAddress : register address in decimal (relative address) # value : 0 or 1 self.dev.write_single_coil(registerAddress, value) # Method to write numeric value on holding register def write_num(self, registerAddress, value, valueType): # Arguments: # registerAddress : register START address in decimal (relative address) # value : numerical value # valueType : UINT16, UINT32, UINT64, INT16, INT32, INT64, FLOAT16, # FLOAT32, FLOAT64, STRING startAddress = registerAddress val = None if valueType == UINT16: val = [value] elif valueType == INT16: val = INT16toUINT16([value]) elif valueType == UINT32: val = INT32toUINT16(value, self.big_endian, signed=False) elif valueType == INT32: val = INT32toUINT16(value, self.big_endian, signed=True) elif valueType == UINT64: val = INT64toUINT16(value, self.big_endian, signed=False) elif valueType == INT64: val = INT64toUINT16(value, self.big_endian, signed=True) elif valueType == FLOAT16: val = FLOAT16toUINT16([value]) elif valueType == FLOAT32: val = FLOAT32toUINT16(value, self.big_endian) elif valueType == FLOAT64: val = FLOAT64toUINT16(value, self.big_endian) elif valueType == STRING: val = STRINGtoUINT16(value, self.big_endian) # write multiple registers self.dev.write_multiple_registers(startAddress, val) def close(self): self.dev.close()
class ClienteMODBUS(): """ Classe Cliente MODBUS """ def __init__(self, server_ip, porta, device_id=1, scan_time=0.1, valor=0, dbpath="C:\database.db"): """ Construtor """ self._scan_time = scan_time self._server_ip = server_ip self._device_id = device_id self._port = porta self._cliente = ModbusClient(host=server_ip, port=porta, unit_id=device_id) self._dbpath = dbpath self._valor = valor self._con = sqlite3.connect(self._dbpath) self._cursor = self._con.cursor() def atendimento(self): """ Método para atendimento do usuário """ try: self._cliente.open() print('\n\033[33m --> Cliente Modbus conectado..\033[m\n') except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') try: atendimento = True while atendimento: print('-' * 100) print('\033[34mCliente Modbus\033[m'.center(100)) print('-' * 100) sel = input( "Qual serviço? \n1- Leitura \n2- Escrita \n3- Configuração \n4- Sair \nNº Serviço: " ) if sel == '1': self.createTable() self.createTableF01() self.createTableF02() self.createTableF03() self.createTableF04() print('\nQual tipo de dado deseja ler?') print( "1- Coil Status \n2- Input Status \n3- Holding Register \n4- Input Register" ) while True: tipo = int(input("Type: ")) if tipo > 4: print('\033[31mDigite um tipo válido..\033[m') sleep(0.5) else: break if tipo == 3 or tipo == 4: while True: val = int( input( "\n1- Decimal \n2- Floating Point \n3- Float Swapped \nLeitura: " )) if val > 3: print('\033[31mDigite um tipo válido..\033[m') sleep(0.5) else: break if val == 1: #valores decimais addr = int(input(f'\nAddress: ')) leng = int(input(f'Length: ')) nvezes = input('Quantidade de leituras: ') print('\nComeçando leitura Decimal..\n') sleep(0.5) try: for i in range(0, int(nvezes)): print(f'\033[33mLeitura {i+1}:\033[m', end='') print( self.lerDado(int(tipo), int(addr), leng)) sleep(self._scan_time) print( '\nValores lidos e inseridos no DB com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') try: sleep(0.5) print( '\033[33m\nTentando novamente..\033[m') if not self._cliente.is_open(): self._cliente.open() sleep(0.5) for i in range(0, int(nvezes)): print( f'\033[33mLeitura {i + 1}:\033[m', end='') print( self.lerDado( int(tipo), int(addr), leng)) sleep(self._scan_time) print( '\nValores lidos e inseridos no DB com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') print( '\nO Cliente não conseguiu receber uma resposta.. \nVoltando ao menu..\n\n' ) sleep(1.5) elif val == 2: #valores FLOAT addr = input(f'\nAddress: ') leng = int(input(f'Length: ')) nvezes = input('Quantidade de leituras: ') print('\nComeçando leitura FLOAT..\n') sleep(0.5) try: for i in range(0, int(nvezes)): print(f'\033[33mLeitura {i + 1}:\033[m', end='') print( self.lerDadoFloat( int(tipo), int(addr), leng)) sleep(self._scan_time) print( '\nValores lidos e inseridos no DB com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m\n') print( 'O Cliente não conseguiu receber uma resposta.. \nVoltando ao menu..\n\n' ) sleep(1.5) elif val == 3: #valores FLOAT SWAPPED addr = input(f'\nAddress: ') leng = int(input(f'Length: ')) nvezes = input('Quantidade de leituras: ') print('\nComeçando leitura FLOAT SWAPPED..\n') sleep(0.5) try: for i in range(0, int(nvezes)): print(f'\033[33mLeitura {i + 1}:\033[m', end='') print( self.lerDadoFloatSwapped( int(tipo), int(addr), leng)) sleep(self._scan_time) print( '\nValores lidos e inseridos no DB com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m\n') print( 'O Cliente não conseguiu receber uma resposta.. \nVoltando ao menu..\n\n' ) sleep(1.5) else: print('\033[31mSeleção inválida..\033[m\n') sleep(0.7) else: addr = input(f'\nAddress: ') leng = int(input(f'Length: ')) nvezes = input('Quantidade de leituras: ') print('\nComeçando leitura..\n') sleep(0.5) try: for i in range(0, int(nvezes)): print(f'\033[33mLeitura {i + 1}:\033[m', end='') print(self.lerDado(int(tipo), int(addr), leng)) sleep(self._scan_time) print( '\nValores lidos e inseridos no DB com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m\n') print( 'O Cliente não conseguiu receber uma resposta.. \nVoltando ao menu..\n\n' ) sleep(1.5) elif sel == '2': print( '\nQual tipo de dado deseja escrever? \n1- Coil Status \n2- Holding Register' ) while True: tipo = int(input("Tipo: ")) if tipo > 2: print('\033[31mDigite um tipo válido..\033[m') sleep(0.5) else: break addr = input(f'Digite o endereço: ') valor = int(input(f'Digite o valor que deseja escrever: ')) try: print('\nEscrevendo..') sleep(0.5) self.escreveDado(int(tipo), int(addr), valor) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') print( '\nO Cliente não conseguiu escrever.. \nVoltando ao menu..\n\n' ) sleep(1.5) elif sel == '3': print('') print('-' * 100) print('Configurações de Leitura'.center(100)) print( f'\n\033[32m->\033[m Configuração atual: - IP Addrs: \033[35m{self._server_ip}\033[m - TCP Port: \033[35m{self._port}\033[m - Device ID: \033[35m{self._device_id}\033[m - Scan_Time: \033[35m{self._scan_time}\033[ms' ) print( '\nQual tipo de configuração deseja fazer? \n1- Endereço IP \n2- Porta TCP \n3- Device ID \n4- ScanTime \n5- Voltar' ) config = int(input("Configuração: ")) if config == 1: ipserv = str(input(' Novo endereço IP: ')) try: self._cliente.close() self._server_ip = ipserv self._cliente = ModbusClient(host=self._server_ip) self._cliente.open() print( f'\nServer IP alterado para {ipserv} com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') print( '\nNão foi possível alterar o endereço IP.. \nVoltando ao menu..\n\n' ) sleep(0.5) elif config == 2: porttcp = input(' Nova porta TCP: ') try: self._cliente.close() self._port = int(porttcp) self._cliente = ModbusClient(port=self._port) self._cliente.open() print( f'\nTCP port alterado para {porttcp} com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') print( '\nNão foi possível alterar a porta.. \nVoltando ao menu..\n\n' ) sleep(0.5) elif config == 3: while True: iddevice = input(' Novo device ID: ') if 0 <= int(iddevice) < 256: break else: print( '\033[31mDevice ID deve ser um número inteiro entre 0 e 256.\033[m', end='') sleep(0.5) try: self._cliente.close() self._device_id = int(iddevice) self._cliente = ModbusClient( unit_id=self._device_id) self._cliente.open() print( f'\nDevice ID alterado para {iddevice} com sucesso!!\n' ) sleep(0.5) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') print( '\nNão foi possível alterar o ID do device.. \nVoltando ao menu..\n\n' ) sleep(0.5) elif config == 4: scant = input(' Novo tempo de varredura [s]: ') try: self._scan_time = float(scant) print( f'\nScan_time alterado para {scant}s com sucesso!!\n' ) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') print( '\nNão foi possível alterar o tempo de varredura.. \nVoltando ao menu..\n\n' ) sleep(0.5) elif config == 5: print('\nVoltando ao menu inicial..\n') sleep(0.5) else: print('\033[31mSeleção inválida..\033[m\n') sleep(0.7) elif sel == '4': sleep(0.2) print('\n\033[32mFechando sistema..\033[m') sleep(0.5) self._cliente.close() atendimento = False else: print('\033[31mSeleção inválida..\033[m\n') sleep(0.7) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def createTable(self): """ Método que cria a tabela para armazenamento dos dados, caso ela não exista """ try: sql_str = f""" CREATE TABLE IF NOT EXISTS pointValues ( ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Address TEXT, Type TEXT, Display TEXT, Value REAL, TimeStamp1 TEXT NOT NULL) """ self._cursor.execute(sql_str) self._con.commit() except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def inserirDB(self, addrs, tipo, disp, value): """ Método para inserção dos dados no DB """ try: date = str( datetime.datetime.fromtimestamp(int( time.time())).strftime("%Y-%m-%d %H:%M:%S")) str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'" sql_str = f'INSERT INTO pointValues (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})' self._cursor.execute(sql_str) self._con.commit() except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def createTableF01(self): """ Método que cria a tabela para armazenamento dos dados, caso ela não exista """ try: sql_str = f""" CREATE TABLE IF NOT EXISTS pointValuesF01 ( ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Address TEXT, Type TEXT, Display TEXT, Value REAL, TimeStamp1 TEXT NOT NULL) """ self._cursor.execute(sql_str) self._con.commit() except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def createTableF02(self): """ Método que cria a tabela para armazenamento dos dados, caso ela não exista """ try: sql_str = f""" CREATE TABLE IF NOT EXISTS pointValuesF02 ( ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Address TEXT, Type TEXT, Display TEXT, Value REAL, TimeStamp1 TEXT NOT NULL) """ self._cursor.execute(sql_str) self._con.commit() except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def createTableF03(self): """ Método que cria a tabela para armazenamento dos dados, caso ela não exista """ try: sql_str = f""" CREATE TABLE IF NOT EXISTS pointValuesF03 ( ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Address TEXT, Type TEXT, Display TEXT, Value REAL, TimeStamp1 TEXT NOT NULL) """ self._cursor.execute(sql_str) self._con.commit() except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def createTableF04(self): """ Método que cria a tabela para armazenamento dos dados, caso ela não exista """ try: sql_str = f""" CREATE TABLE IF NOT EXISTS pointValuesF04 ( ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Address TEXT, Type TEXT, Display TEXT, Value REAL, TimeStamp1 TEXT NOT NULL) """ self._cursor.execute(sql_str) self._con.commit() except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def inserirDBF0(self, addrs, tipo, disp, value): """ Método para inserção dos dados no DB """ try: if tipo == "'F01-CoilStatus'": date = str( datetime.datetime.fromtimestamp(int( time.time())).strftime("%Y-%m-%d %H:%M:%S")) str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'" sql_str = f'INSERT INTO pointValuesF01 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})' self._cursor.execute(sql_str) self._con.commit() elif tipo == "'F02-InputStatus'": date = str( datetime.datetime.fromtimestamp(int( time.time())).strftime("%Y-%m-%d %H:%M:%S")) str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'" sql_str = f'INSERT INTO pointValuesF02 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})' self._cursor.execute(sql_str) self._con.commit() elif tipo == "'F03-HoldingRegister'": date = str( datetime.datetime.fromtimestamp(int( time.time())).strftime("%Y-%m-%d %H:%M:%S")) str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'" sql_str = f'INSERT INTO pointValuesF03 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})' self._cursor.execute(sql_str) self._con.commit() elif tipo == "'F04-InputRegister'": date = str( datetime.datetime.fromtimestamp(int( time.time())).strftime("%Y-%m-%d %H:%M:%S")) str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'" sql_str = f'INSERT INTO pointValuesF04 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})' self._cursor.execute(sql_str) self._con.commit() except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def inserirDBFP(self, addrs, tipo, disp, value): """ Método para inserção dos dados no DB """ try: if tipo == "'F03-HoldingRegister'": date = str( datetime.datetime.fromtimestamp(int( time.time())).strftime("%Y-%m-%d %H:%M:%S")) str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'" sql_str = f'INSERT INTO pointValuesF03 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})' self._cursor.execute(sql_str) self._con.commit() elif tipo == "'F04-InputRegister'": date = str( datetime.datetime.fromtimestamp(int( time.time())).strftime("%Y-%m-%d %H:%M:%S")) str_values = f"'{addrs}', {tipo}, {disp}, {value}, '{date}'" sql_str = f'INSERT INTO pointValuesF04 (Address, Type, Display, Value, TimeStamp1) VALUES ({str_values})' self._cursor.execute(sql_str) self._con.commit() else: print( "Erro ao inserir no DB com Floating Point e Float Swapped!!" ) except Exception as e: print('\033[31mERRO: ', e.args, '\033[m') def lerDado(self, tipo, addr, leng=1): """ Método para leitura MODBUS """ if tipo == 1: co = self._cliente.read_coils(addr - 1, leng) ic = 0 while ic <= leng: if ic == leng: break else: value = co[0 + ic] ic += 1 # print(value) if value == True: value = 1 else: value = 0 ende = str(addr + ic - 1).zfill(5) self.inserirDB(addrs=str(ende), tipo="'F01-CoilStatus'", disp="'Booleano'", value=value) self.inserirDBF0(addrs=str(ende), tipo="'F01-CoilStatus'", disp="'Booleano'", value=value) return co elif tipo == 2: di = self._cliente.read_discrete_inputs(addr - 1, leng) idi = 0 while idi <= leng: if idi == leng: break else: value = di[0 + idi] idi += 1 # print(value) self.inserirDB(addrs=(10000 + addr + idi - 1), tipo="'F02-InputStatus'", disp="'Booleano'", value=value) self.inserirDBF0(addrs=(10000 + addr + idi - 1), tipo="'F02-InputStatus'", disp="'Booleano'", value=value) return di elif tipo == 3: hr = self._cliente.read_holding_registers(addr - 1, leng) ihr = 0 while ihr <= leng: if ihr == leng: break else: value = hr[0 + ihr] ihr += 1 # print(value) self.inserirDB(addrs=(40000 + addr + ihr - 1), tipo="'F03-HoldingRegister'", disp="'Decimal'", value=value) self.inserirDBF0(addrs=(40000 + addr + ihr - 1), tipo="'F03-HoldingRegister'", disp="'Decimal'", value=value) return hr elif tipo == 4: ir = self._cliente.read_input_registers(addr - 1, leng) iir = 0 while iir <= leng: if iir == leng: break else: value = ir[0 + iir] iir += 1 # print(value) self.inserirDB(addrs=(30000 + addr + iir - 1), tipo="'F04-InputRegister'", disp="'Decimal'", value=value) self.inserirDBF0(addrs=(30000 + addr + iir - 1), tipo="'F04-InputRegister'", disp="'Decimal'", value=value) return ir else: print('Tipo de leitura inválido..') def lerDadoFloat(self, tipo, addr, leng): """ Método para leitura FLOAT MODBUS """ i = 0 g = 0 e1 = [] listfloat = [] while i < leng: if tipo == 3: i1 = self._cliente.read_holding_registers(addr - 1 + g, 2) tipore = "'F03-HoldingRegister'" ende = 40000 elif tipo == 4: i1 = self._cliente.read_input_registers(addr - 1 + g, 2) tipore = "'F04-InputRegister'" ende = 30000 else: print('Tipo inválido..') for x in i1: x = bin(x).lstrip("0b") e1.insert(0 + g, x) i += 1 g += 2 e = 0 while e <= leng: e2 = '' for x in e1: e2 = str(f'{e2}{x.rjust(16, "0")} ') e += 1 b2 = str(f'{e2}') e3 = b2.split() y = 0 while y < len(e3): ieee = f'{e3[0+y]}{e3[1+y]}' sign = int(ieee[0]) expo = str(ieee[1:9]) expodec = 0 expopot = 7 for i in range(8): expodec = expodec + (int(expo[i]) * (2**expopot)) expopot -= 1 mant = str(ieee[9:]) mantdec = 0 mantpot = -1 for i in range(23): mantdec = mantdec + (int(mant[i]) * (2**mantpot)) mantpot -= 1 value = ((-1)**sign) * (1 + mantdec) * 2**(expodec - 127) # print(f'{round(value, 3)}') listfloat.append(round(value, 3)) y += 2 self.inserirDB(addrs=(ende + addr + y - 2), tipo=tipore, disp="'Floating Point'", value=round(value, 3)) self.inserirDBFP(addrs=(ende + addr + y - 2), tipo=tipore, disp="'Floating Point'", value=round(value, 3)) return listfloat def lerDadoFloatSwapped(self, tipo, addr, leng): """ Método para leitura FLOAT SWAPPED MODBUS """ i = 0 g = 0 e1 = [] listfloatsp = [] while i < leng: if tipo == 3: i1 = self._cliente.read_holding_registers(addr - 1 + g, 2) tipore = "'F03-HoldingRegister'" ende = 40000 elif tipo == 4: i1 = self._cliente.read_input_registers(addr - 1 + g, 2) tipore = "'F04-InputRegister'" ende = 30000 else: print('Tipo inválido..') i2 = i1[::-1] for x in i2: x = bin(x).lstrip("0b") e1.insert(0 + g, x) i += 1 g += 2 e = 0 while e <= leng: e2 = '' for x in e1: e2 = str(f'{e2}{x.rjust(16, "0")} ') e += 1 b2 = str(f'{e2}') e3 = b2.split() y = 0 while y < len(e3): ieee = f'{e3[0+y]}{e3[1+y]}' sign = int(ieee[0]) expo = str(ieee[1:9]) expodec = 0 expopot = 7 for i in range(8): expodec = expodec + (int(expo[i]) * (2**expopot)) expopot -= 1 mant = str(ieee[9:]) mantdec = 0 mantpot = -1 for i in range(23): mantdec = mantdec + (int(mant[i]) * (2**mantpot)) mantpot -= 1 value = ((-1)**sign) * (1 + mantdec) * 2**(expodec - 127) # print(f'{round(value, 3)}') listfloatsp.append(round(value, 3)) y += 2 self.inserirDB(addrs=(ende + addr + y - 2), tipo=tipore, disp="'Float (Swapped)'", value=round(value, 3)) self.inserirDBFP(addrs=(ende + addr + y - 2), tipo=tipore, disp="'Float (Swapped)'", value=round(value, 3)) return listfloatsp def escreveDado(self, tipo, addr, valor): """ Método para escrita MODBUS """ try: if tipo == 1: print( f'\033[33mValor {valor} escrito no endereço {addr}\033[m\n' ) return self._cliente.write_single_coil(addr - 1, valor) elif tipo == 2: print( f'\033[33mValor {valor} escrito no endereço {addr}\033[m\n' ) return self._cliente.write_single_register(addr - 1, valor) else: print('Tipo de escrita inválido..\n') except Exception as e: print('\033[31mERRO: ', e.args, '\033[m')