Пример #1
0
class NotifyOnCleaningDay(AppBase):
    """Define a feature to send a notification in morning of the cleaning day."""

    APP_SCHEMA = APP_SCHEMA.extend({
        CONF_PROPERTIES:
        vol.Schema(
            {vol.Optional(CONF_REMINDER_TIME): vol_help.valid_time},
            extra=vol.ALLOW_EXTRA,
        ),
        CONF_NOTIFICATIONS:
        vol.Schema(
            {vol.Required(CONF_TARGETS): vol.In(PERSONS.keys())},
            extra=vol.ALLOW_EXTRA,
        ),
    })

    def configure(self) -> None:
        """Configure."""
        self.run_daily(
            self.notify_on_cleaning_day,
            self.parse_time(self.properties[CONF_REMINDER_TIME]),
            constrain_app_enabled=1,
        )

    def notify_on_cleaning_day(self, kwargs: dict) -> None:
        """Send notification in the morning to remind of cleaning day."""
        self.notification_app.notify(
            kind="single",
            level="emergency",
            title="Putztag",
            message=f"Heute ist Putztag. Bitte Möbel richten!",
            targets=self.notifications["targets"],
        )
Пример #2
0
class NotifyOnBadLoginAttempt(AppBase):
    """Define a feature to send a notification when bad login happened."""

    APP_SCHEMA = APP_SCHEMA.extend({
        CONF_NOTIFICATIONS:
        vol.Schema(
            {vol.Required(CONF_TARGETS): vol.In(PERSONS.keys())},
            extra=vol.ALLOW_EXTRA,
        )
    })

    def configure(self):
        """Configure."""
        self.listen_state(
            self.bad_login_attempt,
            "persistent_notification.http_login",
            new="notifying",
        )

    def bad_login_attempt(self, entity: Union[str, dict], attribute: str,
                          old: str, new: str, kwargs: dict) -> None:
        """Send notification when bad login happened."""
        msg = self.get_state("persistent_notification.http_login",
                             attribute="message")
        self.notification_app.notify(
            kind="single",
            level="emergency",
            title="Falscher Loginversuch",
            message=msg,
            targets=self.notifications["targets"],
        )
Пример #3
0
class ToggleOnArrival(SwitchBase):
    """Define a feature to take action on arrival of person/everyone."""

    APP_SCHEMA = APP_SCHEMA.extend({
        CONF_ENTITIES:
        vol.Schema({vol.Required(CONF_SWITCH): vol_help.entity_id},
                   extra=vol.ALLOW_EXTRA),
        CONF_PROPERTIES:
        vol.Schema(
            {
                vol.Required(CONF_ACTION_TYPE): vol.In(ACTION_TYPES),
                vol.Required(CONF_STATE): str,
                vol.Optional(CONF_SPECIFIC_PERSON): vol.In(PERSONS.keys()),
                vol.Optional(CONF_PARAMETERS): dict,
            },
            extra=vol.ALLOW_EXTRA,
        ),
    })

    def configure(self) -> None:
        """Configure."""
        self.switch = self.entities[CONF_SWITCH]
        self.action_type = self.properties[CONF_ACTION_TYPE]
        self.state = self.properties[CONF_STATE]
        self.delay = self.properties.get(CONF_DELAY)
        self.parameters = self.properties.get(CONF_PARAMETERS, {})
        self.person = self.properties.get(CONF_SPECIFIC_PERSON)

        self.listen_state(self.someone_arrived,
                          HOUSE[CONF_PRESENCE_STATE],
                          constrain_app_enabled=1)

    def someone_arrived(self, entity: Union[str, dict], attribute: str,
                        old: str, new: str, kwargs: dict) -> None:
        """Take action when a person arrives."""
        someone_home_states = [
            self.presence_app.HouseState.someone.value,
            self.presence_app.HouseState.everyone.value,
        ]

        # Only take action if noone was home before
        if (new in someone_home_states) and (old not in someone_home_states):
            persons_home = self.presence_app.persons_home
            # Only take action if specified person arrives alone or no
            # person was specified
            if (self.person in persons_home
                    and len(persons_home) == 1) or not self.person:
                if self.delay:
                    self.run_in(
                        self.action_on_schedule,
                        self.delay * 60,
                        action_type=self.action_type,
                        state=self.state,
                        action_entity=self.switch,
                        parameters=self.parameters,
                    )
                else:
                    self.action(self.action_type, self.state, self.switch,
                                **self.parameters)
