def _point_in_time_listener(self, now): """Run when the state of the sensor should be updated.""" self._calculate_next_update() self.async_schedule_update_ha_state() async_track_point_in_utc_time( self.hass, self._point_in_time_listener, self.next_update)
async def async_handle_start_charge(service): """Handle service to start charging.""" # It would be better if this was changed to use nickname, or # an entity name rather than a vin. vin = service.data[ATTR_VIN] if vin in hass.data[DATA_LEAF]: data_store = hass.data[DATA_LEAF][vin] # Send the command to request charging is started to Nissan # servers. If that completes OK then trigger a fresh update to # pull the charging status from the car after waiting a minute # for the charging request to reach the car. result = await hass.async_add_executor_job( data_store.leaf.start_charging) if result: _LOGGER.debug("Start charging sent, " "request updated data in 1 minute") check_charge_at = utcnow() + timedelta(minutes=1) data_store.next_update = check_charge_at async_track_point_in_utc_time( hass, data_store.async_update_data, check_charge_at) else: _LOGGER.debug("Vin %s not recognised for update", vin)
def async_update_data(now): """Update data from IP camera in SCAN_INTERVAL.""" yield from cam.update() async_dispatcher_send(hass, SIGNAL_UPDATE_DATA, host) async_track_point_in_utc_time( hass, async_update_data, utcnow() + interval)
def async_update_heat_data(now): """Update heat data from eight in HEAT_SCAN_INTERVAL.""" yield from eight.update_device_data() async_dispatcher_send(hass, SIGNAL_UPDATE_HEAT) async_track_point_in_utc_time( hass, async_update_heat_data, utcnow() + HEAT_SCAN_INTERVAL)
def async_update_user_data(now): """Update user data from eight in USER_SCAN_INTERVAL.""" yield from eight.update_user_data() async_dispatcher_send(hass, SIGNAL_UPDATE_USER) async_track_point_in_utc_time( hass, async_update_user_data, utcnow() + USER_SCAN_INTERVAL)
def schedule_first(event): """Schedule the first discovery when Home Assistant starts up.""" async_track_point_in_utc_time(hass, scan_devices, dt_util.utcnow()) # discovery local services if 'HASSIO' in os.environ: hass.async_add_job(new_service_found(SERVICE_HASSIO, {}))
def try_again(err: str): """Retry in 15 minutes.""" _LOGGER.warning('Retrying in 15 minutes: %s', err) self._nextrun = None nxt = dt_util.utcnow() + timedelta(minutes=15) if nxt.minute >= 15: async_track_point_in_utc_time(self.hass, self.async_update, nxt)
async def scan_devices(now): """Scan for devices.""" results = await hass.async_add_job(_discover, netdisco) for result in results: hass.async_add_job(new_service_found(*result)) async_track_point_in_utc_time(hass, scan_devices, dt_util.utcnow() + SCAN_INTERVAL)
def point_in_time_listener(self, now): """Run when the state of the sun has changed.""" self.update_sun_position(now) self.update_as_of(now) self.async_schedule_update_ha_state() # Schedule next update at next_change+1 second so sun state has changed async_track_point_in_utc_time( self.hass, self.point_in_time_listener, self.next_change + timedelta(seconds=1))
def scan_devices(now): """Scan for devices.""" results = yield from hass.loop.run_in_executor( None, _discover, netdisco) for result in results: hass.async_add_job(new_service_found(*result)) async_track_point_in_utc_time(hass, scan_devices, dt_util.utcnow() + SCAN_INTERVAL)
async def scan_devices(now): """Scan for devices.""" try: results = await hass.async_add_job(_discover, netdisco) for result in results: hass.async_create_task(new_service_found(*result)) except OSError: logger.error("Network is unreachable") async_track_point_in_utc_time( hass, scan_devices, dt_util.utcnow() + SCAN_INTERVAL)
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)
def update_later(self, when): """Block immediate update requests and schedule one for later.""" if self.blocker: self.blocker() self.blocker = async_track_point_in_utc_time( self.hass, self.unblock_updates, util.dt.utcnow() + timedelta(milliseconds=BULB_LATENCY)) if self.postponed_update: self.postponed_update() if when > BULB_LATENCY: self.postponed_update = async_track_point_in_utc_time( self.hass, self.update_after_transition, util.dt.utcnow() + timedelta(milliseconds=when+BULB_LATENCY))
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the Time and Date sensor.""" if hass.config.time_zone is None: _LOGGER.error("Timezone is not set in Home Assistant configuration") return False devices = [] for variable in config[CONF_DISPLAY_OPTIONS]: device = TimeDateSensor(hass, variable) async_track_point_in_utc_time( hass, device.point_in_time_listener, device.get_next_interval()) devices.append(device) async_add_devices(devices, True)
def update_callback(self, no_delay=False): """Update the sensor's state, if needed. Parameter no_delay is True when device_event_reachable is sent. """ delay = self.device.config_entry.options[CONF_TRIGGER_TIME] if self.remove_timer is not None: self.remove_timer() self.remove_timer = None if self.is_on or delay == 0 or no_delay: self.async_schedule_update_ha_state() return @callback def _delay_update(now): """Timer callback for sensor update.""" LOGGER.debug("%s called delayed (%s sec) update", self.name, delay) self.async_schedule_update_ha_state() self.remove_timer = None self.remove_timer = async_track_point_in_utc_time( self.hass, _delay_update, utcnow() + timedelta(seconds=delay))
def _async_set_timeout(self, action, variables, context, continue_on_timeout): """Schedule a timeout to abort or continue script.""" timeout = action[CONF_TIMEOUT] unsub = None @callback def async_script_timeout(now): """Call after timeout is retrieve.""" with suppress(ValueError): self._async_listener.remove(unsub) # Check if we want to continue to execute # the script after the timeout if continue_on_timeout: self.hass.async_create_task( self.async_run(variables, context)) else: self._log("Timeout reached, abort script.") self.async_stop() unsub = async_track_point_in_utc_time( self.hass, async_script_timeout, date_util.utcnow() + timeout ) self._async_listener.append(unsub)
async def update(now): """Update status from the online service.""" try: if not await connection.update(journal=True): _LOGGER.warning("Could not query server") return False for vehicle in connection.vehicles: if vehicle.vin not in data.vehicles: discover_vehicle(vehicle) async_dispatcher_send(hass, SIGNAL_STATE_UPDATED) return True finally: async_track_point_in_utc_time(hass, update, utcnow() + interval)
def message_received(topic, payload, qos): """Handle new MQTT messages.""" # auto-expire enabled? if self._expire_after is not None and self._expire_after > 0: # Reset old trigger if self._expiration_trigger: self._expiration_trigger() self._expiration_trigger = None # Set new trigger expiration_at = ( dt_util.utcnow() + timedelta(seconds=self._expire_after)) self._expiration_trigger = async_track_point_in_utc_time( self.hass, self.value_is_expired, expiration_at) if self._json_attributes: self._attributes = {} try: json_dict = json.loads(payload) if isinstance(json_dict, dict): attrs = {k: json_dict[k] for k in self._json_attributes & json_dict.keys()} self._attributes = attrs else: _LOGGER.warning("JSON result was not a dictionary") except ValueError: _LOGGER.warning("MQTT payload could not be parsed as JSON") _LOGGER.debug("Erroneous JSON: %s", payload) if self._template is not None: payload = self._template.async_render_with_possible_json_value( payload, self._state) self._state = payload self.async_schedule_update_ha_state()
async def async_start(self, duration): """Start a timer.""" if self._listener: self._listener() self._listener = None newduration = None if duration: newduration = duration self._state = STATUS_ACTIVE # pylint: disable=redefined-outer-name start = dt_util.utcnow() if self._remaining and newduration is None: self._end = start + self._remaining else: if newduration: self._duration = newduration self._remaining = newduration else: self._remaining = self._duration self._end = start + self._duration self._listener = async_track_point_in_utc_time(self._hass, self.async_finished, self._end) await self.async_update_ha_state()
async def update_image(self, image, filename): """Update the camera image.""" if self._state == STATE_IDLE: self._state = STATE_RECORDING self._last_trip = dt_util.utcnow() self.queue.clear() self._filename = filename self.queue.appendleft(image) @callback def reset_state(now): """Set state to idle after no new images for a period of time.""" self._state = STATE_IDLE self._expired_listener = None _LOGGER.debug("Reset state") self.async_schedule_update_ha_state() if self._expired_listener: self._expired_listener() self._expired_listener = async_track_point_in_utc_time( self.hass, reset_state, dt_util.utcnow() + self._timeout) self.async_schedule_update_ha_state()
async def async_start(self, duration): """Start a timer.""" if self._listener: self._listener() self._listener = None newduration = None if duration: newduration = duration event = EVENT_TIMER_STARTED if self._state == STATUS_PAUSED: event = EVENT_TIMER_RESTARTED self._state = STATUS_ACTIVE # pylint: disable=redefined-outer-name start = dt_util.utcnow() if self._remaining and newduration is None: self._end = start + self._remaining else: if newduration: self._duration = newduration self._remaining = newduration else: self._remaining = self._duration self._end = start + self._duration self._hass.bus.async_fire(event, {"entity_id": self.entity_id}) self._listener = async_track_point_in_utc_time(self._hass, self.async_finished, self._end) await self.async_update_ha_state()
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Time and Date sensor.""" if hass.config.time_zone is None: _LOGGER.error("Timezone is not set in Home Assistant configuration") return False sensor_name = config.get(CONF_NAME) advance_days = config.get(CONF_ADVANCE_DAYS) device = LunarDateSensor(hass, sensor_name, advance_days) async_track_point_in_utc_time(hass, device.point_in_time_listener, device.get_next_interval()) async_add_entities([device], True)
def _point_in_time_listener(self, now): """Run when the state of the sensor should be updated.""" self._calculate_next_update() self.async_write_ha_state() self._unsub_update = event.async_track_point_in_utc_time( self.hass, self._point_in_time_listener, self._next_update )
def _ack_callback(): self.device.log(DEBUG, 0, "MLRollerShutter(0): _ack_callback") if timeout is not None: self._position_endtime = time() + timeout self._stop_unsub = async_track_point_in_utc_time( self.hass, self._stop_job, datetime.fromtimestamp(self._position_endtime)) self.device.request_get(mc.NS_APPLIANCE_ROLLERSHUTTER_STATE)
async def _save_auth_tokens(self, *args) -> None: # evohomeclient2 uses naive/local datetimes access_token_expires = _local_dt_to_utc( self.client.access_token_expires) self._app_storage[CONF_USERNAME] = self.params[CONF_USERNAME] self._app_storage[CONF_REFRESH_TOKEN] = self.client.refresh_token self._app_storage[CONF_ACCESS_TOKEN] = self.client.access_token self._app_storage[CONF_ACCESS_TOKEN_EXPIRES] = \ access_token_expires.isoformat() store = self.hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY) await store.async_save(self._app_storage) async_track_point_in_utc_time( self.hass, self._save_auth_tokens, access_token_expires + self.params[CONF_SCAN_INTERVAL])
def __init__(self, hass, altitude, pressure_kpa, zones_sensors, connectors, refresh_interval, evolution_arrows_minutes, remote_api_conf): """Initialize Local File Camera component.""" self.hass = hass self._last_tile_generation = None self._delta_refresh = timedelta(seconds=refresh_interval) self._altitude = altitude self._pressure_kpa = pressure_kpa self.zones_sensors = zones_sensors self.colors_interior_zones = { k: next(POINT_COLORS) for k in sorted(self.zones_sensors[CONF_INTERIOR]) } self.connectors = connectors if evolution_arrows_minutes: len_deque = int( timedelta(minutes=evolution_arrows_minutes) / self._delta_refresh) else: len_deque = 1 self.points = deque([], maxlen=len_deque) self.svg_image_bytes = None self.delta_house = None self.open_house = None self._deadband = 0.5 # ºC self.sensor_attributes = {} # Remote access to sensors in other HA instance self.remote_api = None if remote_api_conf: from homeassistant import remote api = remote.API(remote_api_conf['base_url'], api_password=remote_api_conf.get('api_password'), port=remote_api_conf.get('port', 8123), use_ssl=remote_api_conf.get('use_ssl', False)) assert api.validate_api() self.remote_api = api # Chart regeneration if self.remote_api is not None: # No need to wait async_track_point_in_utc_time(self.hass, self.update_chart, now() + timedelta(seconds=10)) async_track_time_interval(self.hass, self.update_chart, self._delta_refresh)
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Time and Date sensor.""" if hass.config.time_zone is None: _LOGGER.error("Timezone is not set in Home Assistant configuration") return False devices = [] for variable in config[CONF_DISPLAY_OPTIONS]: device = TimeDateSensor(hass, variable) async_track_point_in_utc_time(hass, device.point_in_time_listener, device.get_next_interval()) devices.append(device) async_add_entities(devices, True)
def _start_state_timer(self): """Start state timer.""" if self._state_timer is not None: self._state_timer() self._state_timer = None restore_state_time = dt_util.utcnow() + timedelta(seconds=15) self._state_timer = async_track_point_in_utc_time( self.hass, self._stop_state_timer, restore_state_time)
def _schedule_stream_refresh(self): if self._stream_refresh_unsub is not None: self._stream_refresh_unsub() self._stream_refresh_unsub = async_track_point_in_utc_time( self.hass, self._handle_stream_refresh, # noqa datetime.fromtimestamp(self._url_expiration), )
def _setup_update_at_time(self, update_dttm, state=None, attrs=None): self._updates.append(( async_track_point_in_utc_time(self.hass, self._async_do_update, update_dttm), update_dttm, state, attrs, ))
def is_connected(self): """Return true if the client is connected to the network. If connected to unwanted ssid return False. If is_wired and client.is_wired differ it means that the device is offline and UniFi bug shows device as wired. """ @callback def _scheduled_update(now): """Scheduled callback for update.""" self.is_disconnected = True self.cancel_scheduled_update = None self.async_write_ha_state() if (not self.is_wired and self.controller.option_ssid_filter and self.client.essid not in self.controller.option_ssid_filter): return False if (self.is_wired and self.wired_connection) or (not self.is_wired and self.wireless_connection): if self.cancel_scheduled_update: self.cancel_scheduled_update() self.cancel_scheduled_update = None self.is_disconnected = False if (self.is_wired and self.wired_connection is False) or ( not self.is_wired and self.wireless_connection is False): if not self.is_disconnected and not self.cancel_scheduled_update: self.cancel_scheduled_update = async_track_point_in_utc_time( self.hass, _scheduled_update, dt_util.utcnow() + self.controller.option_detection_time, ) if self.is_disconnected is not None: return not self.is_disconnected if self.is_wired != self.client.is_wired: if not self.wired_bug: self.wired_bug = dt_util.utcnow() since_last_seen = dt_util.utcnow() - self.wired_bug else: self.wired_bug = None # A client that has never been seen cannot be connected. if self.client.last_seen is None: return False since_last_seen = dt_util.utcnow() - dt_util.utc_from_timestamp( float(self.client.last_seen)) if since_last_seen < self.controller.option_detection_time: return True return False
def _schedule_refresh(self) -> None: """Schedule a refresh.""" if self._unsub_refresh: self._unsub_refresh() self._unsub_refresh = None self._unsub_refresh = async_track_point_in_utc_time( self.hass, self._handle_refresh_interval, utcnow() + self.update_interval)
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Workday sensor.""" sensor_name = config.get(CONF_NAME) service_key = config.get(CONF_SERVICE_KEY) workdays = config.get(CONF_WORKDAYS) excludes = config.get(CONF_EXCLUDES) days_offset = config.get(CONF_OFFSET) add_holidays = config.get(CONF_ADD_HOLIDAYS) input_entity = config.get(CONF_INPUT_ENTITY) shopping_list = config.get(CONF_USE_SHOPPING_LIST) device = IsWorkdaySensor( hass, add_holidays, workdays, excludes, days_offset, sensor_name, service_key, input_entity, shopping_list) async_track_point_in_utc_time( hass, device.point_in_time_listener, device.get_next_interval()) async_add_entities([device], True)
def _schedule_event_image_cleanup(self, point_in_time): """Schedules an alarm to remove the image bytes from memory, honoring expiration.""" if self._event_image_cleanup_unsub is not None: self._event_image_cleanup_unsub() self._event_image_cleanup_unsub = async_track_point_in_utc_time( self.hass, self._handle_event_image_cleanup, point_in_time, )
def update_later(self, when): """Schedule an update requests when a transition is over.""" if self.postponed_update: self.postponed_update() self.postponed_update = None if when > 0: self.postponed_update = async_track_point_in_utc_time( self.hass, self.update_after_transition, util.dt.utcnow() + timedelta(milliseconds=when))
def update_later(self, when): """Schedule an update requests when a transition is over.""" if self.postponed_update: self.postponed_update() self.postponed_update = None if when > 0: self.postponed_update = async_track_point_in_utc_time( self.hass, self.update_after_transition, util.dt.utcnow() + timedelta(milliseconds=when))
def async_run(self, variables: Optional[Sequence]=None) -> None: """Run script. This method is a coroutine. """ self.last_triggered = date_util.utcnow() if self._cur == -1: self._log('Running script') self._cur = 0 # Unregister callback if we were in a delay but turn on is called # again. In that case we just continue execution. self._async_remove_listener() for cur, action in islice(enumerate(self.sequence), self._cur, None): if CONF_DELAY in action: # Call ourselves in the future to continue work @asyncio.coroutine def script_delay(now): """Called after delay is done.""" self._async_unsub_delay_listener = None self.hass.async_add_job(self.async_run(variables)) delay = action[CONF_DELAY] if isinstance(delay, template.Template): delay = vol.All( cv.time_period, cv.positive_timedelta)( delay.async_render(variables)) self._async_unsub_delay_listener = \ async_track_point_in_utc_time( self.hass, script_delay, date_util.utcnow() + delay) self._cur = cur + 1 if self._change_listener: self.hass.async_add_job(self._change_listener) return elif CONF_CONDITION in action: if not self._async_check_condition(action, variables): break elif CONF_EVENT in action: self._async_fire_event(action) else: yield from self._async_call_service(action, variables) self._cur = -1 self.last_action = None if self._change_listener: self.hass.async_add_job(self._change_listener)
def _set_auto_off(self, auto_off_time: datetime) -> None: @callback def _auto_off(_): """Reset state of template binary sensor.""" self._state = False self.async_write_ha_state() self._auto_off_time = auto_off_time self._auto_off_cancel = async_track_point_in_utc_time( self.hass, _auto_off, self._auto_off_time)
def _async_track_unavailable(self): if self._remove_unavailability_tracker: self._remove_unavailability_tracker() self._remove_unavailability_tracker = async_track_point_in_utc_time( self.hass, self._async_set_unavailable, utcnow() + TIME_TILL_UNAVAILABLE) if not self._is_available: self._is_available = True return True return False
async def async_turn_on(self, **kwargs): """Power the relay.""" if self._reset_sub is not None: self._reset_sub() self._reset_sub = None self._reset_sub = async_track_point_in_utc_time( self.hass, self._async_turn_off, dt_util.utcnow() + self._time) await self.hass.async_add_executor_job(self._turn_on) self.async_write_ha_state()
def setup_leaf(car_config): """Set up a car.""" _LOGGER.debug("Logging into You+Nissan...") username = car_config[CONF_USERNAME] password = car_config[CONF_PASSWORD] region = car_config[CONF_REGION] leaf = None try: # This might need to be made async (somehow) causes # homeassistant to be slow to start sess = Session(username, password, region) leaf = sess.get_leaf() except KeyError: _LOGGER.error( "Unable to fetch car details..." " do you actually have a Leaf connected to your account?" ) return False except CarwingsError: _LOGGER.error( "An unknown error occurred while connecting to Nissan: %s", sys.exc_info()[0], ) return False _LOGGER.warning( "WARNING: This may poll your Leaf too often, and drain the 12V" " battery. If you drain your cars 12V battery it WILL NOT START" " as the drive train battery won't connect." " Don't set the intervals too low." ) data_store = LeafDataStore(hass, leaf, car_config) hass.data[DATA_LEAF][leaf.vin] = data_store for component in LEAF_COMPONENTS: load_platform(hass, component, DOMAIN, {}, car_config) async_track_point_in_utc_time( hass, data_store.async_update_data, utcnow() + INITIAL_UPDATE )
def _async_track_unavailable(self): if self._remove_unavailability_tracker: self._remove_unavailability_tracker() self._remove_unavailability_tracker = async_track_point_in_utc_time( self.hass, self._async_set_unavailable, utcnow() + TIME_TILL_UNAVAILABLE) if not self._is_available: self._is_available = True return True return False
def update_sun_position(self, utc_point_in_time): """Calculate the position of the sun.""" self.solar_azimuth = round( self.location.solar_azimuth(utc_point_in_time), 2) self.solar_elevation = round( self.location.solar_elevation(utc_point_in_time), 2) _LOGGER.debug("sun position_update@%s: elevation=%s azimuth=%s", utc_point_in_time.isoformat(), self.solar_elevation, self.solar_azimuth) self.async_write_ha_state() # Next update as per the current phase delta = _PHASE_UPDATES[self.phase] # if the next update is within 1.25 of the next # position update just drop it if utc_point_in_time + delta * 1.25 > self._next_change: return async_track_point_in_utc_time(self.hass, self.update_sun_position, utc_point_in_time + delta)
async def test_track_point_in_time(hass): """Test track point in time.""" before_birthday = datetime(1985, 7, 9, 12, 0, 0, tzinfo=dt_util.UTC) birthday_paulus = datetime(1986, 7, 9, 12, 0, 0, tzinfo=dt_util.UTC) after_birthday = datetime(1987, 7, 9, 12, 0, 0, tzinfo=dt_util.UTC) runs = [] async_track_point_in_utc_time( hass, callback(lambda x: runs.append(1)), birthday_paulus ) _send_time_changed(hass, before_birthday) await hass.async_block_till_done() assert len(runs) == 0 _send_time_changed(hass, birthday_paulus) await hass.async_block_till_done() assert len(runs) == 1 # A point in time tracker will only fire once, this should do nothing _send_time_changed(hass, birthday_paulus) await hass.async_block_till_done() assert len(runs) == 1 async_track_point_in_utc_time( hass, callback(lambda x: runs.append(1)), birthday_paulus ) _send_time_changed(hass, after_birthday) await hass.async_block_till_done() assert len(runs) == 2 unsub = async_track_point_in_time( hass, callback(lambda x: runs.append(1)), birthday_paulus ) unsub() _send_time_changed(hass, after_birthday) await hass.async_block_till_done() assert len(runs) == 2
def register_node(self, node_id): if node_id in self._nodes: _LOGGER.debug('detected duplicate registration: %s', node_id) return self._nodes.append(node_id) _LOGGER.debug('registered new node: %s', node_id) if not self._shutdown_interval: _LOGGER.debug('starting background poll: %s', self._scan_interval) self._shutdown_interval = async_track_time_interval( self._hass, self._update, self._scan_interval ) async_track_point_in_utc_time( self._hass, self._update, dt.utcnow() + timedelta(seconds=5) )
def async_run(self, variables: Optional[Sequence] = None) -> None: """Run script. This method is a coroutine. """ self.last_triggered = date_util.utcnow() if self._cur == -1: self._log('Running script') self._cur = 0 # Unregister callback if we were in a delay but turn on is called # again. In that case we just continue execution. self._async_remove_listener() for cur, action in islice(enumerate(self.sequence), self._cur, None): if CONF_DELAY in action: # Call ourselves in the future to continue work @asyncio.coroutine def script_delay(now): """Called after delay is done.""" self._async_unsub_delay_listener = None self.hass.async_add_job(self.async_run(variables)) delay = action[CONF_DELAY] if isinstance(delay, template.Template): delay = vol.All(cv.time_period, cv.positive_timedelta)( delay.async_render(variables)) self._async_unsub_delay_listener = \ async_track_point_in_utc_time( self.hass, script_delay, date_util.utcnow() + delay) self._cur = cur + 1 if self._change_listener: self.hass.async_add_job(self._change_listener) return elif CONF_CONDITION in action: if not self._async_check_condition(action, variables): break elif CONF_EVENT in action: self._async_fire_event(action) else: yield from self._async_call_service(action, variables) self._cur = -1 self.last_action = None if self._change_listener: self.hass.async_add_job(self._change_listener)
def pattern_time_change_listener(_: datetime) -> None: """Listen for matching time_changed events.""" nonlocal time_listener now = time_tracker_utcnow() hass.async_run_hass_job(job, now.astimezone(tz) if tz else now) time_listener = async_track_point_in_utc_time( hass, pattern_time_change_listener, calculate_next(now + timedelta(seconds=1)), )
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Setup the sensor platform.""" sensor_name = config.get(CONF_NAME) icon = config.get(CONF_ICON) epoch = config.get(CONF_EPOCH) frequency = config.get(CONF_FREQUENCY) sensors = [ PeriodicEventSensor(hass, f'{sensor_name} Date', icon, epoch, frequency), PeriodicEventRelativeSensor(hass, sensor_name, icon, epoch, frequency), ] for sensor in sensors: async_track_point_in_utc_time(hass, sensor.point_in_time_listener, sensor.get_next_interval()) async_add_entities(sensors, True)
def state_message_received(msg): """Handle a new received MQTT state message.""" payload = msg.payload # auto-expire enabled? expire_after = self._config.get(CONF_EXPIRE_AFTER) if expire_after is not None and expire_after > 0: # When expire_after is set, and we receive a message, assume device is not expired since it has to be to receive the message self._expired = False # Reset old trigger if self._expiration_trigger: self._expiration_trigger() self._expiration_trigger = None # Set new trigger expiration_at = dt_util.utcnow() + timedelta(seconds=expire_after) self._expiration_trigger = async_track_point_in_utc_time( self.hass, self.value_is_expired, expiration_at ) value_template = self._config.get(CONF_VALUE_TEMPLATE) if value_template is not None: payload = value_template.async_render_with_possible_json_value( payload, variables={"entity_id": self.entity_id} ) if payload == self._config[CONF_PAYLOAD_ON]: self._state = True elif payload == self._config[CONF_PAYLOAD_OFF]: self._state = False else: # Payload is not for this entity # _LOGGER.warning( # "No matching payload found for entity: %s with state topic: %s. Payload: %s, with value template %s", # self._config[CONF_NAME], # self._config[CONF_STATE_TOPIC], # payload, # value_template, # ) return if self._delay_listener is not None: self._delay_listener() self._delay_listener = None off_delay = self._config.get(CONF_OFF_DELAY) if self._state and off_delay is not None: self._delay_listener = evt.async_call_later( self.hass, off_delay, off_delay_listener ) self.async_write_ha_state()
def _async_track_unavailable(self): if self._remove_unavailability_tracker: self._remove_unavailability_tracker() self._remove_unavailability_tracker = async_track_point_in_utc_time( self.hass, self._async_set_unavailable, utcnow() + self._ping_interval + PING_INTERVAL_MARGIN, ) if not self._is_available: self._is_available = True return True return False
def _listen_next_calendar_event(self) -> None: """Set up the calendar event listener.""" if not self._events: return (event_datetime, _event) = self._events[0] _LOGGER.debug("Scheduling next event trigger @ %s", event_datetime) self._unsub_event = async_track_point_in_utc_time( self._hass, self._handle_calendar_event, event_datetime, )
async def interval_listener(now): """Handle elapsed intervals with backoff.""" nonlocal failed, remove try: failed += 1 if await action(now): failed = 0 finally: delay = intervals[failed] if failed < len( intervals) else intervals[-1] remove = async_track_point_in_utc_time(hass, interval_listener, now + delay)
def schedule_update(self) -> None: """Set the next update to be triggered in a minute.""" # Remove any future updates that may be scheduled if self._remove_listener: self._remove_listener() # Schedule update for one minute in the future - so that previously sent # requests can be processed by Nissan servers or the car. update_at = utcnow() + timedelta(minutes=1) self.next_update = update_at self._remove_listener = async_track_point_in_utc_time( self.hass, self.async_update_data, update_at)
async def schedule_update(self, second=10): """Schedule an update after seconds.""" """ If we only getting lines schedule, no need for constant pooling. Some aprox timing calculations based on nubers of results setted for schedule to return. Also since city of Varna doesn't have public transport trough the night, there is no need to pool at that time """ if dt_util.parse_time('23:59:00') <= dt_util.parse_time(dt_util.now( ).strftime('%H:%M:%S')) <= dt_util.parse_time('04:59:59'): future = datetime.combine( dt_util.parse_datetime( dt_util.now().strftime('%Y-%m-%d %H:%M:%S%z')), dt_util.parse_time('04:59:59') ) #future hour - 5:00 in the morning, when the first buses goes from the end stops current = datetime.now() #now tdelta = future - current #return the hours diffrence between the two times, we do calculation here to set next execute after N - hours if tdelta.days < 0: #our interval crosses midnight end time is always earlier than the start time resulting timedalta been negative, lets account for that bellow tdelta = timedelta(days=0, seconds=tdelta.seconds, microseconds=tdelta.microseconds) nxt = dt_util.utcnow() + tdelta else: if self._mode == 'schedule': if second == 1: nxt = dt_util.utcnow() + timedelta(seconds=1) else: if self._max_results <= 10: nxt = dt_util.utcnow() + timedelta(hours=1) elif self._max_results <= 20: nxt = dt_util.utcnow() + timedelta(hours=2) elif self._max_results <= 40: nxt = dt_util.utcnow() + timedelta(hours=4) else: nxt = dt_util.utcnow() + timedelta(hours=6) else: nxt = dt_util.utcnow() + timedelta(seconds=second) _LOGGER.debug("Scheduling next update at %s. UTC time", nxt.strftime('%H:%M:%S')) async_track_point_in_utc_time(self._hass, self.async_update, nxt)
def setup_leaf(car_config): """Set up a car.""" _LOGGER.debug("Logging into You+Nissan...") username = car_config[CONF_USERNAME] password = car_config[CONF_PASSWORD] region = car_config[CONF_REGION] leaf = None try: # This might need to be made async (somehow) causes # homeassistant to be slow to start sess = pycarwings2.Session(username, password, region) leaf = sess.get_leaf() except KeyError: _LOGGER.error( "Unable to fetch car details..." " do you actually have a Leaf connected to your account?") return False except pycarwings2.CarwingsError: _LOGGER.error( "An unknown error occurred while connecting to Nissan: %s", sys.exc_info()[0]) return False _LOGGER.warning( "WARNING: This may poll your Leaf too often, and drain the 12V" " battery. If you drain your cars 12V battery it WILL NOT START" " as the drive train battery won't connect." " Don't set the intervals too low.") data_store = LeafDataStore(hass, leaf, car_config) hass.data[DATA_LEAF][leaf.vin] = data_store for component in LEAF_COMPONENTS: if component != 'device_tracker' or car_config[CONF_NCONNECT]: load_platform(hass, component, DOMAIN, {}, car_config) async_track_point_in_utc_time(hass, data_store.async_update_data, utcnow() + INITIAL_UPDATE)
def update_during_transition(self, when): """Update state at the start and end of a transition.""" if self.postponed_update: self.postponed_update() # Transition has started yield from self.update_hass() # Transition has ended if when > 0: self.postponed_update = async_track_point_in_utc_time( self.hass, self.update_hass, util.dt.utcnow() + timedelta(milliseconds=when))
def state_automation_listener(entity, from_s, to_s): """Listen for state changes and calls action.""" nonlocal async_remove_state_for_cancel, async_remove_state_for_listener def call_action(): """Call action with right context.""" hass.async_run_job(action, { 'trigger': { 'platform': 'state', 'entity_id': entity, 'from_state': from_s, 'to_state': to_s, 'for': time_delta, } }) if time_delta is None: call_action() return @callback def clear_listener(): """Clear all unsub listener.""" nonlocal async_remove_state_for_cancel nonlocal async_remove_state_for_listener async_remove_state_for_listener = None async_remove_state_for_cancel = None @callback def state_for_listener(now): """Fire on state changes after a delay and calls action.""" async_remove_state_for_cancel() clear_listener() call_action() @callback def state_for_cancel_listener(entity, inner_from_s, inner_to_s): """Fire on changes and cancel for listener if changed.""" if inner_to_s.state == to_s.state: return async_remove_state_for_listener() async_remove_state_for_cancel() clear_listener() async_remove_state_for_listener = async_track_point_in_utc_time( hass, state_for_listener, dt_util.utcnow() + time_delta) async_remove_state_for_cancel = async_track_state_change( hass, entity, state_for_cancel_listener)
def state_automation_listener(entity, from_s, to_s): """Listen for state changes and calls action.""" nonlocal async_remove_state_for_cancel, async_remove_state_for_listener def call_action(): """Call action with right context.""" hass.async_run_job(action, { 'trigger': { 'platform': 'state', 'entity_id': entity, 'from_state': from_s, 'to_state': to_s, 'for': time_delta, } }) # Ignore changes to state attributes if from/to is in use if (not match_all and from_s is not None and to_s is not None and from_s.last_changed == to_s.last_changed): return if time_delta is None: call_action() return @callback def state_for_listener(now): """Fire on state changes after a delay and calls action.""" nonlocal async_remove_state_for_listener async_remove_state_for_listener = None clear_listener() call_action() @callback def state_for_cancel_listener(entity, inner_from_s, inner_to_s): """Fire on changes and cancel for listener if changed.""" if inner_to_s.state == to_s.state: return clear_listener() # cleanup previous listener clear_listener() async_remove_state_for_listener = async_track_point_in_utc_time( hass, state_for_listener, dt_util.utcnow() + time_delta) async_remove_state_for_cancel = async_track_state_change( hass, entity, state_for_cancel_listener)
async def async_update_data(self, now): """Update data from nissan leaf.""" # Prevent against a previously scheduled update and an ad-hoc update # started from an update from both being triggered. if self._remove_listener: self._remove_listener() self._remove_listener = None # Clear next update whilst this update is underway self.next_update = None await self.async_refresh_data(now) self.next_update = self.get_next_interval() _LOGGER.debug("Next update=%s", self.next_update) self._remove_listener = async_track_point_in_utc_time( self.hass, self.async_update_data, self.next_update)
def _async_set_timeout(self, action, variables): """Schedule a timeout to abort script.""" timeout = action[CONF_TIMEOUT] unsub = None @callback def async_script_timeout(now): """Call after timeout is retrieve stop script.""" self._async_listener.remove(unsub) self._log("Timout reach, abort script.") self.async_stop() unsub = async_track_point_in_utc_time( self.hass, async_script_timeout, date_util.utcnow() + timeout ) self._async_listener.append(unsub)