Skip to content

Backends

Fabio Manganiello edited this page Dec 30, 2018 · 9 revisions

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.

HTTP server

Backend reference

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.)

Configuration

Configuring the HTTP backend is quite easy. Add these lines to your ~/.config/platypush/config.yaml to get the web server running:

backend.http:
    port: 8008            # Default HTTP port
    websocket_port: 8009  # Default port for the websockets

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:

  • 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

cURL commands

Once you've got your web server running, you can easily send action requests to the Platypush plugins through cURL, Postman etc.

Example 1: play music through the MPD plugin:

curl -XPOST -H 'Content-Type: application/json' \
    -d '{"type":"request", "target":"hostname", "action":"music.mpd.play"}' \
    http://hostname:8008/execute

Example 2: turn on your lights through the Philips Hue plugin:

curl -XPOST -H 'Content-Type: application/json' \
    -d '{"type":"request", "target":"hostname", "action":"lights.hue.on", "args": {"groups": ["Living Room"]}}' \
    http://hostname:8008/execute

Example 3: run a configured procedure:

curl -XPOST -H 'Content-Type: application/json' \
    -d '{"type":"request", "target":"hostname", "action":"procedure.at_home"}' \
    http://hostname:8008/execute

Web panel

The HTTP backend provides you with a web panel that you can use to control your configured plugins. Just point your browser to http://hostname:8008 after enabling the HTTP backend to test it out.

You should see an interface that looks like this. The tabs will are linked to the plugins you have configured in your main config file, for those that provide a web panel tab. If a plugin doesn't require any configuration, you can still entry an explicit configuration line to enable it to notify the web panel to include it in the interface:

tts:
    # I'm fine with the default configuration but I want to make sure
    # that the tab is enabled in the web panel
    disabled: False

You can use the web panel to control your lights, music, video, sensors, motors, switches, and whatever is provided by the plugins.

Dashboard

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.

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 <BASE_URL>/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

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.

RSS feeds backend

Backend reference

Platypush comes with an http.poll backend that allows you to poll web resources (JSON endpoints, RSS feeds etc.) for new items.

Support for new items poll on JSON endpoints is still experimental, as I haven't yet figured out a general-purpose elegant way to do it. But you can use the backend for polling RSS feeds as well. The backend will poll the selected RSS sources for new items and store them on a local database. You can then build few things on top of that:

  • Show the news on your dashboard news carousel widget
  • Ask the assistant to read you the latest news
  • Get a notification whenever some magazine publishes a new article
  • Build a weekly PDF digest of a certain source
  • ...and so on

Sample configuration:

backend.http.poll:
    requests:
        -
            type: platypush.backend.http.request.rss.RssUpdates
            url: http://www.theguardian.com/rss/world
            title: The Guardian - World News
            poll_seconds: 120   # Seconds between two requests
            max_entries: 10     # Maximum number of entries to parse on each scan
        -
            type: platypush.backend.http.request.rss.RssUpdates
            url: http://www.physorg.com/rss-feed
            title: Phys.org
            poll_seconds: 120
            max_entries: 10
        -
            type: platypush.backend.http.request.rss.RssUpdates
            url: http://feeds.feedburner.com/Techcrunch
            title: Tech Crunch
            poll_seconds: 120
            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: 120
            max_entries: 10

You can also configure the backend to generate a digest of the new items it scans from each source - they will be saved under ~/.local/share/platypush/feeds/cache - and to extract the text out of the articles using the Mercury Reader API. After getting a Mercury API token, you can configure an RSS source to generate a feed containing the content of the new seen items like this:

        -
            type: platypush.backend.http.request.rss.RssUpdates
            url: http://feeds.feedburner.com/Techcrunch
            title: Tech Crunch
            mercury_api_key: YOUR_KEY
            digest_format: pdf  # or html
            poll_seconds: 120
            max_entries: 10

Assistant backend

Backend reference

The assistant backend allows you to interact with a built-in voice assistant. Only the Google Assistant is currently supported (sorry Amazon).

All you need to get a full-blown assistant with support for custom commands is any kind of computer with a microphone.