Пример #4
0
class NotifyWhenBinFull(AppBase):
    """Define a feature to send a notification when the bin is full."""

    APP_SCHEMA = APP_SCHEMA.extend({
        CONF_ENTITIES:
        vol.Schema({vol.Required(VACUUM): vol_help.entity_id},
                   extra=vol.ALLOW_EXTRA),
        CONF_NOTIFICATIONS:
        vol.Schema(
            {
                vol.Required(CONF_TARGETS): vol.In(PERSONS.keys()),
                vol.Optional(CONF_INTERVAL): int,
            },
            extra=vol.ALLOW_EXTRA,
        ),
    })

    def configure(self) -> None:
        """Configure."""
        self.listen_state(
            self.notify_bin_full,
            self.vacuum_app.vacuum,
            attribute=BIN_FULL,
            old=False,
            new=True,
            constrain_app_enabled=1,
        )

        self.listen_state(
            self.bin_emptied,
            self.vacuum_app.vacuum,
            attribute=BIN_FULL,
            old=True,
            new=False,
            constrain_app_enabled=1,
        )

    def notify_bin_full(self, entity: Union[str, dict], attribute: str,
                        old: str, new: str, kwargs: dict) -> None:
        """Send repeating notification that bin should be emptied."""
        self.handles[BIN_FULL] = self.notification_app.notify(
            kind="repeat",
            level="home",
            title="Pedro voll!",
            message="Pedro muss geleert werden",
            targets=self.notifications["targets"],
            interval=self.notifications["interval"] * 60,
        )
        self.log("Abfalleimer voll! Benachrichtige zum Leeren.")

    def bin_emptied(self, entity: Union[str, dict], attribute: str, old: str,
                    new: str, kwargs: dict) -> None:
        """Cancel the notification when bin has been emptied."""
        if BIN_FULL in self.handles:
            self.handles.pop(BIN_FULL)()
            self.log("Abfalleimer geleert! Schalte Benachrichtigung aus")
Пример #5
0
 def add_item_to_briefing(self, notification: Notification) -> None:
     """Add given notification to the briefing list."""
     for target in notification.targets.split(","):
         if target in PERSONS.keys():
             self.briefing_list[target] = {
                 notification.title: {
                     TITLE: notification.title,
                     MESSAGE: notification.message,
                     DATA: notification.data,
                 }
             }
Пример #6
0
class NotificationOnChange(AppBase):
    """Define a feature to send a notification when the alarm state changed."""

    APP_SCHEMA = APP_SCHEMA.extend({
        CONF_NOTIFICATIONS:
        vol.Schema(
            {vol.Required(CONF_TARGETS): vol.In(PERSONS.keys())},
            extra=vol.ALLOW_EXTRA,
        )
    })

    def configure(self):
        """Configure."""
        self.listen_state(self.alarm_state_changed,
                          HOUSE[ALARM_STATE],
                          constrain_app_enabled=1)

        self.listen_event(
            self.disarm_on_push_notification,
            "html5_notification.clicked",
            action=WRONG_ALARM,
            constrain_app_enabled=1,
        )

    def alarm_state_changed(self, entity: Union[str, dict], attribute: str,
                            old: str, new: str, kwargs: dict) -> None:
        """Send notification when alarm state changed."""
        self.notification_app.notify(
            kind="single",
            level="emergency",
            title="Alarm Status gewechselt",
            message=f"Der neue Alarm Status ist {new}",
            targets=self.notifications["targets"],
            data={"actions": [{
                "action": WRONG_ALARM,
                "title": "Fehlalarm"
            }]},
        )

    def disarm_on_push_notification(self, event_name: str, data: dict,
                                    kwargs: dict) -> None:
        """Disarm when push notification got clicked."""
        self.security_app.alarm_state = self.security_app.AlarmType.disarmed
        self.log("Fehlalarm, Alarmanlage wird ausgeschaltet!")
