示例#1
0
 def _handle_suppress_state(self, entity, attribute, old, new, kwargs):
   for i in range(0, len(self._suppress_condition)):
     condition = self._suppress_condition[i]
     if conditions.evaluate_condition(
         self, self.datetime(), [condition], triggers={entity: new}):
       self.log('Suppress condition evaluates true: %s (%s: %s->%s)' % (
           condition, entity, old, new))
       self._suppress_evaluation_times[i] = self.datetime()
示例#2
0
 def _get_best_matching_output(self, triggers=None):
     for output in self._config.get(CONF_OUTPUT):
         if conditions.evaluate_condition(self,
                                          self.datetime(),
                                          output.get(CONF_CONDITION),
                                          triggers=triggers):
             return output
     return None
示例#3
0
 def _get_matching_outputs(self, event) -> list:
     event_tags = event.get(scc.CONF_TAGS)
     matches = []
     current_datetime = self._app.datetime()
     for output in self._config.get(scc.CONF_OUTPUTS):
         if scc.CONF_CONDITION in output and not conditions.evaluate_condition(
                 self._app,
                 current_datetime,
                 output[scc.CONF_CONDITION],
                 evaluators=self._output_evaluators,
                 event=event):
             continue
         matches.append(output)
     return matches
示例#4
0
  def _trigger(self, kwargs=None):
    self.log('Evaluating whether or not to fire an event...')

    self._trigger_callback = None
    reference = kwargs[KEY_REFERENCE]

    for i in range(0, len(self._suppress_condition)):
      condition = self._suppress_condition[i]
      eval_time = self._suppress_evaluation_times[i]

      if eval_time:
        seconds_since_suppress = int((reference - eval_time).total_seconds())
        if seconds_since_suppress <= self._window_seconds:
          self.log('Suppress condition \'%s\' triggered too recently (%i secs '
                   'ago), skipping...' % (condition, seconds_since_suppress))
          return False

    for i in range(0, len(self._trigger_condition)):
      condition = self._trigger_condition[i]
      eval_time = self._trigger_evaluation_times[i]

      if not eval_time:
        self.log('Trigger condition \'%s\' has not yet triggered, skipping ...'
            % condition)
        return False
      seconds_since_trigger = int((reference - eval_time).total_seconds())
      if seconds_since_trigger > self._window_seconds:
        self.log('Trigger condition \'%s\' triggered too long ago (%i secs ago), '
                 'skipping...' % (condition, seconds_since_trigger))
        return False

    if self._disable_condition and conditions.evaluate_condition(
        self, self.datetime(), self._disable_condition):
      self.log('Disable condition \'%s\' evalutes true, skipping...' %
          self._disable_condition)
      return False

    if self._last_overall_trigger is not None:
      seconds_since_overall_trigger = int((self.datetime() -
          self._last_overall_trigger).total_seconds())
      if seconds_since_overall_trigger < self._reset_seconds:
        self.log('Overall trigger was too recent (%i secs ago), '
                 'skipping...' % seconds_since_overall_trigger)
        return False

    self._last_overall_trigger = self.datetime()
    self.fire_event(self._event, **self._event_data)
    self.log('Triggered! Fired event: \'%s\' with data \'%s\'' % (
        self._event, self._event_data))
示例#5
0
  def _handle_trigger_state(self, entity, attribute, old, new, kwargs):
    schedule_evaluation = False

    for i in range(0, len(self._trigger_condition)):
      condition = self._trigger_condition[i]
      if conditions.evaluate_condition(
          self, self.datetime(), [condition], triggers={entity: new}):
        self.log('Trigger condition evaluates true: %s (%s: %s->%s)' % (
            condition, entity, old, new))
        self._trigger_evaluation_times[i] = self.datetime()
        schedule_evaluation = True

    if schedule_evaluation and not self._trigger_callback:
      # Keep the time we expect the timeout to fire, and use that as the
      # reference time to avoid appdaemon scheduling delays breaking the time
      # comparisons.
      kwargs = {}
      kwargs[KEY_REFERENCE] = self.datetime() + datetime.timedelta(
          seconds=self._window_seconds)

      self.log('Scheduling trigger evaluation in %i second(s)...' %
          self._window_seconds)
      self._trigger_callback = self.run_in(
          self._trigger, self._window_seconds, **kwargs)
