def _helper(self, data): ''' This factory is used to generate the correct response object from a valid response packet. This decodes from a list of the currently implemented request types. :param data: The response packet to decode :returns: The decoded request or an exception response object ''' function_code = ord(data[0]) _logger.debug("Factory Response[%d]" % function_code) response = self.__lookup.get(function_code, lambda: None)() if function_code > 0x80: code = function_code & 0x7f # strip error portion response = ExceptionResponse(code, ecode.IllegalFunction) if not response: raise ModbusException("Unknown response %d" % function_code) response.decode(data[1:]) if hasattr(response, 'sub_function_code'): lookup = self.__sub_lookup.get(response.function_code, {}) subtype = lookup.get(response.sub_function_code, None) if subtype: response.__class__ = subtype return response
async def test_pb_service_write(hass, do_write, caplog, mock_modbus): """Run test for service write_register.""" func_name = { CALL_TYPE_WRITE_COIL: mock_modbus.write_coil, CALL_TYPE_WRITE_COILS: mock_modbus.write_coils, CALL_TYPE_WRITE_REGISTER: mock_modbus.write_register, CALL_TYPE_WRITE_REGISTERS: mock_modbus.write_registers, } data = { ATTR_HUB: TEST_MODBUS_NAME, ATTR_UNIT: 17, ATTR_ADDRESS: 16, do_write[DATA]: do_write[VALUE], } await hass.services.async_call(DOMAIN, do_write[SERVICE], data, blocking=True) assert func_name[do_write[FUNC]].called assert func_name[do_write[FUNC]].call_args[0] == ( data[ATTR_ADDRESS], data[do_write[DATA]], ) mock_modbus.reset_mock() for return_value in [ ExceptionResponse(0x06), IllegalFunctionRequest(0x06), ModbusException("fail write_"), ]: caplog.set_level(logging.DEBUG) func_name[do_write[FUNC]].return_value = return_value await hass.services.async_call(DOMAIN, do_write[SERVICE], data, blocking=True) assert func_name[do_write[FUNC]].called assert caplog.messages[-1].startswith("Pymodbus:") mock_modbus.reset_mock()
def manipulate_response(self, response): """ Manipulates the actual response according to the required error state. :param response: Modbus response object :return: Modbus response """ skip_encoding = False if not self._manipulator_config: return response else: clear_after = self._manipulator_config.get("clear_after") if clear_after and self._counter > clear_after: logger.info("Resetting manipulator" " after {} responses".format(clear_after)) self.update_manipulator_config(dict(DEFAULT_MANIPULATOR)) return response response_type = self._manipulator_config.get("response_type") if response_type == "error": error_code = self._manipulator_config.get("error_code") logger.warning( "Sending error response for all incoming requests") err_response = ExceptionResponse(response.function_code, error_code) err_response.transaction_id = response.transaction_id err_response.unit_id = response.unit_id response = err_response self._counter += 1 elif response_type == "delayed": delay_by = self._manipulator_config.get("delay_by") logger.warning("Delaying response by {}s for " "all incoming requests".format(delay_by)) time.sleep(delay_by) self._counter += 1 elif response_type == "empty": logger.warning("Sending empty response") self._counter += 1 response.should_respond = False elif response_type == "stray": data_len = self._manipulator_config.get("data_len", 10) if data_len <= 0: logger.warning(f"Invalid data_len {data_len}. " f"Using default lenght 10") data_len = 10 response = os.urandom(data_len) self._counter += 1 skip_encoding = True return response, skip_encoding
def _helper(self, data): function_code = byte2int(data[0]) _logger.debug("Factory Response[%d]" % function_code) response = self.__lookup.get(function_code, lambda: None)() if function_code > 0x80: code = function_code & 0x7f # strip error portion response = ExceptionResponse(code, ecode.IllegalFunction) if not response: raise ModbusException("Unknown response %d" % function_code) response.decode(data[1:]) if hasattr(response, 'sub_function_code'): lookup = self.__sub_lookup.get(response.function_code, {}) subtype = lookup.get(response.sub_function_code, None) if subtype: response.__class__ = subtype return response
def _helper(self, data): ''' This factory is used to generate the correct response object from a valid response packet. This decodes from a list of the currently implemented request types. :param data: The response packet to decode :returns: The decoded request or an exception response object ''' function_code = ord(data[0]) _logger.debug("Factory Response[%d]" % function_code) response = self.__lookup.get(function_code, lambda: None)() if function_code > 0x80: response = ExceptionResponse(function_code & 0x7f, mexcept.IllegalFunction) if not response: raise ModbusException("Unknown response %d" % function_code) response.decode(data[1:]) return response
def __test__ProductionDeviceModMap_get_registers__exception(self): device_data = self.sensorDeviceNS() item_data = device_data.modmap[0] print(item_data) devModMap = ProductionDeviceModMap.factory(item_data) connection = ProductionProtocol.factory(device_data.protocol) result = devModMap.get_registers(connection) exception = ExceptionResponse(131, 1, "IllegalAddress") self.assertEqual(result, exception)
def testRemoteSlaveValidateValues(self): ''' Test validating against a remote slave context ''' client = mock() client.read_coils = lambda a, b: ReadCoilsResponse([1] * 10) client.read_input_registers = lambda a, b: ReadInputRegistersResponse( [10] * 10) client.read_holding_registers = lambda a, b: ExceptionResponse(0x15) context = RemoteSlaveContext(client) result = context.validate(1, 0, 10) self.assertTrue(result) result = context.validate(4, 0, 10) self.assertTrue(result) result = context.validate(3, 0, 10) self.assertFalse(result)
def testRemoteSlaveGetValues(self): ''' Test getting values from a remote slave context ''' client = mock() client.read_coils = lambda a, b: ReadCoilsResponse([1] * 10) client.read_input_registers = lambda a, b: ReadInputRegistersResponse( [10] * 10) client.read_holding_registers = lambda a, b: ExceptionResponse(0x15) context = RemoteSlaveContext(client) result = context.getValues(1, 0, 10) self.assertEqual(result, [1] * 10) result = context.getValues(4, 0, 10) self.assertEqual(result, [10] * 10) result = context.getValues(3, 0, 10) self.assertNotEqual(result, [10] * 10)
async def test_pb_service_write_coil(hass, caplog, mock_modbus): """Run test for service write_coil.""" # Pymodbus write single, response OK. data = { ATTR_HUB: TEST_MODBUS_NAME, ATTR_UNIT: 17, ATTR_ADDRESS: 16, ATTR_STATE: False, } await hass.services.async_call(DOMAIN, SERVICE_WRITE_COIL, data, blocking=True) assert mock_modbus.write_coil.called assert mock_modbus.write_coil.call_args[0] == ( data[ATTR_ADDRESS], data[ATTR_STATE], ) mock_modbus.reset_mock() # Pymodbus write single, response error or exception caplog.set_level(logging.DEBUG) mock_modbus.write_coil.return_value = ExceptionResponse(0x06) await hass.services.async_call(DOMAIN, SERVICE_WRITE_COIL, data, blocking=True) assert mock_modbus.write_coil.called assert caplog.messages[-1].startswith("Pymodbus:") mock_modbus.reset_mock() mock_modbus.write_coil.return_value = IllegalFunctionRequest(0x06) await hass.services.async_call(DOMAIN, SERVICE_WRITE_COIL, data, blocking=True) assert mock_modbus.write_coil.called assert caplog.messages[-1].startswith("Pymodbus:") mock_modbus.reset_mock() mock_modbus.write_coil.side_effect = ModbusException("fail write_") await hass.services.async_call(DOMAIN, SERVICE_WRITE_COIL, data, blocking=True) assert mock_modbus.write_coil.called assert caplog.messages[-1].startswith("Pymodbus:") mock_modbus.reset_mock() # Pymodbus write multiple, response OK. data[ATTR_STATE] = [True, False, True] await hass.services.async_call(DOMAIN, SERVICE_WRITE_COIL, data, blocking=True) assert mock_modbus.write_coils.called assert mock_modbus.write_coils.call_args[0] == ( data[ATTR_ADDRESS], data[ATTR_STATE], ) mock_modbus.reset_mock() # Pymodbus write multiple, response error or exception mock_modbus.write_coils.return_value = ExceptionResponse(0x06) await hass.services.async_call(DOMAIN, SERVICE_WRITE_COIL, data, blocking=True) assert mock_modbus.write_coils.called assert caplog.messages[-1].startswith("Pymodbus:") mock_modbus.reset_mock() mock_modbus.write_coils.return_value = IllegalFunctionRequest(0x06) await hass.services.async_call(DOMAIN, SERVICE_WRITE_COIL, data, blocking=True) assert mock_modbus.write_coils.called assert caplog.messages[-1].startswith("Pymodbus:") mock_modbus.reset_mock() mock_modbus.write_coils.side_effect = ModbusException("fail write_") await hass.services.async_call(DOMAIN, SERVICE_WRITE_COIL, data, blocking=True) assert mock_modbus.write_coils.called assert caplog.messages[-1].startswith("Pymodbus:") mock_modbus.reset_mock()
return_value=now): assert await async_setup_component(hass, DOMAIN, config) is True await hass.async_block_till_done() now = now + timedelta(seconds=DEFAULT_SCAN_INTERVAL + 60) with mock.patch("homeassistant.helpers.event.dt_util.utcnow", return_value=now): async_fire_time_changed(hass, now) await hass.async_block_till_done() @pytest.mark.parametrize( "do_return,do_exception,do_expect", [ [ReadResult([7]), None, "7"], [IllegalFunctionRequest(0x99), None, STATE_UNAVAILABLE], [ExceptionResponse(0x99), None, STATE_UNAVAILABLE], [ReadResult([7]), ModbusException("fail read_"), STATE_UNAVAILABLE], ], ) @pytest.mark.parametrize( "do_type", [CALL_TYPE_REGISTER_HOLDING, CALL_TYPE_REGISTER_INPUT], ) async def test_pb_read_value(hass, caplog, do_type, do_return, do_exception, do_expect, mock_pymodbus): """Run test for different read.""" # the purpose of this test is to test the special # return values from pymodbus: # ExceptionResponse, IllegalResponse
DATA: ATTR_STATE, VALUE: [True, False, True], SERVICE: SERVICE_WRITE_COIL, FUNC: CALL_TYPE_WRITE_COILS, }, ], ) @pytest.mark.parametrize( "do_return", [ { VALUE: ReadResult([0x0001]), DATA: "" }, { VALUE: ExceptionResponse(0x06), DATA: "Pymodbus:" }, { VALUE: IllegalFunctionRequest(0x06), DATA: "Pymodbus:" }, { VALUE: ModbusException("fail write_"), DATA: "Pymodbus:" }, ], ) async def test_pb_service_write(hass, do_write, do_return, caplog, mock_modbus_with_pymodbus): """Run test for service write_register."""
SERVICE: SERVICE_WRITE_COIL, FUNC: CALL_TYPE_WRITE_COIL, }, { DATA: ATTR_STATE, VALUE: [True, False, True], SERVICE: SERVICE_WRITE_COIL, FUNC: CALL_TYPE_WRITE_COILS, }, ], ) @pytest.mark.parametrize( "do_return", [ {VALUE: ReadResult([0x0001]), DATA: ""}, {VALUE: ExceptionResponse(0x06), DATA: "Pymodbus:"}, {VALUE: IllegalFunctionRequest(0x06), DATA: "Pymodbus:"}, {VALUE: ModbusException("fail write_"), DATA: "Pymodbus:"}, ], ) async def test_pb_service_write( hass, do_write, do_return, caplog, mock_modbus_with_pymodbus ): """Run test for service write_register.""" func_name = { CALL_TYPE_WRITE_COIL: mock_modbus_with_pymodbus.write_coil, CALL_TYPE_WRITE_COILS: mock_modbus_with_pymodbus.write_coils, CALL_TYPE_WRITE_REGISTER: mock_modbus_with_pymodbus.write_register, CALL_TYPE_WRITE_REGISTERS: mock_modbus_with_pymodbus.write_registers, }