Пример #7
0
class NotifyOnNewVersion(AppBase):
    """Define an automation to notify when a new version is available."""

    APP_SCHEMA = APP_SCHEMA.extend({
        CONF_ENTITIES:
        vol.Schema(
            {
                vol.Required(CONF_AVAILABLE):
                vol.Schema([vol.Optional(vol_help.entity_id)])
            },
            extra=vol.ALLOW_EXTRA,
        ),
        CONF_NOTIFICATIONS:
        vol.Schema(
            {vol.Required(CONF_TARGETS): vol.In(PERSONS.keys())},
            extra=vol.ALLOW_EXTRA,
        ),
    })

    def configure(self) -> None:
        """Configure."""
        for entity in self.entities[CONF_AVAILABLE]:
            self.listen_state(self.version_changed,
                              entity,
                              constrain_app_enabled=1)

    def version_changed(self, entity: Union[str, dict], attribute: str,
                        old: str, new: str, kwargs: dict) -> None:
        """Send notification when new version is available."""
        self.log(old)
        self.log(new)
        if new != old:
            app = entity.split(".")[1].split("_")[0]
            self.notification_app.notify(
                kind="single",
                level="home",
                title=f"Neue Version für {app}!",
                message=f"Die Version {self.get_state(entity)} "
                f"für {app} ist verfügbar.",
                targets=self.notifications["targets"],
            )
Пример #8
0
class NotifyOnLowBattery(AppBase):
    """Define an automation to notify on low battery."""

    APP_SCHEMA = APP_SCHEMA.extend({
        CONF_ENTITIES:
        vol.Schema(
            {
                vol.Required(CONF_TRACKING_DEVICES):
                vol.Schema([vol.Optional(vol_help.entity_id)])
            },
            extra=vol.ALLOW_EXTRA,
        ),
        CONF_NOTIFICATIONS:
        vol.Schema(
            {vol.Required(CONF_TARGETS): vol.In(PERSONS.keys())},
            extra=vol.ALLOW_EXTRA,
        ),
        CONF_PROPERTIES:
        vol.Schema({vol.Optional(CONF_BATTERY_LOW_THRESHOLD): int},
                   extra=vol.ALLOW_EXTRA),
    })

    def configure(self) -> None:
        """Configure."""
        for entity in self.entities[CONF_TRACKING_DEVICES]:
            self.listen_state(self.battery_low,
                              entity,
                              constrain_app_enabled=1)

    def battery_low(self, entity: Union[str, dict], attribute: str, old: str,
                    new: str, kwargs: dict) -> None:
        """Send notification when battery is below threshold."""
        if float(new) < float(self.properties[CONF_BATTERY_LOW_THRESHOLD]):
            self.notification_app.notify(
                kind="single",
                level="home",
                title="Batterie niedrig!",
                message=f"Die Batterie für {entity} ist niedrig.",
                targets=self.notifications["targets"],
            )
Пример #9
0
class NotifyOnDeviceOffline(AppBase):
    """Define an automation to notify on device going offline."""

    APP_SCHEMA = APP_SCHEMA.extend({
        CONF_ENTITIES:
        vol.Schema(
            {
                vol.Required(CONF_TRACKING_DEVICES):
                vol.Schema([vol.Optional(vol_help.entity_id)])
            },
            extra=vol.ALLOW_EXTRA,
        ),
        CONF_NOTIFICATIONS:
        vol.Schema(
            {vol.Required(CONF_TARGETS): vol.In(PERSONS.keys())},
            extra=vol.ALLOW_EXTRA,
        ),
    })

    def configure(self) -> None:
        """Configure."""
        for entity in self.entities[CONF_TRACKING_DEVICES]:
            device_type = entity.split(".")[0]
            if device_type == SWITCH:
                self.listen_state(
                    self.device_offline,
                    entity,
                    new=OFF,
                    duration=60 * 5,
                    constrain_app_enabled=1,
                )
            elif device_type == DEVICE_TRACKER:
                self.listen_state(
                    self.device_offline,
                    entity,
                    new=NOT_HOME,
                    duration=60 * 5,
                    constrain_app_enabled=1,
                )
            elif device_type == ZWAVE:
                self.listen_state(
                    self.device_offline,
                    entity,
                    new=UNKNOWN,
                    duration=60 * 5,
                    constrain_app_enabled=1,
                )
                self.listen_state(
                    self.device_offline,
                    entity,
                    new=UNAVAILABLE,
                    duration=60 * 5,
                    constrain_app_enabled=1,
                )
            elif device_type in (SENSOR, BINARY_SENSOR):
                self.listen_state(
                    self.device_offline,
                    entity,
                    new=UNAVAILABLE,
                    duration=60 * 5,
                    constrain_app_enabled=1,
                )

    def device_offline(self, entity: Union[str, dict], attribute: str,
                       old: str, new: str, kwargs: dict) -> None:
        """Send notification when device is offline longer than 5 minutes."""
        self.notification_app.notify(
            kind="single",
            level="emergency",
            title="Gerät offline!",
            message=f"Das folgende Gerät ist offline {entity}",
            targets=self.notifications["targets"],
        )