示例#6
0
    def _trigger_callback(self, entity, attribute, old, new, kwargs):
        activate = kwargs[KEY_ACTIVATE]
        self.log('Trigger callback (activate=%s): %s (old: %s, new: %s)' %
                 (activate, entity, old, new))

        if old == 'unavailable':
            self.log(
                'Unavailable: Skipping previously unavailable state for: %s' %
                entity)
            return

        if self._is_disabled():
            self.log('Disabled: Skipping trigger for: %s' % entity)
            return
        elif self._pause_timer:
            self.log('Paused: Skipping trigger for: %s' % entity)
            return
        elif self._manual_mode:
            self.log('Manual mode: Skipping trigger for: %s' % entity)
            return

        triggers = {entity: new}
        condition = self._config.get(
            CONF_TRIGGER_ACTIVATE_CONDITION
            if activate else CONF_TRIGGER_DEACTIVATE_CONDITION)
        triggered = conditions.evaluate_condition(self,
                                                  self.datetime(),
                                                  condition,
                                                  triggers=triggers)

        activate_key = KEY_ACTIVATE if activate else KEY_DEACTIVATE

        if triggered:
            output = self._get_best_matching_output(triggers=triggers)
            if output:
                # Prune last actions list.
                self._prune_last_actions()
                self.log('Last-actions: %s' % self._last_actions)

                # Safety precaution: Pause changes if more distinct actions than
                # max_actions_per_min (avoid lights flapping due to more configuration
                # choices).  (e.g. imagine a trigger than turns lights on when
                # brightness dips below X, but turns them off when it rises above X: a
                # poorly configured instance could cause the lights to flap)
                # Implicitly, this is allowing multiple repitions of the same action
                # with no pauseing (e.g. repeatedly turning on the same light due to
                # walking past multiple motion sensors is just fine).
                max_actions_per_min = self._config.get(
                    CONF_MAX_ACTIONS_PER_MIN)

                if self._opposing_last_actions() >= max_actions_per_min:
                    self.log(
                        'Pausing attempts to %s output as >%i (%s) distinct '
                        'actions have been executed in the last minute: %s' %
                        (activate_key, max_actions_per_min,
                         CONF_MAX_ACTIONS_PER_MIN, output))
                    # Pause for 1 minute (it's max actions per minute).
                    self._pause_timer.create(seconds=1 * 60)
                    self._update_status()
                    return

                # If this would just activate the exact same output, just reset
                # the timer rather than re-activating (as otherwise we lose custom
                # adjustments made to the lighting).
                if (activate and self._main_timer and self._last_actions
                        and self._last_actions[0][1] == activate
                        and self._last_actions[0][2] == output):
                    self.log('Same output triggered by %s. '
                             'Resetting timer only.' % entity)
                    self._main_timer.create(self._get_soft_timeout())
                else:
                    if activate:
                        self._main_timer.create(self._get_soft_timeout())
                    else:
                        self._main_timer.cancel()
                    self._activate(output, activate=activate)

                self._last_trigger[activate_key] = self.get_state(
                    entity, attribute=KEY_FRIENDLY_NAME)

                self._update_status()
示例#7
0
 def _is_disabled(self):
     return (self._config.get(CONF_DISABLE_CONDITION)
             and conditions.evaluate_condition(
                 self, self.datetime(),
                 self._config.get(CONF_DISABLE_CONDITION)))
示例#8
0
 def _should_extend(self):
     return (self._config.get(CONF_EXTEND_CONDITION)
             and conditions.evaluate_condition(
                 self, self.datetime(),
                 self._config.get(CONF_EXTEND_CONDITION)))