def test_is_up(hass): """Test retrieving next sun events.""" utc_now = datetime(2016, 11, 1, 12, 0, 0, tzinfo=dt_util.UTC) with patch("homeassistant.helpers.condition.dt_util.utcnow", return_value=utc_now): assert not sun.is_up(hass) utc_now = datetime(2016, 11, 1, 18, 0, 0, tzinfo=dt_util.UTC) with patch("homeassistant.helpers.condition.dt_util.utcnow", return_value=utc_now): assert sun.is_up(hass)
def test_is_up(self): """Test retrieving next sun events.""" utc_now = datetime(2016, 11, 1, 12, 0, 0, tzinfo=dt_util.UTC) with patch('homeassistant.helpers.condition.dt_util.utcnow', return_value=utc_now): self.assertFalse(sun.is_up(self.hass)) utc_now = datetime(2016, 11, 1, 18, 0, 0, tzinfo=dt_util.UTC) with patch('homeassistant.helpers.condition.dt_util.utcnow', return_value=utc_now): self.assertTrue(sun.is_up(self.hass))
def test_is_up(self): """Test retrieving next sun events.""" utc_now = datetime(2016, 11, 1, 12, 0, 0, tzinfo=dt_util.UTC) with patch('homeassistant.helpers.condition.dt_util.utcnow', return_value=utc_now): assert not sun.is_up(self.hass) utc_now = datetime(2016, 11, 1, 18, 0, 0, tzinfo=dt_util.UTC) with patch('homeassistant.helpers.condition.dt_util.utcnow', return_value=utc_now): assert sun.is_up(self.hass)
def condition(self): """Return the condition.""" return self._translate_condition( self._get_cc_value(self.coordinator.data[CURRENT], CC_V3_ATTR_CONDITION), is_up(self.hass), )
def _forecast_dict( self, forecast_dt: datetime, use_datetime: bool, condition: int | str, precipitation: float | None, precipitation_probability: float | None, temp: float | None, temp_low: float | None, wind_direction: float | None, wind_speed: float | None, ) -> dict[str, Any]: """Return formatted Forecast dict from ClimaCell forecast data.""" if use_datetime: translated_condition = self._translate_condition( condition, is_up(self.hass, forecast_dt)) else: translated_condition = self._translate_condition(condition, True) data = { ATTR_FORECAST_TIME: forecast_dt.isoformat(), ATTR_FORECAST_CONDITION: translated_condition, ATTR_FORECAST_NATIVE_PRECIPITATION: precipitation, ATTR_FORECAST_PRECIPITATION_PROBABILITY: precipitation_probability, ATTR_FORECAST_NATIVE_TEMP: temp, ATTR_FORECAST_NATIVE_TEMP_LOW: temp_low, ATTR_FORECAST_WIND_BEARING: wind_direction, ATTR_FORECAST_NATIVE_WIND_SPEED: wind_speed, } return {k: v for k, v in data.items() if v is not None}
def check_light_on_dev_state_change(entity, old_state, new_state): """Handle tracked device state changes.""" lights_are_on = group.is_on(light_group) light_needed = not (lights_are_on or is_up(hass)) # These variables are needed for the elif check now = dt_util.utcnow() start_point = calc_time_for_light_when_sunset() # Do we need lights? if light_needed: logger.info("Home coming event for %s. Turning lights on", entity) light.async_turn_on(light_ids, profile=light_profile) # Are we in the time span were we would turn on the lights # if someone would be home? # Check this by seeing if current time is later then the point # in time when we would start putting the lights on. elif (start_point and start_point < now < get_astral_event_next(hass, 'sunset')): # Check for every light if it would be on if someone was home # when the fading in started and turn it on if so for index, light_id in enumerate(light_ids): if now > start_point + index * LIGHT_TRANSITION_TIME: light.async_turn_on(light_id) else: # If this light didn't happen to be turned on yet so # will all the following then, break. break
def check_light_on_dev_state_change(entity, old_state, new_state): """Handle tracked device state changes.""" lights_are_on = group.is_on(hass, light_group) light_needed = not (lights_are_on or is_up(hass)) # These variables are needed for the elif check now = dt_util.utcnow() start_point = calc_time_for_light_when_sunset() # Do we need lights? if light_needed: logger.info("Home coming event for %s. Turning lights on", entity) light.async_turn_on(hass, light_ids, profile=light_profile) # Are we in the time span were we would turn on the lights # if someone would be home? # Check this by seeing if current time is later then the point # in time when we would start putting the lights on. elif (start_point and start_point < now < get_astral_event_next(hass, 'sunset')): # Check for every light if it would be on if someone was home # when the fading in started and turn it on if so for index, light_id in enumerate(light_ids): if now > start_point + index * LIGHT_TRANSITION_TIME: light.async_turn_on(hass, light_id) else: # If this light didn't happen to be turned on yet so # will all the following then, break. break
def condition(self): """Return condition.""" if self._temperature is None: return STATE_UNKNOWN if self._humidity > 80: return 'rainy' if is_up(self._hass): return 'sunny' return 'clear-night'
def _get_condition(self, weather_code, timestamp=None): """Get weather condition from weather data.""" if weather_code == WEATHER_CODE_SUNNY_OR_CLEAR_NIGHT: if timestamp: timestamp = dt.utc_from_timestamp(timestamp) if sun.is_up(self.hass, timestamp): return ATTR_CONDITION_SUNNY return ATTR_CONDITION_CLEAR_NIGHT return [k for k, v in CONDITION_CLASSES.items() if weather_code in v][0]
def _forecast_dict( self, forecast_dt: datetime, use_datetime: bool, condition: int | str, precipitation: float | None, precipitation_probability: float | None, temp: float | None, temp_low: float | None, wind_direction: float | None, wind_speed: float | None, ) -> dict[str, Any]: """Return formatted Forecast dict from ClimaCell forecast data.""" if use_datetime: translated_condition = self._translate_condition( condition, is_up(self.hass, forecast_dt) ) else: translated_condition = self._translate_condition(condition, True) if self.hass.config.units.is_metric: if precipitation: precipitation = round( distance_convert(precipitation / 12, LENGTH_FEET, LENGTH_METERS) * 1000, 4, ) if wind_speed: wind_speed = round( speed_convert( wind_speed, SPEED_MILES_PER_HOUR, SPEED_KILOMETERS_PER_HOUR ), 4, ) data = { ATTR_FORECAST_TIME: forecast_dt.isoformat(), ATTR_FORECAST_CONDITION: translated_condition, ATTR_FORECAST_PRECIPITATION: precipitation, ATTR_FORECAST_PRECIPITATION_PROBABILITY: precipitation_probability, ATTR_FORECAST_TEMP: temp, ATTR_FORECAST_TEMP_LOW: temp_low, ATTR_FORECAST_WIND_BEARING: wind_direction, ATTR_FORECAST_WIND_SPEED: wind_speed, } return {k: v for k, v in data.items() if v is not None}
def check_light_on_dev_state_change(entity, old_state, new_state): """Handle tracked device state changes.""" lights_are_on = any_light_on() light_needed = not (lights_are_on or is_up(hass)) # These variables are needed for the elif check now = dt_util.utcnow() start_point = calc_time_for_light_when_sunset() # Do we need lights? if light_needed: logger.info("Home coming event for %s. Turning lights on", entity) hass.async_create_task( hass.services.async_call( DOMAIN_LIGHT, SERVICE_TURN_ON, {ATTR_ENTITY_ID: light_ids, ATTR_PROFILE: light_profile}, ) ) # Are we in the time span were we would turn on the lights # if someone would be home? # Check this by seeing if current time is later then the point # in time when we would start putting the lights on. elif start_point and start_point < now < get_astral_event_next( hass, SUN_EVENT_SUNSET ): # Check for every light if it would be on if someone was home # when the fading in started and turn it on if so for index, light_id in enumerate(light_ids): if now > start_point + index * LIGHT_TRANSITION_TIME: hass.async_create_task( hass.services.async_call( DOMAIN_LIGHT, SERVICE_TURN_ON, {ATTR_ENTITY_ID: light_id} ) ) else: # If this light didn't happen to be turned on yet so # will all the following then, break. break
def _forecast_dict( hass: HomeAssistantType, forecast_dt: datetime, use_datetime: bool, condition: str, precipitation: Optional[float], precipitation_probability: Optional[float], temp: Optional[float], temp_low: Optional[float], wind_direction: Optional[float], wind_speed: Optional[float], ) -> Dict[str, Any]: """Return formatted Forecast dict from ClimaCell forecast data.""" if use_datetime: translated_condition = _translate_condition(condition, is_up(hass, forecast_dt)) else: translated_condition = _translate_condition(condition, True) if hass.config.units.is_metric: if precipitation: precipitation = ( distance_convert(precipitation / 12, LENGTH_FEET, LENGTH_METERS) * 1000 ) if temp: temp = temp_convert(temp, TEMP_FAHRENHEIT, TEMP_CELSIUS) if temp_low: temp_low = temp_convert(temp_low, TEMP_FAHRENHEIT, TEMP_CELSIUS) if wind_speed: wind_speed = distance_convert(wind_speed, LENGTH_MILES, LENGTH_KILOMETERS) data = { ATTR_FORECAST_TIME: forecast_dt.isoformat(), ATTR_FORECAST_CONDITION: translated_condition, ATTR_FORECAST_PRECIPITATION: precipitation, ATTR_FORECAST_PRECIPITATION_PROBABILITY: precipitation_probability, ATTR_FORECAST_TEMP: temp, ATTR_FORECAST_TEMP_LOW: temp_low, ATTR_FORECAST_WIND_BEARING: wind_direction, ATTR_FORECAST_WIND_SPEED: wind_speed, } return {k: v for k, v in data.items() if v is not None}
async def async_setup(hass, config): """Set up the triggers to control lights based on device presence.""" logger = logging.getLogger(__name__) device_tracker = hass.components.device_tracker group = hass.components.group light = hass.components.light person = hass.components.person conf = config[DOMAIN] disable_turn_off = conf.get(CONF_DISABLE_TURN_OFF) light_group = conf.get(CONF_LIGHT_GROUP) light_profile = conf.get(CONF_LIGHT_PROFILE) device_group = conf.get(CONF_DEVICE_GROUP) if device_group is None: device_entity_ids = hass.states.async_entity_ids(device_tracker.DOMAIN) else: device_entity_ids = group.get_entity_ids(device_group, device_tracker.DOMAIN) device_entity_ids.extend( group.get_entity_ids(device_group, person.DOMAIN)) if not device_entity_ids: logger.error("No devices found to track") return False # Get the light IDs from the specified group if light_group is None: light_ids = hass.states.async_entity_ids(light.DOMAIN) else: light_ids = group.get_entity_ids(light_group, light.DOMAIN) if not light_ids: logger.error("No lights found to turn on") return False @callback def anyone_home(): """Test if anyone is home.""" return any(device_tracker.is_on(dt_id) for dt_id in device_entity_ids) @callback def any_light_on(): """Test if any light on.""" return any(light.is_on(light_id) for light_id in light_ids) def calc_time_for_light_when_sunset(): """Calculate the time when to start fading lights in when sun sets. Returns None if no next_setting data available. Async friendly. """ next_setting = get_astral_event_next(hass, SUN_EVENT_SUNSET) if not next_setting: return None return next_setting - LIGHT_TRANSITION_TIME * len(light_ids) def async_turn_on_before_sunset(light_id): """Turn on lights.""" if not anyone_home() or light.is_on(light_id): return hass.async_create_task( hass.services.async_call( DOMAIN_LIGHT, SERVICE_TURN_ON, { ATTR_ENTITY_ID: light_id, ATTR_TRANSITION: LIGHT_TRANSITION_TIME.seconds, ATTR_PROFILE: light_profile, }, )) def async_turn_on_factory(light_id): """Generate turn on callbacks as factory.""" @callback def async_turn_on_light(now): """Turn on specific light.""" async_turn_on_before_sunset(light_id) return async_turn_on_light # Track every time sun rises so we can schedule a time-based # pre-sun set event @callback def schedule_light_turn_on(now): """Turn on all the lights at the moment sun sets. We will schedule to have each light start after one another and slowly transition in. """ start_point = calc_time_for_light_when_sunset() if not start_point: return for index, light_id in enumerate(light_ids): async_track_point_in_utc_time( hass, async_turn_on_factory(light_id), start_point + index * LIGHT_TRANSITION_TIME, ) async_track_point_in_utc_time( hass, schedule_light_turn_on, get_astral_event_next(hass, SUN_EVENT_SUNRISE)) # If the sun is already above horizon schedule the time-based pre-sun set # event. if is_up(hass): schedule_light_turn_on(None) @callback def check_light_on_dev_state_change(entity, old_state, new_state): """Handle tracked device state changes.""" lights_are_on = any_light_on() light_needed = not (lights_are_on or is_up(hass)) # These variables are needed for the elif check now = dt_util.utcnow() start_point = calc_time_for_light_when_sunset() # Do we need lights? if light_needed: logger.info("Home coming event for %s. Turning lights on", entity) hass.async_create_task( hass.services.async_call( DOMAIN_LIGHT, SERVICE_TURN_ON, { ATTR_ENTITY_ID: light_ids, ATTR_PROFILE: light_profile }, )) # Are we in the time span were we would turn on the lights # if someone would be home? # Check this by seeing if current time is later then the point # in time when we would start putting the lights on. elif start_point and start_point < now < get_astral_event_next( hass, SUN_EVENT_SUNSET): # Check for every light if it would be on if someone was home # when the fading in started and turn it on if so for index, light_id in enumerate(light_ids): if now > start_point + index * LIGHT_TRANSITION_TIME: hass.async_create_task( hass.services.async_call(DOMAIN_LIGHT, SERVICE_TURN_ON, {ATTR_ENTITY_ID: light_id})) else: # If this light didn't happen to be turned on yet so # will all the following then, break. break async_track_state_change( hass, device_entity_ids, check_light_on_dev_state_change, STATE_NOT_HOME, STATE_HOME, ) if disable_turn_off: return True @callback def turn_off_lights_when_all_leave(entity, old_state, new_state): """Handle device group state change.""" # Make sure there is not someone home if anyone_home(): return # Check if any light is on if not any_light_on(): return logger.info( "Everyone has left but there are lights on. Turning them off") hass.async_create_task( hass.services.async_call(DOMAIN_LIGHT, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: light_ids})) async_track_state_change( hass, device_entity_ids, turn_off_lights_when_all_leave, STATE_HOME, STATE_NOT_HOME, ) return True
def condition(self): """Return the condition.""" return self._translate_condition( self._get_current_property(CC_ATTR_CONDITION), is_up(self.hass), )
def async_setup(hass, config): """Set up the triggers to control lights based on device presence.""" logger = logging.getLogger(__name__) device_tracker = get_component('device_tracker') group = get_component('group') light = get_component('light') conf = config[DOMAIN] disable_turn_off = conf.get(CONF_DISABLE_TURN_OFF) light_group = conf.get(CONF_LIGHT_GROUP, light.ENTITY_ID_ALL_LIGHTS) light_profile = conf.get(CONF_LIGHT_PROFILE) device_group = conf.get( CONF_DEVICE_GROUP, device_tracker.ENTITY_ID_ALL_DEVICES) device_entity_ids = group.get_entity_ids( hass, device_group, device_tracker.DOMAIN) if not device_entity_ids: logger.error("No devices found to track") return False # Get the light IDs from the specified group light_ids = group.get_entity_ids(hass, light_group, light.DOMAIN) if not light_ids: logger.error("No lights found to turn on") return False def calc_time_for_light_when_sunset(): """Calculate the time when to start fading lights in when sun sets. Returns None if no next_setting data available. Async friendly. """ next_setting = get_astral_event_next(hass, 'sunset') if not next_setting: return None return next_setting - LIGHT_TRANSITION_TIME * len(light_ids) def async_turn_on_before_sunset(light_id): """Turn on lights.""" if not device_tracker.is_on(hass) or light.is_on(hass, light_id): return light.async_turn_on(hass, light_id, transition=LIGHT_TRANSITION_TIME.seconds, profile=light_profile) def async_turn_on_factory(light_id): """Generate turn on callbacks as factory.""" @callback def async_turn_on_light(now): """Turn on specific light.""" async_turn_on_before_sunset(light_id) return async_turn_on_light # Track every time sun rises so we can schedule a time-based # pre-sun set event @callback def schedule_light_turn_on(now): """Turn on all the lights at the moment sun sets. We will schedule to have each light start after one another and slowly transition in. """ start_point = calc_time_for_light_when_sunset() if not start_point: return for index, light_id in enumerate(light_ids): async_track_point_in_utc_time( hass, async_turn_on_factory(light_id), start_point + index * LIGHT_TRANSITION_TIME) async_track_point_in_utc_time(hass, schedule_light_turn_on, get_astral_event_next(hass, 'sunrise')) # If the sun is already above horizon schedule the time-based pre-sun set # event. if is_up(hass): schedule_light_turn_on(None) @callback def check_light_on_dev_state_change(entity, old_state, new_state): """Handle tracked device state changes.""" lights_are_on = group.is_on(hass, light_group) light_needed = not (lights_are_on or is_up(hass)) # These variables are needed for the elif check now = dt_util.utcnow() start_point = calc_time_for_light_when_sunset() # Do we need lights? if light_needed: logger.info("Home coming event for %s. Turning lights on", entity) light.async_turn_on(hass, light_ids, profile=light_profile) # Are we in the time span were we would turn on the lights # if someone would be home? # Check this by seeing if current time is later then the point # in time when we would start putting the lights on. elif (start_point and start_point < now < get_astral_event_next(hass, 'sunset')): # Check for every light if it would be on if someone was home # when the fading in started and turn it on if so for index, light_id in enumerate(light_ids): if now > start_point + index * LIGHT_TRANSITION_TIME: light.async_turn_on(hass, light_id) else: # If this light didn't happen to be turned on yet so # will all the following then, break. break async_track_state_change( hass, device_entity_ids, check_light_on_dev_state_change, STATE_NOT_HOME, STATE_HOME) if disable_turn_off: return True @callback def turn_off_lights_when_all_leave(entity, old_state, new_state): """Handle device group state change.""" if not group.is_on(hass, light_group): return logger.info( "Everyone has left but there are lights on. Turning them off") light.async_turn_off(hass, light_ids) async_track_state_change( hass, device_group, turn_off_lights_when_all_leave, STATE_HOME, STATE_NOT_HOME) return True
def async_setup(hass, config): """Set up the triggers to control lights based on device presence.""" logger = logging.getLogger(__name__) device_tracker = get_component('device_tracker') group = get_component('group') light = get_component('light') conf = config[DOMAIN] disable_turn_off = conf.get(CONF_DISABLE_TURN_OFF) light_group = conf.get(CONF_LIGHT_GROUP, light.ENTITY_ID_ALL_LIGHTS) light_profile = conf.get(CONF_LIGHT_PROFILE) device_group = conf.get(CONF_DEVICE_GROUP, device_tracker.ENTITY_ID_ALL_DEVICES) device_entity_ids = group.get_entity_ids(hass, device_group, device_tracker.DOMAIN) if not device_entity_ids: logger.error("No devices found to track") return False # Get the light IDs from the specified group light_ids = group.get_entity_ids(hass, light_group, light.DOMAIN) if not light_ids: logger.error("No lights found to turn on") return False def calc_time_for_light_when_sunset(): """Calculate the time when to start fading lights in when sun sets. Returns None if no next_setting data available. Async friendly. """ next_setting = get_astral_event_next(hass, 'sunset') if not next_setting: return None return next_setting - LIGHT_TRANSITION_TIME * len(light_ids) def async_turn_on_before_sunset(light_id): """Turn on lights.""" if not device_tracker.is_on(hass) or light.is_on(hass, light_id): return light.async_turn_on(hass, light_id, transition=LIGHT_TRANSITION_TIME.seconds, profile=light_profile) def async_turn_on_factory(light_id): """Generate turn on callbacks as factory.""" @callback def async_turn_on_light(now): """Turn on specific light.""" async_turn_on_before_sunset(light_id) return async_turn_on_light # Track every time sun rises so we can schedule a time-based # pre-sun set event @callback def schedule_light_turn_on(now): """Turn on all the lights at the moment sun sets. We will schedule to have each light start after one another and slowly transition in. """ start_point = calc_time_for_light_when_sunset() if not start_point: return for index, light_id in enumerate(light_ids): async_track_point_in_utc_time( hass, async_turn_on_factory(light_id), start_point + index * LIGHT_TRANSITION_TIME) async_track_point_in_utc_time(hass, schedule_light_turn_on, get_astral_event_next(hass, 'sunrise')) # If the sun is already above horizon schedule the time-based pre-sun set # event. if is_up(hass): schedule_light_turn_on(None) @callback def check_light_on_dev_state_change(entity, old_state, new_state): """Handle tracked device state changes.""" lights_are_on = group.is_on(hass, light_group) light_needed = not (lights_are_on or is_up(hass)) # These variables are needed for the elif check now = dt_util.utcnow() start_point = calc_time_for_light_when_sunset() # Do we need lights? if light_needed: logger.info("Home coming event for %s. Turning lights on", entity) light.async_turn_on(hass, light_ids, profile=light_profile) # Are we in the time span were we would turn on the lights # if someone would be home? # Check this by seeing if current time is later then the point # in time when we would start putting the lights on. elif (start_point and start_point < now < get_astral_event_next(hass, 'sunset')): # Check for every light if it would be on if someone was home # when the fading in started and turn it on if so for index, light_id in enumerate(light_ids): if now > start_point + index * LIGHT_TRANSITION_TIME: light.async_turn_on(hass, light_id) else: # If this light didn't happen to be turned on yet so # will all the following then, break. break async_track_state_change(hass, device_entity_ids, check_light_on_dev_state_change, STATE_NOT_HOME, STATE_HOME) if disable_turn_off: return True @callback def turn_off_lights_when_all_leave(entity, old_state, new_state): """Handle device group state change.""" if not group.is_on(hass, light_group): return logger.info( "Everyone has left but there are lights on. Turning them off") light.async_turn_off(hass, light_ids) async_track_state_change(hass, device_group, turn_off_lights_when_all_leave, STATE_HOME, STATE_NOT_HOME) return True