diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index 4b87a7c..2cd74e4 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
[bumpversion]
-current_version = 1.2.0a1
+current_version = 1.2.0
commit = True
tag = True
diff --git a/HISTORY.rst b/HISTORY.rst
index 5113b8c..ce6c1b8 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -2,6 +2,14 @@
History
=======
+v1.3.0 (2018-09-23)
+-------------------
+
+- Pushbullet notifications
+- Home Assistant ``access_token`` option
+- Amazon-dash v2.0.0 disclaimer
+
+
v1.2.0 (2018-09-03)
-------------------
diff --git a/README.rst b/README.rst
index 48229aa..7a11964 100644
--- a/README.rst
+++ b/README.rst
@@ -93,6 +93,7 @@ Also available on `AUR `_.
openhab: 192.168.1.140
item: open_door
state: "ON"
+ confirmation: send-pb
44:65:0D:75:A7:B2: # IFTTT example
name: Pompadour
ifttt: cdxxx-_gEJ3wdU04yyyzzz
@@ -104,6 +105,10 @@ Also available on `AUR `_.
token: '402642618:QwGDgiKE3LqdkNAtBkq0UEeBoDdpZYw8b4h'
to: 24291592
is_default: false
+ send-pb:
+ service: pushbullet
+ token: 'o.BbbPYjJizbPr2gSWgXGmqNTt6T9Rew51'
+ is_default: false
**UPGRADE** from `previous versions `_
@@ -119,7 +124,7 @@ The following execution methods are supported with your Amazon Dash button with
Amazon-dash also allows you to **send a confirmation** after pressing a button. You will also receive a message in
-case of failure. Currently only **Telegram** is supported.
+case of failure. **Telegram** and **Pushbullet** are supported.
For more information see
diff --git a/amazon-dash.png b/amazon-dash.png
index 0463ef9..f661b0a 100644
Binary files a/amazon-dash.png and b/amazon-dash.png differ
diff --git a/amazon_dash/__init__.py b/amazon_dash/__init__.py
index 12e56b6..7395f21 100644
--- a/amazon_dash/__init__.py
+++ b/amazon_dash/__init__.py
@@ -1,2 +1,2 @@
-__version__ = '1.2.0a1'
\ No newline at end of file
+__version__ = '1.2.0'
\ No newline at end of file
diff --git a/amazon_dash/config.py b/amazon_dash/config.py
index a099508..c981662 100644
--- a/amazon_dash/config.py
+++ b/amazon_dash/config.py
@@ -106,7 +106,10 @@
"type": "object",
"properties": {
"service": {
- "enum": ['telegram']
+ "enum": [
+ 'telegram',
+ 'pushbullet',
+ ]
},
"token": {
"type": "string",
diff --git a/amazon_dash/confirmations.py b/amazon_dash/confirmations.py
index 48c1f70..7a90800 100644
--- a/amazon_dash/confirmations.py
+++ b/amazon_dash/confirmations.py
@@ -47,8 +47,48 @@ def send(self, message, success=True):
))
+class PushbulletConfirmation(ConfirmationBase):
+ url_base = 'https://api.pushbullet.com/v2/pushes'
+ name = 'pushbullet'
+ required_fields = ('token',)
+ one_field_of = {'device_iden', 'email', 'channel_tag', 'client_id'}
+ to_field = None
+
+ def __init__(self, data):
+ one_fields = set(data) & self.one_field_of
+ if len(one_fields) > 1:
+ raise InvalidConfig(extra_body='Only one in {} is required for {} notifications'.format(
+ ', '.join(one_fields), self.name))
+ elif one_fields:
+ self.to_field = one_fields.pop()
+ super(PushbulletConfirmation, self).__init__(data)
+
+ def get_data(self, body, title=''):
+ data = {
+ "type": "note",
+ "body": body,
+ }
+ if title:
+ data["title"] = title
+ if self.to_field:
+ data[self.to_field] = self.data[self.to_field]
+ return data
+
+ def send(self, message, success=True):
+ try:
+ r = requests.post(self.url_base, json=self.get_data(message),
+ headers={'Access-Token': self.data['token']})
+ except RequestException as e:
+ raise ConfirmationError('Unable to connect to Pushbullet servers on pushbullet confirmation: {}'.format(e))
+ try:
+ r.json()
+ except JSONDecodeError:
+ raise ConfirmationError('Invalid JSON response in pushbullet confirmation (server error?)')
+
+
CONFIRMATIONS = {
'telegram': TelegramConfirmation,
+ 'pushbullet': PushbulletConfirmation,
'disabled': DisabledConfirmation,
}
diff --git a/amazon_dash/execute.py b/amazon_dash/execute.py
index dc130a0..48c9d17 100644
--- a/amazon_dash/execute.py
+++ b/amazon_dash/execute.py
@@ -341,9 +341,13 @@ def get_url(self):
return url
def get_headers(self):
- return {
- 'x-ha-access': self.data['access']
- } if 'access' in self.data else {}
+ headers = {}
+ if 'access_token' in self.data:
+ headers['Authorization'] = 'Bearer {0}'.format(self.data['access_token'])
+ elif 'access' in self.data:
+ headers['x-ha-access'] = self.data['access']
+
+ return headers
class ExecuteOpenHab(ExecuteOwnApiBase):
diff --git a/amazon_dash/install/amazon-dash.yml b/amazon_dash/install/amazon-dash.yml
index c916349..e701fc4 100644
--- a/amazon_dash/install/amazon-dash.yml
+++ b/amazon_dash/install/amazon-dash.yml
@@ -53,6 +53,10 @@ devices:
# token: '402642618:QwGDgiKE3LqdkNAtBkq0UEeBoDdpZYw8b4h' # Telegram token. Get it from Bothfather
# to: 24291592 # Your Telegram id. You can get it using @get_id_bot
# is_default: true # Use by default this confirmation for all devices
+# send-pb:
+# service: pushbullet
+# token: 'o.BbbPYjJizbPr2gSWgXGmqNTt6T9Rew51'
+# is_default: false
# Need help? See the documentation:
# http://docs.nekmo.org/amazon-dash/config_file.html
diff --git a/amazon_dash/tests/test_confirmations.py b/amazon_dash/tests/test_confirmations.py
index 8c16690..5e69919 100644
--- a/amazon_dash/tests/test_confirmations.py
+++ b/amazon_dash/tests/test_confirmations.py
@@ -4,7 +4,7 @@
import requests_mock
from amazon_dash.confirmations import get_confirmation, DisabledConfirmation, get_confirmation_instance, \
- TelegramConfirmation, ConfirmationBase
+ TelegramConfirmation, ConfirmationBase, PushbulletConfirmation
from amazon_dash.exceptions import InvalidConfig, ConfirmationError
@@ -71,3 +71,40 @@ def test_server_error(self):
m.post(telegram.url_base.format('foo'), exc=requests.exceptions.ConnectTimeout)
with self.assertRaises(ConfirmationError):
telegram.send('spam')
+
+
+class TestPushbulletConfirmation(unittest.TestCase):
+ def get_pushbullet(self, extra=None):
+ extra = extra or {}
+ return PushbulletConfirmation(dict({'token': 'foo'}, **extra))
+
+ def test_send(self):
+ pushbullet = self.get_pushbullet()
+ with requests_mock.mock() as m:
+ m.post(pushbullet.url_base, text='{}')
+ pushbullet.send('spam')
+ self.assertTrue(m.called_once)
+
+ def test_invalid_json(self):
+ pushbullet = self.get_pushbullet()
+ with requests_mock.mock() as m:
+ m.post(pushbullet.url_base, text='{"}invalid')
+ with self.assertRaises(ConfirmationError):
+ pushbullet.send('spam')
+
+ def test_server_error(self):
+ pushbullet = self.get_pushbullet()
+ with requests_mock.mock() as m:
+ m.post(pushbullet.url_base, exc=requests.exceptions.ConnectTimeout)
+ with self.assertRaises(ConfirmationError):
+ pushbullet.send('spam')
+
+ def test_extra_to(self):
+ with self.assertRaises(InvalidConfig):
+ self.get_pushbullet({'device_iden': 'foo', 'email': 'bar'})
+
+ def test_to_device_iden(self):
+ pushbullet = self.get_pushbullet({'device_iden': 'bar'})
+ with requests_mock.mock() as m:
+ m.post(pushbullet.url_base, additional_matcher=lambda r: r.json().get('device_iden') == 'bar', text='{}')
+ pushbullet.send('spam')
diff --git a/amazon_dash/tests/test_execute.py b/amazon_dash/tests/test_execute.py
index b478f5c..0474fa9 100644
--- a/amazon_dash/tests/test_execute.py
+++ b/amazon_dash/tests/test_execute.py
@@ -132,7 +132,7 @@ def test_get_shell(self):
class TestExecuteUrl(unittest.TestCase):
no_body_methods = ['get', 'head', 'delete', 'connect', 'options', 'trace']
url = 'http://domain.com'
-
+
def setUp(self):
super(TestExecuteUrl, self).setUp()
self.session_mock = requests_mock.Mocker()
@@ -297,6 +297,13 @@ def test_execute_with_access(self):
assis.execute()
self.assertTrue(m.called_once)
+ def test_execute_with_access_token(self):
+ with requests_mock.mock() as m:
+ m.post(self.url, text='success', request_headers={'Authorization': 'Bearer abcde12345'})
+ assis = ExecuteHomeAssistant('key', self.default_data(extra_data={'access_token': 'abcde12345'}))
+ assis.execute()
+ self.assertTrue(m.called_once)
+
class TestExecuteOpenHab(unittest.TestCase):
path = '/rest/items/test'
diff --git a/docs/config_file.rst b/docs/config_file.rst
index eaa68de..0d82cad 100644
--- a/docs/config_file.rst
+++ b/docs/config_file.rst
@@ -61,6 +61,7 @@ Real example:
openhab: 192.168.1.140
item: open_door
state: "ON"
+ confirmation: send-pb
44:65:0D:75:A7:B2:
name: Pompadour
ifttt: cdxxx-_gEJ3wdU04yyyzzz
@@ -72,6 +73,10 @@ Real example:
token: '402642618:QwGDgiKE3LqdkNAtBkq0UEeBoDdpZYw8b4h'
to: 24291592
is_default: false
+ send-pb:
+ service: pushbullet
+ token: 'o.BbbPYjJizbPr2gSWgXGmqNTt6T9Rew51'
+ is_default: false
Common options
@@ -98,7 +103,7 @@ for each device. The available exection methods are:
* **cmd**: local command line command. Arguments can be placed after the command.
* **url**: Call a url.
-* **homeassistant**: send event to Homeassistant. This argument must be the address to the hass server (protocol and
+* **homeassistant**: send event to Home Assistant. This argument must be the address to the hass server (protocol and
port are optional. By default http and 8123, respectively).
* **openhab**: send event to OpenHAB. This argument must be the address to the hass server (protocol and
port are optional. By default http and 8080, respectively).
@@ -248,13 +253,21 @@ Example:
confirmation: send-tg
-Homeassistant event
-~~~~~~~~~~~~~~~~~~~
+Home Assistant event
+~~~~~~~~~~~~~~~~~~~~
When the **homeassistant execution method** is used, the following options are available.
* **event** (required): Event name to send.
* **data**: Event data to send. Use json as string.
-* **access**: HomeAssistant password for API (``x-ha-access`` header).
+* **access_token**: Long-lived Home Assistant access token.
+* **access**: Home Assistant legacy API password (``x-ha-access`` header).
+
+Starting with version 0.78 of Home Assistant, there are two ways Amazon Dash can authenticate:
+
+1. By providing a long-lived access token (generated within your Home Assistant profile page) via the ``access_token`` option.
+2. By providing the legacy Home Assistant API password via the ``access`` option.
+
+Although both options currently work, the Home Assistant project plans to deprecate (and likely remove) the legacy API password in the future; therefore, to properly future proof your Amazon Dash setup, the long-lived access token option is recommended.
The protocol and the port in the address of the Homeassistant server are optional. The syntax of the address is:
``[://][:]. For example: ``https://hassio.local:1234``.
@@ -337,6 +350,7 @@ Confirmations
-------------
The following **services** are supported to send confirmation messages.
+
Telegram
~~~~~~~~
For use a telegram service you need to define:
@@ -361,3 +375,32 @@ have not started a conversation before.
token: '402642618:QwGDgiKE3LqdkNAtBkq0UEeBoDdpZYw8b4h'
to: 24291592
is_default: false
+
+
+Pushbullet
+~~~~~~~~~~
+For use a pushbullet service you need to define:
+
+* **token**: Get it in your pushbullet Access Token (create a token): https://www.pushbullet.com/#settings/account
+
+Optional: set a target (you can only set a target):
+
+* **device_iden**: Device identifier. To get your device identifier:
+ ``$ curl --header 'Access-Token: ' https://api.pushbullet.com/v2/devices``
+* **email**: Useful to send a message to your contacts.
+* **channel_tag**: Send to all subscribers to your channel.
+* **client_iden**: Send to all users who have granted access to your OAuth client.
+
+.. code-block:: yaml
+
+ # amazon-dash.yml
+ # ---------------
+ settings:
+ delay: 10
+ devices:
+ # ...
+ confirmations:
+ send-pb:
+ service: pushbullet
+ token: 'o.BbbPYjJizbPr2gSWgXGmqNTt6T9Rew51'
+ is_default: false
diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst
index 89fd95c..8477981 100644
--- a/docs/troubleshooting.rst
+++ b/docs/troubleshooting.rst
@@ -11,6 +11,8 @@ are:
* Tcpdump.
* Sudo
+Amazon-dash v2.0.0 will only be compatible with Python 3.6+. This version is currently in development.
+
Why root is required
--------------------
diff --git a/images/amazon-dash.xcf b/images/amazon-dash.xcf
index 8db373e..8402bd5 100644
Binary files a/images/amazon-dash.xcf and b/images/amazon-dash.xcf differ