Пример #10
0
 def everyone_vacation(self):
     """Return true if everyone is on vacation."""
     return self.who_in_state(self.PresenceState.extended_away) == list(
         PERSONS.keys())
Пример #11
0
 def everyone_home(self) -> bool:
     """Return true if everyone is home."""
     return self.persons_home == list(PERSONS.keys())
Пример #12
0
class ReminderAutomation(AppBase):
    """Define a feature for recurring or one time reminders."""

    APP_SCHEMA = APP_SCHEMA.extend({
        CONF_PROPERTIES:
        vol.Schema(
            {
                vol.Required(CONF_TITLE):
                str,
                vol.Required(CONF_MESSAGE):
                str,
                vol.Required(CONF_REMINDER_DATE):
                vol_help.valid_date,
                vol.Required(CONF_REMINDER_TIME):
                vol_help.valid_time,
                vol.Optional(CONF_REPEAT):
                vol.Schema({
                    vol.Required(CONF_REPEAT_TYPE): vol.In(REPEAT_TYPES),
                    vol.Required(CONF_REPEAT_FREQ): int,
                }),
            },
            extra=vol.ALLOW_EXTRA,
        ),
        CONF_NOTIFICATIONS:
        vol.Schema(
            {
                vol.Required(CONF_TARGETS): vol.In(PERSONS.keys()),
                vol.Optional(CONF_INTERVAL): int,
            },
            extra=vol.ALLOW_EXTRA,
        ),
    })

    def configure(self) -> None:
        """Configure."""
        self.reminder_time = self.properties[CONF_REMINDER_TIME]
        self.reminder_date = datetime.strptime(
            self.properties[CONF_REMINDER_DATE], "%d.%m.%Y")
        self.repeat_type = self.properties[CONF_REPEAT][CONF_REPEAT_TYPE]
        self.repeat_freq = self.properties[CONF_REPEAT][CONF_REPEAT_FREQ]

        self.run_daily(
            self.check_reminder_date,
            self.parse_time(self.properties[CONF_REMINDER_TIME]),
            constrain_app_enabled=1,
        )

        self.listen_event(
            self.disable_on_push_notification,
            "html5_notification.clicked",
            action=DONE,
            constrain_app_enabled=1,
        )

    def check_reminder_date(self, kwargs: dict) -> None:
        """Check if today is a reminder day, if yes send reminder."""
        days_to_reminder_date = (datetime.today() - self.reminder_date).days
        divisor = None
        if self.repeat_type == DAYS:
            divisor = self.repeat_freq
        elif self.repeat_type == WEEKS:
            divisor = self.repeat_freq * 7
        elif self.repeat_type == MONTHS:
            divisor = self.repeat_freq * 30

        if days_to_reminder_date % divisor == 0:
            self.send_reminder()
            self.log("Erinnerungstag! Erinnerung gesendet.")

    def send_reminder(self) -> None:
        """Send a repeating actionable push notification as a reminder."""
        self.handles[REMINDER] = self.notification_app.notify(
            kind="repeat",
            level="home",
            title=self.properties[CONF_TITLE],
            message=self.properties[CONF_MESSAGE],
            targets=self.notifications[CONF_TARGETS],
            interval=self.notifications[CONF_INTERVAL] * 60,
            data={"actions": [{
                "action": DONE,
                "title": "Erledigt"
            }]},
        )

    def disable_on_push_notification(self, event_name: str, data: dict,
                                     kwargs: dict) -> None:
        """Disable reminder when 'done' got clicked on push notification."""
        if REMINDER in self.handles:
            self.handles.pop(REMINDER)()
            self.log("Aufgabe erledigt! Schalte Erinnerung aus.")
