- Pre-define notification categories which contain 1-4 actions.
- Notify iOS app with
data.push.category
set toALARM
(which contains actions namedSOUND_ALARM
andSILENCE_ALARM
). - Push notification delivered to device
SOUND_ALARM
button on notification pressed- Identifier of button (
SOUND_ALARM
) sent back to HA as theactionName
property of the eventios.notification_action_fired
.
-
-
Save robbiet480/a12be2ab6401f182952f0f95f6b229ff to your computer and use it in GitHub Desktop.
ios: | |
push_categories: # Defines actionable notifications. Categories are groups of actions. You specify the category in the notification. | |
- name: Alarm | |
identifier: 'ALARM' # Must be unique and ALL CAPS | |
actions: | |
- identifier: 'SOUND_ALARM' # Must be unique and ALL CAPS | |
title: 'Sound Alarm' # Needs to be short! | |
activationMode: 'background' # or background. The mode in which to run the app when the action is performed. | |
authenticationRequired: yes # A Boolean value indicating whether the user must unlock the device before the action is performed. | |
destructive: yes # A Boolean value indicating whether the action is destructive. When the value of this property is true, the system displays the corresponding button differently to indicate that the action is destructive. | |
behavior: 'default' # or TextInput. When TextInput the system provides a way for the user to enter a text response to be included with the notification. | |
context: 'default' # or Minimal. Default = In this context, the full UI is displayed for the notification’s alert. You may specify up to four custom actions in this context. Minimal = In this context, a minimal UI is displayed for the notification’s alert. You may specify up to two custom actions in this context. | |
- identifier: 'SILENCE_ALARM' # Must be unique and ALL CAPS | |
title: 'Silence Alarm' # Needs to be short! | |
activationMode: 'background' # or background. The mode in which to run the app when the action is performed. | |
authenticationRequired: yes # A Boolean value indicating whether the user must unlock the device before the action is performed. | |
destructive: no # A Boolean value indicating whether the action is destructive. When the value of this property is true, the system displays the corresponding button differently to indicate that the action is destructive. | |
behavior: 'TextInput' # Default or TextInput. When TextInput the system provides a way for the user to enter a text response to be included with the notification. | |
context: 'default' # or Minimal. Default = In this context, the full UI is displayed for the notification’s alert. You may specify up to four custom actions in this context. Minimal = In this context, a minimal UI is displayed for the notification’s alert. You may specify up to two custom actions in this context. | |
textInputButtonTitle: 'Silencio!' # Only for iOS 10 when behavior is TextInput. | |
textInputPlaceholder: '...' # Only for iOS 10 when behavior is TextInput. | |
parameters: # iOS 9 only. Use this dictionary to specify any behavior-specific data for the action. For example, if you set behavior to TextInput you can use the UIUserNotificationTextInputActionButtonTitleKey key, which lets you customize the title of the button displayed by the text input interface. | |
UIUserNotificationTextInputActionButtonTitleKey: "Silencio!" | |
notify: | |
- name: iOSApp | |
platform: ios | |
target: '<TOKEN FROM SETTINGS>' | |
automation: | |
- alias: Notify iOS app | |
trigger: | |
... | |
action: | |
service: notify.iOSApp | |
data: | |
message: “Something happened at home!” | |
data: | |
push: | |
badge: 5 | |
sound: <SOUND FILE HERE> | |
category: "ALARM" # Needs to match the top level identifier you used in the ios configuration | |
action_data: # Anything passed in action_data will get echoed back to Home Assistant. | |
entity_id: light.test | |
my_custom_data: foo_bar | |
- alias: iOS app notification action pressed | |
trigger: | |
platform: event | |
event_type: ios.notification_action_fired | |
event_data: | |
actionName: SOUND_ALARM | |
action: | |
... |
""" | |
Native Home Assistant iOS app component. Should be put into ~/.homeassistant/custom_components/ios.py. | |
For more details about this platform, please refer to the documentation at | |
https://home-assistant.io/components/ios/ | |
""" | |
import os | |
import json | |
import logging | |
import requests | |
import homeassistant.loader as loader | |
from homeassistant.const import ( | |
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP) | |
from homeassistant.components.notify import (ATTR_TARGET, ATTR_TITLE, | |
ATTR_MESSAGE, ATTR_DATA) | |
from homeassistant.components.http import HomeAssistantView | |
_LOGGER = logging.getLogger(__name__) | |
PUSH_URL = "https://mj28d17jwj.execute-api.us-west-2.amazonaws.com/prod/push" | |
DOMAIN = "ios" | |
DEPENDENCIES = ["http"] | |
DEVICES_FILE = "ios_devices.conf" | |
DEVICE_IDENTIFIED = "device_identified" | |
DEVICES = None | |
PUSH_CONFIGURATION = None | |
def config_from_file(filename, config=None): | |
"""Small configuration file management function.""" | |
if config: | |
# We"re writing configuration | |
try: | |
with open(filename, "w") as fdesc: | |
fdesc.write(json.dumps(config)) | |
except IOError as error: | |
_LOGGER.error("Saving config file failed: %s", error) | |
return False | |
return True | |
else: | |
# We"re reading config | |
if os.path.isfile(filename): | |
try: | |
with open(filename, "r") as fdesc: | |
return json.loads(fdesc.read()) | |
except IOError as error: | |
_LOGGER.error("Reading config file failed: %s", error) | |
# This won"t work yet | |
return False | |
else: | |
return {} | |
def setup(hass, config): | |
DEVICES = config_from_file(hass.config.path(DEVICES_FILE)) | |
app_config = config[DOMAIN] | |
push_categories = app_config.get("push_categories", []) | |
discovery = loader.get_component("discovery") | |
device_tracker = loader.get_component("device_tracker") | |
zeroconf = loader.get_component("zeroconf") | |
zeroconf.setup(hass, config) | |
hass.wsgi.register_view(iOSAppPushConfigView(hass, push_categories)) | |
hass.wsgi.register_view(iOSAppIdentifyDeviceView(hass)) | |
def device_identified(event): | |
print("DEVICE IDENTIFIED EVENT FIRED", event) | |
permanentID = event.data.get("device").get("permanentID") | |
DEVICES[permanentID] = event.data | |
if not config_from_file(hass.config.path(DEVICES_FILE), DEVICES): | |
_LOGGER.error("failed to save config file") | |
hass.bus.listen(DEVICE_IDENTIFIED, device_identified) | |
return True | |
def notify(title="", message="", target=""): | |
data = {ATTR_MESSAGE: message, ATTR_TITLE: title, ATTR_TARGET: target} | |
response = requests.put(PUSH_URL, json=data, timeout=10) | |
if response.status_code != 200: | |
_LOGGER.exception("Error sending message. Response %d: %s:", | |
response.status_code, response.reason) | |
class iOSAppPushConfigView(HomeAssistantView): | |
requires_auth = False | |
url = "/api/ios/push" | |
name = "api:ios:push" | |
def __init__(self, hass, push_categories): | |
super().__init__(hass) | |
self.push_categories = push_categories | |
def get(self, request): | |
return self.json(self.push_categories) | |
class iOSAppIdentifyDeviceView(HomeAssistantView): | |
requires_auth = False | |
url = "/api/ios/identify" | |
name = "api:ios:identify" | |
def __init__(self, hass): | |
super().__init__(hass) | |
def post(self, request): | |
print("IDENTIFY DEVICE DATA", request.json) | |
self.hass.bus.fire(DEVICE_IDENTIFIED, request.json) | |
return self.json({"status": "ok"}) |
# You can now use iTunes to upload your own sounds. | |
US-EN-Daisy-Back-Door-Motion.wav | |
US-EN-Daisy-Back-Door-Open.wav | |
US-EN-Daisy-Front-Door-Motion.wav | |
US-EN-Daisy-Front-Door-Open.wav | |
US-EN-Daisy-Front-Window-Open.wav | |
US-EN-Daisy-Garage-Door-Open.wav | |
US-EN-Daisy-Guest-Bath-Leak.wav | |
US-EN-Daisy-Kitchen-Sink-Leak.wav | |
US-EN-Daisy-Kitchen-Window-Open.wav | |
US-EN-Daisy-Laundry-Room-Leak.wav | |
US-EN-Daisy-Master-Bath-Leak.wav | |
US-EN-Daisy-Master-Bedroom-Window-Open.wav | |
US-EN-Daisy-Office-Window-Open.wav | |
US-EN-Daisy-Refrigerator-Leak.wav | |
US-EN-Daisy-Water-Heater-Leak.wav | |
# Added in build 27 | |
US-EN-Alexa-Back-Door-Opened.wav | |
US-EN-Alexa-Back-Door-Unlocked.wav | |
US-EN-Alexa-Basement-Door-Opened.wav | |
US-EN-Alexa-Basement-Door-Unlocked.wav | |
US-EN-Alexa-Boyfriend-Is-Arriving.wav | |
US-EN-Alexa-Daughter-Is-Arriving.wav | |
US-EN-Alexa-Front-Door-Opened.wav | |
US-EN-Alexa-Front-Door-Unlocked.wav | |
US-EN-Alexa-Garage-Door-Opened.wav | |
US-EN-Alexa-Girlfriend-Is-Arriving.wav | |
US-EN-Alexa-Good-Morning.wav | |
US-EN-Alexa-Good-Night.wav | |
US-EN-Alexa-Husband-Is-Arriving.wav | |
US-EN-Alexa-Mail-Has-Arrived.wav | |
US-EN-Alexa-Motion-At-Back-Door.wav | |
US-EN-Alexa-Motion-At-Front-Door.wav | |
US-EN-Alexa-Motion-Detected-Generic.wav | |
US-EN-Alexa-Motion-In-Back-Yard.wav | |
US-EN-Alexa-Motion-In-Basement.wav | |
US-EN-Alexa-Motion-In-Front-Yard.wav | |
US-EN-Alexa-Motion-In-Garage.wav | |
US-EN-Alexa-Patio-Door-Opened.wav | |
US-EN-Alexa-Patio-Door-Unlocked.wav | |
US-EN-Alexa-Smoke-Detected-Generic.wav | |
US-EN-Alexa-Smoke-Detected-In-Basement.wav | |
US-EN-Alexa-Smoke-Detected-In-Garage.wav | |
US-EN-Alexa-Smoke-Detected-In-Kitchen.wav | |
US-EN-Alexa-Son-Is-Arriving.wav | |
US-EN-Alexa-Water-Detected-Generic.wav | |
US-EN-Alexa-Water-Detected-In-Basement.wav | |
US-EN-Alexa-Water-Detected-In-Garage.wav | |
US-EN-Alexa-Water-Detected-In-Kitchen.wav | |
US-EN-Alexa-Welcome-Home.wav | |
US-EN-Alexa-Wife-Is-Arriving.wav | |
US-EN-Morgan-Freeman-Back-Door-Closed.wav | |
US-EN-Morgan-Freeman-Back-Door-Locked.wav | |
US-EN-Morgan-Freeman-Back-Door-Opened.wav | |
US-EN-Morgan-Freeman-Back-Door-Unlocked.wav | |
US-EN-Morgan-Freeman-Basement-Door-Closed.wav | |
US-EN-Morgan-Freeman-Basement-Door-Locked.wav | |
US-EN-Morgan-Freeman-Basement-Door-Opened.wav | |
US-EN-Morgan-Freeman-Basement-Door-Unlocked.wav | |
US-EN-Morgan-Freeman-Boss-Is-Arriving.wav | |
US-EN-Morgan-Freeman-Boyfriend-Is-Arriving.wav | |
US-EN-Morgan-Freeman-Cleaning-Supplies-Closet-Opened.wav | |
US-EN-Morgan-Freeman-Coworker-Is-Arriving.wav | |
US-EN-Morgan-Freeman-Daughter-Is-Arriving.wav | |
US-EN-Morgan-Freeman-Friend-Is-Arriving.wav | |
US-EN-Morgan-Freeman-Front-Door-Closed.wav | |
US-EN-Morgan-Freeman-Front-Door-Locked.wav | |
US-EN-Morgan-Freeman-Front-Door-Opened.wav | |
US-EN-Morgan-Freeman-Front-Door-Unlocked.wav | |
US-EN-Morgan-Freeman-Garage-Door-Closed.wav | |
US-EN-Morgan-Freeman-Garage-Door-Opened.wav | |
US-EN-Morgan-Freeman-Girlfriend-Is-Arriving.wav | |
US-EN-Morgan-Freeman-Good-Morning.wav | |
US-EN-Morgan-Freeman-Good-Night.wav | |
US-EN-Morgan-Freeman-Liquor-Cabinet-Opened.wav | |
US-EN-Morgan-Freeman-Motion-Detected.wav | |
US-EN-Morgan-Freeman-Motion-In-Basement.wav | |
US-EN-Morgan-Freeman-Motion-In-Bedroom.wav | |
US-EN-Morgan-Freeman-Motion-In-Game-Room.wav | |
US-EN-Morgan-Freeman-Motion-In-Garage.wav | |
US-EN-Morgan-Freeman-Motion-In-Kitchen.wav | |
US-EN-Morgan-Freeman-Motion-In-Living-Room.wav | |
US-EN-Morgan-Freeman-Motion-In-Theater.wav | |
US-EN-Morgan-Freeman-Motion-In-Wine-Cellar.wav | |
US-EN-Morgan-Freeman-Patio-Door-Closed.wav | |
US-EN-Morgan-Freeman-Patio-Door-Locked.wav | |
US-EN-Morgan-Freeman-Patio-Door-Opened.wav | |
US-EN-Morgan-Freeman-Patio-Door-Unlocked.wav | |
US-EN-Morgan-Freeman-Roommate-Is-Arriving.wav | |
US-EN-Morgan-Freeman-Searching-For-Car-Keys.wav | |
US-EN-Morgan-Freeman-Setting-The-Mood.wav | |
US-EN-Morgan-Freeman-Smartthings-Detected-A-Flood.wav | |
US-EN-Morgan-Freeman-Smartthings-Detected-Carbon-Monoxide.wav | |
US-EN-Morgan-Freeman-Smartthings-Detected-Smoke.wav | |
US-EN-Morgan-Freeman-Smoke-Detected-In-Basement.wav | |
US-EN-Morgan-Freeman-Smoke-Detected-In-Garage.wav | |
US-EN-Morgan-Freeman-Smoke-Detected-In-Kitchen.wav | |
US-EN-Morgan-Freeman-Someone-Is-Arriving.wav | |
US-EN-Morgan-Freeman-Son-Is-Arriving.wav | |
US-EN-Morgan-Freeman-Starting-Movie-Mode.wav | |
US-EN-Morgan-Freeman-Starting-Party-Mode.wav | |
US-EN-Morgan-Freeman-Starting-Romance-Mode.wav | |
US-EN-Morgan-Freeman-Turning-Off-All-The-Lights.wav | |
US-EN-Morgan-Freeman-Turning-Off-The-Air-Conditioner.wav | |
US-EN-Morgan-Freeman-Turning-Off-The-Bar-Lights.wav | |
US-EN-Morgan-Freeman-Turning-Off-The-Chandelier.wav | |
US-EN-Morgan-Freeman-Turning-Off-The-Family-Room-Lights.wav | |
US-EN-Morgan-Freeman-Turning-Off-The-Hallway-Lights.wav | |
US-EN-Morgan-Freeman-Turning-Off-The-Kitchen-Light.wav | |
US-EN-Morgan-Freeman-Turning-Off-The-Light.wav | |
US-EN-Morgan-Freeman-Turning-Off-The-Lights.wav | |
US-EN-Morgan-Freeman-Turning-Off-The-Mood-Lights.wav | |
US-EN-Morgan-Freeman-Turning-Off-The-TV.wav | |
US-EN-Morgan-Freeman-Turning-On-The-Air-Conditioner.wav | |
US-EN-Morgan-Freeman-Turning-On-The-Bar-Lights.wav | |
US-EN-Morgan-Freeman-Turning-On-The-Chandelier.wav | |
US-EN-Morgan-Freeman-Turning-On-The-Family-Room-Lights.wav | |
US-EN-Morgan-Freeman-Turning-On-The-Hallway-Lights.wav | |
US-EN-Morgan-Freeman-Turning-On-The-Kitchen-Light.wav | |
US-EN-Morgan-Freeman-Turning-On-The-Light.wav | |
US-EN-Morgan-Freeman-Turning-On-The-Lights.wav | |
US-EN-Morgan-Freeman-Turning-On-The-Mood-Lights.wav | |
US-EN-Morgan-Freeman-Turning-On-The-TV.wav | |
US-EN-Morgan-Freeman-Vacate-The-Premises.wav | |
US-EN-Morgan-Freeman-Water-Detected-In-Basement.wav | |
US-EN-Morgan-Freeman-Water-Detected-In-Garage.wav | |
US-EN-Morgan-Freeman-Water-Detected-In-Kitchen.wav | |
US-EN-Morgan-Freeman-Welcome-Home.wav | |
US-EN-Morgan-Freeman-Wife-Is-Arriving.wav |
""" | |
iOS platform for notify component. Should be put into ~/.homeassistant/custom_components/notify/ios.py. | |
(Yes, actually notify/ios.py, even though the filename on Gist is notify_ios.py). | |
For more details about this platform, please refer to the documentation at | |
https://home-assistant.io/components/notify.ios/ | |
""" | |
import logging | |
import requests | |
from homeassistant.components.notify import ( | |
ATTR_TARGET, ATTR_TITLE, ATTR_TITLE_DEFAULT, ATTR_MESSAGE, | |
ATTR_DATA, DOMAIN, BaseNotificationService) | |
_LOGGER = logging.getLogger(__name__) | |
PUSH_URL = "https://mj28d17jwj.execute-api.us-west-2.amazonaws.com/prod/push" | |
# DEPENDENCIES = ["ios"] | |
def get_service(hass, config): | |
"""Get the iOS notification service.""" | |
message = config.get(ATTR_MESSAGE) | |
target = config.get(ATTR_TARGET) | |
title = config.get(ATTR_TITLE) | |
return iOSNotificationService(message, title, target) | |
# pylint: disable=too-few-public-methods, too-many-arguments | |
class iOSNotificationService(BaseNotificationService): | |
"""Implement the notification service for iOS.""" | |
def __init__(self, message, title, target): | |
"""Initialize the service.""" | |
self._message = message | |
self._title = title | |
self._target = target | |
def send_message(self, message="", title=None, target=None, **kwargs): | |
"""Send a message to the Lambda APNS gateway.""" | |
data = { | |
ATTR_MESSAGE: message, | |
ATTR_TARGET: target | |
} | |
"""Don't send the default title because | |
it makes Apple Watch notifications look bad""" | |
if title != ATTR_TITLE_DEFAULT: | |
data[ATTR_TITLE] = title | |
elif title == ATTR_TITLE_DEFAULT and self._title is not None: | |
data[ATTR_TITLE] = self._title | |
if target is None: | |
data[ATTR_TARGET] = self._target | |
if kwargs.get(ATTR_DATA) is not None: | |
data[ATTR_DATA] = kwargs.get(ATTR_DATA) | |
response = requests.put(PUSH_URL, json=data, timeout=10) | |
if response.status_code not in (200, 201): | |
_LOGGER.exception( | |
"Error sending message. Response %d: %s:", | |
response.status_code, response.reason) |
Will show a map with a red tipped pin at the coordinates given. The map will be centered at the coordinates given.
service: notify.iOSApp
data:
message: Something happened at home!
data:
push:
category: map
action_data:
latitude: 40.785091
longitude: -73.968285
The notification thumbnail will be a still image from the camera. The notification content is a real time stream of a camera.
You can use the attachment parameters content-type
and hide-thumbnail
with camera.
You can view an example here.
service: notify.iOSApp
data:
message: Motion detected in the Living Room
data:
push:
category: camera
entity_id: camera.demo_camera
The thumbnail of the notification will be the media at the URL. The notification content is the media at the URL.
Attachment can be used with custom push notification categories/actions.
service: notify.iOSApp
data:
message: Something happened at home!
data:
attachment:
url: https://67.media.tumblr.com/ab04c028a5244377a0ab96e73915e584/tumblr_nfn3ztLjxk1tq4of6o1_400.gif
content-type: gif
hide-thumbnail: false
If the attachment does not appear please ensure it is in one of the following formats:
Maximum file size: 5 MB
Formats:
- AIFF
- WAV
- MP3
- MPEG4 Audio
Maximum file size: 10 MB
Formats:
- JPEG
- GIF
- PNG
Maximum file size: 50 MB
Formats:
- MPEG
- MPEG2
- MPEG4
- AVI
You can pass the following keys to change the behavior of the attachment:
The URL of content to use as the attachment. This URL must be accessible from the Internet, or the receiving device must be on the same network as the hosted content.
By default, the extension of the URL will be checked to determine the filetype. If there is no extension/it can't be determined you can manually provide a file extension.
If set to true
the thumbnail will not show on the notification. The content will only be viewable by expanding.
Ha@633475