async def test_sensor_with_forecast(hass): """Test states of the sensor with forecast.""" await init_integration(hass, forecast=True) registry = er.async_get(hass) state = hass.states.get("sensor.home_hours_of_sun_0d") assert state assert state.state == "7.2" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_ICON) == "mdi:weather-partly-cloudy" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TIME_HOURS entry = registry.async_get("sensor.home_hours_of_sun_0d") assert entry assert entry.unique_id == "0123456-hoursofsun-0" state = hass.states.get("sensor.home_realfeel_temperature_max_0d") assert state assert state.state == "29.8" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE entry = registry.async_get("sensor.home_realfeel_temperature_max_0d") assert entry state = hass.states.get("sensor.home_realfeel_temperature_min_0d") assert state assert state.state == "15.1" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE entry = registry.async_get("sensor.home_realfeel_temperature_min_0d") assert entry assert entry.unique_id == "0123456-realfeeltemperaturemin-0" state = hass.states.get("sensor.home_thunderstorm_probability_day_0d") assert state assert state.state == "40" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_ICON) == "mdi:weather-lightning" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE entry = registry.async_get("sensor.home_thunderstorm_probability_day_0d") assert entry assert entry.unique_id == "0123456-thunderstormprobabilityday-0" state = hass.states.get("sensor.home_thunderstorm_probability_night_0d") assert state assert state.state == "40" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_ICON) == "mdi:weather-lightning" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE entry = registry.async_get("sensor.home_thunderstorm_probability_night_0d") assert entry assert entry.unique_id == "0123456-thunderstormprobabilitynight-0" state = hass.states.get("sensor.home_uv_index_0d") assert state assert state.state == "5" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_ICON) == "mdi:weather-sunny" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UV_INDEX assert state.attributes.get("level") == "Moderate" entry = registry.async_get("sensor.home_uv_index_0d") assert entry assert entry.unique_id == "0123456-uvindex-0"
async def test_loading_extra_values(hass, hass_storage): """Test we load extra data from the registry.""" hass_storage[er.STORAGE_KEY] = { "version": er.STORAGE_VERSION, "data": { "entities": [ { "entity_id": "test.named", "platform": "super_platform", "unique_id": "with-name", "name": "registry override", }, { "entity_id": "test.no_name", "platform": "super_platform", "unique_id": "without-name", }, { "entity_id": "test.disabled_user", "platform": "super_platform", "unique_id": "disabled-user", "disabled_by": er.DISABLED_USER, }, { "entity_id": "test.disabled_hass", "platform": "super_platform", "unique_id": "disabled-hass", "disabled_by": er.DISABLED_HASS, }, { "entity_id": "test.invalid__entity", "platform": "super_platform", "unique_id": "invalid-hass", "disabled_by": er.DISABLED_HASS, }, ] }, } await er.async_load(hass) registry = er.async_get(hass) assert len(registry.entities) == 4 entry_with_name = registry.async_get_or_create("test", "super_platform", "with-name") entry_without_name = registry.async_get_or_create("test", "super_platform", "without-name") assert entry_with_name.name == "registry override" assert entry_without_name.name is None assert not entry_with_name.disabled entry_disabled_hass = registry.async_get_or_create("test", "super_platform", "disabled-hass") entry_disabled_user = registry.async_get_or_create("test", "super_platform", "disabled-user") assert entry_disabled_hass.disabled assert entry_disabled_hass.disabled_by == er.DISABLED_HASS assert entry_disabled_user.disabled assert entry_disabled_user.disabled_by == er.DISABLED_USER
async def test_async_get_device_class_lookup(hass): """Test registry device class lookup.""" hass.state = CoreState.not_running ent_reg = er.async_get(hass) ent_reg.async_get_or_create( "binary_sensor", "light", "battery_charging", device_id="light_device_entry_id", device_class="battery_charging", ) ent_reg.async_get_or_create( "sensor", "light", "battery", device_id="light_device_entry_id", device_class="battery", ) ent_reg.async_get_or_create("light", "light", "demo", device_id="light_device_entry_id") ent_reg.async_get_or_create( "binary_sensor", "vacuum", "battery_charging", device_id="vacuum_device_entry_id", device_class="battery_charging", ) ent_reg.async_get_or_create( "sensor", "vacuum", "battery", device_id="vacuum_device_entry_id", device_class="battery", ) ent_reg.async_get_or_create("vacuum", "vacuum", "demo", device_id="vacuum_device_entry_id") ent_reg.async_get_or_create( "binary_sensor", "remote", "battery_charging", device_id="remote_device_entry_id", device_class="battery_charging", ) ent_reg.async_get_or_create("remote", "remote", "demo", device_id="remote_device_entry_id") device_lookup = ent_reg.async_get_device_class_lookup({ ("binary_sensor", "battery_charging"), ("sensor", "battery") }) assert device_lookup == { "remote_device_entry_id": { ( "binary_sensor", "battery_charging", ): "binary_sensor.remote_battery_charging" }, "light_device_entry_id": { ( "binary_sensor", "battery_charging", ): "binary_sensor.light_battery_charging", ("sensor", "battery"): "sensor.light_battery", }, "vacuum_device_entry_id": { ( "binary_sensor", "battery_charging", ): "binary_sensor.vacuum_battery_charging", ("sensor", "battery"): "sensor.vacuum_battery", }, }
async def test_sensors( hass, connect, mock_devices, mock_available_temps, create_device_registry_devices, ): """Test creating an AsusWRT sensor.""" entity_reg = er.async_get(hass) # init config entry config_entry = MockConfigEntry( domain=DOMAIN, data=CONFIG_DATA, options={CONF_CONSIDER_HOME: 60}, ) # init variable unique_id = DOMAIN obj_prefix = slugify(DEFAULT_PREFIX) sensor_prefix = f"{sensor.DOMAIN}.{obj_prefix}" # Pre-enable the status sensor for sensor_name in SENSOR_NAMES: sensor_id = slugify(sensor_name) entity_reg.async_get_or_create( sensor.DOMAIN, DOMAIN, f"{unique_id} {DEFAULT_PREFIX} {sensor_name}", suggested_object_id=f"{obj_prefix}_{sensor_id}", disabled_by=None, ) config_entry.add_to_hass(hass) # initial devices setup assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() async_fire_time_changed(hass, utcnow() + timedelta(seconds=30)) await hass.async_block_till_done() assert hass.states.get(f"{device_tracker.DOMAIN}.test").state == STATE_HOME assert hass.states.get( f"{device_tracker.DOMAIN}.testtwo").state == STATE_HOME assert hass.states.get(f"{sensor_prefix}_download_speed").state == "160.0" assert hass.states.get(f"{sensor_prefix}_download").state == "60.0" assert hass.states.get(f"{sensor_prefix}_upload_speed").state == "80.0" assert hass.states.get(f"{sensor_prefix}_upload").state == "50.0" assert hass.states.get(f"{sensor_prefix}_load_avg_1m").state == "1.1" assert hass.states.get(f"{sensor_prefix}_load_avg_5m").state == "1.2" assert hass.states.get(f"{sensor_prefix}_load_avg_15m").state == "1.3" assert hass.states.get(f"{sensor_prefix}_devices_connected").state == "2" # assert temperature availability exception is handled correctly assert not hass.states.get(f"{sensor_prefix}_2_4ghz_temperature") assert not hass.states.get(f"{sensor_prefix}_5ghz_temperature") assert not hass.states.get(f"{sensor_prefix}_cpu_temperature") # add one device and remove another mock_devices.pop(MOCK_MAC_1) mock_devices[MOCK_MAC_3] = Device(MOCK_MAC_3, "192.168.1.4", "TestThree") async_fire_time_changed(hass, utcnow() + timedelta(seconds=30)) await hass.async_block_till_done() # consider home option set, all devices still home assert hass.states.get(f"{device_tracker.DOMAIN}.test").state == STATE_HOME assert hass.states.get( f"{device_tracker.DOMAIN}.testtwo").state == STATE_HOME assert hass.states.get( f"{device_tracker.DOMAIN}.testthree").state == STATE_HOME assert hass.states.get(f"{sensor_prefix}_devices_connected").state == "2" hass.config_entries.async_update_entry(config_entry, options={CONF_CONSIDER_HOME: 0}) await hass.async_block_till_done() async_fire_time_changed(hass, utcnow() + timedelta(seconds=30)) await hass.async_block_till_done() # consider home option not set, device "test" not home assert hass.states.get( f"{device_tracker.DOMAIN}.test").state == STATE_NOT_HOME # checking temperature sensors without exceptions mock_available_temps.append(True) await hass.config_entries.async_reload(config_entry.entry_id) await hass.async_block_till_done() async_fire_time_changed(hass, utcnow() + timedelta(seconds=30)) await hass.async_block_till_done() assert hass.states.get(f"{sensor_prefix}_load_avg_15m").state == "1.3" assert hass.states.get( f"{sensor_prefix}_2_4ghz_temperature").state == "40.0" assert not hass.states.get(f"{sensor_prefix}_5ghz_temperature") assert hass.states.get(f"{sensor_prefix}_cpu_temperature").state == "71.2"
async def async_create_miio_device_and_coordinator( hass: core.HomeAssistant, entry: config_entries.ConfigEntry): """Set up a data coordinator and one miio device to service multiple entities.""" model: str = entry.data[CONF_MODEL] host = entry.data[CONF_HOST] token = entry.data[CONF_TOKEN] name = entry.title device = None migrate = False update_method = _async_update_data_default coordinator_class = DataUpdateCoordinator if (model not in MODELS_HUMIDIFIER and model not in MODELS_FAN and model not in MODELS_VACUUM and not model.startswith(ROBOROCK_GENERIC) and not model.startswith(ROCKROBO_GENERIC)): return _LOGGER.debug("Initializing with host %s (token %s...)", host, token[:5]) # Humidifiers if model in MODELS_HUMIDIFIER_MIOT: device = AirHumidifierMiot(host, token) migrate = True elif model in MODELS_HUMIDIFIER_MJJSQ: device = AirHumidifierMjjsq(host, token, model=model) migrate = True elif model in MODELS_HUMIDIFIER_MIIO: device = AirHumidifier(host, token, model=model) migrate = True # Airpurifiers and Airfresh elif model in MODEL_AIRPURIFIER_3C: device = AirPurifierMB4(host, token) elif model in MODELS_PURIFIER_MIOT: device = AirPurifierMiot(host, token) elif model.startswith("zhimi.airpurifier."): device = AirPurifier(host, token) elif model.startswith("zhimi.airfresh."): device = AirFresh(host, token) elif (model in MODELS_VACUUM or model.startswith(ROBOROCK_GENERIC) or model.startswith(ROCKROBO_GENERIC)): device = RoborockVacuum(host, token) update_method = _async_update_data_vacuum coordinator_class = DataUpdateCoordinator[VacuumCoordinatorData] # Pedestal fans elif model in MODEL_TO_CLASS_MAP: device = MODEL_TO_CLASS_MAP[model](host, token) elif model in MODELS_FAN_MIIO: device = Fan(host, token, model=model) else: _LOGGER.error( "Unsupported device found! Please create an issue at " "https://github.com/syssi/xiaomi_airpurifier/issues " "and provide the following data: %s", model, ) return if migrate: # Removing fan platform entity for humidifiers and migrate the name to the config entry for migration entity_registry = er.async_get(hass) entity_id = entity_registry.async_get_entity_id( "fan", DOMAIN, entry.unique_id) if entity_id: # This check is entities that have a platform migration only and should be removed in the future if migrate_entity_name := entity_registry.async_get( entity_id).name: hass.config_entries.async_update_entry( entry, title=migrate_entity_name) entity_registry.async_remove(entity_id)
if not color_modes: return False return ColorMode.COLOR_TEMP in color_modes def get_supported_color_modes(hass: HomeAssistant, entity_id: str) -> set | None: """Get supported color modes for a light entity. First try the statemachine, then entity registry. This is the equivalent of entity helper get_supported_features. """ if state := hass.states.get(entity_id): return state.attributes.get(ATTR_SUPPORTED_COLOR_MODES) entity_registry = er.async_get(hass) if not (entry := entity_registry.async_get(entity_id)): raise HomeAssistantError(f"Unknown entity {entity_id}") if not entry.capabilities: return None return entry.capabilities.get(ATTR_SUPPORTED_COLOR_MODES) # Float that represents transition time in seconds to make change. ATTR_TRANSITION = "transition" # Lists holding color values ATTR_RGB_COLOR = "rgb_color" ATTR_RGBW_COLOR = "rgbw_color" ATTR_RGBWW_COLOR = "rgbww_color"
async def test_switches(hass, aioclient_mock): """Test the update_items function with some clients.""" config_entry = await setup_unifi_integration( hass, aioclient_mock, options={ CONF_BLOCK_CLIENT: [BLOCKED["mac"], UNBLOCKED["mac"]], CONF_TRACK_CLIENTS: False, CONF_TRACK_DEVICES: False, }, clients_response=[CLIENT_1, CLIENT_4], devices_response=[DEVICE_1], clients_all_response=[BLOCKED, UNBLOCKED, CLIENT_1], dpigroup_response=DPI_GROUPS, dpiapp_response=DPI_APPS, ) controller = hass.data[UNIFI_DOMAIN][config_entry.entry_id] assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 4 switch_1 = hass.states.get("switch.poe_client_1") assert switch_1 is not None assert switch_1.state == "on" assert switch_1.attributes["power"] == "2.56" assert switch_1.attributes[SWITCH_DOMAIN] == "00:00:00:00:01:01" assert switch_1.attributes["port"] == 1 assert switch_1.attributes["poe_mode"] == "auto" switch_4 = hass.states.get("switch.poe_client_4") assert switch_4 is None blocked = hass.states.get("switch.block_client_1") assert blocked is not None assert blocked.state == "off" unblocked = hass.states.get("switch.block_client_2") assert unblocked is not None assert unblocked.state == "on" dpi_switch = hass.states.get("switch.block_media_streaming") assert dpi_switch is not None assert dpi_switch.state == "on" assert dpi_switch.attributes["icon"] == "mdi:network" ent_reg = er.async_get(hass) for entry_id in ( "switch.poe_client_1", "switch.block_client_1", "switch.block_media_streaming", ): assert ent_reg.async_get(entry_id).entity_category is EntityCategory.CONFIG # Block and unblock client aioclient_mock.post( f"https://{controller.host}:1234/api/s/{controller.site}/cmd/stamgr", ) await hass.services.async_call( SWITCH_DOMAIN, "turn_off", {"entity_id": "switch.block_client_1"}, blocking=True ) assert aioclient_mock.call_count == 11 assert aioclient_mock.mock_calls[10][2] == { "mac": "00:00:00:00:01:01", "cmd": "block-sta", } await hass.services.async_call( SWITCH_DOMAIN, "turn_on", {"entity_id": "switch.block_client_1"}, blocking=True ) assert aioclient_mock.call_count == 12 assert aioclient_mock.mock_calls[11][2] == { "mac": "00:00:00:00:01:01", "cmd": "unblock-sta", } # Enable and disable DPI aioclient_mock.put( f"https://{controller.host}:1234/api/s/{controller.site}/rest/dpiapp/5f976f62e3c58f018ec7e17d", ) await hass.services.async_call( SWITCH_DOMAIN, "turn_off", {"entity_id": "switch.block_media_streaming"}, blocking=True, ) assert aioclient_mock.call_count == 13 assert aioclient_mock.mock_calls[12][2] == {"enabled": False} await hass.services.async_call( SWITCH_DOMAIN, "turn_on", {"entity_id": "switch.block_media_streaming"}, blocking=True, ) assert aioclient_mock.call_count == 14 assert aioclient_mock.mock_calls[13][2] == {"enabled": True} # Make sure no duplicates arise on generic signal update async_dispatcher_send(hass, controller.signal_update) await hass.async_block_till_done() assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 4
async def async_setup_entry( # noqa: C901 hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up Z-Wave JS from a config entry.""" use_addon = entry.data.get(CONF_USE_ADDON) if use_addon: await async_ensure_addon_running(hass, entry) client = ZwaveClient(entry.data[CONF_URL], async_get_clientsession(hass)) dev_reg = device_registry.async_get(hass) ent_reg = entity_registry.async_get(hass) entry_hass_data: dict = hass.data[DOMAIN].setdefault(entry.entry_id, {}) entry_hass_data[DATA_CLIENT] = client entry_hass_data[DATA_PLATFORM_SETUP] = {} registered_unique_ids: dict[str, dict[str, set[str]]] = defaultdict(dict) discovered_value_ids: dict[str, set[str]] = defaultdict(set) async def async_handle_discovery_info( device: device_registry.DeviceEntry, disc_info: ZwaveDiscoveryInfo, value_updates_disc_info: dict[str, ZwaveDiscoveryInfo], ) -> None: """Handle discovery info and all dependent tasks.""" # This migration logic was added in 2021.3 to handle a breaking change to # the value_id format. Some time in the future, this call (as well as the # helper functions) can be removed. async_migrate_discovered_value( hass, ent_reg, registered_unique_ids[device.id][disc_info.platform], device, client, disc_info, ) platform_setup_tasks = entry_hass_data[DATA_PLATFORM_SETUP] platform = disc_info.platform if platform not in platform_setup_tasks: platform_setup_tasks[platform] = hass.async_create_task( hass.config_entries.async_forward_entry_setup(entry, platform)) await platform_setup_tasks[platform] LOGGER.debug("Discovered entity: %s", disc_info) async_dispatcher_send(hass, f"{DOMAIN}_{entry.entry_id}_add_{platform}", disc_info) # If we don't need to watch for updates return early if not disc_info.assumed_state: return value_updates_disc_info[disc_info.primary_value.value_id] = disc_info # If this is the first time we found a value we want to watch for updates, # return early if len(value_updates_disc_info) != 1: return # add listener for value updated events entry.async_on_unload( disc_info.node.on( "value updated", lambda event: async_on_value_updated_fire_event( value_updates_disc_info, event["value"]), )) async def async_on_node_ready(node: ZwaveNode) -> None: """Handle node ready event.""" LOGGER.debug("Processing node %s", node) # register (or update) node in device registry device = register_node_in_dev_reg(hass, entry, dev_reg, client, node) # We only want to create the defaultdict once, even on reinterviews if device.id not in registered_unique_ids: registered_unique_ids[device.id] = defaultdict(set) value_updates_disc_info: dict[str, ZwaveDiscoveryInfo] = {} # run discovery on all node values and create/update entities await asyncio.gather(*(async_handle_discovery_info( device, disc_info, value_updates_disc_info) for disc_info in async_discover_node_values( node, device, discovered_value_ids))) # add listeners to handle new values that get added later for event in ("value added", "value updated", "metadata updated"): entry.async_on_unload( node.on( event, lambda event: hass.async_create_task( async_on_value_added(value_updates_disc_info, event[ "value"])), )) # add listener for stateless node value notification events entry.async_on_unload( node.on( "value notification", lambda event: async_on_value_notification(event[ "value_notification"]), )) # add listener for stateless node notification events entry.async_on_unload( node.on( "notification", lambda event: async_on_notification(event["notification"]), )) async def async_on_node_added(node: ZwaveNode) -> None: """Handle node added event.""" platform_setup_tasks = entry_hass_data[DATA_PLATFORM_SETUP] # We need to set up the sensor platform if it hasn't already been setup in # order to create the node status sensor if SENSOR_DOMAIN not in platform_setup_tasks: platform_setup_tasks[SENSOR_DOMAIN] = hass.async_create_task( hass.config_entries.async_forward_entry_setup( entry, SENSOR_DOMAIN)) # This guard ensures that concurrent runs of this function all await the # platform setup task if not platform_setup_tasks[SENSOR_DOMAIN].done(): await platform_setup_tasks[SENSOR_DOMAIN] # Create a node status sensor for each device async_dispatcher_send( hass, f"{DOMAIN}_{entry.entry_id}_add_node_status_sensor", node) # we only want to run discovery when the node has reached ready state, # otherwise we'll have all kinds of missing info issues. if node.ready: await async_on_node_ready(node) return # if node is not yet ready, register one-time callback for ready state LOGGER.debug("Node added: %s - waiting for it to become ready", node.node_id) node.once( "ready", lambda event: hass.async_create_task( async_on_node_ready(event["node"])), ) # we do submit the node to device registry so user has # some visual feedback that something is (in the process of) being added register_node_in_dev_reg(hass, entry, dev_reg, client, node) async def async_on_value_added(value_updates_disc_info: dict[ str, ZwaveDiscoveryInfo], value: Value) -> None: """Fire value updated event.""" # If node isn't ready or a device for this node doesn't already exist, we can # let the node ready event handler perform discovery. If a value has already # been processed, we don't need to do it again device_id = get_device_id(client, value.node) if (not value.node.ready or not (device := dev_reg.async_get_device({device_id})) or value.value_id in discovered_value_ids[device.id]): return LOGGER.debug("Processing node %s added value %s", value.node, value) await asyncio.gather(*(async_handle_discovery_info( device, disc_info, value_updates_disc_info) for disc_info in async_discover_single_value( value, device, discovered_value_ids)))
async def test_roku_binary_sensors(hass: HomeAssistant, init_integration: MockConfigEntry) -> None: """Test the Roku binary sensors.""" entity_registry = er.async_get(hass) device_registry = dr.async_get(hass) state = hass.states.get("binary_sensor.my_roku_3_headphones_connected") entry = entity_registry.async_get( "binary_sensor.my_roku_3_headphones_connected") assert entry assert state assert entry.unique_id == f"{UPNP_SERIAL}_headphones_connected" assert entry.entity_category is None assert state.state == STATE_OFF assert state.attributes.get( ATTR_FRIENDLY_NAME) == "My Roku 3 Headphones Connected" assert state.attributes.get(ATTR_ICON) == "mdi:headphones" assert ATTR_DEVICE_CLASS not in state.attributes state = hass.states.get("binary_sensor.my_roku_3_supports_airplay") entry = entity_registry.async_get( "binary_sensor.my_roku_3_supports_airplay") assert entry assert state assert entry.unique_id == f"{UPNP_SERIAL}_supports_airplay" assert entry.entity_category == EntityCategory.DIAGNOSTIC assert state.state == STATE_OFF assert state.attributes.get( ATTR_FRIENDLY_NAME) == "My Roku 3 Supports AirPlay" assert state.attributes.get(ATTR_ICON) == "mdi:cast-variant" assert ATTR_DEVICE_CLASS not in state.attributes state = hass.states.get("binary_sensor.my_roku_3_supports_ethernet") entry = entity_registry.async_get( "binary_sensor.my_roku_3_supports_ethernet") assert entry assert state assert entry.unique_id == f"{UPNP_SERIAL}_supports_ethernet" assert entry.entity_category == EntityCategory.DIAGNOSTIC assert state.state == STATE_ON assert state.attributes.get( ATTR_FRIENDLY_NAME) == "My Roku 3 Supports Ethernet" assert state.attributes.get(ATTR_ICON) == "mdi:ethernet" assert ATTR_DEVICE_CLASS not in state.attributes state = hass.states.get("binary_sensor.my_roku_3_supports_find_remote") entry = entity_registry.async_get( "binary_sensor.my_roku_3_supports_find_remote") assert entry assert state assert entry.unique_id == f"{UPNP_SERIAL}_supports_find_remote" assert entry.entity_category == EntityCategory.DIAGNOSTIC assert state.state == STATE_OFF assert state.attributes.get( ATTR_FRIENDLY_NAME) == "My Roku 3 Supports Find Remote" assert state.attributes.get(ATTR_ICON) == "mdi:remote" assert ATTR_DEVICE_CLASS not in state.attributes assert entry.device_id device_entry = device_registry.async_get(entry.device_id) assert device_entry assert device_entry.identifiers == {(DOMAIN, UPNP_SERIAL)} assert device_entry.connections == { (dr.CONNECTION_NETWORK_MAC, "b0:a7:37:96:4d:fb"), (dr.CONNECTION_NETWORK_MAC, "b0:a7:37:96:4d:fa"), } assert device_entry.manufacturer == "Roku" assert device_entry.model == "Roku 3" assert device_entry.name == "My Roku 3" assert device_entry.entry_type is None assert device_entry.sw_version == "7.5.0" assert device_entry.hw_version == "4200X" assert device_entry.suggested_area is None
async def async_remove_orphaned_entries_service(gateway: DeconzGateway) -> None: """Remove orphaned deCONZ entries from device and entity registries.""" device_registry = dr.async_get(gateway.hass) entity_registry = er.async_get(gateway.hass) entity_entries = async_entries_for_config_entry( entity_registry, gateway.config_entry.entry_id ) entities_to_be_removed = [] devices_to_be_removed = [ entry.id for entry in device_registry.devices.values() if gateway.config_entry.entry_id in entry.config_entries ] # Don't remove the Gateway host entry if gateway.api.config.mac: gateway_host = device_registry.async_get_device( connections={(CONNECTION_NETWORK_MAC, gateway.api.config.mac)}, identifiers=set(), ) if gateway_host and gateway_host.id in devices_to_be_removed: devices_to_be_removed.remove(gateway_host.id) # Don't remove the Gateway service entry gateway_service = device_registry.async_get_device( identifiers={(DOMAIN, gateway.api.config.bridge_id)}, connections=set() ) if gateway_service and gateway_service.id in devices_to_be_removed: devices_to_be_removed.remove(gateway_service.id) # Don't remove devices belonging to available events for event in gateway.events: if event.device_id in devices_to_be_removed: devices_to_be_removed.remove(event.device_id) for entry in entity_entries: # Don't remove available entities if entry.unique_id in gateway.entities[entry.domain]: # Don't remove devices with available entities if entry.device_id in devices_to_be_removed: devices_to_be_removed.remove(entry.device_id) continue # Remove entities that are not available entities_to_be_removed.append(entry.entity_id) # Remove unavailable entities for entity_id in entities_to_be_removed: entity_registry.async_remove(entity_id) # Remove devices that don't belong to any entity for device_id in devices_to_be_removed: if ( len( async_entries_for_device( entity_registry, device_id, include_disabled_entities=True ) ) == 0 ): device_registry.async_remove_device(device_id)
async def test_shabbat_times_sensor( hass, legacy_patchable_time, language, now, candle_lighting, havdalah, diaspora, tzname, latitude, longitude, result, ): """Test sensor output for upcoming shabbat/yomtov times.""" time_zone = dt_util.get_time_zone(tzname) test_time = now.replace(tzinfo=time_zone) hass.config.time_zone = tzname hass.config.latitude = latitude hass.config.longitude = longitude registry = er.async_get(hass) with alter_time(test_time): assert await async_setup_component( hass, jewish_calendar.DOMAIN, { "jewish_calendar": { "name": "test", "language": language, "diaspora": diaspora, "candle_lighting_minutes_before_sunset": candle_lighting, "havdalah_minutes_after_sunset": havdalah, } }, ) await hass.async_block_till_done() future = dt_util.utcnow() + timedelta(seconds=30) async_fire_time_changed(hass, future) await hass.async_block_till_done() for sensor_type, result_value in result.items(): if not sensor_type.startswith(language): continue sensor_type = sensor_type.replace(f"{language}_", "") result_value = (dt_util.as_utc(result_value).isoformat() if isinstance( result_value, dt) else result_value) assert hass.states.get(f"sensor.test_{sensor_type}").state == str( result_value), f"Value for {sensor_type}" entity = registry.async_get(f"sensor.test_{sensor_type}") target_sensor_type = sensor_type.replace("parshat_hashavua", "weekly_portion") target_uid = "_".join( map( str, [ latitude, longitude, tzname, HDATE_DEFAULT_ALTITUDE, diaspora, language, candle_lighting, havdalah, target_sensor_type, ], )) assert entity.unique_id == target_uid
async def test_issur_melacha_sensor( hass, legacy_patchable_time, now, candle_lighting, havdalah, diaspora, tzname, latitude, longitude, result, ): """Test Issur Melacha sensor output.""" time_zone = dt_util.get_time_zone(tzname) test_time = time_zone.localize(now) hass.config.time_zone = time_zone hass.config.latitude = latitude hass.config.longitude = longitude registry = er.async_get(hass) with alter_time(test_time): assert await async_setup_component( hass, jewish_calendar.DOMAIN, { "jewish_calendar": { "name": "test", "language": "english", "diaspora": diaspora, "candle_lighting_minutes_before_sunset": candle_lighting, "havdalah_minutes_after_sunset": havdalah, } }, ) await hass.async_block_till_done() future = dt_util.utcnow() + timedelta(seconds=30) async_fire_time_changed(hass, future) await hass.async_block_till_done() assert (hass.states.get( "binary_sensor.test_issur_melacha_in_effect").state == result) entity = registry.async_get( "binary_sensor.test_issur_melacha_in_effect") target_uid = "_".join( map( str, [ latitude, longitude, time_zone, HDATE_DEFAULT_ALTITUDE, diaspora, "english", candle_lighting, havdalah, "issur_melacha_in_effect", ], )) assert entity.unique_id == target_uid
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up this integration using UI.""" client = FrigateApiClient(entry.data.get(CONF_URL), async_get_clientsession(hass)) coordinator = FrigateDataUpdateCoordinator(hass, client=client) await coordinator.async_config_entry_first_refresh() try: server_version = await client.async_get_version() config = await client.async_get_config() except FrigateApiClientError as exc: raise ConfigEntryNotReady from exc if AwesomeVersion(server_version) <= AwesomeVersion( FRIGATE_VERSION_ERROR_CUTOFF): _LOGGER.error( "Using a Frigate server (%s) with version %s <= %s which is not " "compatible -- you must upgrade: %s", entry.data[CONF_URL], server_version, FRIGATE_VERSION_ERROR_CUTOFF, FRIGATE_RELEASES_URL, ) return False model = f"{(await async_get_integration(hass, DOMAIN)).version}/{server_version}" hass.data[DOMAIN][entry.entry_id] = { ATTR_COORDINATOR: coordinator, ATTR_CLIENT: client, ATTR_CONFIG: config, ATTR_MODEL: model, } # Remove old devices associated with cameras that have since been removed # from the Frigate server, keeping the 'master' device for this config # entry. current_devices: set[tuple[str, str]] = set( {get_frigate_device_identifier(entry)}) for item in get_cameras_and_zones(config): current_devices.add(get_frigate_device_identifier(entry, item)) device_registry = dr.async_get(hass) for device_entry in dr.async_entries_for_config_entry( device_registry, entry.entry_id): for identifier in device_entry.identifiers: if identifier in current_devices: break else: device_registry.async_remove_device(device_entry.id) # Cleanup old clips switch (<v0.9.0) if it exists. entity_registry = er.async_get(hass) for camera in config["cameras"].keys(): unique_id = get_frigate_entity_unique_id(entry.entry_id, SWITCH_DOMAIN, f"{camera}_clips") entity_id = entity_registry.async_get_entity_id( SWITCH_DOMAIN, DOMAIN, unique_id) if entity_id: entity_registry.async_remove(entity_id) # Remove old `camera_image_height` option. if CONF_CAMERA_STATIC_IMAGE_HEIGHT in entry.options: new_options = entry.options.copy() new_options.pop(CONF_CAMERA_STATIC_IMAGE_HEIGHT) hass.config_entries.async_update_entry(entry, options=new_options) hass.config_entries.async_setup_platforms(entry, PLATFORMS) entry.async_on_unload(entry.add_update_listener(_async_entry_updated)) return True
async def test_default_setup(hass, dsmr_connection_fixture): """Test the default setup.""" (connection_factory, transport, protocol) = dsmr_connection_fixture from dsmr_parser.obis_references import ( CURRENT_ELECTRICITY_USAGE, ELECTRICITY_ACTIVE_TARIFF, GAS_METER_READING, ) from dsmr_parser.objects import CosemObject, MBusObject entry_data = { "port": "/dev/ttyUSB0", "dsmr_version": "2.2", "precision": 4, "reconnect_interval": 30, "serial_id": "1234", "serial_id_gas": "5678", } entry_options = { "time_between_update": 0, } telegram = { CURRENT_ELECTRICITY_USAGE: CosemObject( [{"value": Decimal("0.0"), "unit": ENERGY_KILO_WATT_HOUR}] ), ELECTRICITY_ACTIVE_TARIFF: CosemObject([{"value": "0001", "unit": ""}]), GAS_METER_READING: MBusObject( [ {"value": datetime.datetime.fromtimestamp(1551642213)}, {"value": Decimal(745.695), "unit": "m3"}, ] ), } mock_entry = MockConfigEntry( domain="dsmr", unique_id="/dev/ttyUSB0", data=entry_data, options=entry_options ) mock_entry.add_to_hass(hass) await hass.config_entries.async_setup(mock_entry.entry_id) await hass.async_block_till_done() registry = er.async_get(hass) entry = registry.async_get("sensor.power_consumption") assert entry assert entry.unique_id == "1234_Power_Consumption" entry = registry.async_get("sensor.gas_consumption") assert entry assert entry.unique_id == "5678_Gas_Consumption" telegram_callback = connection_factory.call_args_list[0][0][2] # make sure entities have been created and return 'unknown' state power_consumption = hass.states.get("sensor.power_consumption") assert power_consumption.state == STATE_UNKNOWN assert ( power_consumption.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.POWER ) assert power_consumption.attributes.get(ATTR_ICON) is None assert ( power_consumption.attributes.get(ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT ) assert power_consumption.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is None # simulate a telegram pushed from the smartmeter and parsed by dsmr_parser telegram_callback(telegram) # after receiving telegram entities need to have the chance to update await asyncio.sleep(0) # ensure entities have new state value after incoming telegram power_consumption = hass.states.get("sensor.power_consumption") assert power_consumption.state == "0.0" assert ( power_consumption.attributes.get("unit_of_measurement") == ENERGY_KILO_WATT_HOUR ) # tariff should be translated in human readable and have no unit power_tariff = hass.states.get("sensor.power_tariff") assert power_tariff.state == "low" assert power_tariff.attributes.get(ATTR_DEVICE_CLASS) is None assert power_tariff.attributes.get(ATTR_ICON) == "mdi:flash" assert power_tariff.attributes.get(ATTR_STATE_CLASS) is None assert power_tariff.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "" # check if gas consumption is parsed correctly gas_consumption = hass.states.get("sensor.gas_consumption") assert gas_consumption.state == "745.695" assert gas_consumption.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.GAS assert ( gas_consumption.attributes.get(ATTR_STATE_CLASS) == SensorStateClass.TOTAL_INCREASING ) assert ( gas_consumption.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == VOLUME_CUBIC_METERS )
async def test_tracked_devices(hass): """Test the update_items function with some devices.""" controller = await setup_unifi_integration( hass, devices_response=[DEVICE_1, DEVICE_2], ) assert len(hass.states.async_entity_ids(TRACKER_DOMAIN)) == 2 device_1 = hass.states.get("device_tracker.device_1") assert device_1 assert device_1.state == "home" device_2 = hass.states.get("device_tracker.device_2") assert device_2 assert device_2.state == "not_home" # State change signalling work device_1_copy = copy(DEVICE_1) device_1_copy["next_interval"] = 20 event = {"meta": {"message": MESSAGE_DEVICE}, "data": [device_1_copy]} controller.api.message_handler(event) device_2_copy = copy(DEVICE_2) device_2_copy["next_interval"] = 50 event = {"meta": {"message": MESSAGE_DEVICE}, "data": [device_2_copy]} controller.api.message_handler(event) await hass.async_block_till_done() device_1 = hass.states.get("device_tracker.device_1") assert device_1.state == "home" device_2 = hass.states.get("device_tracker.device_2") assert device_2.state == "home" async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=90)) await hass.async_block_till_done() device_1 = hass.states.get("device_tracker.device_1") assert device_1.state == "not_home" device_2 = hass.states.get("device_tracker.device_2") assert device_2.state == "home" # Disabled device is unavailable device_1_copy = copy(DEVICE_1) device_1_copy["disabled"] = True event = {"meta": {"message": MESSAGE_DEVICE}, "data": [device_1_copy]} controller.api.message_handler(event) await hass.async_block_till_done() device_1 = hass.states.get("device_tracker.device_1") assert device_1.state == STATE_UNAVAILABLE # Update device registry when device is upgraded device_2_copy = copy(DEVICE_2) device_2_copy["version"] = EVENT_DEVICE_2_UPGRADED["version_to"] message = {"meta": {"message": MESSAGE_DEVICE}, "data": [device_2_copy]} controller.api.message_handler(message) event = {"meta": {"message": MESSAGE_EVENT}, "data": [EVENT_DEVICE_2_UPGRADED]} controller.api.message_handler(event) await hass.async_block_till_done() # Verify device registry has been updated entity_registry = await hass.helpers.entity_registry.async_get_registry() entry = entity_registry.async_get("device_tracker.device_2") device_registry = await hass.helpers.device_registry.async_get_registry() device = device_registry.async_get(entry.device_id) assert device.sw_version == EVENT_DEVICE_2_UPGRADED["version_to"]
async def test_rokutv_binary_sensors( hass: HomeAssistant, init_integration: MockConfigEntry, mock_device: RokuDevice, mock_roku: MagicMock, ) -> None: """Test the Roku binary sensors.""" entity_registry = er.async_get(hass) device_registry = dr.async_get(hass) state = hass.states.get( "binary_sensor.58_onn_roku_tv_headphones_connected") entry = entity_registry.async_get( "binary_sensor.58_onn_roku_tv_headphones_connected") assert entry assert state assert entry.unique_id == "YN00H5555555_headphones_connected" assert entry.entity_category is None assert state.state == STATE_OFF assert (state.attributes.get(ATTR_FRIENDLY_NAME) == '58" Onn Roku TV Headphones Connected') assert state.attributes.get(ATTR_ICON) == "mdi:headphones" assert ATTR_DEVICE_CLASS not in state.attributes state = hass.states.get("binary_sensor.58_onn_roku_tv_supports_airplay") entry = entity_registry.async_get( "binary_sensor.58_onn_roku_tv_supports_airplay") assert entry assert state assert entry.unique_id == "YN00H5555555_supports_airplay" assert entry.entity_category == EntityCategory.DIAGNOSTIC assert state.state == STATE_ON assert (state.attributes.get(ATTR_FRIENDLY_NAME) == '58" Onn Roku TV Supports AirPlay') assert state.attributes.get(ATTR_ICON) == "mdi:cast-variant" assert ATTR_DEVICE_CLASS not in state.attributes state = hass.states.get("binary_sensor.58_onn_roku_tv_supports_ethernet") entry = entity_registry.async_get( "binary_sensor.58_onn_roku_tv_supports_ethernet") assert entry assert state assert entry.unique_id == "YN00H5555555_supports_ethernet" assert entry.entity_category == EntityCategory.DIAGNOSTIC assert state.state == STATE_ON assert (state.attributes.get(ATTR_FRIENDLY_NAME) == '58" Onn Roku TV Supports Ethernet') assert state.attributes.get(ATTR_ICON) == "mdi:ethernet" assert ATTR_DEVICE_CLASS not in state.attributes state = hass.states.get( "binary_sensor.58_onn_roku_tv_supports_find_remote") entry = entity_registry.async_get( "binary_sensor.58_onn_roku_tv_supports_find_remote") assert entry assert state assert entry.unique_id == "YN00H5555555_supports_find_remote" assert entry.entity_category == EntityCategory.DIAGNOSTIC assert state.state == STATE_ON assert (state.attributes.get(ATTR_FRIENDLY_NAME) == '58" Onn Roku TV Supports Find Remote') assert state.attributes.get(ATTR_ICON) == "mdi:remote" assert ATTR_DEVICE_CLASS not in state.attributes assert entry.device_id device_entry = device_registry.async_get(entry.device_id) assert device_entry assert device_entry.identifiers == {(DOMAIN, "YN00H5555555")} assert device_entry.connections == { (dr.CONNECTION_NETWORK_MAC, "d8:13:99:f8:b0:c6"), (dr.CONNECTION_NETWORK_MAC, "d4:3a:2e:07:fd:cb"), } assert device_entry.manufacturer == "Onn" assert device_entry.model == "100005844" assert device_entry.name == '58" Onn Roku TV' assert device_entry.entry_type is None assert device_entry.sw_version == "9.2.0" assert device_entry.hw_version == "7820X" assert device_entry.suggested_area == "Living room"
async def test_single_shot_status_sensor_state_via_mqtt( hass, mqtt_mock, setup_tasmota): """Test state update via MQTT.""" entity_reg = er.async_get(hass) # Pre-enable the status sensor entity_reg.async_get_or_create( Platform.SENSOR, "tasmota", "00000049A3BC_status_sensor_status_sensor_status_restart_reason", suggested_object_id="tasmota_status", disabled_by=None, ) config = copy.deepcopy(DEFAULT_CONFIG) mac = config["mac"] async_fire_mqtt_message( hass, f"{DEFAULT_PREFIX}/{mac}/config", json.dumps(config), ) await hass.async_block_till_done() await hass.async_block_till_done() state = hass.states.get("sensor.tasmota_status") assert state.state == "unavailable" assert not state.attributes.get(ATTR_ASSUMED_STATE) async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/LWT", "Online") await hass.async_block_till_done() state = hass.states.get("sensor.tasmota_status") assert state.state == STATE_UNKNOWN assert not state.attributes.get(ATTR_ASSUMED_STATE) # Test polled state update async_fire_mqtt_message( hass, "tasmota_49A3BC/stat/STATUS1", '{"StatusPRM":{"RestartReason":"Some reason"}}', ) await hass.async_block_till_done() state = hass.states.get("sensor.tasmota_status") assert state.state == "Some reason" # Test polled state update is ignored async_fire_mqtt_message( hass, "tasmota_49A3BC/stat/STATUS1", '{"StatusPRM":{"RestartReason":"Another reason"}}', ) await hass.async_block_till_done() state = hass.states.get("sensor.tasmota_status") assert state.state == "Some reason" # Device signals online again async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/LWT", "Online") await hass.async_block_till_done() state = hass.states.get("sensor.tasmota_status") assert state.state == "Some reason" # Test polled state update async_fire_mqtt_message( hass, "tasmota_49A3BC/stat/STATUS1", '{"StatusPRM":{"RestartReason":"Another reason"}}', ) await hass.async_block_till_done() state = hass.states.get("sensor.tasmota_status") assert state.state == "Another reason" # Test polled state update is ignored async_fire_mqtt_message( hass, "tasmota_49A3BC/stat/STATUS1", '{"StatusPRM":{"RestartReason":"Third reason"}}', ) await hass.async_block_till_done() state = hass.states.get("sensor.tasmota_status") assert state.state == "Another reason"
async def test_sensors( hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_wled: MagicMock, ) -> None: """Test the creation and values of the WLED sensors.""" registry = er.async_get(hass) # Pre-create registry entries for disabled by default sensors registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "aabbccddeeff_uptime", suggested_object_id="wled_rgb_light_uptime", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "aabbccddeeff_free_heap", suggested_object_id="wled_rgb_light_free_memory", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "aabbccddeeff_wifi_signal", suggested_object_id="wled_rgb_light_wifi_signal", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "aabbccddeeff_wifi_rssi", suggested_object_id="wled_rgb_light_wifi_rssi", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "aabbccddeeff_wifi_channel", suggested_object_id="wled_rgb_light_wifi_channel", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "aabbccddeeff_wifi_bssid", suggested_object_id="wled_rgb_light_wifi_bssid", disabled_by=None, ) # Setup mock_config_entry.add_to_hass(hass) test_time = datetime(2019, 11, 11, 9, 10, 32, tzinfo=dt_util.UTC) with patch("homeassistant.components.wled.sensor.utcnow", return_value=test_time): await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.async_block_till_done() state = hass.states.get("sensor.wled_rgb_light_estimated_current") assert state assert ( state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == ELECTRIC_CURRENT_MILLIAMPERE ) assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_CURRENT assert state.state == "470" entry = registry.async_get("sensor.wled_rgb_light_estimated_current") assert entry assert entry.unique_id == "aabbccddeeff_estimated_current" assert entry.entity_category == ENTITY_CATEGORY_DIAGNOSTIC state = hass.states.get("sensor.wled_rgb_light_uptime") assert state assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TIMESTAMP assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is None assert state.state == "2019-11-11T09:10:00+00:00" entry = registry.async_get("sensor.wled_rgb_light_uptime") assert entry assert entry.unique_id == "aabbccddeeff_uptime" assert entry.entity_category == ENTITY_CATEGORY_DIAGNOSTIC state = hass.states.get("sensor.wled_rgb_light_free_memory") assert state assert state.attributes.get(ATTR_ICON) == "mdi:memory" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == DATA_BYTES assert state.state == "14600" assert entry.entity_category == ENTITY_CATEGORY_DIAGNOSTIC entry = registry.async_get("sensor.wled_rgb_light_free_memory") assert entry assert entry.unique_id == "aabbccddeeff_free_heap" assert entry.entity_category == ENTITY_CATEGORY_DIAGNOSTIC state = hass.states.get("sensor.wled_rgb_light_wifi_signal") assert state assert state.attributes.get(ATTR_ICON) == "mdi:wifi" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE assert state.state == "76" assert entry.entity_category == ENTITY_CATEGORY_DIAGNOSTIC entry = registry.async_get("sensor.wled_rgb_light_wifi_signal") assert entry assert entry.unique_id == "aabbccddeeff_wifi_signal" assert entry.entity_category == ENTITY_CATEGORY_DIAGNOSTIC state = hass.states.get("sensor.wled_rgb_light_wifi_rssi") assert state assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_SIGNAL_STRENGTH assert ( state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == SIGNAL_STRENGTH_DECIBELS_MILLIWATT ) assert state.state == "-62" entry = registry.async_get("sensor.wled_rgb_light_wifi_rssi") assert entry assert entry.unique_id == "aabbccddeeff_wifi_rssi" assert entry.entity_category == ENTITY_CATEGORY_DIAGNOSTIC state = hass.states.get("sensor.wled_rgb_light_wifi_channel") assert state assert state.attributes.get(ATTR_ICON) == "mdi:wifi" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is None assert state.state == "11" entry = registry.async_get("sensor.wled_rgb_light_wifi_channel") assert entry assert entry.unique_id == "aabbccddeeff_wifi_channel" assert entry.entity_category == ENTITY_CATEGORY_DIAGNOSTIC state = hass.states.get("sensor.wled_rgb_light_wifi_bssid") assert state assert state.attributes.get(ATTR_ICON) == "mdi:wifi" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is None assert state.state == "AA:AA:AA:AA:AA:BB" entry = registry.async_get("sensor.wled_rgb_light_wifi_bssid") assert entry assert entry.unique_id == "aabbccddeeff_wifi_bssid" assert entry.entity_category == ENTITY_CATEGORY_DIAGNOSTIC
async def test_device_exists(hass, ev_entry): """Test subaru lock entity exists.""" entity_registry = er.async_get(hass) entry = entity_registry.async_get(DEVICE_ID) assert entry
async def test_sensors( hass: HomeAssistant, init_integration: MockConfigEntry, ) -> None: """Test the Forecast.Solar sensors.""" entry_id = init_integration.entry_id entity_registry = er.async_get(hass) device_registry = dr.async_get(hass) state = hass.states.get("sensor.energy_production_today") entry = entity_registry.async_get("sensor.energy_production_today") assert entry assert state assert entry.unique_id == f"{entry_id}_energy_production_today" assert state.state == "100.0" assert (state.attributes.get(ATTR_FRIENDLY_NAME) == "Estimated Energy Production - Today") assert state.attributes.get(ATTR_STATE_CLASS) is None assert state.attributes.get( ATTR_UNIT_OF_MEASUREMENT) == ENERGY_KILO_WATT_HOUR assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_ENERGY assert ATTR_ICON not in state.attributes state = hass.states.get("sensor.energy_production_tomorrow") entry = entity_registry.async_get("sensor.energy_production_tomorrow") assert entry assert state assert entry.unique_id == f"{entry_id}_energy_production_tomorrow" assert state.state == "200.0" assert (state.attributes.get(ATTR_FRIENDLY_NAME) == "Estimated Energy Production - Tomorrow") assert state.attributes.get(ATTR_STATE_CLASS) is None assert state.attributes.get( ATTR_UNIT_OF_MEASUREMENT) == ENERGY_KILO_WATT_HOUR assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_ENERGY assert ATTR_ICON not in state.attributes state = hass.states.get("sensor.power_highest_peak_time_today") entry = entity_registry.async_get("sensor.power_highest_peak_time_today") assert entry assert state assert entry.unique_id == f"{entry_id}_power_highest_peak_time_today" assert state.state == "2021-06-27T13:00:00+00:00" assert state.attributes.get( ATTR_FRIENDLY_NAME) == "Highest Power Peak Time - Today" assert state.attributes.get(ATTR_STATE_CLASS) is None assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TIMESTAMP assert ATTR_UNIT_OF_MEASUREMENT not in state.attributes assert ATTR_ICON not in state.attributes state = hass.states.get("sensor.power_highest_peak_time_tomorrow") entry = entity_registry.async_get( "sensor.power_highest_peak_time_tomorrow") assert entry assert state assert entry.unique_id == f"{entry_id}_power_highest_peak_time_tomorrow" assert state.state == "2021-06-27T14:00:00+00:00" assert (state.attributes.get(ATTR_FRIENDLY_NAME) == "Highest Power Peak Time - Tomorrow") assert state.attributes.get(ATTR_STATE_CLASS) is None assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TIMESTAMP assert ATTR_UNIT_OF_MEASUREMENT not in state.attributes assert ATTR_ICON not in state.attributes state = hass.states.get("sensor.power_production_now") entry = entity_registry.async_get("sensor.power_production_now") assert entry assert state assert entry.unique_id == f"{entry_id}_power_production_now" assert state.state == "300000" assert (state.attributes.get(ATTR_FRIENDLY_NAME) == "Estimated Power Production - Now") assert state.attributes.get(ATTR_STATE_CLASS) == STATE_CLASS_MEASUREMENT assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == POWER_WATT assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_POWER assert ATTR_ICON not in state.attributes state = hass.states.get("sensor.energy_current_hour") entry = entity_registry.async_get("sensor.energy_current_hour") assert entry assert state assert entry.unique_id == f"{entry_id}_energy_current_hour" assert state.state == "800.0" assert (state.attributes.get(ATTR_FRIENDLY_NAME) == "Estimated Energy Production - This Hour") assert state.attributes.get(ATTR_STATE_CLASS) is None assert state.attributes.get( ATTR_UNIT_OF_MEASUREMENT) == ENERGY_KILO_WATT_HOUR assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_ENERGY assert ATTR_ICON not in state.attributes state = hass.states.get("sensor.energy_next_hour") entry = entity_registry.async_get("sensor.energy_next_hour") assert entry assert state assert entry.unique_id == f"{entry_id}_energy_next_hour" assert state.state == "900.0" assert (state.attributes.get(ATTR_FRIENDLY_NAME) == "Estimated Energy Production - Next Hour") assert state.attributes.get(ATTR_STATE_CLASS) is None assert state.attributes.get( ATTR_UNIT_OF_MEASUREMENT) == ENERGY_KILO_WATT_HOUR assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_ENERGY assert ATTR_ICON not in state.attributes assert entry.device_id device_entry = device_registry.async_get(entry.device_id) assert device_entry assert device_entry.identifiers == {(DOMAIN, f"{entry_id}")} assert device_entry.manufacturer == "Forecast.Solar" assert device_entry.name == "Solar Production Forecast" assert device_entry.entry_type == ENTRY_TYPE_SERVICE assert not device_entry.model assert not device_entry.sw_version
async def test_restore_client_succeed(hass, aioclient_mock): """Test that RestoreEntity works as expected.""" POE_DEVICE = { "device_id": "12345", "ip": "1.0.1.1", "mac": "00:00:00:00:01:01", "last_seen": 1562600145, "model": "US16P150", "name": "POE Switch", "port_overrides": [ { "poe_mode": "off", "port_idx": 1, "portconf_id": "5f3edd2aba4cc806a19f2db2", } ], "port_table": [ { "media": "GE", "name": "Port 1", "op_mode": "switch", "poe_caps": 7, "poe_class": "Unknown", "poe_current": "0.00", "poe_enable": False, "poe_good": False, "poe_mode": "off", "poe_power": "0.00", "poe_voltage": "0.00", "port_idx": 1, "port_poe": True, "portconf_id": "5f3edd2aba4cc806a19f2db2", "up": False, }, ], "state": 1, "type": "usw", "version": "4.0.42.10433", } POE_CLIENT = { "hostname": "poe_client", "ip": "1.0.0.1", "is_wired": True, "last_seen": 1562600145, "mac": "00:00:00:00:00:01", "name": "POE Client", "oui": "Producer", } fake_state = core.State( "switch.poe_client", "off", { "power": "0.00", "switch": POE_DEVICE["mac"], "port": 1, "poe_mode": "auto", }, ) config_entry = config_entries.ConfigEntry( version=1, domain=UNIFI_DOMAIN, title="Mock Title", data=ENTRY_CONFIG, source="test", options={}, entry_id=DEFAULT_CONFIG_ENTRY_ID, ) registry = er.async_get(hass) registry.async_get_or_create( SWITCH_DOMAIN, UNIFI_DOMAIN, f'{POE_SWITCH}-{POE_CLIENT["mac"]}', suggested_object_id=POE_CLIENT["hostname"], config_entry=config_entry, ) with patch( "homeassistant.helpers.restore_state.RestoreEntity.async_get_last_state", return_value=fake_state, ): await setup_unifi_integration( hass, aioclient_mock, options={ CONF_TRACK_CLIENTS: False, CONF_TRACK_DEVICES: False, }, clients_response=[], devices_response=[POE_DEVICE], clients_all_response=[POE_CLIENT], ) assert len(hass.states.async_entity_ids(SWITCH_DOMAIN)) == 1 poe_client = hass.states.get("switch.poe_client") assert poe_client.state == "off"
async def _device_connect(self, location: str) -> None: """Connect to the device now that it's available.""" _LOGGER.debug("Connecting to device at %s", location) async with self._device_lock: if self._device: _LOGGER.debug( "Trying to connect when device already connected") return domain_data = get_domain_data(self.hass) # Connect to the base UPNP device upnp_device = await domain_data.upnp_factory.async_create_device( location) # Create/get event handler that is reachable by the device, using # the connection's local IP to listen only on the relevant interface _, event_ip = await async_get_local_ip(location, self.hass.loop) self._event_addr = self._event_addr._replace(host=event_ip) event_handler = await domain_data.async_get_event_notifier( self._event_addr, self.hass) # Create profile wrapper self._device = DmrDevice(upnp_device, event_handler) self.location = location # Subscribe to event notifications try: self._device.on_event = self._on_event await self._device.async_subscribe_services( auto_resubscribe=True) except UpnpResponseError as err: # Device rejected subscription request. This is OK, variables # will be polled instead. _LOGGER.debug("Device rejected subscription: %r", err) except UpnpError as err: # Don't leave the device half-constructed self._device.on_event = None self._device = None await domain_data.async_release_event_notifier(self._event_addr ) _LOGGER.debug( "Error while subscribing during device connect: %r", err) raise if (not self.registry_entry or not self.registry_entry.config_entry_id or self.registry_entry.device_id): return # Create linked HA DeviceEntry now the information is known. dev_reg = device_registry.async_get(self.hass) device_entry = dev_reg.async_get_or_create( config_entry_id=self.registry_entry.config_entry_id, # Connections are based on the root device's UDN, and the DMR # embedded device's UDN. They may be the same, if the DMR is the # root device. connections={ ( device_registry.CONNECTION_UPNP, self._device.profile_device.root_device.udn, ), (device_registry.CONNECTION_UPNP, self._device.udn), }, identifiers={(DOMAIN, self.unique_id)}, default_manufacturer=self._device.manufacturer, default_model=self._device.model_name, default_name=self._device.name, ) # Update entity registry to link to the device ent_reg = entity_registry.async_get(self.hass) ent_reg.async_get_or_create( self.registry_entry.domain, self.registry_entry.platform, self.unique_id, device_id=device_entry.id, )
async def test_ecobee3_setup(hass): """Test that a Ecbobee 3 can be correctly setup in HA.""" accessories = await setup_accessories_from_file(hass, "ecobee3.json") config_entry, pairing = await setup_test_accessories(hass, accessories) entity_registry = er.async_get(hass) climate = entity_registry.async_get("climate.homew") assert climate.unique_id == "homekit-123456789012-16" climate_helper = Helper(hass, "climate.homew", pairing, accessories[0], config_entry) climate_state = await climate_helper.poll_and_get_state() assert climate_state.attributes["friendly_name"] == "HomeW" assert climate_state.attributes["supported_features"] == ( SUPPORT_TARGET_TEMPERATURE | SUPPORT_TARGET_TEMPERATURE_RANGE | SUPPORT_TARGET_HUMIDITY) assert climate_state.attributes["hvac_modes"] == [ "off", "heat", "cool", "heat_cool", ] assert climate_state.attributes["min_temp"] == 7.2 assert climate_state.attributes["max_temp"] == 33.3 assert climate_state.attributes["min_humidity"] == 20 assert climate_state.attributes["max_humidity"] == 50 climate_sensor = entity_registry.async_get( "sensor.homew_current_temperature") assert climate_sensor.unique_id == "homekit-123456789012-aid:1-sid:16-cid:19" occ1 = entity_registry.async_get("binary_sensor.kitchen") assert occ1.unique_id == "homekit-AB1C-56" occ1_helper = Helper(hass, "binary_sensor.kitchen", pairing, accessories[0], config_entry) occ1_state = await occ1_helper.poll_and_get_state() assert occ1_state.attributes["friendly_name"] == "Kitchen" occ2 = entity_registry.async_get("binary_sensor.porch") assert occ2.unique_id == "homekit-AB2C-56" occ3 = entity_registry.async_get("binary_sensor.basement") assert occ3.unique_id == "homekit-AB3C-56" device_registry = dr.async_get(hass) climate_device = device_registry.async_get(climate.device_id) assert climate_device.manufacturer == "ecobee Inc." assert climate_device.name == "HomeW" assert climate_device.model == "ecobee3" assert climate_device.sw_version == "4.2.394" assert climate_device.via_device_id is None # Check that an attached sensor has its own device entity that # is linked to the bridge sensor_device = device_registry.async_get(occ1.device_id) assert sensor_device.manufacturer == "ecobee Inc." assert sensor_device.name == "Kitchen" assert sensor_device.model == "REMOTE SENSOR" assert sensor_device.sw_version == "1.0.0" assert sensor_device.via_device_id == climate_device.id
class ScannerEntity(BaseTrackerEntity): """Base class for a tracked device that is on a scanned network.""" @property def ip_address(self) -> str | None: """Return the primary ip address of the device.""" return None @property def mac_address(self) -> str | None: """Return the mac address of the device.""" return None @property def hostname(self) -> str | None: """Return hostname of the device.""" return None @property def state(self) -> str: """Return the state of the device.""" if self.is_connected: return STATE_HOME return STATE_NOT_HOME @property def is_connected(self) -> bool: """Return true if the device is connected to the network.""" raise NotImplementedError @property def unique_id(self) -> str | None: """Return unique ID of the entity.""" return self.mac_address @final @property def device_info(self) -> DeviceInfo | None: """Device tracker entities should not create device registry entries.""" return None @property def entity_registry_enabled_default(self) -> bool: """Return if entity is enabled by default.""" # If mac_address is None, we can never find a device entry. return ( # Do not disable if we won't activate our attach to device logic self.mac_address is None or self.device_info is not None # Disable if we automatically attach but there is no device or self.find_device_entry() is not None) @callback def add_to_platform_start( self, hass: HomeAssistant, platform: EntityPlatform, parallel_updates: asyncio.Semaphore | None, ) -> None: """Start adding an entity to a platform.""" super().add_to_platform_start(hass, platform, parallel_updates) if self.mac_address and self.unique_id: _async_register_mac( hass, platform.platform_name, self.mac_address, self.unique_id, ) if self.is_connected: _async_connected_device_registered( hass, self.mac_address, self.ip_address, self.hostname, ) @callback def find_device_entry(self) -> dr.DeviceEntry | None: """Return device entry.""" assert self.mac_address is not None return dr.async_get(self.hass).async_get_device( set(), {(dr.CONNECTION_NETWORK_MAC, self.mac_address)}) async def async_internal_added_to_hass(self) -> None: """Handle added to Home Assistant.""" # Entities without a unique ID don't have a device if (not self.registry_entry or not self.platform or not self.platform.config_entry or not self.mac_address or (device_entry := self.find_device_entry()) is None # Entities should not have a device info. We opt them out # of this logic if they do. or self.device_info): if self.device_info: LOGGER.debug("Entity %s unexpectedly has a device info", self.entity_id) await super().async_internal_added_to_hass() return # Attach entry to device if self.registry_entry.device_id != device_entry.id: self.registry_entry = er.async_get(self.hass).async_update_entity( self.entity_id, device_id=device_entry.id) # Attach device to config entry if self.platform.config_entry.entry_id not in device_entry.config_entries: dr.async_get(self.hass).async_update_device( device_entry.id, add_config_entry_id=self.platform.config_entry.entry_id, ) # Do this last or else the entity registry update listener has been installed await super().async_internal_added_to_hass()
async def test_all_optional_config(hass, calls): """Test: including all optional templates is ok.""" with assert_setup_component(1, "template"): assert await setup.async_setup_component( hass, "template", { "template": { "unique_id": "test", "button": { "press": { "service": "test.automation" }, "device_class": "restart", "unique_id": "test", "name": "test", "icon": "mdi:test", }, } }, ) await hass.async_block_till_done() await hass.async_start() await hass.async_block_till_done() _verify( hass, STATE_UNKNOWN, { CONF_DEVICE_CLASS: "restart", CONF_FRIENDLY_NAME: "test", CONF_ICON: "mdi:test", }, _TEST_OPTIONS_BUTTON, ) now = dt.datetime.now(dt.timezone.utc) with patch("homeassistant.util.dt.utcnow", return_value=now): await hass.services.async_call( BUTTON_DOMAIN, SERVICE_PRESS, {CONF_ENTITY_ID: _TEST_OPTIONS_BUTTON}, blocking=True, ) assert len(calls) == 1 _verify( hass, now.isoformat(), { CONF_DEVICE_CLASS: "restart", CONF_FRIENDLY_NAME: "test", CONF_ICON: "mdi:test", }, _TEST_OPTIONS_BUTTON, ) er = async_get(hass) assert er.async_get_entity_id("button", "template", "test-test")
def _async_migrate_unique_id( hass: HomeAssistant, discovery_info: DiscoveryInfoType | None ) -> None: """Change unique_ids used in 2021.4 to exchange individual color switch address for brightness address.""" entity_registry = er.async_get(hass) if not discovery_info or not discovery_info["platform_config"]: return platform_config = discovery_info["platform_config"] for entity_config in platform_config: individual_colors_config = entity_config.get(LightSchema.CONF_INDIVIDUAL_COLORS) if individual_colors_config is None: continue try: ga_red_switch = individual_colors_config[LightSchema.CONF_RED][KNX_ADDRESS][ 0 ] ga_green_switch = individual_colors_config[LightSchema.CONF_GREEN][ KNX_ADDRESS ][0] ga_blue_switch = individual_colors_config[LightSchema.CONF_BLUE][ KNX_ADDRESS ][0] except KeyError: continue # normalize group address strings ga_red_switch = parse_device_group_address(ga_red_switch) ga_green_switch = parse_device_group_address(ga_green_switch) ga_blue_switch = parse_device_group_address(ga_blue_switch) # white config is optional so it has to be checked for `None` extra white_config = individual_colors_config.get(LightSchema.CONF_WHITE) white_switch = ( white_config.get(KNX_ADDRESS) if white_config is not None else None ) ga_white_switch = ( parse_device_group_address(white_switch[0]) if white_switch is not None else None ) old_uid = ( f"{ga_red_switch}_" f"{ga_green_switch}_" f"{ga_blue_switch}_" f"{ga_white_switch}" ) entity_id = entity_registry.async_get_entity_id("light", DOMAIN, old_uid) if entity_id is None: continue ga_red_brightness = parse_device_group_address( individual_colors_config[LightSchema.CONF_RED][ LightSchema.CONF_BRIGHTNESS_ADDRESS ][0] ) ga_green_brightness = parse_device_group_address( individual_colors_config[LightSchema.CONF_GREEN][ LightSchema.CONF_BRIGHTNESS_ADDRESS ][0] ) ga_blue_brightness = parse_device_group_address( individual_colors_config[LightSchema.CONF_BLUE][ LightSchema.CONF_BRIGHTNESS_ADDRESS ][0] ) new_uid = f"{ga_red_brightness}_{ga_green_brightness}_{ga_blue_brightness}" entity_registry.async_update_entity(entity_id, new_unique_id=new_uid)
async def test_restore_states(hass): """Test restoring states.""" hass.state = CoreState.not_running registry = er.async_get(hass) registry.async_get_or_create( "light", "hue", "1234", suggested_object_id="simple", ) # Should not be created registry.async_get_or_create( "light", "hue", "5678", suggested_object_id="disabled", disabled_by=er.DISABLED_HASS, ) registry.async_get_or_create( "light", "hue", "9012", suggested_object_id="all_info_set", capabilities={"max": 100}, supported_features=5, device_class="mock-device-class", original_name="Mock Original Name", original_icon="hass:original-icon", ) hass.bus.async_fire(EVENT_HOMEASSISTANT_START, {}) await hass.async_block_till_done() simple = hass.states.get("light.simple") assert simple is not None assert simple.state == STATE_UNAVAILABLE assert simple.attributes == {"restored": True, "supported_features": 0} disabled = hass.states.get("light.disabled") assert disabled is None all_info_set = hass.states.get("light.all_info_set") assert all_info_set is not None assert all_info_set.state == STATE_UNAVAILABLE assert all_info_set.attributes == { "max": 100, "supported_features": 5, "device_class": "mock-device-class", "restored": True, "friendly_name": "Mock Original Name", "icon": "hass:original-icon", } registry.async_remove("light.disabled") registry.async_remove("light.simple") registry.async_remove("light.all_info_set") await hass.async_block_till_done() assert hass.states.get("light.simple") is None assert hass.states.get("light.disabled") is None assert hass.states.get("light.all_info_set") is None
async def test_eve_degree_setup(hass): """Test that the accessory can be correctly setup in HA.""" accessories = await setup_accessories_from_file(hass, "eve_degree.json") config_entry, pairing = await setup_test_accessories(hass, accessories) entity_registry = er.async_get(hass) device_registry = dr.async_get(hass) sensors = [ ( "sensor.eve_degree_aa11_temperature", "homekit-AA00A0A00000-22", "Eve Degree AA11 Temperature", ), ( "sensor.eve_degree_aa11_humidity", "homekit-AA00A0A00000-27", "Eve Degree AA11 Humidity", ), ( "sensor.eve_degree_aa11_air_pressure", "homekit-AA00A0A00000-aid:1-sid:30-cid:32", "Eve Degree AA11 - Air Pressure", ), ( "sensor.eve_degree_aa11_battery", "homekit-AA00A0A00000-17", "Eve Degree AA11 Battery", ), ( "number.eve_degree_aa11", "homekit-AA00A0A00000-aid:1-sid:30-cid:33", "Eve Degree AA11", ), ] device_ids = set() for (entity_id, unique_id, friendly_name) in sensors: entry = entity_registry.async_get(entity_id) assert entry.unique_id == unique_id helper = Helper( hass, entity_id, pairing, accessories[0], config_entry, ) state = await helper.poll_and_get_state() assert state.attributes["friendly_name"] == friendly_name device = device_registry.async_get(entry.device_id) assert device.manufacturer == "Elgato" assert device.name == "Eve Degree AA11" assert device.model == "Eve Degree 00AAA0000" assert device.sw_version == "1.2.8" assert device.via_device_id is None device_ids.add(entry.device_id) # All entities should be part of same device assert len(device_ids) == 1
async def test_sensors( hass: HomeAssistant, init_integration: MockConfigEntry, ) -> None: """Test the PVOutput sensors.""" entity_registry = er.async_get(hass) device_registry = dr.async_get(hass) state = hass.states.get("sensor.frenck_s_solar_farm_energy_consumed") entry = entity_registry.async_get( "sensor.frenck_s_solar_farm_energy_consumed") assert entry assert state assert entry.unique_id == "12345_energy_consumption" assert entry.entity_category is None assert state.state == "1000" assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.ENERGY assert (state.attributes.get(ATTR_FRIENDLY_NAME) == "Frenck's Solar Farm Energy consumed") assert state.attributes.get( ATTR_STATE_CLASS) is SensorStateClass.TOTAL_INCREASING assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == ENERGY_WATT_HOUR assert ATTR_ICON not in state.attributes state = hass.states.get("sensor.frenck_s_solar_farm_energy_generated") entry = entity_registry.async_get( "sensor.frenck_s_solar_farm_energy_generated") assert entry assert state assert entry.unique_id == "12345_energy_generation" assert entry.entity_category is None assert state.state == "500" assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.ENERGY assert (state.attributes.get(ATTR_FRIENDLY_NAME) == "Frenck's Solar Farm Energy generated") assert state.attributes.get( ATTR_STATE_CLASS) is SensorStateClass.TOTAL_INCREASING assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == ENERGY_WATT_HOUR assert ATTR_ICON not in state.attributes state = hass.states.get("sensor.frenck_s_solar_farm_efficiency") entry = entity_registry.async_get("sensor.frenck_s_solar_farm_efficiency") assert entry assert state assert entry.unique_id == "12345_normalized_output" assert entry.entity_category is None assert state.state == "0.5" assert state.attributes.get( ATTR_FRIENDLY_NAME) == "Frenck's Solar Farm Efficiency" assert state.attributes.get( ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT assert (state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == f"{ENERGY_KILO_WATT_HOUR}/{POWER_KILO_WATT}") assert ATTR_DEVICE_CLASS not in state.attributes assert ATTR_ICON not in state.attributes state = hass.states.get("sensor.frenck_s_solar_farm_power_consumed") entry = entity_registry.async_get( "sensor.frenck_s_solar_farm_power_consumed") assert entry assert state assert entry.unique_id == "12345_power_consumption" assert entry.entity_category is None assert state.state == "2500" assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.POWER assert (state.attributes.get(ATTR_FRIENDLY_NAME) == "Frenck's Solar Farm Power consumed") assert state.attributes.get( ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == POWER_WATT assert ATTR_ICON not in state.attributes state = hass.states.get("sensor.frenck_s_solar_farm_power_generated") entry = entity_registry.async_get( "sensor.frenck_s_solar_farm_power_generated") assert entry assert state assert entry.unique_id == "12345_power_generation" assert entry.entity_category is None assert state.state == "1500" assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.POWER assert (state.attributes.get(ATTR_FRIENDLY_NAME) == "Frenck's Solar Farm Power generated") assert state.attributes.get( ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == POWER_WATT assert ATTR_ICON not in state.attributes state = hass.states.get("sensor.frenck_s_solar_farm_temperature") entry = entity_registry.async_get("sensor.frenck_s_solar_farm_temperature") assert entry assert state assert entry.unique_id == "12345_temperature" assert entry.entity_category is None assert state.state == "20.2" assert state.attributes.get( ATTR_DEVICE_CLASS) == SensorDeviceClass.TEMPERATURE assert state.attributes.get( ATTR_FRIENDLY_NAME) == "Frenck's Solar Farm Temperature" assert state.attributes.get( ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert ATTR_ICON not in state.attributes state = hass.states.get("sensor.frenck_s_solar_farm_voltage") entry = entity_registry.async_get("sensor.frenck_s_solar_farm_voltage") assert entry assert state assert entry.unique_id == "12345_voltage" assert entry.entity_category is None assert state.state == "220.5" assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.VOLTAGE assert state.attributes.get( ATTR_FRIENDLY_NAME) == "Frenck's Solar Farm Voltage" assert state.attributes.get( ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT assert state.attributes.get( ATTR_UNIT_OF_MEASUREMENT) == ELECTRIC_POTENTIAL_VOLT assert ATTR_ICON not in state.attributes assert entry.device_id device_entry = device_registry.async_get(entry.device_id) assert device_entry assert device_entry.identifiers == {(DOMAIN, "12345")} assert device_entry.manufacturer == "PVOutput" assert device_entry.model == "Super Inverters Inc." assert device_entry.name == "Frenck's Solar Farm" assert device_entry.configuration_url == "https://pvoutput.org/list.jsp?sid=12345" assert device_entry.entry_type is None assert device_entry.sw_version is None assert device_entry.hw_version is None
async def test_sensor_enabled_without_forecast(hass): """Test enabling an advanced sensor.""" registry = er.async_get(hass) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-apparenttemperature", suggested_object_id="home_apparent_temperature", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-cloudcover", suggested_object_id="home_cloud_cover", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-dewpoint", suggested_object_id="home_dew_point", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-realfeeltemperatureshade", suggested_object_id="home_realfeel_temperature_shade", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-wetbulbtemperature", suggested_object_id="home_wet_bulb_temperature", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-wind", suggested_object_id="home_wind", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-windchilltemperature", suggested_object_id="home_wind_chill_temperature", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-windgust", suggested_object_id="home_wind_gust", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-cloudcoverday-0", suggested_object_id="home_cloud_cover_day_0d", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-cloudcovernight-0", suggested_object_id="home_cloud_cover_night_0d", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-grass-0", suggested_object_id="home_grass_pollen_0d", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-mold-0", suggested_object_id="home_mold_pollen_0d", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-ozone-0", suggested_object_id="home_ozone_0d", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-ragweed-0", suggested_object_id="home_ragweed_pollen_0d", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-realfeeltemperatureshademax-0", suggested_object_id="home_realfeel_temperature_shade_max_0d", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-realfeeltemperatureshademin-0", suggested_object_id="home_realfeel_temperature_shade_min_0d", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-tree-0", suggested_object_id="home_tree_pollen_0d", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-windgustday-0", suggested_object_id="home_wind_gust_day_0d", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-windgustnight-0", suggested_object_id="home_wind_gust_night_0d", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-windday-0", suggested_object_id="home_wind_day_0d", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "0123456-windnight-0", suggested_object_id="home_wind_night_0d", disabled_by=None, ) await init_integration(hass, forecast=True) state = hass.states.get("sensor.home_apparent_temperature") assert state assert state.state == "22.8" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE entry = registry.async_get("sensor.home_apparent_temperature") assert entry assert entry.unique_id == "0123456-apparenttemperature" state = hass.states.get("sensor.home_cloud_cover") assert state assert state.state == "10" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE assert state.attributes.get(ATTR_ICON) == "mdi:weather-cloudy" entry = registry.async_get("sensor.home_cloud_cover") assert entry assert entry.unique_id == "0123456-cloudcover" state = hass.states.get("sensor.home_dew_point") assert state assert state.state == "16.2" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE entry = registry.async_get("sensor.home_dew_point") assert entry assert entry.unique_id == "0123456-dewpoint" state = hass.states.get("sensor.home_realfeel_temperature_shade") assert state assert state.state == "21.1" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE entry = registry.async_get("sensor.home_realfeel_temperature_shade") assert entry assert entry.unique_id == "0123456-realfeeltemperatureshade" state = hass.states.get("sensor.home_wet_bulb_temperature") assert state assert state.state == "18.6" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE entry = registry.async_get("sensor.home_wet_bulb_temperature") assert entry assert entry.unique_id == "0123456-wetbulbtemperature" state = hass.states.get("sensor.home_wind_chill_temperature") assert state assert state.state == "22.8" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE entry = registry.async_get("sensor.home_wind_chill_temperature") assert entry assert entry.unique_id == "0123456-windchilltemperature" state = hass.states.get("sensor.home_wind_gust") assert state assert state.state == "20.3" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == SPEED_KILOMETERS_PER_HOUR assert state.attributes.get(ATTR_ICON) == "mdi:weather-windy" entry = registry.async_get("sensor.home_wind_gust") assert entry assert entry.unique_id == "0123456-windgust" state = hass.states.get("sensor.home_wind") assert state assert state.state == "14.5" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == SPEED_KILOMETERS_PER_HOUR assert state.attributes.get(ATTR_ICON) == "mdi:weather-windy" entry = registry.async_get("sensor.home_wind") assert entry assert entry.unique_id == "0123456-wind" state = hass.states.get("sensor.home_cloud_cover_day_0d") assert state assert state.state == "58" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE assert state.attributes.get(ATTR_ICON) == "mdi:weather-cloudy" entry = registry.async_get("sensor.home_cloud_cover_day_0d") assert entry assert entry.unique_id == "0123456-cloudcoverday-0" state = hass.states.get("sensor.home_cloud_cover_night_0d") assert state assert state.state == "65" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE assert state.attributes.get(ATTR_ICON) == "mdi:weather-cloudy" entry = registry.async_get("sensor.home_cloud_cover_night_0d") assert entry state = hass.states.get("sensor.home_grass_pollen_0d") assert state assert state.state == "0" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert ( state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == CONCENTRATION_PARTS_PER_CUBIC_METER ) assert state.attributes.get("level") == "Low" assert state.attributes.get(ATTR_ICON) == "mdi:grass" entry = registry.async_get("sensor.home_grass_pollen_0d") assert entry assert entry.unique_id == "0123456-grass-0" state = hass.states.get("sensor.home_mold_pollen_0d") assert state assert state.state == "0" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert ( state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == CONCENTRATION_PARTS_PER_CUBIC_METER ) assert state.attributes.get("level") == "Low" assert state.attributes.get(ATTR_ICON) == "mdi:blur" entry = registry.async_get("sensor.home_mold_pollen_0d") assert entry assert entry.unique_id == "0123456-mold-0" state = hass.states.get("sensor.home_ozone_0d") assert state assert state.state == "32" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get("level") == "Good" assert state.attributes.get(ATTR_ICON) == "mdi:vector-triangle" entry = registry.async_get("sensor.home_ozone_0d") assert entry assert entry.unique_id == "0123456-ozone-0" state = hass.states.get("sensor.home_ragweed_pollen_0d") assert state assert state.state == "0" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert ( state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == CONCENTRATION_PARTS_PER_CUBIC_METER ) assert state.attributes.get("level") == "Low" assert state.attributes.get(ATTR_ICON) == "mdi:sprout" entry = registry.async_get("sensor.home_ragweed_pollen_0d") assert entry assert entry.unique_id == "0123456-ragweed-0" state = hass.states.get("sensor.home_realfeel_temperature_shade_max_0d") assert state assert state.state == "28.0" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE entry = registry.async_get("sensor.home_realfeel_temperature_shade_max_0d") assert entry assert entry.unique_id == "0123456-realfeeltemperatureshademax-0" state = hass.states.get("sensor.home_realfeel_temperature_shade_min_0d") assert state assert state.state == "15.1" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == TEMP_CELSIUS assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TEMPERATURE entry = registry.async_get("sensor.home_realfeel_temperature_shade_min_0d") assert entry assert entry.unique_id == "0123456-realfeeltemperatureshademin-0" state = hass.states.get("sensor.home_tree_pollen_0d") assert state assert state.state == "0" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert ( state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == CONCENTRATION_PARTS_PER_CUBIC_METER ) assert state.attributes.get("level") == "Low" assert state.attributes.get(ATTR_ICON) == "mdi:tree-outline" entry = registry.async_get("sensor.home_tree_pollen_0d") assert entry assert entry.unique_id == "0123456-tree-0" state = hass.states.get("sensor.home_wind_day_0d") assert state assert state.state == "13.0" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == SPEED_KILOMETERS_PER_HOUR assert state.attributes.get("direction") == "SSE" assert state.attributes.get(ATTR_ICON) == "mdi:weather-windy" entry = registry.async_get("sensor.home_wind_day_0d") assert entry assert entry.unique_id == "0123456-windday-0" state = hass.states.get("sensor.home_wind_night_0d") assert state assert state.state == "7.4" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == SPEED_KILOMETERS_PER_HOUR assert state.attributes.get("direction") == "WNW" assert state.attributes.get(ATTR_ICON) == "mdi:weather-windy" entry = registry.async_get("sensor.home_wind_night_0d") assert entry assert entry.unique_id == "0123456-windnight-0" state = hass.states.get("sensor.home_wind_gust_day_0d") assert state assert state.state == "29.6" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == SPEED_KILOMETERS_PER_HOUR assert state.attributes.get("direction") == "S" assert state.attributes.get(ATTR_ICON) == "mdi:weather-windy" entry = registry.async_get("sensor.home_wind_gust_day_0d") assert entry assert entry.unique_id == "0123456-windgustday-0" state = hass.states.get("sensor.home_wind_gust_night_0d") assert state assert state.state == "18.5" assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == SPEED_KILOMETERS_PER_HOUR assert state.attributes.get("direction") == "WSW" assert state.attributes.get(ATTR_ICON) == "mdi:weather-windy" entry = registry.async_get("sensor.home_wind_gust_night_0d") assert entry assert entry.unique_id == "0123456-windgustnight-0"