Пример #13
0
class NotifyWhenWasherDone(AppBase):
    """Define a feature to send a notification when the washer has finished."""

    APP_SCHEMA = APP_SCHEMA.extend({
        CONF_PROPERTIES:
        vol.Schema({vol.Required(vol.In(THRESHOLDS_TYPES)): int},
                   extra=vol.ALLOW_EXTRA),
        CONF_NOTIFICATIONS:
        vol.Schema(
            {
                vol.Required(CONF_TARGETS): vol.In(PERSONS.keys()),
                vol.Required(CONF_MSG): str,
                vol.Optional(CONF_INTERVAL): int,
            },
            extra=vol.ALLOW_EXTRA,
        ),
    })

    def configure(self) -> None:
        """Configure."""
        self.listen_state(
            self.power_changed,
            self.manager.entities[CONF_POWER],
            constrain_app_enabled=1,
        )

        self.listen_state(
            self.status_changed,
            self.manager.entities[CONF_STATUS],
            constrain_app_enabled=1,
        )

        self.listen_event(
            self.cancel_on_push_notification,
            "html5_notification.clicked",
            action=DONE,
            constrain_app_enabled=1,
        )

    def power_changed(self, entity: Union[str, dict], attribute: str, old: str,
                      new: str, kwargs: dict) -> None:
        """Set washer state based on power change."""
        power = float(new)
        thresholds = self.properties[CONF_THRESHOLDS]
        if (self.manager.washer_state != self.manager.WasherStates.running
                and power >= thresholds[CONF_RUNNING_THRESHOLD]):
            self.manager.washer_state = self.manager.WasherStatus.running
            self.log("Washer set to Running")
        elif (self.manager.washer_state == self.manager.WasherStates.running
              and power <= thresholds[CONF_DRYING_THRESHOLD]):
            self.manager.washer_state = self.manager.WasherStatus.drying
            self.log("Washer set to Drying")
        elif (self.manager.washer_state == self.manager.WasherStates.drying
              and power == thresholds[CONF_CLEAN_THRESHOLD]):
            self.manager.washer_state = self.manager.WasherStatus.clean
            self.log("Washer set to Clean")

    def status_changed(self, entity: Union[str, dict], attribute: str,
                       old: str, new: str, kwargs: dict) -> None:
        """Take action based on status change."""
        if new == self.manager.WasherStates.clean.value:
            self.handles[WASHER_CLEAN] = self.notification_app.notify(
                kind="repeat",
                level="home",
                title="Waschgerät fertig!",
                message=self.notifications[CONF_MSG],
                targets=self.notifications[CONF_TARGETS],
                interval=self.notifications[CONF_INTERVAL] * 60,
                data={"actions": [{
                    "action": DONE,
                    "title": "Erledigt"
                }]},
            )
            self.log("Waschgerät fertig! Benachrichtige zum Leeren!")

        elif old == self.manager.WasherStates.clean.value:
            if WASHER_CLEAN in self.handles:
                self.handles.pop(WASHER_CLEAN)()
                self.log("Waschgerät geleert. Schalte Benachrichtigung aus.")

    def cancel_on_push_notification(self, event_name: str, data: dict,
                                    kwargs: dict) -> None:
        """Cancel the notification when push notification got clicked."""
        self.manager.washer_state = self.manager.WasherStates.dirty
        self.log("Waschgerät wurde geleert!")