Follow the instructions on the Google Assistant SDK website to get started by enabling the Assistant API, get a credentials file and install the required dependencies.

Then enable the Assistant backend through a configuration like this:

backend.assistant.google:
    device_model_id: Platypush                                         # A unique device ID - default: Platypush
    credentials_file: ~/.config/google-oauthlib-tool/credentials.json  # Path to the JSON credentials file

Restart Platypush and test it out by saying Ok Google or Hey Google. Have fun.

You can also enable the Assistant plugin to programmatically start or stop the conversation without saying the hotword.

Assistant events

You can build event hooks on assistant events - on conversation start, end, timeout, on speech recognized, on response processed etc.

For example, to play some custom sound when the conversation starts or ends:

event.hook.AssistantConversationStarted:
    if:
        type: platypush.message.event.assistant.ConversationStartEvent
    then:
        action: shell.exec
        args:
            cmd: 'aplay /usr/share/sounds/conversation_start.wav'

event.hook.AssistantConversationEnded:
    if:
        type: platypush.message.event.assistant.ConversationEndEvent
    then:
        action: shell.exec
        args:
            cmd: 'aplay /usr/share/sounds/conversation_end.wav'

Or play the radio by just saying it using the Mopidy plugin + the TuneIn backend for Mopidy:

event.hook.PlayRadioAssistantCommand:
    if:
        type: platypush.message.event.assistant.SpeechRecognizedEvent
        phrase: "play (the)? radio"
    then:
        action: music.mpd.play
        args:
            resource: tunein:station:radio_id

Note the use of (the)? in the phrase filter. The phrase filter supports basic regular expressions, so the filter above would trigger the hook whether the assistant recognizes "play the radio" or "play radio" - and even if the phrase is recognized within the context of a larger sentence.

You can also extract named tokens out of the recognized phrase. Take a look at this example that enables you to search for a song or an album by saying the artist and the title and play the first matched result:

event.hook.SearchSongVoiceCommand:
    if:
        type: platypush.message.event.assistant.SpeechRecognizedEvent
        # Use the ${} notation to denote a portion of the recognized phrase to be extracted
        # until the next recognized token or the end of the string.
        phrase: "play ${title} by ${artist}"
    then:
        -
            action: procedure.search_and_play_song

procedure.sync.search_and_play_song:
    -
        # Clear the content of the current playlist
        action: music.mpd.clear
    -
        # Disable shuffle mode
        action: music.mpd.random
        args:
            value: 0
    -
        # Perform an mpd search. Note how we re-used the "title" and "artist"
        # context variables parsed from the voice assistant event
        action: music.mpd.search
        args:
            filter:
                - artist
                - ${artist}
                - any
                - ${title}
    -
        # Play the first of the search results above. Note how we re-used the
        # "output" context variable, that contains the output of the previous
        # action (an array in the case of `music.mpd.search`), to get the file id
        # of the first result and pass it to `music.mpd.play`
        action: music.mpd.play
        args:
            resource: ${output[0]['file']}

Or search and play YouTube videos:

event.hook.PlayYoutubeVideo:
    if:
        type: platypush.message.event.assistant.SpeechRecognizedEvent
        phrase: "play ${query} on youtube"
    then:
        action: video.omxplayer.search
        args:
            query: ${query}
            autoplay: True
            queue_results: True
            types:
                - youtube

Or a torrent (will first have to download it and then stream it):

event.hook.PlayTorrent:
    if:
        type: platypush.message.event.assistant.SpeechRecognizedEvent
        phrase: "play (the)? torrent ${query}"
    then:
        action: video.omxplayer.search
        args:
            query: ${query}
            autoplay: True
            queue_results: True
            types:
                - torrent

Or (of course) turn on the lights:

event.hook.LightsOnAssistantCommand:
    if:
        type: platypush.message.event.assistant.SpeechRecognizedEvent
        phrase: "turn on (the)? lights?"
    then:
        action: light.hue.on

Or start a light animation:

event.hook.LightsAnimationOnAssistantCommand:
    if:
        type: platypush.message.event.assistant.SpeechRecognizedEvent
        phrase: "start (the)? animation"
    then:
        action: procedure.LightsAnimationOnAssistantCommand

