Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Ability to override the announcement prefix spoken by Alexa. #4

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

[![hacs_badge](https://img.shields.io/badge/HACS-Default-orange.svg)](https://github.com/custom-components/hacs)

## New in v1.0.6: Door/Window Open Delay, and Close Announcement Control
## New in v1.1.1:
- Ability to override the announcement prefix spoken by Alexa.

Alexa and other smart speakers (media_player) announce your doors/windows opening and closing. Comes in handy specially for garage doors or side/main exits for homes and shops where you need to stay informed of any changes. Trust me, it's a secured feeling to know the status of your garage, main/side exits.
## Overview

Ever since we've set this up in our home, we don't think we can do without it now. Your home suddenly gets a voice, something like Jarvis ... Awesome!
Alexa and other smart speakers (media_player) announce your doors/windows opening and closing. Comes in handy specially for garage doors or side/main exits for homes and shops where you need to stay informed of any changes. Trust me, it's a secured feeling to know the status of your garage, main/side exits.

Ever since we've set this up in our home, we don't think we can do without it now. Your home suddenly gets a voice, something like Jarvis ... Awesome!

Please ⭐ this repo if you like my work and also check out my other repos like
- [Home Assistant 'STEROIDS' Configuration](https://github.com/UbhiTS/ha-config-ataraxis)
Expand Down Expand Up @@ -42,6 +45,7 @@ alexa_door_window_announce:
close: True
start_time: "00:00:00"
end_time: "23:59:59"
announcement_prefix: "Attention "
debug: false
```

Expand All @@ -55,6 +59,7 @@ key | optional | type | default | description
`announcements\|close` | True | bool | True | Announce the closing of the door. Set to False if you just want opening announcements.
`announcements\|start_time` | True | time | 00:00:00 | The time to enable the service. (24h format)
`announcements\|end_time` | True | time | 23:59:59 | The time to disable the service. (24h format)
`announcements\|announcement_prefix` | True | string | Your attention please. The | The initial phrase spoken by Alexa during alerts
`debug` | True | bool | False | if True, outputs messages to the AppDaemon Log

## Thank you! :raised_hands:
Expand All @@ -66,7 +71,7 @@ If you like my work and feel gracious, you can buy me a beer below ;)

<a href="https://www.buymeacoffee.com/ubhits" target="_blank">
<img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png"
alt="Buy Me A Beer"
alt="Buy Me A Beer"
style="height:41px !important; width:174px !important;" />
</a>

Expand Down
55 changes: 29 additions & 26 deletions apps/alexa_door_window_announce.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,53 +32,55 @@ def initialize(self):
self.announce_close = True
self.time_start = datetime.strptime("00:00:00", '%H:%M:%S').time()
self.time_end = datetime.strptime("23:59:59", '%H:%M:%S').time()
self.announcement_prefix = "Your attention please. The "

self.closing_handles = []

if "announcements" in self.args:
delay = datetime.strptime(self.args["announcements"]["delay"], '%H:%M:%S').time() if "delay" in self.args["announcements"] else datetime.strptime("00:00:00", '%H:%M:%S').time()

self.delay = timedelta(hours = delay.hour, minutes = delay.minute, seconds = delay.second)
self.announce_close = bool(self.args["announcements"]["close"]) if "close" in self.args["announcements"] else self.announce_close
self.time_start = datetime.strptime(self.args["announcements"]["start_time"], '%H:%M:%S').time() if "start_time" in self.args["announcements"] else self.time_start
self.time_end = datetime.strptime(self.args["announcements"]["end_time"], '%H:%M:%S').time() if "end_time" in self.args["announcements"] else self.time_end
self.announcement_prefix = self.args["announcements"]["announcement_prefix"] if "announcement_prefix" in self.args["announcements"] else self.announcement_prefix

if "doors_windows" in self.args:
for door_window_sensor in self.args["doors_windows"]:

domain = door_window_sensor.split(".")[0].lower()

if domain in ["binary_sensor"]:
self.listen_state(self.door_window_state_changed, door_window_sensor, old = "off", new = "on", duration = self.delay.total_seconds())
self.listen_state(self.door_window_state_changed, door_window_sensor, old = "off", new = "on", duration = self.delay.total_seconds(), announcement_prefix = self.announcement_prefix)

elif domain in ["cover"]:
self.listen_state(self.door_window_state_changed, door_window_sensor, old = "closed", new = "open", duration = self.delay.total_seconds())
self.listen_state(self.door_window_state_changed, door_window_sensor, old = "opening", new = "open", duration = self.delay.total_seconds())
self.listen_state(self.door_window_state_changed, door_window_sensor, old = "closed", new = "open", duration = self.delay.total_seconds(), announcement_prefix = self.announcement_prefix)
self.listen_state(self.door_window_state_changed, door_window_sensor, old = "opening", new = "open", duration = self.delay.total_seconds(), announcement_prefix = self.announcement_prefix)
else:
self.debug_log("UNSUPPORTED DOMAIN: " + door_window_sensor)

init_log = [f" START {self.time_start}\n END {self.time_end}"]

if self.delay.total_seconds() > 0:
init_log += [f"\n DELAY {int(self.delay.total_seconds())}"]
if self.announce_close:
init_log += [f"\n CLOSE ANNOUNCE"]

self.debug_log("\n**** INIT - ALEXA DOOR WINDOW ANNOUNCE ****\n" + "".join(init_log))

self.debug = bool(self.args["debug"]) if "debug" in self.args else self.debug


def door_window_state_changed(self, entity, attribute, old, new, kwargs):

domain = entity.split(".")[0].lower() # cover, binary_sensor

if self.announce_close:

if new in ["on","open"]:

# add closing state listener for this entity

if domain == "binary_sensor":
self.closing_handles += [
self.listen_state(self.door_window_state_changed, entity, old = "on", new = "off", oneshot = True)
Expand All @@ -88,11 +90,11 @@ def door_window_state_changed(self, entity, attribute, old, new, kwargs):
self.listen_state(self.door_window_state_changed, entity, old = "open", new = "closed", oneshot = True),
self.listen_state(self.door_window_state_changed, entity, old = "closing", new = "closed", oneshot = True)
]

elif new in ["off", "closed"]:

# delete closing state listeners for this entity

# unregister all closing handles if exists, this is a workaround for the bug in HA
# where garage door openers have different open / close states when triggered
# from HA > open, closing, closed, opening, open
Expand All @@ -106,33 +108,34 @@ def door_window_state_changed(self, entity, attribute, old, new, kwargs):
del self.closing_handles[i]
except:
del self.closing_handles[i]

friendly_name = self.get_state(entity, attribute = "friendly_name")

state = "changed"
if new in ["off","closed"]: state = "closed"
elif new in ["on","open"]: state = "opened"

if not self.is_time_okay(self.time_start, self.time_end):
self.debug_log(f"DOOR/WINDOW TIME LOG ONLY: {entity.split('.')[1]}|{state}")
return

delay = 0
if "alexas" in self.args:
for alexa in self.args["alexas"]:
self.run_in(self.announce_state, delay, sensor_name = entity, friendly_name = friendly_name, state = state, alexa = alexa)
self.run_in(self.announce_state, delay, sensor_name = entity, friendly_name = friendly_name, state = state, alexa = alexa, announcement_prefix = self.announcement_prefix)
delay = delay + 5


def announce_state(self, kwargs):

sensor_name = kwargs["sensor_name"]
friendly_name = kwargs["friendly_name"]
state = kwargs["state"]
alexa = kwargs["alexa"]

announcement_prefix = kwargs["announcement_prefix"]

try:
self.call_service("notify/alexa_media", data = {"type":"tts", "method":"all"}, target = alexa, title = "Home Assistant: Door/Window Announce", message = f"Your attention please. The {friendly_name} has been {state}.")
self.call_service("notify/alexa_media", data = {"type":"tts", "method":"all"}, target = alexa, title = "Home Assistant: Door/Window Announce", message = f"{announcement_prefix} {friendly_name} has been {state}.")
finally:
self.debug_log(f"DOOR/WINDOW ANNOUNCE: {sensor_name.split('.')[1]}|{state}|{alexa.split('.')[1]}")

Expand All @@ -143,7 +146,7 @@ def is_time_okay(self, start, end):
return start <= current_time and current_time <= end
else:
return start <= current_time or current_time <= end

def debug_log(self, message):
if self.debug:
self.log(message)