diff --git a/examples/conf/config.yaml b/examples/conf/config.yaml
index bb70e562..263366dd 100644
--- a/examples/conf/config.yaml
+++ b/examples/conf/config.yaml
@@ -16,21 +16,21 @@
# Using multiple files is encouraged in the case of large configurations
# that can easily end up in a messy config.yaml file, as they help you
# keep your configuration more organized.
-include:
- - include/logging.yaml
- - include/media.yaml
- - include/sensors.yaml
+#include:
+# - include/logging.yaml
+# - include/media.yaml
+# - include/sensors.yaml
# platypush logs on stdout by default. You can use the logging section to specify
# an alternative file or change the logging level.
-logging:
- filename: ~/.local/log/platypush/platypush.log
- level: INFO
+#logging:
+# filename: ~/.local/log/platypush/platypush.log
+# level: INFO
# The device_id is used by many components of platypush and it should uniquely
# identify a device in your network. If nothing is specified then the hostname
# will be used.
-device_id: myname
+#device_id: my_device
## --
## Plugin configuration examples
@@ -46,31 +46,31 @@ device_id: myname
# https://docs.platypush.tech/en/latest/platypush/plugins/light.hue.html
# for reference. You can easily install the required dependencies for the plugin through
# pip install 'platypush[hue]'
-light.hue:
- # IP address or hostname of the Hue bridge
- bridge: 192.168.1.10
- # Groups that will be handled by default if nothing is specified on the request
- groups:
- - Living Room
+#light.hue:
+# # IP address or hostname of the Hue bridge
+# bridge: 192.168.1.10
+# # Groups that will be handled by default if nothing is specified on the request
+# groups:
+# - Living Room
# Example configuration of music.mpd plugin, see
# https://docs.platypush.tech/en/latest/platypush/plugins/music.mpd.html
# You can easily install the dependencies through pip install 'platypush[mpd]'
-music.mpd:
- host: localhost
- port: 6600
+#music.mpd:
+# host: localhost
+# port: 6600
# Example configuration of media.chromecast plugin, see
# https://docs.platypush.tech/en/latest/platypush/plugins/media.chromecast.html
# You can easily install the dependencies through pip install 'platypush[chromecast]'
-media.chromecast:
- chromecast: Living Room TV
+#media.chromecast:
+# chromecast: Living Room TV
# Plugins with empty configuration can also be explicitly enabled by specifying
# enabled=True or disabled=False (it's a good practice if you want the
# corresponding web panel to be enabled, if available)
-camera:
- enabled: True
+#camera:
+# enabled: True
# Support for last.fm scrobbling. Install dependencies with 'pip install "platypush[lastfm]"
lastfm:
@@ -81,13 +81,11 @@ lastfm:
# Support for calendars - in this case Google and Facebook calendars
# Installing the dependencies: pip install 'platypush[ical,google]'
-calendar:
- calendars:
- -
- type: platypush.plugins.google.calendar.GoogleCalendarPlugin
- -
- type: platypush.plugins.calendar.ical.CalendarIcalPlugin
- url: https://www.facebook.com/events/ical/upcoming/?uid=your_user_id&key=your_key
+#calendar:
+# calendars:
+# - type: platypush.plugins.google.calendar.GoogleCalendarPlugin
+# - type: platypush.plugins.calendar.ical.CalendarIcalPlugin
+# url: https://www.facebook.com/events/ical/upcoming/?uid=your_user_id&key=your_key
## --
## Backends configuration examples
@@ -118,77 +116,49 @@ calendar:
backend.http:
# Listening port
port: 8008
+ # Websocket port
+ websocket_port: 8009
# Through resource_dirs you can specify external folders whose content can be accessed on
# the web server through a custom URL. In the case below we have a Dropbox folder containing
# our pictures and we mount it to the '/carousel' endpoint.
resource_dirs:
- carousel: ~/Dropbox/Photos/carousel
-
- # Dashboard configuration. The dashboard is a collection of widgets and it's organized in
- # multiple rows. Each rows can be split in 12 columns. Therefore 'columns: 12' will make
- # a widget span over the whole row, while 'columns: 6' will make a widget take half the
- # horizontal space of a column.
- dashboard:
- widgets:
- -
- widget: calendar
- columns: 6
- -
- widget: music
- columns: 3
- -
- widget: date-time-weather
- columns: 3
- -
- widget: image-carousel
- columns: 6
- images_path: ~/Dropbox/Photos/carousel
- refresh_seconds: 15
- -
- widget: rss-news
- # Requires backend.http.poll to be enabled with some
- # RSS sources and write them to sqlite db
- columns: 6
- limit: 25
- db: "sqlite:////home/user/.local/share/platypush/feeds/rss.db"
+ carousel: /mnt/hd/photos/carousel
# The HTTP poll backend is a versatile backend that can monitor for HTTP-based resources and
# trigger events whenever new entries are available. In the example below we show how to use
# the backend to listen for changes on a set of RSS feeds. New content will be stored by default
# on a SQLite database under ~/.local/share/platypush/feeds/rss.db.
# Install the required dependencies through 'pip install "platypush[rss,db]"'
-backend.http.poll:
- requests:
- -
- # HTTP poll type (RSS)
- type: platypush.backend.http.request.rss.RssUpdates
- # Remote URL
- url: http://www.theguardian.com/rss/world
- # Custom title
- title: The Guardian - World News
- # How often we should check for changes
- poll_seconds: 600
- # Maximum number of new entries to be processed
- max_entries: 10
- -
- type: platypush.backend.http.request.rss.RssUpdates
- url: http://www.physorg.com/rss-feed
- title: Phys.org
- poll_seconds: 600
- max_entries: 10
- -
- type: platypush.backend.http.request.rss.RssUpdates
- url: http://feeds.feedburner.com/Techcrunch
- title: Tech Crunch
- poll_seconds: 600
- max_entries: 10
- -
- type: platypush.backend.http.request.rss.RssUpdates
- url: http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml
- title: The New York Times
- poll_seconds: 300
- max_entries: 10
+#backend.http.poll:
+# requests:
+# - type: platypush.backend.http.request.rss.RssUpdates # HTTP poll type (RSS)
+# # Remote URL
+# url: http://www.theguardian.com/rss/world
+# # Custom title
+# title: The Guardian - World News
+# # How often we should check for changes
+# poll_seconds: 600
+# # Maximum number of new entries to be processed
+# max_entries: 10
+#
+# - type: platypush.backend.http.request.rss.RssUpdates
+# url: http://www.physorg.com/rss-feed
+# title: Phys.org
+# poll_seconds: 600
+# max_entries: 10
+#
+# - type: platypush.backend.http.request.rss.RssUpdates
+# url: http://feeds.feedburner.com/Techcrunch
+# title: Tech Crunch
+# poll_seconds: 600
+# max_entries: 10
+#
+# - type: platypush.backend.http.request.rss.RssUpdates
+# url: http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml
+# title: The New York Times
+# poll_seconds: 300
+# max_entries: 10
# MQTT backend. Installed required dependencies through 'pip install "platypush[mqtt]"'
backend.mqtt:
@@ -196,15 +166,15 @@ backend.mqtt:
host: mqtt-server
# By default the backend will listen for messages on the platypush_bus_mq/device_id
# topic, but you can change the prefix using the topic attribute
- topic: my_platypush_bus
+# topic: MyBus
# Raw TCP socket backend. It can run commands sent as JSON over telnet or netcat
-backend.tcp:
- port: 3333
+#backend.tcp:
+# port: 3333
# Websocket backend. Install required dependencies through 'pip install "platypush[http]"'
-backend.websocket:
- port: 8765
+#backend.websocket:
+# port: 8765
## --
## Assistant configuration examples
@@ -254,9 +224,12 @@ backend.assistant.snowboy:
assistant.echo:
audio_player: mplayer
-# Install Google Assistant dependencies with 'pip install "platypush[google-assistant]"'
-assistant.google.pushtotalk:
- language: en-US
+# Install Google Assistant dependencies with 'pip install "platypush[google-assistant-legacy]"'
+assistant.google:
+ enabled: True
+
+backend.assistant.google:
+ enabled: True
## --
## Procedure examples
@@ -327,14 +300,14 @@ procedure.outside_home:
procedure.send_request(target, action, args):
- action: mqtt.send_message
args:
- topic: my_platypush_bus/${target}
+ topic: platypush_bus_mq/${target}
host: mqtt-server
port: 1883
msg:
type: request
target: ${target}
action: ${action}
- args: "${context.get('args', {}}"
+ args: ${args}
## --
## Event hook examples
@@ -418,4 +391,3 @@ cron.TestCron:
- action: shell.exec
args:
cmd: ~/bin/myscript.sh
-
diff --git a/examples/conf/dashboard.xml b/examples/conf/dashboard.xml
new file mode 100644
index 00000000..71e5e8aa
--- /dev/null
+++ b/examples/conf/dashboard.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/conf/hook.py b/examples/conf/hook.py
new file mode 100644
index 00000000..2ad765f4
--- /dev/null
+++ b/examples/conf/hook.py
@@ -0,0 +1,43 @@
+# A more versatile way to define event hooks than the YAML format of `config.yaml` is through native Python scripts.
+# You can define hooks as simple Python functions that use the `platypush.event.hook.hook` decorator to specify on
+# which event type they should be called, and optionally on which event attribute values.
+#
+# Event hooks should be stored in Python files under `~/.config/platypush/scripts`. All the functions that use the
+# @hook decorator will automatically be discovered and imported as event hooks into the platform at runtime.
+
+# `run` is a utility function that runs a request by name (e.g. `light.hue.on`).
+from platypush.utils import run
+
+# @hook decorator
+from platypush.event.hook import hook
+
+# Event types that you want to react to
+from platypush.message.event.assistant import ConversationStartEvent, SpeechRecognizedEvent
+
+
+@hook(SpeechRecognizedEvent, phrase='play ${title} by ${artist}')
+def on_music_play_command(event, title=None, artist=None, **context):
+ """
+ This function will be executed when a SpeechRecognizedEvent with `phrase="play the music"` is triggered.
+ `event` contains the event object and `context` any key-value info from the running context.
+ Note that in this specific case we can leverage the token-extraction feature of SpeechRecognizedEvent through
+ ${} that operates on regex-like principles to extract any text that matches the pattern into context variables.
+ """
+ results = run('music.mpd.search', filter={
+ 'artist': artist,
+ 'title': title,
+ })
+
+ if results:
+ run('music.mpd.play', results[0]['file'])
+ else:
+ run('tts.say', "I can't find any music matching your query")
+
+
+@hook(ConversationStartEvent)
+def on_conversation_start(event, **context):
+ """
+ A simple hook that gets invoked when a new conversation starts with a voice assistant and simply pauses the music
+ to make sure that your speech is properly detected.
+ """
+ run('music.mpd.pause_if_playing')
diff --git a/platypush/backend/http/__init__.py b/platypush/backend/http/__init__.py
index 9ab87039..55d86bea 100644
--- a/platypush/backend/http/__init__.py
+++ b/platypush/backend/http/__init__.py
@@ -12,36 +12,137 @@ from platypush.utils import get_ssl_server_context, set_thread_name
class HttpBackend(Backend):
"""
- The HTTP backend is a general-purpose web server that you can leverage:
+ The HTTP backend is a general-purpose web server.
- * To execute Platypush commands via HTTP calls. Example::
+ Example configuration:
- curl -XPOST -H 'Content-Type: application/json' -H "X-Token: your_token" \\
- -d '{
- "type":"request",
- "target":"nodename",
- "action":"tts.say",
- "args": {"phrase":"This is a test"}
- }' \\
- http://localhost:8008/execute
+ .. code-block:: yaml
+
+ backend.http:
+ # Default HTTP listen port
+ port: 8008
+ # Default websocket port
+ websocket_port: 8009
+ # External folders that will be exposed over `/resources/`
+ resource_dirs:
+ photos: /mnt/hd/photos
+ videos: /mnt/hd/videos
+ music: /mnt/hd/music
+
+ You can leverage this backend:
+
+ * To execute Platypush commands via HTTP calls. In order to do so:
+
+ ** Register a user to Platypush through the web panel (usually served on ``http://host:8008/``).
+
+ ** Generate a token for your user, either through the web panel (Settings -> Generate Token) or via API:
+
+ .. code-block:: shell
+
+ curl -XPOST -H 'Content-Type: application/json' -d '
+ {
+ "username": "$YOUR_USER",
+ "password": "$YOUR_PASSWORD"
+ }' http://host:8008/auth
+
+ ** Execute actions through the ``/execute`` endpoint:
+
+ .. code-block:: shell
+
+ curl -XPOST -H 'Content-Type: application/json' -H "Authorization: Bearer $YOUR_TOKEN" -d '
+ {
+ "type": "request",
+ "action": "tts.say",
+ "args": {
+ "text": "This is a test"
+ }
+ }' http://localhost:8008/execute
* To interact with your system (and control plugins and backends) through the Platypush web panel,
- by default available on your web root document. Any plugin that you have configured and available as a panel
- plugin will appear on the web panel as well as a tab.
+ by default available on ``http://host:8008/``. Any configured plugin that has an available panel
+ plugin will be automatically added to the web panel.
- * To display a fullscreen dashboard with your configured widgets, by default available under ``/dashboard/``
+ * To display a fullscreen dashboard with custom widgets.
- * To stream media over HTTP through the ``/media`` endpoint
+ ** Widgets are available as Vue.js components under
+ ``platypush/backend/http/webapp/src/components/widgets``.
+
+ ** Explore their options (some may require some plugins or backends to be configured in order to work) and
+ create a new dashboard template under ``~/.config/platypush/dashboards``- e.g. ``main.xml``:
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ** The dashboard will be accessible under ``http://host:8008/dashboard/``, where ``name=main`` if for
+ example you stored your template under ``~/.config/platypush/dashboards/main.xml``.
+
+ * To expose custom endpoints that can be called as web hooks by other applications and run some custom logic.
+ All you have to do in this case is to create a hook on a
+ :class:`platypush.message.event.http.hook.WebhookEvent` with the endpoint that you want to expose and store
+ it under e.g. ``~/.config/platypush/scripts/hooks.py``:
+
+ .. code-block:: python
+
+ from platypush.context import get_plugin
+ from platypush.event.hook import hook
+ from platypush.message.event.http.hook import WebhookEvent
+
+ hook_token = 'abcdefabcdef'
+
+ # Expose the hook under the /hook/lights_toggle endpoint
+ @hook(WebhookEvent, hook='lights_toggle')
+ def lights_toggle(event, **context):
+ # Do any checks on the request
+ assert event.headers.get('X-Token') == hook_token, 'Unauthorized'
+
+ # Run some actions
+ lights = get_plugin('light.hue')
+ lights.toggle()
Any plugin can register custom routes under ``platypush/backend/http/app/routes/plugins``.
Any additional route is managed as a Flask blueprint template and the `.py`
module can expose lists of routes to the main webapp through the
``__routes__`` object (a list of Flask blueprints).
- Note that if you set up a main token, it will be required for any HTTP
- interaction - either as ``X-Token`` HTTP header, on the query string
- (attribute name: ``token``), as part of the JSON payload root (attribute
- name: ``token``), or via HTTP basic auth (any username works).
+ Security: Access to the endpoints requires at least one user to be registered. Access to the endpoints is regulated
+ in the following ways (with the exception of event hooks, whose logic is up to the user):
+
+ * **Simple authentication** - i.e. registered username and password.
+ * **JWT token** provided either over as ``Authorization: Bearer`` header or ``GET`` ``?token=``
+ parameter. A JWT token can be generated either through the web panel or over the ``/auth`` endpoint.
+ * **Global platform token**, usually configured on the root of the ``config.yaml`` as ``token: ``.
+ It can provided either over on the ``X-Token`` header or as a ``GET`` ``?token=`` parameter.
+ * **Session token**, generated upon login, it can be used to authenticate requests through the ``Cookie`` header
+ (cookie name: ``session_token``).
Requires:
diff --git a/platypush/plugins/music/mpd/__init__.py b/platypush/plugins/music/mpd/__init__.py
index b0743619..eef92932 100644
--- a/platypush/plugins/music/mpd/__init__.py
+++ b/platypush/plugins/music/mpd/__init__.py
@@ -16,9 +16,13 @@ class MusicMpdPlugin(MusicPlugin):
sources through plugins (e.g. Spotify, TuneIn, Soundcloud, local files
etc.).
+ **NOTE**: As of Mopidy 3.0 MPD is an optional interface provided by the ``mopidy-mpd`` extension. Make sure that you
+ have the extension installed and enabled on your instance to use this plugin with your server.
+
Requires:
* **python-mpd2** (``pip install python-mpd2``)
+
"""
_client_lock = threading.RLock()
diff --git a/platypush/plugins/zigbee/mqtt.py b/platypush/plugins/zigbee/mqtt.py
index ba05bf7d..f17a050f 100644
--- a/platypush/plugins/zigbee/mqtt.py
+++ b/platypush/plugins/zigbee/mqtt.py
@@ -33,8 +33,8 @@ class ZigbeeMqttPlugin(MqttPlugin, SwitchPlugin):
.. code-block:: shell
- wget https://github.com/Koenkk/Z-Stack-firmware/raw/master/coordinator/Z-Stack_Home_1.2/bin/default/CC2531_DEFAULT_20190608.zip
- unzip CC2531_DEFAULT_20190608.zip
+ wget https://github.com/Koenkk/Z-Stack-firmware/raw/master/coordinator/Z-Stack_Home_1.2/bin/default/CC2531_DEFAULT_20201127.zip
+ unzip CC2531_DEFAULT_20201127.zip
[sudo] cc-tool -e -w CC2531ZNP-Prod.hex
- You can disconnect your debugger and downloader cable once the firmware is flashed.