procedure.sync.LightsAnimationOnAssistantCommand:
    -
        action: light.hue.stop_animation
    -
        action: light.hue.animate
        args:
            animation: color_transition
            sat_range: [230,255]
            bri_range: [127,255]
            hue_range: [0,65535]

If you use the web panel or the dashboard you'll also notice that the assistant events (conversation start and end, speech recognized and processed response) will also be shown as pop-up notifications.

Redis backend

Backend reference

Redis is an in-memory data structure store. It can be used as an in-memory store, as a cache or as a message broker. Obviously, latter case is quite interesting when it comes to Platypush :)

Redis is also used heavily by some of our plugins and backends to communicate and synchronize properly, especially if the components live in different processes (for example, the web server) and need to exchange messages with the main process. Redis is a perfect candidate for the purpose. It has a low latency, and the server is lightweight enough to run even on a Raspberry Pi Zero without issues. It's therefore strongly recommended to enable both the Redis plugin and backend (and install a local Redis server) to take full advantage of Platypush features.

For instance, the web server backend leverages Redis to dispatch and receive inter-process messages over the websocket interface - used to deliver push notifications to the web clients.

After installing and starting a local Redis server, configure your backend:

backend.redis:
    queue: platypush_bus_mq  # Default queue where messages will be delivered
    redis_args:
        host: localhost      # Default
        port: 6379           # Default

Messages received over the configured queue (requests, responses or events) will be routed to the application bus. A typical use case is when you want to set up another script or application that runs its own logic and you want it to interact with some Platypush plugin - all you have to do is to push an action request in JSON format on the configured Redis queue.

MQTT backend

Backend reference

MQTT is a message-queue based protocol to exchange messages across devices. MQTT implementations like Paho MQTT, Mosquitto and Adafruit IO are quite popular for communication across IoT devices. You can interact with an MQTT service through this plugin to build any arbitrary complex message-based logic across your Platypush devices. The asynchronous nature of MQTT makes it a better candidate over the HTTP plugin to deliver messages to other devices if you don't mind much about the response.

The MQTT backend will listen on a specific message queue (or topic in MQTT terminology) and, just like the Redis plugin, it will post any recognized Platypush JSON message (request, response or event) to the main application.

Example configuration:

backend.mqtt:
    host: mqtt_server        # IP or hostname that hosts the MQTT server
    port: 1883               # MQTT port
    topic: platypush_bus_mq  # Queue to listen on. Note that the hostname will be appended,
                             # so that each each device can listen on its own queue. Therefore
                             # the actual topic name will be "platypush_bus_mq/hostname"

You can now start sending messages to your backend through the MQTT plugin or another app, also running on another machine.

Websocket backend

Backend reference

You can send messages to Platypush over a websocket connection. Example configuration:

backend.websocket:
    port: 8765               # Websocket port (default: 8765)
    bind_address: 0.0.0.0    # Bind address (default: 0.0.0.0, accept any connection)
    ssl_cert: ~/.ssl/certs/localhost.pem  # Path to the PEM certificate file if you want to enable SSL (default: None)
    client_timeout: 60       # Close an inactive websocket client connection after these many seconds.
                             # A zero-value will keep the connection alive until closure or client timeout
                             # (default: 60 seconds)

After enabling you can easily send messages to Platypush through your JavaScript code, for example:

var socket = new WebSocket('ws://hostname:8765');
socket.onmessage = (msg) => {
    console.log(msg);
};

var msg = {"type":"request", "target":"hostname", "action":"plugin.action"};
socket.send(JSON.stringify(msg));

Or through command-line tools like wscat:

wscat -w 0 -c 'ws://turing:8765' -x '{"type":"request", "target":"hostname", "action":"light.batsignal.on"}'

TCP backend

Backend reference

Platypush comes with a simple TCP socket-backend that will simply read JSON messages from a specified port, forward them to the bus and process the responses back on the client socket. Example configuration:

backend.tcp:
    port: 5555               # Listen port
    bind_address: 0.0.0.0    # Bind address (default: 0.0.0.0, accept any connection)
    listen_queue: 5          # Size of the TCP connections pool (default: 5)

