async def async_step_user(self, user_input: dict[str, Any] = None) -> FlowResult: """Handle the initial step.""" errors = {} if user_input is not None: # Grab the API key and add it to the rest of the config before continuing if self._import_config: self._import_config[CONF_API_KEY] = user_input[CONF_API_KEY] user_input = self._import_config.copy() await self.async_set_unique_id( unique_id=_get_unique_id(self.hass, user_input)) self._abort_if_unique_id_configured() latitude = user_input.get(CONF_LATITUDE, self.hass.config.latitude) longitude = user_input.get(CONF_LONGITUDE, self.hass.config.longitude) if CONF_NAME not in user_input: user_input[CONF_NAME] = DEFAULT_NAME # Append zone name if it exists and we are using the default name if zone_state := async_active_zone(self.hass, latitude, longitude): zone_name = zone_state.attributes[CONF_FRIENDLY_NAME] user_input[CONF_NAME] += f" - {zone_name}" try: await TomorrowioV4( user_input[CONF_API_KEY], str(latitude), str(longitude), session=async_get_clientsession(self.hass), ).realtime([TMRW_ATTR_TEMPERATURE]) except CantConnectException: errors["base"] = "cannot_connect" except InvalidAPIKeyException: errors[CONF_API_KEY] = "invalid_api_key" except RateLimitedException: errors[CONF_API_KEY] = "rate_limited" except Exception: # pylint: disable=broad-except _LOGGER.exception("Unexpected exception") errors["base"] = "unknown" if not errors: options: Mapping[str, Any] = {CONF_TIMESTEP: DEFAULT_TIMESTEP} # Store the old config entry ID and retrieve options to recreate the entry if self.source == config_entries.SOURCE_IMPORT: old_config_entry_id = self.context["old_config_entry_id"] old_config_entry = self.hass.config_entries.async_get_entry( old_config_entry_id) assert old_config_entry options = dict(old_config_entry.options) user_input["old_config_entry_id"] = old_config_entry_id return self.async_create_entry( title=user_input[CONF_NAME], data=user_input, options=options, )
def async_update(self): """Update state of entity. This method is a coroutine. """ if not self.last_seen: return elif self.location_name: self._state = self.location_name elif self.gps is not None and self.source_type == SOURCE_TYPE_GPS: zone_state = zone.async_active_zone( self.hass, self.gps[0], self.gps[1], self.gps_accuracy) if zone_state is None: self._state = STATE_NOT_HOME elif zone_state.entity_id == zone.ENTITY_ID_HOME: self._state = STATE_HOME else: self._state = zone_state.name elif self.stale(): self._state = STATE_NOT_HOME self.gps = None self.last_update_home = False else: self._state = STATE_HOME self.last_update_home = True
def async_update(self): """Update state of entity. This method is a coroutine. """ if not self.last_seen: return elif self.location_name: self._state = self.location_name elif self.gps is not None and self.source_type == SOURCE_TYPE_GPS: zone_state = zone.async_active_zone(self.hass, self.gps[0], self.gps[1], self.gps_accuracy) if zone_state is None: self._state = STATE_NOT_HOME elif zone_state.entity_id == zone.ENTITY_ID_HOME: self._state = STATE_HOME else: self._state = zone_state.name elif self.stale(): self._state = STATE_NOT_HOME self.gps = None self.last_update_home = False else: self._state = STATE_HOME self.last_update_home = True
async def test_active_zone_prefers_smaller_zone_if_same_distance(hass): """Test zone size preferences.""" latitude = 32.880600 longitude = -117.237561 assert await setup.async_setup_component( hass, zone.DOMAIN, { "zone": [ { "name": "Small Zone", "latitude": latitude, "longitude": longitude, "radius": 250, }, { "name": "Big Zone", "latitude": latitude, "longitude": longitude, "radius": 500, }, ] }, ) active = zone.async_active_zone(hass, latitude, longitude) assert "zone.small_zone" == active.entity_id
async def test_unavailable_zone(hass): """Test active zone with unavailable zones.""" assert await setup.async_setup_component(hass, DOMAIN, {"zone": {}}) hass.states.async_set("zone.bla", "unavailable", {"restored": True}) assert zone.async_active_zone(hass, 0.0, 0.01) is None assert zone.in_zone(hass.states.get("zone.bla"), 0, 0) is False
def test_active_zone_skips_passive_zones_2(self): """Test active and passive zones.""" assert setup.setup_component( self.hass, zone.DOMAIN, { 'zone': [ { 'name': 'Active Zone', 'latitude': 32.880800, 'longitude': -117.237561, 'radius': 500, }, ] }) self.hass.block_till_done() active = zone.async_active_zone(self.hass, 32.880700, -117.237561) assert 'zone.active_zone' == active.entity_id
async def test_active_zone_skips_passive_zones_2(hass): """Test active and passive zones.""" assert await setup.async_setup_component( hass, zone.DOMAIN, { "zone": [{ "name": "Active Zone", "latitude": 32.880800, "longitude": -117.237561, "radius": 500, }] }, ) await hass.async_block_till_done() active = zone.async_active_zone(hass, 32.880700, -117.237561) assert "zone.active_zone" == active.entity_id
def test_active_zone_skips_passive_zones(self): """Test active and passive zones.""" assert setup.setup_component( self.hass, zone.DOMAIN, { 'zone': [ { 'name': 'Passive Zone', 'latitude': 32.880600, 'longitude': -117.237561, 'radius': 250, 'passive': True }, ] }) self.hass.block_till_done() active = zone.async_active_zone(self.hass, 32.880600, -117.237561) assert active is None
def state(self) -> str | None: """Return the state of the device.""" if self.location_name is not None: return self.location_name if self.latitude is not None and self.longitude is not None: zone_state = zone.async_active_zone(self.hass, self.latitude, self.longitude, self.location_accuracy) if zone_state is None: state = STATE_NOT_HOME elif zone_state.entity_id == zone.ENTITY_ID_HOME: state = STATE_HOME else: state = zone_state.name return state return None
async def test_active_zone_skips_passive_zones(hass): """Test active and passive zones.""" assert await setup.async_setup_component( hass, zone.DOMAIN, { "zone": [{ "name": "Passive Zone", "latitude": 32.880600, "longitude": -117.237561, "radius": 250, "passive": True, }] }, ) await hass.async_block_till_done() active = zone.async_active_zone(hass, 32.880600, -117.237561) assert active is None
def test_active_zone_prefers_smaller_zone_if_same_distance_2(self): """Test zone size preferences.""" latitude = 32.880600 longitude = -117.237561 assert setup.setup_component( self.hass, zone.DOMAIN, { 'zone': [ { 'name': 'Smallest Zone', 'latitude': latitude, 'longitude': longitude, 'radius': 50, }, ] }) active = zone.async_active_zone(self.hass, latitude, longitude) assert 'zone.smallest_zone' == active.entity_id
def test_active_zone_prefers_smaller_zone_if_same_distance_2(self): """Test zone size preferences.""" latitude = 32.880600 longitude = -117.237561 assert setup.setup_component( self.hass, zone.DOMAIN, { "zone": [{ "name": "Smallest Zone", "latitude": latitude, "longitude": longitude, "radius": 50, }] }, ) active = zone.async_active_zone(self.hass, latitude, longitude) assert "zone.smallest_zone" == active.entity_id