diff --git a/Backends.md b/Backends.md index 4cd65b2..77ba9d7 100644 --- a/Backends.md +++ b/Backends.md @@ -21,18 +21,24 @@ * [Smart cards backend](#smart-cards-backend) * [Weather forecast backend](#weather-forecast-backend) - -Platypush backends are components that can listen for event on any source that generates events or messages. Platypush can support through backends things like message queues, HTTP requests, voice assistant interactions, music player events, MIDI events, button events, measurements from sensors, events from smart cards and more. You can see a backend as a component that runs in its own thread or process and posts messages, action requests or events to the main bus when something happens. +Platypush backends are components that can listen for events on any source that generates events or messages. Platypush +can support through backends things like message queues, HTTP requests, voice assistant interactions, music player +events, MIDI events, button events, measurements from sensors, events from smart cards and more. You can see a backend +as a component that runs in its own thread or process and posts messages, action requests or events to the main bus when +something happens. # HTTP server [Backend reference](https://docs.platypush.tech/en/latest/platypush/backend/http.html) -The HTTP server is a powerful feature of Platypush and one of the main ways to interact with the application and its components. If configured, the HTTP backend will run a Flask server (default port: 8008) that you can use to interact with Platypush in several ways: +The HTTP server is a powerful feature of Platypush and one of the main ways to interact with the application and its +components. If configured, the HTTP backend will run a Flask server (default port: 8008) that you can use to interact +with Platypush in several ways: 1. To send action requests as JSON messages through the web API 2. To control the configured plugins (lights, switches, music, sensors etc.) through the web panel -3. As a dashboard to show on a monitor or a tv with your favourite widgets (calendar, music player, weather, sensors state, news etc.) +3. As a dashboard to show on a monitor or a tv with your favourite widgets (calendar, music player, weather, sensors + state, news etc.) ## Configuration @@ -46,12 +52,36 @@ backend.http: Websockets are used both in the web panel and dashboard interfaces to deliver real-time messages to the plugins and widgets. -**NOTE**: If you configured a security `token` on your Platypush instance (warmly recommended), then all the HTTP calls need to bear that token either: +## Authentication -- On the `X-Token` header -- On the query string (`?token=...`) -- At the top level of the JSON request (`{"type":"request", ..., "token":"..."}`) -- Through interactive basic HTTP authentication in case of browser-based interaction +The HTTP backend acts also as a user registration and authentication gateway. After configuring it in your +`config.yaml`, start Platypush and head to `http://host:8008/`. If no users have yet been created, you should see a +user registration panel, otherwise a login interface will be prompted. + +Upon registration, you can generate an API token that can be used in your calls either: + +- Through the web panel. Create a user/login to the web panel, head to the Settings (gear icon in the menu), select + _Generate Token_, enter your username and password and its expiry date, and a new JWT token will be generated. + +- Through the API, using the `/auth` endpoint: + +```shell +$ curl -XPOST -H "Content-Type: application/json" --data '{ + "username":"user", + "password":"pass" +}' http://host:8008/auth + +{ + "token": "..." +} +``` + +Once you have a JWT token, you can use it on your API calls either: + +- On the `Authorization` header (format: `Authorization: Bearer `) [advised]. +- On the `X-Token` header. +- On the query string (`?token=...`). +- At the top level of the JSON request (`{"type":"request", ..., "token":"..."}`). ## cURL commands @@ -61,7 +91,8 @@ Example 1: play music through the [MPD plugin](plugins#mpd-mopidy-support): ```shell curl -XPOST -H 'Content-Type: application/json' \ - -d '{"type":"request", "target":"hostname", "action":"music.mpd.play"}' \ + -H "Authorization: Bearer $TOKEN" \ + -d '{"type":"request", "action":"music.mpd.play"}' \ http://hostname:8008/execute ``` @@ -69,7 +100,8 @@ Example 2: turn on your lights through the [Philips Hue plugin](plugins#philips- ```shell curl -XPOST -H 'Content-Type: application/json' \ - -d '{"type":"request", "target":"hostname", "action":"lights.hue.on", "args": {"groups": ["Living Room"]}}' \ + -H "Authorization: Bearer $TOKEN" \ + -d '{"type":"request", "action":"lights.hue.on", "args": {"groups": ["Living Room"]}}' \ http://hostname:8008/execute ``` @@ -77,7 +109,8 @@ Example 3: run a configured procedure: ```shell curl -XPOST -H 'Content-Type: application/json' \ - -d '{"type":"request", "target":"hostname", "action":"procedure.at_home"}' \ + -H "Authorization: Bearer $TOKEN" \ + -d '{"type":"request", "action":"procedure.at_home"}' \ http://hostname:8008/execute ``` @@ -96,49 +129,354 @@ tts: You can use the web panel to control your lights, music, video, sensors, motors, switches, and whatever is provided by the plugins. -## Dashboard +## Dashboards -You can use Platypush to power a fullscreen dashboard with your calendar, music state, photos, weather forecast, news, sensors state etc. to show on a computer, tv or laptop screen. +You can use Platypush to power a fullscreen dashboard with your calendar, music state, photos, weather forecast, news, +sensors state etc. to show on a computer, tv or laptop screen. -Change your `backend.http` configuration to also include the widgets that you want to include on the dashboard. +The configuration for dashboards has changed since Platypush 0.20.0 - while only one dashboard per service was +previously supported, and configured directly inside of the `backend.http` configuration, it's now possible to configure +multiple dashboards and do it directly in an HTML-like format that allows much more flexibility. + +Dashboards consist of *widgets*, which are customizable components that can be freely arranged on the dashboard canvas. + +Widgets are Vue components stored under +[`backend/http/webapp/src/components/widgets`](https://git.platypush.tech/platypush/platypush/-/tree/master/platypush/backend/http/webapp/src/components/widgets). +Widgets are available for most of a common dashboard's components - such as calendar, music status, time and weather, +image and news carousels. You can easily grab the configuration of each widget by looking at the `props` defined on the +associated Vue component (*TODO: manage self-generated documentation for widgets*), and some widgets may require some +other plugin or backend to be enabled in order to work - for example, `Calendar` requires the `calendar` plugin, +`Weather` requires the `weather.openweathermap` plugin, and so on. + +Dashboard configurations are stored by default under the `~/.config/platypush/dashboards` folder. Each dashboard should +be an XML file. + +Let's take a look at a simple dashboard configuration that includes the following widgets: + +- A calendar +- A music status widget +- A date/time/weather widget +- An image carousel +- A news carousel + +### Calendar + +- Dependencies installation: + +```shell +# Support for Google Calendar and ICal calendar URLs +$ [sudo] pip install 'platypush[ical,google]' +``` + +- Grant app access to the calendar API, if you are using a Google Calendar: + +```shell +python -m platypush.plugins.google.credentials \ + "https://www.googleapis.com/auth/calendar.readonly" \ + /path/to/your/google/api/client_secret.json +``` + +- `config.yaml` configuration: + +```yaml +calendar: + # Monitor your Google Calendar and an ICal calendar (e.g. your Facebook events calendar) + calendars: + - type: platypush.plugins.google.calendar.GoogleCalendarPlugin + - type: platypush.plugins.calendar.ical.CalendarIcalPlugin + url: https://www.facebook.com/events/ical/upcoming/?uid=YOUR_UID&key=YOUR_KEY +``` + +### Music state and current track + +This is currently only supported for MPD/Mopidy integrations - but, given the amount of music service plugins available +for Mopidy, this should easily cover most of the use cases out there. + +Also, note that since the version 3.0 Mopidy no longer exposes the MPD interface by default - you'll have to install the +`mopidy-mpd` package separately. + +- Install the MPD dependencies: + +```shell +$ [sudo] pip install 'platypush[mpd]' +``` + +- Configure the MPD plugin and, if you are using Mopidy, the Mopidy backend (for real-time monitoring): + +```yaml +music.mpd: + host: localhost + port: 6600 + +backend.music.mopidy: + enabled: True +``` + +### Date/time/weather widget + +Get an OpenWeatherMap API token and configure the associated Platypush plugin: + +```yaml +weather.openweathermap: + token: YOUR_TOKEN + lat: YOUR_LAT + long: YOUR_LONG + # Otherwise, you can also configure the default location by + # city ID or free search +``` + +### Image carousel + +You can configure one or more directories on the system to be exposed over the web server as *resources*. This enables +you to easily expose images stored on your drive as HTTP URLs. For example: ```yaml backend.http: - port: 8008 - websocket_port: 8009 - - # resource_dirs allows you to expose the content of some absolute directories on your - # filesystem as static elements through the webserver under the /resources URL. - # In the example below, the files under ~/Dropbox/Photos/carousel will be accessible through - # http://localhost:8008/resources/carousel - resource_dirs: - carousel: ~/Dropbox/Photos/carousel - - dashboard: # Your dashboard configuration - background_image: https://some/background.png # Background image - widgets: # Widgets configuration - calendar: # Calendar widget. It requires the calendar plugin to be configured - columns: 6 # 6 columns on the first row - music: # Music playback state. It requires the music.mpd plugin to be configured - columns: 3 # 3 columns on the first row - date-time-weather: # Date, weather and sensors plugin - columns: 3 # 3 columns on the first row - image-carousel: # Photo carousel - columns: 6 # 6 columns on the second row - images_path: ~/Dropbox/Photos/carousel # Path to scan for carousel pictures. - # It must be a subdirectory of at least - # one item of resource_dirs. - refresh_seconds: 15 # Time between two pictures - rss-news: # News from your RSS feeds - # Requires backend.http.poll to be enabled with some - # RSS sources, and configured to write items to sqlite db - columns: 6 # 6 columns on the second row - limit: 25 # Maximum number of items to show in a carousel news iteration - db: "sqlite:////home/blacklight/.local/share/platypush/feeds/rss.db" # Database where the HTTP poll backend - # stores the RSS items + # ... + resource_dirs: + photos: /mnt/hd/Photos ``` -Note that you can design the layout of the dashboard by specifying how many columns a widget should take. Each row contains 12 columns. In the example above, for example, we placed the calendar widget to occupy half of the first row while the music and weather widgets take one quarter each, and the second row is split between the image carousel and the news carousel. +You can now access your photos over `http://host:8008/resources/photos/PHOTO.jpg` - we'll see soon how to import this +folder into a carousel widget. + +### News carousel + +- Install the dependencies: + +```shell +$ [sudo] pip install 'platypush[rss]' +``` + +- Configure the RSS feeds you want to scan: + +```yaml +backend.http.poll: + requests: + - type: platypush.backend.http.request.rss.RssUpdates + url: http://site1.com/rss + title: Site 1 + poll_seconds: 600 + max_entries: 10 + + - type: platypush.backend.http.request.rss.RssUpdates + url: http://site2.com/rss + title: Site 2 + poll_seconds: 600 + max_entries: 10 +``` + +Feed updates by default will be stored in `~/.local/share/platypush/feeds/rss.db` - we'll use that in a moment. + +### Adding the widgets + +Once all the dependencies are installed and configured, you can add the widgets to the dashboard. + +Dashboard templates are stored as XML files under `~/.config/platypush/dashboards`. Create a new file under this folder +(e.g. `main.xml`) with the following content: + +```xml + + + + + + + + + + + + + +``` + +A few observations: + +- `` is the root element of a dashboard template. + +- A dashboard is organized in rows, so all the widgets belonging to the same `` element will be displayed on the + same row. + +- Each row is divided into 12 columns, and you can specify the width of a widget through the `col-n` class, where `n` is + the width of the widget in column - for example, `col-6` means that the widget takes half of the row. + +- Column width can be made reactive through the `-s-`, `-m-`, `-l-` and `-xl-` modifiers. The following statement, for + example, means that the width of the `` widget will be 100% of the row on a small screen, 50% on a medium + screen (usually tablet-sized screens) and 25% on a large screen (usually desktop-sized screens or larger): + +```xml + +``` + +- You can also specify custom classes on a widget definition or custom a custom CSS style through the `class` and + `style` attributes. + +Once configured, you can access your dashboard on `http://host:8008/dashboard/main` - assuming that the template you +just created was stored in a file named `main.xml`: + +![Dashboard screenshot](https://blog.platypush.tech/img/dashboard-1.png) + +### Creating custom widgets + +In some cases you may want to have a UI that shows specific information from plugins (for example, sensor data, or +toggles/sliders for some specific devices or services), but that information isn't provided by the default widgets that +come with Platypush. Alternatively, the application's main web panel exposes lots of information and features from +plugins, but it requires some clicking around to get it, while you may want a simple dashboard that shows all the +information you need on a single view. + +Platypush provides a way for you to define custom widgets through the `` widget. You can use `` to +define reactive widgets with custom HTML and JavaScript and using a few base ingredients to build complex interfaces. +The following elements can be used inside of a `` widget: + +- ``: a basic element that shows some text and an optional icon and performs one or more specified actions when + clicked. + +- ``: an element used to interact with devices or services with an on/off binary state and toggle their state + upon user interaction. + +- ``: an element used to interact with devices or services with a numeric value included in a specified range. + +- ``: an element used to display read-only values from custom devices, services or endpoints. + +Let's take an example where we want to build a widget to show and manage in one single component the devices and +controls in a living room. These include: + +- A TV connected to a Tp-Link Wi-Fi smart switch. + +- A Zigbee temperature sensor. + +- A Z-Wave dimmer. + +- Music playback control. + +A widget that displays and controls these features can be written as it follows: + +```xml + + + + +

Living Room

+ + + + + + + + + + + + + TV Switch + + + + self.refresh() + + + + + + self.value = Object.values(await self.request('switch.tplink.status')) + .filter((dev) => dev.name === 'TV Switch')[0].on + + + + + + + + + VALUE_ID_ON_NET + {{ self.value }} + + + + + + self.value = await self.request('zwave.get_value', + {id_on_network: 'VALUE_ID_ON_NET'}).data + + + + if (event.value.id_on_network === 'VALUE_ID_ON_NET') + self.value = event.value.data + + + + + + + + + self.value = await self.request('zigbee.mqtt.device_get', + {'device': 'Temperature Sensor', 'property': 'temperature'}).temperature + + + + if (event.device === 'Temperature Sensor' && event.properties.temperature != null) + self.value = event.properties.temperature + + + +
+
+
+``` + +A few words on what's happening here: + +- The `` widget, under the hood, is a Vue template. This means that you can easily embed your custom HTML + into it. + +- Each element should have a `name` (displayed on the UI) and can optionally have either an `icon-class` or an + `icon-url` - the former would select a FontAwesome icon class for the element, the latter an icon URL. You can also + use `icon-color` when using `icon-class` to change the icon's color. + +- Elements usually have an `` tag, which can contain one or more `` tags representing the actions to + execute upon user interaction. + +- Each `` tag can also have one or more child tags, each representing an argument + to be passed to the action. + +- An `` tag can optionally have a `` or an `` tag, containing a JavaScript routine to be + executed respectively before or after the actions are run. In the example above, `` runs `self.refresh()` on + the `` tag so that the value is updated after user interaction. + +- You can access the reference to the element in your JavaScript code through the `self` object. Each element usually + has a `value` property (binary state in the case of a switch, numeric value in the case of a slider or sensor, etc.) + that can be read and modified by your snippets. + +- You can also embed the current `value` property (or any other variable or property) in an action argument through the + following syntax: `{{ self.value }}`. + +- The `self` object also has a `.request()` method that runs an action through `backend.http`. It takes two arguments: + the action name and an optional object with its arguments. + +- All the custom JS snippets are automatically wrapped inside of an `async` function, so you can use `await` inside of + them. + +- An element can also have one or more `` defined as JavaScript snippets to run when a particular event + occurs. Available handler tags: + + - ``: Handler to be called when the element is mounted and at regular intervals, specified by the `interval` + parameter (in seconds). This handler can also be programmatically called from other snippets through + `self.refresh()`. + + - ``: Handler called when the element is first mounted. + + - ``: Handler called when a specific platform event is received - the type of the event can be specified with + the `type` parameter. In the example above, we have defined an event handler on `ZwaveValueChangedEvent` events, so + that the element will be updated when the Z-Wave dimmer value gets updated, and one on + `ZigbeeMqttDevicePropertySetEvent` events to update the widget when a new temperature value is received. + +- An `event` object is passed to the event handlers and it can be accessed from your snippets. + +This is all you need to know to create your custom dashboards - feel free to look in the documented properties of the +widgets for more advanced use cases. # RSS feeds backend @@ -438,14 +776,14 @@ socket.onmessage = (msg) => { console.log(msg); }; -var msg = {"type":"request", "target":"hostname", "action":"plugin.action"}; +var msg = {"type":"request", "action":"plugin.action"}; socket.send(JSON.stringify(msg)); ``` Or through command-line tools like [wscat](https://www.npmjs.com/package/wscat): ```shell -wscat -w 0 -c 'ws://turing:8765' -x '{"type":"request", "target":"hostname", "action":"light.batsignal.on"}' +wscat -w 0 -c 'ws://turing:8765' -x '{"type":"request", "action":"light.batsignal.on"}' ``` # TCP backend @@ -464,7 +802,7 @@ backend.tcp: After enabling and restarting Platypush you can easily test this backend with tools like telnet or netcat: ```shell -echo -n '{"type":"request", "target":"hostname", "action":"plugin.action"}' | nc hostname 5555 +echo -n '{"type":"request", "action":"plugin.action"}' | nc hostname 5555 ``` # Pushbullet backend @@ -651,7 +989,7 @@ You can also communicate the other way around: you can programmatically send pus You can also connect [IFTTT](https://ifttt.com) to Platypush actions by leveraging Pushbullet. For example, you can create an applet triggered on sunset (date/time channel) to turn on the lights by sending a push like this to your Platypush device: ```json -{"type":"request", "target":"hostname", "action":"light.hue.on"} +{"type":"request", "action":"light.hue.on"} ``` # Kafka backend @@ -830,8 +1168,13 @@ If you want to take a picture through the cURL interface: ```bash curl -XPOST -H 'Content-Type: application/json' \ - -d '{"type":"request", "target":"hostname", "action":"camera.pi.take_picture", "args": {"image_file":"/tmp/my_picture.jpg"}}' \ - http://hostname:8008/execute + -H "Authorization: Bearer $TOKEN" -d '{ + "type":"request", + "action":"camera.pi.take_picture", + "args": { + "image_file":"/tmp/my_picture.jpg" + } + }' http://hostname:8008/execute ``` # Sensor backends diff --git a/Plugins.md b/Plugins.md index c93837c..6e2c3b5 100644 --- a/Plugins.md +++ b/Plugins.md @@ -361,16 +361,6 @@ curl -XPOST -H 'Content-Type: application/json' \ http://hostname:8008/execute ``` -# Shell plugin - -[Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/shell.html) - -You can also run custom shell commands on the target machine through the `shell` plugin, that requires no configuration. Example of remote execution through the `pusher` script: - -```shell -pusher --target hostname --action shell.exec --cmd "uname -a" -``` - # HTTP requests plugin [Plugin reference](https://docs.platypush.tech/en/latest/platypush/plugins/http.request.html) diff --git a/Quickstart.md b/Quickstart.md index 170af85..3690a2c 100644 --- a/Quickstart.md +++ b/Quickstart.md @@ -369,21 +369,10 @@ This would be a sample snippet for an Apache Kafka configuration: ```yaml backend.kafka: - pusher: True # Default pusher backend server: server:9092 # Kafka server and port topic: platypush # Topic prefix. Note: platypush will create a topic for each device named . ``` -Note: specifying `pusher: True` on a backend configuration means that that backend will be the default one used to deliver requests or events to other nodes through the `pusher` script, if no `--backend` option is passed. - -## Local backend configuration - -```yaml -backend.local: - request_fifo: /tmp/platypush-requests.fifo - response_fifo: /tmp/platypush-responses.fifo -``` - ## Google Assistant configuration Follow the steps on the [Google Assistant SDK](https://github.com/googlesamples/assistant-sdk-python/tree/master/google-assistant-sdk) page and get the assistant sample running on your machine. @@ -456,4 +445,3 @@ Now you can take a more in-depth to look to the available: - [Plugins](plugins) - [Backends](backends) -