After enabling and restarting Platypush you can easily test this backend with tools like telnet or netcat:

echo -n '{"type":"request", "target":"hostname", "action":"plugin.action"}' | nc hostname 5555

Pushbullet backend

Backend reference

Pushbullet is a quite cool piece of software to keep your devices in sync, exchange messages, synchronize clipboards and sms across devices, access remote files, and so on. You can install it as an Android or iPhone app, as a browser extension, or use it from your browser directly. It can be quite powerful if paired with Platypush - and it has the first backend I have developed as well. You can use the plugin in pair with the backend to do things like:

  • Send URLs, text and Platypush messages to your Android devices
  • Trigger Platypush actions through your Android device, wherever you are
  • Synchronize the clipboards
  • Synchronize your phone notifications to your Raspberry Pi
  • Send and receive pictures
  • ...and so on

To integrate your Pushbullet events with Platypush:

  1. Sign up or login to Pushbullet

  2. Create an API token

  3. Register the device you want to synchronize with Platypush - download the Pushbullet app on your Android or iOS device, or install the browser extension

  4. Enable the extra features you wish to have on your Pushbullet account - e.g. universal copy&paste to keep the clipboards in sync also with your Platypush devices, remote file access etc.

  5. Configure your Pushbullet backend on Platypush:

backend.pushbullet:
    token: YOUR_PUSHBULLET_TOKEN
    device: platypush   # Name of your Platypush virtual device on Pushbullet

Restart Platypush and perform some events that generate Pushbullet messages - try to send a note or a picture to your virtual Platypush device, get a notification on your Android phone or dismiss a notification, copy some text or URL if you enabled the universal copy&paste feature. You should be able to see the received event messages in the application logs (by default under ~/.local/log/platypush/platypush.log).

Example message trace when you copy some text on a device connected to your Pushbullet account:

{
   "type":"event",
   "target":"hostname",
   "origin":"hostname",
   "id":"123abc",
   "args":{
      "type":"platypush.message.event.pushbullet.PushbulletEvent",
      "source_user_iden":"USER_ID",
      "source_device_iden":"DEVICE_ID",
      "body":"Check out this link copied from my phone: https://www.google.com",
      "push_type":"clip"
   }
}

Message in case you send a Pushbullet text note to your Platypush device:

{
   "type":"event",
   "target":"hostname",
   "origin":"hostname",
   "id":"123abc",
   "args":{
      "type":"platypush.message.event.pushbullet.PushbulletEvent",
      "active":true,
      "iden":"NOTIFICATION_ID",
      "created":1532382991.8475788,
      "modified":1532382991.851993,
      "dismissed":false,
      "guid":"unique client notification id",
      "direction":"self",
      "sender_iden":"SENDER_ID",
      "sender_email":"myself@gmail.com",
      "sender_email_normalized":"myself@gmail.com",
      "sender_name":"My Name",
      "receiver_iden":"RECEIVED_ID",
      "receiver_email":"myself@gmail.com",
      "receiver_email_normalized":"myself@gmail.com",
      "target_device_iden":"TARGET_DEVICE_ID",
      "source_device_iden":"SOURCE_DEVICE_ID",
      "awake_app_guids":[
         "extension-25qrgzolngx"
      ],
      "body":"Take a look at this note!",
      "push_type":"note"
   }
}

Message in case you receive a push notification on one of your connected Android devices (in this case an Android message):

{
   "type":"platypush.message.event.pushbullet.PushbulletEvent",
   "source_device_iden":"SOURCE_DEVICE_ID",
   "source_user_iden":"SOURCE_USER_ID",
   "client_version":289,
   "dismissible":true,
   "icon":"base64 encoded jpeg icon",
   "title":"Facebook Friend sent a message",
   "body":"How are your plans for tonight?",
   "application_name":"Messenger",
   "package_name":"com.facebook.orca",
   "notification_id":"10000",
   "notification_tag":"NOTIFICATION_TAG",
   "conversation_iden":"{\"package_name\":\"com.facebook.orca\",\"tag\":\"NOTIFICATION_TAG\",\"id\":10000}",
   "push_type":"mirror"
}

