async def async_setup_entry(opp, entry, async_add_entities): """Set up the Tibber sensor.""" tibber_connection = opp.data.get(TIBBER_DOMAIN) entity_registry = async_get_entity_reg(opp) device_registry = async_get_dev_reg(opp) entities = [] for home in tibber_connection.get_homes(only_active=False): try: await home.update_info() except asyncio.TimeoutError as err: _LOGGER.error("Timeout connecting to Tibber home: %s ", err) raise PlatformNotReady() from err except aiohttp.ClientError as err: _LOGGER.error("Error connecting to Tibber home: %s ", err) raise PlatformNotReady() from err if home.has_active_subscription: entities.append(TibberSensorElPrice(home)) if home.has_real_time_consumption: await home.rt_subscribe( TibberRtDataHandler(async_add_entities, home, opp).async_callback ) # migrate old_id = home.info["viewer"]["home"]["meteringPointData"]["consumptionEan"] if old_id is None: continue # migrate to new device ids old_entity_id = entity_registry.async_get_entity_id( "sensor", TIBBER_DOMAIN, old_id ) if old_entity_id is not None: entity_registry.async_update_entity( old_entity_id, new_unique_id=home.home_id ) # migrate to new device ids device_entry = device_registry.async_get_device({(TIBBER_DOMAIN, old_id)}) if device_entry and entry.entry_id in device_entry.config_entries: device_registry.async_update_device( device_entry.id, new_identifiers={(TIBBER_DOMAIN, home.home_id)} ) async_add_entities(entities, True)
def async_get_node_from_device_id(opp: OpenPeerPower, device_id: str) -> ZwaveNode: """ Get node from a device ID. Raises ValueError if device is invalid or node can't be found. """ device_entry = async_get_dev_reg(opp).async_get(device_id) if not device_entry: raise ValueError("Device ID is not valid") # Use device config entry ID's to validate that this is a valid zwave_js device # and to get the client config_entry_ids = device_entry.config_entries config_entry_id = next( (config_entry_id for config_entry_id in config_entry_ids if cast( ConfigEntry, opp.config_entries.async_get_entry(config_entry_id), ).domain == DOMAIN), None, ) if config_entry_id is None or config_entry_id not in opp.data[DOMAIN]: raise ValueError( "Device is not from an existing zwave_js config entry") client = opp.data[DOMAIN][config_entry_id][DATA_CLIENT] # Get node ID from device identifier, perform some validation, and then get the # node identifier = next( (get_home_and_node_id_from_device_id(identifier) for identifier in device_entry.identifiers if identifier[0] == DOMAIN), None, ) node_id = int(identifier[1]) if identifier is not None else None if node_id is None or node_id not in client.driver.controller.nodes: raise ValueError("Device node can't be found") return client.driver.controller.nodes[node_id]
async def test_bulk_set_config_parameters(opp, client, multisensor_6, integration): """Test the bulk_set_partial_config_parameters service.""" dev_reg = async_get_dev_reg(opp) device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0] # Test setting config parameter by property and property_key await opp.services.async_call( DOMAIN, SERVICE_BULK_SET_PARTIAL_CONFIG_PARAMETERS, { ATTR_DEVICE_ID: device.id, ATTR_CONFIG_PARAMETER: 102, ATTR_CONFIG_VALUE: 241, }, blocking=True, ) assert len(client.async_send_command_no_wait.call_args_list) == 1 args = client.async_send_command_no_wait.call_args[0][0] assert args["command"] == "node.set_value" assert args["nodeId"] == 52 assert args["valueId"] == { "commandClass": 112, "property": 102, } assert args["value"] == 241 client.async_send_command_no_wait.reset_mock() await opp.services.async_call( DOMAIN, SERVICE_BULK_SET_PARTIAL_CONFIG_PARAMETERS, { ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR, ATTR_CONFIG_PARAMETER: 102, ATTR_CONFIG_VALUE: { 1: 1, 16: 1, 32: 1, 64: 1, 128: 1, }, }, blocking=True, ) assert len(client.async_send_command_no_wait.call_args_list) == 1 args = client.async_send_command_no_wait.call_args[0][0] assert args["command"] == "node.set_value" assert args["nodeId"] == 52 assert args["valueId"] == { "commandClass": 112, "property": 102, } assert args["value"] == 241 client.async_send_command_no_wait.reset_mock() await opp.services.async_call( DOMAIN, SERVICE_BULK_SET_PARTIAL_CONFIG_PARAMETERS, { ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR, ATTR_CONFIG_PARAMETER: 102, ATTR_CONFIG_VALUE: { "0x1": 1, "0x10": 1, "0x20": 1, "0x40": 1, "0x80": 1, }, }, blocking=True, ) assert len(client.async_send_command_no_wait.call_args_list) == 1 args = client.async_send_command_no_wait.call_args[0][0] assert args["command"] == "node.set_value" assert args["nodeId"] == 52 assert args["valueId"] == { "commandClass": 112, "property": 102, } assert args["value"] == 241 client.async_send_command_no_wait.reset_mock() # Test that when a device is awake, we call async_send_command instead of # async_send_command_no_wait multisensor_6.handle_wake_up(None) await opp.services.async_call( DOMAIN, SERVICE_BULK_SET_PARTIAL_CONFIG_PARAMETERS, { ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR, ATTR_CONFIG_PARAMETER: 102, ATTR_CONFIG_VALUE: { 1: 1, 16: 1, 32: 1, 64: 1, 128: 1, }, }, blocking=True, ) assert len(client.async_send_command.call_args_list) == 1 args = client.async_send_command.call_args[0][0] assert args["command"] == "node.set_value" assert args["nodeId"] == 52 assert args["valueId"] == { "commandClass": 112, "property": 102, } assert args["value"] == 241 client.async_send_command.reset_mock()
async def test_set_value(opp, client, climate_danfoss_lc_13, integration): """Test set_value service.""" dev_reg = async_get_dev_reg(opp) device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0] await opp.services.async_call( DOMAIN, SERVICE_SET_VALUE, { ATTR_ENTITY_ID: CLIMATE_DANFOSS_LC13_ENTITY, ATTR_COMMAND_CLASS: 117, ATTR_PROPERTY: "local", ATTR_VALUE: 2, }, blocking=True, ) assert len(client.async_send_command_no_wait.call_args_list) == 1 args = client.async_send_command_no_wait.call_args[0][0] assert args["command"] == "node.set_value" assert args["nodeId"] == 5 assert args["valueId"] == { "commandClassName": "Protection", "commandClass": 117, "endpoint": 0, "property": "local", "propertyName": "local", "ccVersion": 2, "metadata": { "type": "number", "readable": True, "writeable": True, "label": "Local protection state", "states": { "0": "Unprotected", "2": "NoOperationPossible" }, }, "value": 0, } assert args["value"] == 2 client.async_send_command_no_wait.reset_mock() # Test that when a command fails we raise an exception client.async_send_command.return_value = {"success": False} with pytest.raises(SetValueFailed): await opp.services.async_call( DOMAIN, SERVICE_SET_VALUE, { ATTR_DEVICE_ID: device.id, ATTR_COMMAND_CLASS: 117, ATTR_PROPERTY: "local", ATTR_VALUE: 2, ATTR_WAIT_FOR_RESULT: True, }, blocking=True, ) assert len(client.async_send_command.call_args_list) == 1 args = client.async_send_command.call_args[0][0] assert args["command"] == "node.set_value" assert args["nodeId"] == 5 assert args["valueId"] == { "commandClassName": "Protection", "commandClass": 117, "endpoint": 0, "property": "local", "propertyName": "local", "ccVersion": 2, "metadata": { "type": "number", "readable": True, "writeable": True, "label": "Local protection state", "states": { "0": "Unprotected", "2": "NoOperationPossible" }, }, "value": 0, } assert args["value"] == 2 # Test missing device and entities keys with pytest.raises(vol.MultipleInvalid): await opp.services.async_call( DOMAIN, SERVICE_SET_VALUE, { ATTR_COMMAND_CLASS: 117, ATTR_PROPERTY: "local", ATTR_VALUE: 2, ATTR_WAIT_FOR_RESULT: True, }, blocking=True, )
async def test_set_config_parameter(opp, client, multisensor_6, integration): """Test the set_config_parameter service.""" dev_reg = async_get_dev_reg(opp) ent_reg = async_get_ent_reg(opp) entity_entry = ent_reg.async_get(AIR_TEMPERATURE_SENSOR) # Test setting config parameter by property and property_key await opp.services.async_call( DOMAIN, SERVICE_SET_CONFIG_PARAMETER, { ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR, ATTR_CONFIG_PARAMETER: 102, ATTR_CONFIG_PARAMETER_BITMASK: 1, ATTR_CONFIG_VALUE: 1, }, blocking=True, ) assert len(client.async_send_command_no_wait.call_args_list) == 1 args = client.async_send_command_no_wait.call_args[0][0] assert args["command"] == "node.set_value" assert args["nodeId"] == 52 assert args["valueId"] == { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 102, "propertyName": "Group 2: Send battery reports", "propertyKey": 1, "metadata": { "type": "number", "readable": True, "writeable": True, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": True, "label": "Group 2: Send battery reports", "description": "Include battery information in periodic reports to Group 2", "isFromConfig": True, }, "value": 0, } assert args["value"] == 1 client.async_send_command_no_wait.reset_mock() # Test setting parameter by property name await opp.services.async_call( DOMAIN, SERVICE_SET_CONFIG_PARAMETER, { ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR, ATTR_CONFIG_PARAMETER: "Group 2: Send battery reports", ATTR_CONFIG_VALUE: 1, }, blocking=True, ) assert len(client.async_send_command_no_wait.call_args_list) == 1 args = client.async_send_command_no_wait.call_args[0][0] assert args["command"] == "node.set_value" assert args["nodeId"] == 52 assert args["valueId"] == { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 102, "propertyName": "Group 2: Send battery reports", "propertyKey": 1, "metadata": { "type": "number", "readable": True, "writeable": True, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": True, "label": "Group 2: Send battery reports", "description": "Include battery information in periodic reports to Group 2", "isFromConfig": True, }, "value": 0, } assert args["value"] == 1 client.async_send_command_no_wait.reset_mock() # Test setting parameter by property name and state label await opp.services.async_call( DOMAIN, SERVICE_SET_CONFIG_PARAMETER, { ATTR_DEVICE_ID: entity_entry.device_id, ATTR_CONFIG_PARAMETER: "Temperature Threshold (Unit)", ATTR_CONFIG_VALUE: "Fahrenheit", }, blocking=True, ) assert len(client.async_send_command_no_wait.call_args_list) == 1 args = client.async_send_command_no_wait.call_args[0][0] assert args["command"] == "node.set_value" assert args["nodeId"] == 52 assert args["valueId"] == { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 41, "propertyName": "Temperature Threshold (Unit)", "propertyKey": 15, "metadata": { "type": "number", "readable": True, "writeable": True, "valueSize": 3, "min": 1, "max": 2, "default": 1, "format": 0, "allowManualEntry": False, "states": { "1": "Celsius", "2": "Fahrenheit" }, "label": "Temperature Threshold (Unit)", "isFromConfig": True, }, "value": 0, } assert args["value"] == 2 client.async_send_command_no_wait.reset_mock() # Test setting parameter by property and bitmask await opp.services.async_call( DOMAIN, SERVICE_SET_CONFIG_PARAMETER, { ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR, ATTR_CONFIG_PARAMETER: 102, ATTR_CONFIG_PARAMETER_BITMASK: "0x01", ATTR_CONFIG_VALUE: 1, }, blocking=True, ) assert len(client.async_send_command_no_wait.call_args_list) == 1 args = client.async_send_command_no_wait.call_args[0][0] assert args["command"] == "node.set_value" assert args["nodeId"] == 52 assert args["valueId"] == { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 102, "propertyName": "Group 2: Send battery reports", "propertyKey": 1, "metadata": { "type": "number", "readable": True, "writeable": True, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": True, "label": "Group 2: Send battery reports", "description": "Include battery information in periodic reports to Group 2", "isFromConfig": True, }, "value": 0, } assert args["value"] == 1 # Test that an invalid entity ID raises a ValueError with pytest.raises(ValueError): await opp.services.async_call( DOMAIN, SERVICE_SET_CONFIG_PARAMETER, { ATTR_ENTITY_ID: "sensor.fake_entity", ATTR_CONFIG_PARAMETER: "Temperature Threshold (Unit)", ATTR_CONFIG_VALUE: "Fahrenheit", }, blocking=True, ) # Test that an invalid device ID raises a ValueError with pytest.raises(ValueError): await opp.services.async_call( DOMAIN, SERVICE_SET_CONFIG_PARAMETER, { ATTR_DEVICE_ID: "fake_device_id", ATTR_CONFIG_PARAMETER: "Temperature Threshold (Unit)", ATTR_CONFIG_VALUE: "Fahrenheit", }, blocking=True, ) # Test that we can't include a bitmask value if parameter is a string with pytest.raises(vol.Invalid): await opp.services.async_call( DOMAIN, SERVICE_SET_CONFIG_PARAMETER, { ATTR_DEVICE_ID: entity_entry.device_id, ATTR_CONFIG_PARAMETER: "Temperature Threshold (Unit)", ATTR_CONFIG_PARAMETER_BITMASK: 1, ATTR_CONFIG_VALUE: "Fahrenheit", }, blocking=True, ) non_zwave_js_config_entry = MockConfigEntry(entry_id="fake_entry_id") non_zwave_js_config_entry.add_to_opp(opp) non_zwave_js_device = dev_reg.async_get_or_create( config_entry_id=non_zwave_js_config_entry.entry_id, identifiers={("test", "test")}, ) # Test that a non Z-Wave JS device raises a ValueError with pytest.raises(ValueError): await opp.services.async_call( DOMAIN, SERVICE_SET_CONFIG_PARAMETER, { ATTR_DEVICE_ID: non_zwave_js_device.id, ATTR_CONFIG_PARAMETER: "Temperature Threshold (Unit)", ATTR_CONFIG_VALUE: "Fahrenheit", }, blocking=True, ) zwave_js_device_with_invalid_node_id = dev_reg.async_get_or_create( config_entry_id=integration.entry_id, identifiers={(DOMAIN, "500-500")}) # Test that a Z-Wave JS device with an invalid node ID raises a ValueError with pytest.raises(ValueError): await opp.services.async_call( DOMAIN, SERVICE_SET_CONFIG_PARAMETER, { ATTR_DEVICE_ID: zwave_js_device_with_invalid_node_id.id, ATTR_CONFIG_PARAMETER: "Temperature Threshold (Unit)", ATTR_CONFIG_VALUE: "Fahrenheit", }, blocking=True, ) non_zwave_js_entity = ent_reg.async_get_or_create( "test", "sensor", "test_sensor", suggested_object_id="test_sensor", config_entry=non_zwave_js_config_entry, ) # Test that a non Z-Wave JS entity raises a ValueError with pytest.raises(ValueError): await opp.services.async_call( DOMAIN, SERVICE_SET_CONFIG_PARAMETER, { ATTR_ENTITY_ID: non_zwave_js_entity.entity_id, ATTR_CONFIG_PARAMETER: "Temperature Threshold (Unit)", ATTR_CONFIG_VALUE: "Fahrenheit", }, blocking=True, ) # Test that when a device is awake, we call async_send_command instead of # async_send_command_no_wait multisensor_6.handle_wake_up(None) await opp.services.async_call( DOMAIN, SERVICE_SET_CONFIG_PARAMETER, { ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR, ATTR_CONFIG_PARAMETER: 102, ATTR_CONFIG_PARAMETER_BITMASK: 1, ATTR_CONFIG_VALUE: 1, }, blocking=True, ) assert len(client.async_send_command.call_args_list) == 1 args = client.async_send_command.call_args[0][0] assert args["command"] == "node.set_value" assert args["nodeId"] == 52 assert args["valueId"] == { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 102, "propertyName": "Group 2: Send battery reports", "propertyKey": 1, "metadata": { "type": "number", "readable": True, "writeable": True, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": True, "label": "Group 2: Send battery reports", "description": "Include battery information in periodic reports to Group 2", "isFromConfig": True, }, "value": 0, } assert args["value"] == 1 client.async_send_command.reset_mock()