Пример #14
0
class VacuumAutomation(AppBase):
    """Define a feature for scheduled cleaning cycle including
       cancellation when someone arrives home."""

    APP_SCHEMA = APP_SCHEMA.extend({
        CONF_ENTITIES:
        vol.Schema({vol.Required(VACUUM): vol_help.entity_id},
                   extra=vol.ALLOW_EXTRA),
        CONF_PROPERTIES:
        vol.Schema({vol.Optional(CONF_CLEANING_TIME): str},
                   extra=vol.ALLOW_EXTRA),
        CONF_NOTIFICATIONS:
        vol.Schema(
            {vol.Required(CONF_TARGETS): vol.In(PERSONS.keys())},
            extra=vol.ALLOW_EXTRA,
        ),
    })

    class VacuumState(Enum):
        """Define an enum for vacuum states."""

        charging = "Charging"
        running = "Running"
        returning = "User Docking"
        stuck = "Stuck"

    def configure(self) -> None:
        """Configure."""
        self.started_by_app = False
        self.vacuum = self.entities[VACUUM]
        cleaning_time = self.parse_time(
            self.properties.get(CONF_CLEANING_TIME, "11:00:00"))

        # scheduled clean cycle
        self.run_daily(self.start_cleaning,
                       cleaning_time,
                       constrain_app_enabled=1)

        # cycle finished
        self.listen_state(
            self.cleaning_finished,
            self.vacuum,
            attribute=STATUS,
            old=self.VacuumState.returning.value,
            new=self.VacuumState.charging.value,
        )

        # cancel cycle if someone arrives home
        self.listen_state(self.cancel_cleaning, HOUSE[PRESENCE_STATE])

        # notify when vacuum stuck
        self.listen_state(
            self.vacuum_stuck,
            self.vacuum,
            attribute=STATUS,
            new=self.VacuumState.stuck.value,
        )

        # turn on/off cleaning mode when cleaning/finished cleaning
        self.listen_state(self.set_cleaning_mode_input_boolean,
                          self.vacuum,
                          attribute=STATUS)

    def start_cleaning(self, kwargs: dict) -> None:
        """Start the scheduled cleaning cycle."""
        self.call_service("vacuum/start_pause", entity_id=self.vacuum)
        self.started_by_app = True
        self.log("Pedro startet die Reinigung!")

    def cleaning_finished(self, entity: Union[str, dict], attribute: str,
                          old: str, new: str, kwargs: dict) -> None:
        """Deactivate input boolean when cleaning cycle finished."""
        self.started_by_app = False
        self.log("Pedro hat die Reinigung beendet")

    def cancel_cleaning(self, entity: Union[str, dict], attribute: str,
                        old: str, new: str, kwargs: dict) -> None:
        """Cancel the cleaning cycle when someone arrives home."""
        if (not self.presence_app.noone_home and self.started_by_app
            ) and self.vacuum_state == self.VacuumState.running.value:
            self.call_service("vacuum/return_to_base", entity_id=self.vacuum)
            self.started_by_app = False
            self.log("Jemand ist gerade angekommen, beende Reiningung!")

    def vacuum_stuck(self, entity: Union[str, dict], attribute: str, old: str,
                     new: str, kwargs: dict) -> None:
        """Notify that the vacuum is stuck."""
        self.notification_app.notify(
            kind="single",
            level="emergency",
            title="Pedro steckt fest!",
            message="Pedro steckt fest und braucht Hilfe!",
            targets=self.notifications["targets"],
        )
        self.log("Pedro steckt fest, sende Benachrichtigung.")

    def set_cleaning_mode_input_boolean(self, entity: Union[str, dict],
                                        attribute: str, old: str, new: str,
                                        kwargs: dict) -> None:
        """Set the input boolean for the cleaning mode."""
        if "cleaning_mode" in MODES and old != new:
            if new == self.VacuumState.running.value:
                self.turn_on(MODES[CLEANING_MODE])
            elif new in (self.VacuumState.charging.value,
                         self.VacuumState.stuck.value):
                self.turn_off(MODES[CLEANING_MODE])

    @property
    def vacuum_state(self) -> "VacuumState":
        """Return the current state of the vacuum cleaner."""
        return self.get_state(self.vacuum, attribute="status")