Message processed when you send a file to your Platypush virtual device over Pushbullet:

{
   "active":true,
   "iden":"PUSH_ID",
   "created":1532383937.424952,
   "modified":1532383937.437808,
   "dismissed":false,
   "guid":"unique client notification id",
   "direction":"self",
   "sender_iden":"SENDER_ID",
   "sender_email":"myself@gmail.com",
   "sender_email_normalized":"myself@gmail.com",
   "sender_name":"My Name",
   "receiver_iden":"RECEIVED_ID",
   "receiver_email":"myself@gmail.com",
   "receiver_email_normalized":"myself@gmail.com",
   "target_device_iden":"TARGET_DEVICE_ID",
   "source_device_iden":"SOURCE_DEVICE_ID",
   "file_name":"My Picture 123.jpg",
   "file_type":"image/jpeg",
   "file_url":"https://dl2.pushbulletusercontent.com/My-Picture-123.jpg",
   "image_width":814,
   "image_height":726,
   "image_url":"https://lh3.googleusercontent.com/IMAGE_ID",
   "push_type":"file"
}

Also, if you enabled notification mirroring on your Pushbullet devices, then any new push notification will be shown on the Platypush web panel and dashboard as well.

Now you can start building your rules on Pushbullet events. A full example:

event.hook.OnPushbulletEvent:
    if:
        type: platypush.message.event.pushbullet.PushbulletEvent
    then:
        action: procedure.OnPushbulletEvent


procedure.sync.OnPushbulletEvent:
    # If it's a clipboard message coming from a device with universal copy&paste enabled,
    # then synchronize the text body to the system clipboard of the device where Platypush runs.
    # It basically extends the universal copy&paste also to your Platypush devices even if
    # they don't have the Pushbullet browser extension or app installed.
    - if ${context['event'].args['push_type'] == 'clip'}:
        -
            action: clipboard.copy
            args:
                text: ${context['event'].args['body']}

    # If it's a picture being sent over Pushbullet, then copy it on my USB hard drive
    - if ${context['event'].args['push_type'] == 'file' and context['event'].args['file_type'].startswith('image/')}:
        -
            action: shell.exec
            args:
                cmd: "wget -O \"/mnt/hd/images/${context['event'].args['file_name']}\" \"${context['event'].args['file_url']}\""

    # Back up to a local folder the text notes being sent to Platypush over Pushbullet
    - if ${context['event'].args['push_type'] == 'note'}:
        -
            action: shell.exec
            args:
                cmd: "cat <<EOF > \"/home/user/notes/${context['event'].args['iden']}\"\n${context['event'].args['body']}\nEOF"

You can also send raw Platypush messages (requests, responses and events) over Pushbullet as raw JSON. If Platypush can interpret a Pushbullet push as a valid JSON message, then it will route it to the main application bus.

Such feature is quite useful for example to execute plugin actions or deliver events to your Platypush devices through your Android device, using Tasker with the Pushbullet plugin. For instance, you can create a rule that sends a specific text to your Platypush device or a JSON request with a properly formatted request whenever your phone enters your home area, for example to turn on the lights or the heating.

You can also communicate the other way around: you can programmatically send pushes to Pushbullet from Platypush using the plugin and you can build rules in Tasker on your mobile device to execute specific actions depending on the received message - for example start ringing if you say "find my phone" to the assistant, play a song by URI on the Spotify app, open Google Maps with the directions from your home to a specific place, and so on.

You can also connect IFTTT 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:

{"type":"request", "target":"hostname", "action":"light.hue.on"}

Kafka backend

Backend reference

Apache Kafka is a distributed streaming platform that allows you to build flexible message-based interfaces across your devices.

You can connect Platypush to a Kafka broker server through this backend and configure it to listen for messages on a specific topic (default topic name: platypush.<device_id>).

Messages received over the topic will:

  • Be processed as Platypush messages (requests, responses or messages) if they are valid JSON-formatted messages
  • Trigger a KafkaMessageEvent that you can build event hooks on otherwise

The configuration is quite straightforward:

backend.kafka:
    server: host:9092  # Kafka broker server and port to connect to
    topic: platypush   # Default topic prefix to listen on. The actual topic name will be <topic>.<device_id>

MPD/Mopidy backend

Backend reference

You can use this backend to get events from your MPD/Mopidy music server, for instance when a new track is being played, when the playback is paused/resumed or when the current playlist changes.

Configuration:

backend.music.mpd:
    server: localhost  # MPD/Mopidy server
    port: 6600         # Server port (default: 6600)
    poll_seconds: 3    # How often you want to poll the server for updates (default: 3 seconds)

An example that sends a scrobble request to Last.FM when a new track is played:

event.hook.ScrobbleNewTrack:
    if:
        type: platypush.message.event.music.NewPlayingTrackEvent
    then:
        -
            action: lastfm.scrobble
            args:
                artist: ${track['artist']}
                title: ${track['title']}
        -
            action: lastfm.update_now_playing
            args:
                artist: ${track['artist']}
                title: ${track['title']}

MIDI backend

Backend reference

You can listen for events on a MIDI port. You can use to do things like connecting a MIDI keyboard or drumkit. You can set up cool things like controlling your house with your MIDI piano - with 88 keys you've got plenty of configuration choices :)

Backend configuration:

backend.midi:
    device_name: MIDI_device_name   # MIDI device name to listen for events
    midi_throttle_time: 0.5         # Set this (in seconds) if you want to throttle your MIDI messages.
                                    # Useful in case you want to connect MIDI events to some plugin
                                    # with a lower throughput and prevent flooding it.

Example that allows you to control the brightness of your Philips Hue lights using the slider on a connected MIDI controller:

event.hook.OnMidiEvent:
    if:
        type: platypush.message.event.midi.MidiMessageEvent
    then:
        action: procedure.OnMidiEvent

procedure.sync.OnMidiEvent:
    # In this case the slider we want to listen to for MIDI events is on Channel 1 (MIDI 0xba)
    # if they are related to main volume changes (MIDI message 2nd value: 7)
    - if ${context['event'].args['message'][0] == 0xb0 and context['event'].args['message'][1] == 7}:
        -
            action: light.hue.bri
            args:
                # MIDI values are between 0 and 127, Hue brightness is between 0 and 255.
                # Multiply the MIDI value by 2 to map it into the brightness space.
                value: ${message[2] * 2}
                groups:
                    - Living Room

Flic buttons backend

Backend reference

Flic buttons are clever smart buttons controlled over bluetooth. You can get the app and configure it to run anything on a button press - running Tasker actions, playing some media, make a phone call etc. - or you can get the Flic backend configured on Platypush to use the buttons to control actions on your computer or Raspberry instead of your phone.

The backend requires the available Flic SDK to be installed and the flicd daemon to be running. Then you'll have to pair your buttons with the Platypush device. Afterwards, you're ready to configure the backend and start creating some rules:

backend.button.flic:
    server: localhost   # Server where the flicd daemon runs

Some examples:

event.hook.MusicPauseFlicButton:
    if:
        type: platypush.message.event.button.flic.FlicButtonEvent
        btn_addr: 00:11:22:33:44:55   # Address of the button that will trigger this event
        sequence:                     # Sequence press
            - ShortPressEvent
    then:
        -
            action: music.mpd.pause   # Toggle playback play/pause

Note the use of the sequence filter on the event. The default Flic app supports by default three types of presses - short, long and double press - that means maximum three possible actions per button.

This backend gives you more freedom instead, you can configure your own custom sequences of short/long press actions (a long press is a press that lasts longer than 0.3 seconds), and even build your own "Morse code" to trigger actions - as long as it's practical and you can remember which sequence is for what of course :)

Another example that starts an assistant conversation when the button is pressed three times (short press):

event.hook.FlicButtonStartConversation:
    if:
        type: platypush.message.event.button.flic.FlicButtonEvent
        btn_addr: 00:11:22:33:44:55
        sequence:
            - ShortPressEvent
            - ShortPressEvent
            - ShortPressEvent
    then:
        action: assistant.google.start_conversation

Camera backend

Raspberry Pi camera backend

Backend reference

Control your RaspberryPi camera, take pictures or record either to file or to a network stream through this backend.

You can programmatically control this backend (start and stop recording or take pictures) through the Pi Camera plugin.

Sample configuration:

backend.camera.pi:
    listen_port: 2222    # TCP camera listen port
    start_recording_on_startup: true  # If set (default) then the camera will start recording at startup. Otherwise,
                                      # you can start recording with a call to the `camera.pi.start_recording` action

See the online reference for all the supported camera options.

Once restarted Platypush you can connect to your Pi camera through a remote client using for instance vlc or mplayer:

# VLC
vlc tcp/h264://hostname:2222

# MPlayer
mplayer -fps 200 -demuxer h264es ffmpeg://tcp://hostname:2222

If you want to take a picture through the cURL interface:

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

Sensor backends

Platypush comes with a wide selection of backends to interact with sensors of various types. And you can easily create your own backend to interact with a new class of sensors by extending the base sensor backend and implement the get_measurement method to get the values. Any sensor backend gets a configuration interface that allows you to specify the poll interval and the thresholds:

backend.sensor.sensor_name:
    poll_seconds: 2   # How often get_measurement will be called to check for new data
    thresholds:       # Map of thresholds for your sensors. It assumes that get_measurement returns
                      # a dictionary like {"sensor_1":0.1, "sensor_2":0.2, ...}.
                      # If the values go above or below one of the configured thresholds,
                      # then either a SensorDataAboveThresholdEvent or SensorDataBelowThresholdEvent
                      # will be triggered.
        temperature: 25.0
        humidity: 60.0
        luminosity: 10.0

A sensor backend will trigger three types of events:

Infrared sensors

ZeroBorg backend

Backend reference

The ZeroBorg is a nice piece of circuitry that pairs quite well with any Raspberry and allows you to easily control motors. It also comes with a built-in infrared sensor. If this backend is enabled, it will listen for infrared events (e.g. from one of your remotes) that you can map to run any custom action.

Configuration to enable the backend:

backend.sensor.ir.zeroborg:
    disabled: False

Then restart Platypush and check the application logs while you generate infrared events through e.g. a tv or stereo remote. You'll see the mapped infrared message in the logs as a hexadecimal string:

Received event: {"id": "...", "args": {"message": "FFFF805151445445154455145444", "type": "platypush.message.event.sensor.ir.IrKeyDownEvent"}, "origin": "hostname", "target": "hostname", "type": "event"}
Received event: {"id": "...", "args": {"message": "FFFF", "type": "platypush.message.event.sensor.ir.IrKeyUpEvent"}, "origin": "hostname", "target": "hostname", "type": "event"}

You can then build event hooks when a specific key is pressed:

event.hook.OnRemoteBlueLightPress:
    if:
        type: platypush.message.event.sensor.ir.IrKeyDownEvent
        message: FFFF805151445445154455145444
    then:
        action: light.hue.on

MCP3008

Backend reference

The MCP3008 is a very useful ADC converter that you can use to read data from multiple analog sources and transmit them to a digital device that doesn't support direct GPIO analog input (like the Raspberry Pi). You can use it instead of an Arduino or serial device if you want lower latency, or a more compact or cheaper solution.

Sample configuration:

backend.sensor.mcp3008:
    poll_seconds: 2

Note that this backend requires the MCP3008 plugin to be configured as well.

You can now configure event hooks based on the events you get:

# Save new sensor measurements to a database table
event.hook.OnSensorData:
    if:
        type: platypush.message.event.sensor.SensorDataChangeEvent
    then:
        action: db.insert
        engine: sqlite:////home/user/sensors.db
        table: measurements
        records:
            - temperature: ${data['temperature']}

# Or deliver it to an Adafruit IO feed
event.hook.OnSensorData_2:
    if:
        type: platypush.message.event.sensor.SensorDataChangeEvent
    then:
        action: adafruit.io.send
        args:
            feed: house-temperature
            value: ${data['temperature']}

# Turn on a fan connected to a smart switch if the temperature goes above threshold
event.hook.OnSensorAboveThreshold:
    if:
        type: platypush.message.event.sensor.SensorDataAboveThresholdEvent
    then:
        action: switch.tplink.on
        args:
            device: fan

Arduino and serial backend

Backend reference

It's possible to poll for sensor events on a serial interface as well, e.g. through an Arduino or compatible device. The only advice is to program your microcontroller so that it returns sensors data as a JSON string over the serial interface, e.g.

{"temperature":22.5, "humidity":45, "luminosity":35.0}

Then all you have to do is to configure the serial plugin to point to your serial device and enable the serial backend like you would do with any other sensors backend:

backend.sensor.sensor_name:
    poll_seconds: 2   # How often get_measurement will be called to check for new data
    thresholds:       # Map of thresholds for your sensors. It assumes that get_measurement returns
                      # a dictionary like {"sensor_1":0.1, "sensor_2":0.2, ...}.
                      # If the values go above or below one of the configured thresholds,
                      # then either a SensorDataAboveThresholdEvent or SensorDataBelowThresholdEvent
                      # will be triggered.
        temperature: 25.0
        humidity: 60.0
        luminosity: 10.0

You can now configure your event hooks on SensorDataChangeEvent, SensorDataAboveThresholdEvent and SensorDataBelowThresholdEvent events.

inotify backend

Backend reference

inotify is a Linux kernel subsystem that allows you to monitor events on your filesystem (file opened, changed, created etc.).

Platypush provides an inotify backend that can trigger events whenever a monitored filesystem resource (file or directory) is opened, changed, created, removed etc.

Example configuration:

backend.inotify:
    watch_paths:    # Paths (files or directories) to be watched for events
        - /home/user/my_dir
        - /etc/passwd
        - /mnt/hd/media

You can now create event hooks whenever a file is changed, opened etc.:

# Send me an email whenever /etc/passwd is changed
event.hook.OnFileChanged:
    if:
        type: platypush.message.event.path.PathModifyEvent
        path: /etc/passwd
    then:
        action: google.mail.compose
        args:
            sender: me@gmail.com
            to: me@gmail.com
            subject: /etc/passwd file changed
            body: The /etc/passwd file has been changed
            files:
                - /etc/passwd

Smart cards backend

Backend reference

You can use the smart card backend to read smart card (NFC) events through a USB or compatible NFC card reader.

Configuration:

backend.scard:
    atr:    # List of ATRs (Answer To Reset, a standard answer provided by smart cards
            # conforming to the ISO/IEC 7816 standard that identifies the card's
            # producer, model and state) tha to react on. If not specified (default),
            # then Platypush will react on events from any card, otherwise only
            # for these selected ATRs
        - ATR1
        - ATR2
        - ATR3

Remember that if you want to enable a backend with no configuration all you have to do is configure it with the disabled: false line.

So far this backend will trigger events only upon detected/removed card, adding the detected ATR to the event context.

You can get the ATR of a smart card with an NFC utils app, or you can approach the card to the reader while Platypush is running and then get the ATR from the triggered event.

You can then build event hooks like these, that emulate the "hotel room" lights behaviour through a smart card:

# Turn on the lights when the reader detects a smart card with a specific ATR
event.hook.OnSmartCardDetected:
    if:
        type: platypush.message.event.scard.SmartCardDetectedEvent
        atr: ATR1
    then:
        action: light.hue.on

# Turn off the lights when the card is removed from the reader
event.hook.OnSmartCardRemoved:
    if:
        type: platypush.message.event.scard.SmartCardRemovedEvent
        atr: ATR1
    then:
        action: light.hue.off

You cannot however, as of now, use the backend to parse the content of the smart card and build action based on the content. The reason is that such features are hard to achieve through the pyscard library alone, while it's relatively easy through the nfc library. However the nfc library does not work with Python 3 yet. As soon as the compatibility is fixed though it's very likely that more granular events based on the card content will be available.

For now, you can for instance put your own custom Platypush commands on a smart card (e.g. to control lights, music or automate anything you want) through this procedure:

  • Use an app like NFC Tools Pro to write your NFC tags. Write text records containing valid Platypush commands as JSON
  • Use this script (run it with Python 2) that will listen for NFC events, parse the records on the card and dispatch them to Platypush if they are recognized

Weather forecast backend

Backend reference