{"id":13585155,"url":"https://github.com/blacklight/platypush","last_synced_at":"2025-12-13T19:25:16.084Z","repository":{"id":26585929,"uuid":"109421017","full_name":"blacklight/platypush","owner":"blacklight","description":"A versatile and extensible platform for automation with hundreds of supported integrations","archived":false,"fork":false,"pushed_at":"2025-04-30T20:31:25.000Z","size":126522,"stargazers_count":300,"open_issues_count":4,"forks_count":21,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-05-15T12:06:31.827Z","etag":null,"topics":["automation","bluetooth","dashboard","home-automation","iot","mqtt","platform","pushbullet","raspberry-pi","sensors","voice-assistant","websocket","zigbee","zwave"],"latest_commit_sha":null,"homepage":"https://platypush.tech","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/blacklight.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-11-03T16:56:24.000Z","updated_at":"2025-04-30T20:31:29.000Z","dependencies_parsed_at":"2024-03-08T20:19:29.197Z","dependency_job_id":"cbafa1f3-fbb5-4313-88af-454fd80009d1","html_url":"https://github.com/blacklight/platypush","commit_stats":null,"previous_names":["blacklight/runbullet"],"tags_count":116,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blacklight%2Fplatypush","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blacklight%2Fplatypush/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blacklight%2Fplatypush/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blacklight%2Fplatypush/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/blacklight","download_url":"https://codeload.github.com/blacklight/platypush/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254337613,"owners_count":22054253,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","bluetooth","dashboard","home-automation","iot","mqtt","platform","pushbullet","raspberry-pi","sensors","voice-assistant","websocket","zigbee","zwave"],"created_at":"2024-08-01T15:04:46.281Z","updated_at":"2025-12-13T19:25:11.018Z","avatar_url":"https://github.com/blacklight.png","language":"Python","funding_links":["https://github.com/sponsors/blacklight","https://paypal.me/fabiomanganiello"],"categories":["Python"],"sub_categories":[],"readme":"![Platypush logo](https://static.platypush.tech/images/platypush-banner.png)\n\n[![Build Status](https://ci-cd.platypush.tech/api/badges/platypush/platypush/status.svg)](https://ci-cd.platypush.tech/platypush/platypush)\n[![Issues](https://img.shields.io/gitea/issues/open/platypush/platypush?gitea_url=https://git.platypush.tech)](https://git.platypush.tech/platypush/platypush/issues)\n[![Github stars](https://img.shields.io/github/stars/blacklight/platypush?style=flat\u0026logo=Github)](https://github.com/blacklight/platypush)\n[![Github forks](https://img.shields.io/github/forks/blacklight/platypush?style=flat\u0026logo=Github)](https://github.com/blacklight/platypush)\n[![Last Commit](https://img.shields.io/github/last-commit/BlackLight/platypush.svg)](https://git.platypush.tech/platypush/platypush/commits/branch/master)\n[![Join chat on Matrix](https://img.shields.io/matrix/platypush:matrix.platypush.tech.svg?server_fqdn=matrix.platypush.tech\u0026label=chat\u0026logo=matrix)](https://matrix.to/#/#platypush:matrix.platypush.tech)\n\n[![pip version](https://img.shields.io/pypi/v/platypush.svg?style=flat)](https://pypi.python.org/pypi/platypush/)\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/1ecffafe2b5d4f1db215bed2a95a8a7b)](https://app.codacy.com/gh/blacklight/platypush/dashboard?utm_source=gh\u0026utm_medium=referral\u0026utm_content=\u0026utm_campaign=Badge_grade)\n[![CodeFactor](https://www.codefactor.io/repository/github/blacklight/platypush/badge)](https://www.codefactor.io/repository/github/blacklight/platypush)\n[![Contributions](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://git.platypush.tech/platypush/platypush/src/branch/master/CONTRIBUTING.md)\n[![License](https://img.shields.io/github/license/BlackLight/platypush.svg)](https://git.platypush.tech/platypush/platypush/src/branch/master/LICENSE.txt)\n[![Sponsor](https://img.shields.io/github/sponsors/blacklight)](https://github.com/sponsors/blacklight)\n\n[![Blog](https://img.shields.io/badge/-Blog-9532CA?logo=LiveJournal)](https://blog.platypush.tech)\n[![Documentation](https://img.shields.io/badge/-Docs-022AC5?logo=GitBook)](https://docs.platypush.tech)\n[![Wiki](https://img.shields.io/badge/-Wiki-00AA40?logo=Docs.rs)](https://git.platypush.tech/platypush/platypush/wiki)\n[![Join chat on IRC](https://img.shields.io/badge/-IRC-4542CA?logo=LiveChat)](irc://platypush@irc.platypush.tech:6697)\n[![Support](https://img.shields.io/badge/-PayPal-CACA30?logo=PayPal)](https://paypal.me/fabiomanganiello)\n\n\u003c!-- toc --\u003e\n\n- [Introduction](#introduction)\n  * [What it can do](#what-it-can-do)\n- [Core concepts](#core-concepts)\n- [A few examples](#a-few-examples)\n  * [Turn on the lights when I say so](#turn-on-the-lights-when-i-say-so)\n  * [Play the music when I say so](#play-the-music-when-i-say-so)\n  * [Turn on the lights when the sun goes down](#turn-on-the-lights-when-the-sun-goes-down)\n  * [Event matching and token extraction through hook templates](#event-matching-and-token-extraction-through-hook-templates)\n  * [Complex hook conditions](#complex-hook-conditions)\n  * [Turn off the lights at 1 AM](#turn-off-the-lights-at-1-am)\n  * [Greet me with lights and music when I come home](#greet-me-with-lights-and-music-when-i-come-home)\n- [Core Installation](#core-installation)\n  * [System package manager installation](#system-package-manager-installation)\n    + [Arch Linux](#arch-linux)\n    + [Debian/Ubuntu](#debianubuntu)\n    + [Fedora](#fedora)\n  * [`pip`](#pip)\n  * [Docker](#docker)\n    + [Base image installation](#base-image-installation)\n    + [The docker-compose way](#the-docker-compose-way)\n    + [Exposing host devices](#exposing-host-devices)\n  * [Manual installation](#manual-installation)\n- [Plugins installation](#plugins-installation)\n  * [`pip`](#pip-1)\n  * [Web interface](#web-interface)\n  * [Docker (`platydock`)](#docker-platydock)\n  * [Virtual environment (`platyvenv`)](#virtual-environment-platyvenv)\n  * [Manual installation](#manual-installation-1)\n- [HTTP API](#http-api)\n  * [The _Execute_ tab](#the-_execute_-tab)\n- [Websocket API](#websocket-api)\n  * [Events](#events)\n  * [Actions](#actions)\n- [Web hooks](#web-hooks)\n- [Entities](#entities)\n- [Configuration](#configuration)\n  * [Configuration file](#configuration-file)\n    + [Scripts directory](#scripts-directory)\n    + [Splitting configuration on multiple files](#splitting-configuration-on-multiple-files)\n  * [Working directory](#working-directory)\n  * [Database](#database)\n  * [Device ID](#device-id)\n  * [systemd service](#systemd-service)\n  * [Redis](#redis)\n  * [nginx](#nginx)\n- [The Web interface](#the-web-interface)\n  * [Other Web panels](#other-web-panels)\n  * [Dashboards](#dashboards)\n  * [PWA support](#pwa-support)\n- [Two-factor authentication](#two-factor-authentication)\n- [Mobile app](#mobile-app)\n- [Browser extension](#browser-extension)\n- [Tests](#tests)\n\n\u003c!-- tocstop --\u003e\n\n## Introduction\n\nPlatypush is a general-purpose and extensible platform for automation across\nmultiple services and devices with [hundreds of supported\nintegrations](https://docs.platypush.tech/plugins.html).\n\nIt enables users to create their own self-hosted pieces of automation based on\nevents (*if this happens then do that*)\nand it provides a comprehensive and customizable user interface that collects\neverything you need to visualize and control under one roof.\n\nIt borrows concepts from [IFTTT](https://ifttt.com),\n[Tasker](https://tasker.joaoapps.com/) and [Home\nAssistant](https://www.home-assistant.io/) to provide an environment where the\nuser can easily connect things together. It focuses on an automation-as-code\nand API-first approach, offering power users great flexibility in customizing\ntheir routines.\n\nIt's built with compatibility and flexibility in mind, and it can easily run on\nany device that can run a Python interpreter - from a Raspberry Pi, to an old\nsmartphone, to a beefy server.\n\n### What it can do\n\nYou can use Platypush to do things like:\n\n- [Control your smart\n  lights](https://blog.platypush.tech/article/Ultimate-self-hosted-automation-with-Platypush)\n- [Control your music across multiple\n  devices](https://blog.platypush.tech/article/Build-your-open-source-multi-room-and-multi-provider-sound-server-with-Platypush-Mopidy-and-Snapcast)\n- [Create custom and privacy-secure voice assistants that run custom hooks on\n  your\n  phrases](https://blog.platypush.tech/article/Build-custom-voice-assistants)\n- Build integrations between sensors,\n  [cameras](https://docs.platypush.tech/platypush/plugins/camera.pi.html),\n  [microphones](https://docs.platypush.tech/platypush/plugins/sound.html)\n  and [machine learning\n  models](https://docs.platypush.tech/platypush/plugins/tensorflow.html)\n  to create smart pieces of automation for e.g. [people\n  detection](https://blog.platypush.tech/article/Detect-people-with-a-RaspberryPi-a-thermal-camera-Platypush-and-a-pinch-of-machine-learning)\n  or [sound\n  detection](https://blog.platypush.tech/article/Create-your-smart-baby-monitor-with-Platypush-and-Tensorflow)\n- [Display events from your calendars and build automation on\n  them](https://docs.platypush.tech/platypush/plugins/calendar.html)\n- [Build automation routines and visualizations from your sensors\n  data](https://blog.platypush.tech/article/How-to-build-your-personal-infrastructure-for-data-collection-and-visualization)\n- [Control and automate a self-built\n  robot](https://docs.platypush.tech/platypush/plugins/gpio.zeroborg.html)\n- [Deliver automated newsletters from custom RSS\n  digests](https://blog.platypush.tech/article/Deliver-customized-newsletters-from-RSS-feeds-with-Platypush)\n- [Synchronize the clipboards on your\n  devices](https://docs.platypush.tech/platypush/plugins/clipboard.html)\n- [Implement custom text-to-speech\n  logic](https://docs.platypush.tech/platypush/plugins/tts.html)\n- [Build any kind of automation routines with your Android device using\n  Tasker](https://blog.platypush.tech/article/How-to-build-your-personal-infrastructure-for-data-collection-and-visualization)\n- Play local\n  videos,\n  YouTube videos and torrent media from any device and service, to any device, with support for [Kodi](https://docs.platypush.tech/platypush/plugins/media.kodi.html), [Chromecast](https://docs.platypush.tech/platypush/plugins/media.chromecast.html), [VLC](https://docs.platypush.tech/platypush/plugins/media.vlc.html), [Jellyfin](https://docs.platypush.tech/platypush/plugins/media.jellyfin.html), [Plex](https://docs.platypush.tech/platypush/plugins/media.plex.html) and more\n- [Get weather forecast events for your location and build automation routines on them](https://docs.platypush.tech/platypush/plugins/weather.darksky.html)\n- [Create a custom single hub for Zigbee and Z-Wave smart devices](https://blog.platypush.tech/article/Transform-a-RaspberryPi-into-a-universal-Zigbee-and-Z-Wave-bridge)\n- Build your own web dashboard with calendar, weather, news and music controls\n  (basically, anything that has a Platypush web widget)\n- ...and much more (basically, anything that comes with a [Platypush plugin](https://docs.platypush.tech)).\n\nThe full list of available integrations is available at\n[docs.platypush.tech](https://docs.platypush.tech), which also contains a more\nin-depth wiki on the features supported by the platform.\n\nThe wiki is also mirrored on\n[git.platypush.tech](https://git.platypush.tech/platypush/platypush/wiki).\n\n[The blog](https://blog.platypush.tech) regularly publishes content with\nstep-by-step tutorials and recipes.\n\n## Core concepts\n\nThe foundations of Platypush rest on a few simple building blocks that offer\ngreat versatility to build arbitrarily complex automation routines:\n\n- 🧩 **Plugins**. Plugins are the bread-and-butter of the platform. Each plugin\n  exposes an API to interact with an integration - there are plugins for media\n  players and devices, calendars, sensors, voice assistants, smart devices,\n  cloud services, and so on.\n\n  - ⏻ **Actions**. These are the methods of a plugin transparently exposed to the\n    user over a simple JSON RPC API, and they are always expressed in the\n    format `\u003cplugin_name\u003e.\u003caction_name\u003e`. For instance,\n    [`light.hue.on`](https://docs.platypush.tech/platypush/plugins/light.hue.html#platypush.plugins.light.hue.LightHuePlugin.on)\n    can be used to turn on Philips Hue-compatible lights,\n    [`media.vlc.play`](https://docs.platypush.tech/platypush/plugins/media.vlc.html#platypush.plugins.media.vlc.MediaVlcPlugin.play)\n    to play some media on a VLC player, etc.\n\n  - ⚙️ **Backends**. These are special integrations whose main purpose is to\n    deliver messages to the main application. The principal one is the\n    [`http` backend](https://docs.platypush.tech/platypush/backend/http.html),\n    which exposes the HTTP and WebSocket APIs, serves the main UI and is used\n    by several integrations to provide additional services. A [`nodered`\n    backend](https://docs.platypush.tech/platypush/backend/nodered.html) is\n    also available to expose a Platypush action component to a Node-RED\n    instance, as well as an internal [`redis`\n    backend](https://docs.platypush.tech/platypush/backend/redis.html) and an\n    (insecure) [`tcp`\n    backend](https://docs.platypush.tech/platypush/backend/tcp.html) to receive\n    raw messages.\n\n- 📧 **Events**. Plugins emit _events_ whenever some particular conditions happen\n  for example, a [new media track is\n  played](https://docs.platypush.tech/platypush/events/media.html#platypush.message.event.media.MediaPlayEvent),\n  a [voice assistant conversation has\n  started](https://docs.platypush.tech/platypush/events/assistant.html#platypush.message.event.assistant.ConversationStartEvent),\n  and so on.\n\n  - 🪝 **Hooks**. Users can define custom callbacks on events in the form of\n    *hooks*. Hooks can contain lists of actions to execute when a certain event\n    matches the hook *condition*, or any kind of custom logic - for example,\n    *send a notification on my phone when the presence sensor in my garage goes\n    on*, or *use a TTS plugin to process the digest of the latest RSS feeds if\n    I tell the voice assistant \"play the news\"*. Event hooks can be expressed\n    either in YAML format or as Python runtime scripts.\n\n- 📜 **Procedures**. Procedures are custom snippets of logic that can be invoked\n  using the Platypush API. For example, you can define an `at_home` procedure\n  that will be executed when you arrive home, which turns on the lights, plays\n  the music, sets the thermostat temperature etc., and then call it using the\n  Platypush API from any device. Like event hooks, procedures can be defined\n  both in YAML format (good if you just want to execute lists of actions\n  without much added logic), or as Python scripts.\n\n  - 🕗 **Cronjobs**. Cronjobs are special procedures that can be executed either\n    at regular intervals (the [UNIX cron\n    syntax](https://linuxhandbook.com/crontab/) is supported), or at a specific\n    time (one-shot). Just like procedures, they can be defined either in YAML or\n    as Python scripts.\n\n- 💡 **Entities**. Some plugins expose generic _entities_ - such a lights,\n  sensors, media players, switches, voice assistants etc. These entities can be\n  controlled through [the same generic\n  APIs](https://docs.platypush.tech/platypush/plugins/entities.html), emit [the\n  same types of\n  events](https://docs.platypush.tech/platypush/events/entities.html), can\n  be controlled from the same Web view or dashboard, and their state is\n  persisted across runs.\n\n## A few examples\n\nThe bulk of the configuration of Platypush lives under the `config.yaml` file.\nAn extensive [`config.yaml`\nexample](https://git.platypush.tech/platypush/platypush/src/branch/master/platypush/config/config.yaml)\nis provided in the repo. All the sections are optional - the only one enabled by\ndefault is the HTTP server, `backend.http`, but that is optional too.\n\nLet's take an example where we want to control the following entities:\n\n- A Philips Hue bridge and its connected smart lights.\n\n- An on-device voice assistant (we'll consider the Google Assistant in this\n  example as it's the easiest to configure, although Google deprecated the\n  Assistant libraries long ago).\n\n- A compatible music player - we'll consider MPD/Mopidy in this example as they\n  are the ones best supported in Platypush, and Mopidy also offers plugins with\n  basically any audio backend out there.\n\nWe'll need the following plugins enabled in the `config.yaml`:\n\n- [`light.hue`](https://docs.platypush.tech/platypush/plugins/light.hue.html)\n- [`assistant.google`](https://docs.platypush.tech/platypush/plugins/assistant.google.html)\n- [`music.mopidy`](https://docs.platypush.tech/platypush/plugins/music.mopidy.html)\n  or\n  [`music.mpd`](https://docs.platypush.tech/platypush/plugins/music.mpd.html)\n  (they expose the same API)\n\nThe documentation pages of these plugins already provide some comprehensive\nconfiguration snippets that you can use.\n\nThe most basic configuration would be something like this:\n\n```yaml\n# Enable it if you want the enable the HTTP API and the Web interface\nbackend.http:\n\nlight.hue:\n  # IP/hostname of the Hue bridge\n  bridge: 192.168.1.10\n  # Default groups that should be targeted by actions if none is specified\n  # (default: all lights/groups)\n  groups:\n    - Living Room\n\n# Check the plugin documentation on how to get the credentials\nassistant.google:\n\nmusic.mopidy:  # Or music.mpd\n  # IP/hostname of the MPD/Mopidy server\n  host: 192.168.1.2\n```\n\nNow that we have our integrations configured, let's build some automation routines.\n\n### Turn on the lights when I say so\n\nIn this case we will have to create a hook that listens to a\n[`SpeechRecognizedEvent`](https://docs.platypush.tech/platypush/events/assistant.html#platypush.message.event.assistant.SpeechRecognizedEvent)\ntriggered by the assistant - for example, when we say \"_OK, Google_\" followed\nby \"_turn on the lights_\".\n\nWe can declare the hook in YAML format directly in the `config.yaml`, or in one\nof the files included in it through the `include:` directive:\n\n```yaml\nevent.hook.turn_lights_on_voice_command:\n  if:\n    type: platypush.message.event.assistant.SpeechRecognizedEvent\n    # Note that a minimal regex-like syntax is supported here.\n    # This condition matches both a phrase that contains\n    # \"turn on the lights\" and one that contains \"turn on lights\"\n    phrase: \"turn on (the)? lights\"\n  then:\n    - action: light.hue.on\n      args:\n      groups:\n        - Living Room\n```\n\nOr we can declare the hook in a Python script - you just have to create a `.py`\nfile (e.g. `lights.py`) under a `scripts` directory located under the same\nfolder as your `config.yaml`:\n\n```python\nfrom platypush import run, when\nfrom platypush.events.assistant import SpeechRecognizedEvent\n\n@when(SpeechRecognizedEvent, phrase=\"turn on (the)? lights\")\ndef lights_on_voice_command():  # Also accepts an optional `event` argument\n  run('light.hue.on', groups=['Living Room'])\n```\n\nOr, using the `get_plugin` API:\n\n```python\nfrom platypush import get_plugin, when\nfrom platypush.events.assistant import SpeechRecognizedEvent\n\n@when(SpeechRecognizedEvent, phrase=\"turn on (the)? lights\")\ndef lights_on_voice_command():\n  get_plugin('light.hue').on(groups=['Living Room'])\n```\n\n### Play the music when I say so\n\nThe approach is similar for a \"_play the music_\" voice command. YAML:\n\n```yaml\nevent.hook.play_music_voice_command:\n  if:\n    type: platypush.message.event.assistant.SpeechRecognizedEvent\n    phrase: \"play (the)? music\"\n  then:\n    - action: music.mopidy.play\n```\n\nPython:\n\n```python\nfrom platypush import run, when\nfrom platypush.events.assistant import SpeechRecognizedEvent\n\n@when(SpeechRecognizedEvent, phrase=\"play (the)? music\")\ndef lights_on_voice_command():\n  run('music.mopidy.play')\n```\n\n### Turn on the lights when the sun goes down\n\nThis example requires the [`sun`\nplugin](https://docs.platypush.tech/platypush/plugins/sun.html) configured:\n\n```yaml\nsun:\n  latitude: LAT\n  longitude: LONG\n```\n\nYou can then simply subscribe to\n[`SunsetEvent`](https://docs.platypush.tech/platypush/events/sun.html#platypush.message.event.sun.SunsetEvent).\nYAML:\n\n```yaml\nevent.hook.sunset_lights_on:\n  if:\n    type: platypush.message.event.sun.SunsetEvent\n  then:\n    - action: light.hue.on\n```\n\nPython:\n\n```python\nfrom platypush import run, when\nfrom platypush.events.sun import SunsetEvent\n\n@when(SunsetEvent)\ndef sunset_lights_on():\n  run('light.hue.on')\n```\n\n### Event matching and token extraction through hook templates\n\nYou can also operate token extraction from event arguments if the values are\nstrings.\n\nFor example, you can use advanced pattern matching and token extraction to\ncreate voice assistant hooks that will match a template with parametrized field\nwhich will be passed as arguments to your event hook:\n\n```python\nfrom platypush import run, when\nfrom platypush.events.assistant import SpeechRecognizedEvent\n\n@when(SpeechRecognizedEvent, phrase='play ${title} by ${artist}')\ndef on_music_play_command(event, title, artist):\n  results = run(\n    'music.mpd.search',\n    filter={\n      'artist': artist,\n      'title': title,\n    }\n  )\n\n  if results:\n    run('music.mpd.play', results[0]['file'])\n```\n\n### Complex hook conditions\n\nYour event hooks can include more complex filters too. Structured filters\nagainst partial event arguments are also possible, and relational operators are\nsupported as well. For example:\n\n```python\nfrom platypush import when\nfrom platypush.events.sensor import SensorDataChangeEvent\n\n@when(SensorDataChangeEvent, data=1):\ndef hook_1(event):\n    \"\"\"\n    Triggered when event.data == 1\n    \"\"\"\n\n@when(SensorDataChangeEvent, data={'state': 1}):\ndef hook_2(event):\n    \"\"\"\n    Triggered when event.data['state'] == 1\n    \"\"\"\n\n@when(SensorDataChangeEvent, data={\n  'temperature': {'$gt': 25},\n  'humidity': {'$le': 15}\n}):\ndef hook_3(event):\n    \"\"\"\n    Triggered when event.data['temperature'] \u003e 25 and\n    event.data['humidity'] \u003c= 15.\n    \"\"\"\n```\n\nThe supported relational fields are the same supported by ElasticSearch - `$gt`\nfor greater than, `$lt` for lesser than, `$ge` for greater or equal, `$ne` for\nnot equal, etc.\n\n### Turn off the lights at 1 AM\n\nWe can use a `cron` for this case. YAML:\n\n```yaml\ncron.lights_off_night:\n  # Run this every day at 1 AM\n  cron_expression: '0 1 * * *'\n  actions:\n      - action: light.hue.off\n```\n\nPython:\n\n```python\nfrom platypush import cron, run\n\n@cron('0 1 * * *')\ndef lights_off_night():\n  run('light.hue.off')\n```\n\n### Greet me with lights and music when I come home\n\nLet's create an `at_home` procedure for this purpose. We can also use a\ntext-to-speech plugin like the [`tts`\nplugin](https://docs.platypush.tech/platypush/plugins/tts.html) (it requires no\nconfiguration as it relies on the Google Translate frontend API, but other,\nmore sophisticated plugins are also available) to have a warm voice to welcome\nus home. YAML:\n\n```yaml\n# Make sure that the sound plugin is also enabled, for audio processing\nsound:\n\nprocedure.at_home:\n  - action: tts.say\n    args:\n      text: \"Welcome home!\"\n\n  # Get luminosity data from a sensor - e.g. LTR559\n  - action: gpio.sensor.ltr559.get_data\n\n  # If it's lower than a certain threshold, turn on the lights.\n  # Note that we can directly access attributes returned by the\n  # previous request(s) as local context variables within the\n  # procedure/hook/cron. In this case, `light` is an attribute returned\n  # on the response of the previous command.\n\n  # Otherwise, you can also use the special `output` variable to get only\n  # the response of the latest action, e.g. `output['light']`\n\n  # Also note the use of the special `if ${}` construct. It accepts\n  # a snippet of Python code and it can access variables within the\n  # current context.\n  - if ${light is not None and light \u003c 110}:\n      - action: light.hue.on\n\n  - action: music.mopidy.play\n    args:\n      resource: \"uri:to:my:favourite:playlist\"\n```\n\nPython:\n\n```python\nfrom platypush import procedure, run\n\n@procedure(\"at_home\")\ndef at_home_proc():\n  run('tts.say', text='Welcome home!')\n\n  luminosity = run('gpio.sensor.ltr559.get_data').get('light', 0)\n  if luminosity \u003c 110:\n    run('light.hue.on')\n\n  run('music.mopidy.play', resource='uri:to:my:favourite:playlist')\n```\n\nYou can then call the procedure from a hook or another script:\n\n```python\nfrom platypush import run\n\nrun('procedure.at_home')\n```\n\nOr, from YAML:\n\n```yaml\nprocedure.some_other_procedure:\n  - action: procedure.at_home\n```\n\nOr using the [available APIs](#http-api).\n\n## Core Installation\n\n### System package manager installation\n\n#### Arch Linux\n\nYou can either install the\n[`platypush`](https://aur.archlinux.org/packages/platypush) package (for the\nlatest stable version) or the\n[`platypush-git`](https://aur.archlinux.org/packages/platypush-git) package\n(for the latest git version) through your favourite AUR package manager. For\nexample, using `yay`:\n\n```bash\n$ yay platypush\n# Or\n$ yay platypush-git\n```\n\nThe Arch Linux packages on AUR are automatically updated upon new git commits\nor tags.\n\n#### Debian/Ubuntu\n\n1. Add the Platypush APT key to your trusted keyring:\n\n  ```\n  # wget -q -O \\\n      /etc/apt/trusted.gpg.d/platypush.asc \\\n      https://apt.platypush.tech/pubkey.txt\n  ```\n\n2. Add the Platypush repository to your APT sources:\n\n  ```\n  #  wget -q -O \\\n      /etc/apt/sources.list.d/platypush.list \\\n      https://apt.platypush.tech/lists/platypush-\u003cdeb_version\u003e-\u003cbranch\u003e.list\n  ```\n\n  Where:\n\n  - `deb_version` can be either:\n\n    - `stable`: current Debian stable\n    - `oldstable`: previous Debian stable\n    - `ubuntu`: latest Ubuntu release\n\n  - `branch` can be either:\n\n    - `main`: latest stable release\n    - `dev`: a package always in sync with the latest git version\n\n  For example, to install the latest stable tags on Debian stable:\n\n  ```\n  # wget -q -O \\\n      /etc/apt/sources.list.d/platypush.list \\\n      https://apt.platypush.tech/lists/platypush-stable-main.list\n  ```\n\n3. Update your repos and install Platypush:\n\n  ```\n  # apt update\n  # apt install platypush\n  ```\n\n#### Fedora\n\nRPM builds targeting the latest Fedora release are automatically built on every\npush pipeline.\n\nTo install Platypush via RPM on Fedora:\n\n- Add the Platypush RPM repository configuration to the package manager:\n\n```\n# yum config-manager --add-repo https://rpm.platypush.tech/platypush.repo\n```\n\n- Install Platypush, either the latest stable release or the rolling release\n  updated on every commit to the main branch:\n\n```\n# yum install platypush\n# Or\n# yum install platypush-git\n```\n\n### `pip`\n\n```bash\n$ pip install platypush\n```\n\nOr, for the latest git version:\n\n```bash\n# Official repo\n$ pip install git+https://git.platypush.tech/platypush/platypush\n# Github mirror\n$ pip install git+https://github.com/blacklight/platypush\n```\n\n### Docker\n\n#### Base image installation\n\n```bash\n$ docker run -it --name platypush \\\n    -p 8008:8008 \\\n    -e \"PLATYPUSH_DEVICE_ID=my-device\" \\\n    -v /path/to/your/platypush/config:/etc/platypush \\\n    -v /path/to/your/platypush/share:/var/lib/platypush \\\n    quay.io/platypush/platypush\n```\n\nThe following architectures are currently supported:\n\n- `amd64`/`x86_64` (standard Intel-based architectures)\n- `arm64`/`aarch64` (ARM64, such as modern ARM-based MacBooks, most of the\n  Android devices or RaspberryPi 4 and 5)\n- `armv7l` (older ARM-based devices, such as RaspberryPi 2 and 3 or older\n  Android devices)\n\nThe Web service will be available on `http://localhost:8008`, and a default\nconfiguration file will be initialized under\n`/path/to/your/platypush/config/config.yaml` if not available. The next\nexecutions of the service can be triggered via `docker start platypush`.\n\nNote that this will install an Alpine-based image. For other base images (e.g.\nDebian, Ubuntu or Fedora) please consult the [custom docker-compose\nway](#the-docker-compose-way).\n\nAlso note that any extra plugin dependencies installed in the container will be\nlost if the container is removed.\n\nIn order to preserve the state of the container after installing and configuring\nyour plugins, you can leverage the `docker commit` command:\n\n```bash\n❯ docker ps\nCONTAINER ID   IMAGE                         COMMAND                  CREATED          STATUS         PORTS                                       NAMES\nf00546d3bd35   quay.io/platypush/platypush   \"/bin/sh -c 'platypu…\"   38 minutes ago   Up 8 minutes   0.0.0.0:8008-\u003e8008/tcp, :::8008-\u003e8008/tcp   platypush\n❯ docker commit f00546d3bd35 my-custom-platypush-image\nsha256:13d4a4cae4e7eedee924a8a79deae9a9978aa70b46699c1f2abfd16bf5ed910b\n# You can now use the my-custom-platypush-image even if the container is destroyed\n```\n\nAlternatively, you can use [the `platydock` command](#docker-(platydock)) to\ndirectly create a Docker image or a `Dockerfile` from a configuration, with all\nthe required plugins and dependencies pre-installed.\n\n#### The docker-compose way\n\n```bash\n$ git clone https://git.platypush.tech/platypush/platypush.git\n$ cd platypush\n# Copy .env.example to .env and edit docker-compose.yml if required.\n# In particular, you may want /etc/platypush and /var/lib/platypush\n# to point to directories on your hosts\n$ docker compose up\n```\n\nNote that the default `Dockerfile` uses Alpine, but in `docker-compose.yml` you\ncan also specify an alternative `Dockerfile` - Debian, Ubuntu and Fedora are\nsupported.\n\n#### Exposing host devices\n\nNote that some plugins may require access to the host hardware - such as USB\ndevices, Bluetooth adapters etc.\n\nIn order to make these devices visible to the Docker container you may need to\nexplicitly mount them as volumes.\n\nFor example, the [`serial`\nplugin](https://docs.platypush.tech/platypush/plugins/serial.html) may need to\naccess an Arduino/ESP device over USB. You can export only that device to the\nDocker container:\n\n```bash\n$ docker run --device=/dev/ttyUSB0 ...\n# Or, if you set up static naming via udev rules\n$ docker run --device=/dev/arduino ...\n```\n\nOr, through `docker-compose.yml`:\n\n```yaml\nservices:\n  platypush:\n    # ...\n    devices:\n      - /dev/ttyUSB0\n```\n\nOtherwise, for privileged access to the USB bus on a Linux host:\n\n```bash\n$ docker run --priviliged -v /dev/bus/usb:/dev/bus/usb ...\n```\n\nOr, through `docker-compose.yml`:\n\n```yaml\nservices:\n  platypush:\n    # ...\n    volumes:\n      - /dev/bus/usb:/dev/bus/usb\n```\n\n### Manual installation\n\n```shell\n$ git clone https://git.platypush.tech/platypush/platypush.git\n$ cd platypush\n$ pip install .\n```\n\n## Plugins installation\n\nAll the plugins included in the main repo will be available once you have\ninstalled the core platform.\n\nHowever, some plugins may require extra (optional) dependencies. You have\nseveral ways of installing those dependencies:\n\n### `pip`\n\nYou can install extra dependencies via pip extras:\n\n```shell\npip install 'platypush[plugin1,plugin2,...]'\n```\n\nFor example:\n\n```shell\npip install 'platypush[light.hue,music.mpd,rss]'\n```\n\nWill install Platypush with the dependencies for the `light.hue`, `music.mpd`\nand `rss` plugins.\n\n### Web interface\n\nPlugins can be installed from the Web interface too. Navigate to the\n_Extensions_ entry in the sidebar, select the extension that you want to install,\nselect the _Install_ tab and click _Install_.\n\n![Screenshot of the extensions installation Web\nview](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/install-ui-screenshot.jpg)\n\nThis section also includes the _Configuration_ tab, with a ready-to-paste\nconfiguration snippet template for that plugin, as well as a documentation page\nthat includes all the actions supported by a given plugin and the events it\ntriggers.\n\n### Docker (`platydock`)\n\nIf you already have the base installation of Platypush on your machine, and you\nhave a configuration file with a custom set of integrations, then you may opt\nto generate a custom Docker image from your configuration file, with all the\nextra dependencies configured, using the `platydock` command.\n\nThe following command:\n\n```shell\n❯ platydock -c /path/to/your/config.yaml -d platypush-test\n```\n\nWill create a Platypush Docker image for a device with ID `platypush-test`,\nwith all the requirements for the additional integrations listed in\n`config.yaml`.\n\nYou can pass the `--print` option if you just want to print the content of the\noutput `Dockerfile` instead of generating the image.\n\nBy default the image will use Alpine Linux as a base. You can use the\n`-i`/`--image` to specify another supported base image - `ubuntu`, `debian` or\n`fedora`.\n\n### Virtual environment (`platyvenv`)\n\nIf you already have the base installation of Platypush on your machine, and you\nhave a configuration file with a custom set of integrations, then you may opt\nto generate a custom virtual environment from your configuration file, with all\nthe extra dependencies configured, using the `platyvenv` command.\n\nThe following command:\n\n```bash\n❯ platyvenv -c /path/to/your/config.yaml -o /path/to/your/venv\n```\n\nWill create a new virtual environment under `/path/to/your/venv` using the\nspecified `config.yaml` to determine which optional dependencies should be installed.\n\nYou can then run Platypush after activating your new environment:\n\n```bash\n❯ source /path/to/your/venv/bin/activate\n❯ platypush -c /path/to/your/config.yaml\n```\n\n### Manual installation\n\nThe [plugin/backend documentation](https://docs.platypush.tech) reports all the\ndependencies required by each plugin, as well as the commands to install them\non multiple platforms.\n\nIf you want to customize your installation, or if you need to install\ndependencies for a plugin that requires some manual steps, you can check out\nany plugin-specific installation steps from its documentation.\n\n## HTTP API\n\nActions and procedures can also be called using the JSON-RPC API exposed by\nPlatypush.\n\nYour configuration requires the [`backend.http`\nsection](https://docs.platypush.tech/platypush/backend/http.html) enabled if\nyou want to use the HTTP API - default listen port: `8008`.\n\nAfter ensuring that the HTTP backend is enabled, head to\n`http://localhost:8008` and register a new user.\n\n![Platypush local user registration\npage](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/registration-page-screenshot.png)\n\nFrom the Web UI, head to _Settings_ → _Tokens_, insert your password again and\nclick _Generate JWT token_.\n\n![User token generation UI](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/tokens-ui-screenshot.png)\n\nAlternatively, you can retrieve a token via HTTP request:\n\n```shell\n❯ curl -XPOST -H 'Content-Type: application/json' -d '\n{\n  \"username\": \"$YOUR_USER\",\n  \"password\": \"$YOUR_PASSWORD\"\n}' http://localhost:8008/auth\n```\n\nYou can then send requests to Platypush using a simple RPC API:\n\n```bash\n❯ curl -XPOST \\\n    -d '{\"type\":\"request\", \"action\":\"procedure.at_home\"}' \\\n    -H \"Authorization: Bearer $YOUR_TOKEN\" \\\n    -H \"Content-Type: application/json\" \\\n    http://localhost:8008/execute\n❮\n{\n  \"id\": \"724754df98968247a284557ce32f74bb\",\n  \"type\": \"response\",\n  \"target\": \"http\",\n  \"origin\": \"myhost\",\n  \"_timestamp\": 1716575901.046127,\n  \"response\": {\n    \"output\": {\n      \"success\": true\n    },\n    \"errors\": []\n  }\n}\n```\n\nIf your procedure returned something, then that will be returned on the API\nresponse too, so downstream consumers can use it.\n\nThe `POST /execute` endpoint accepts a payload in the format:\n\n```javascript\n{\n  \"type\": \"request\",  // Constant\n  \"action\": \"\u003cplugin-name\u003e.\u003caction-name\u003e\",  // Or procedure.\u003cname\u003e\n  \"args\": {\n    \"arg1\": \"arg2\",\n    // ...\n  }\n}\n```\n\nIn our `procedure.at_home` example, you can for instance create an automation\nsnippet paired with your phone that runs the routine whenever you arrive home\n(or your phone does):\n\n1. Install an app like [Tasker](https://tasker.joaoapps.com/) to create\n   automation tasks on your Android device.\n\n2. Install a plugin like [AutoLocation](https://joaoapps.com/autolocation/) to\n   create automation tasks based on your phone's location.\n\n3. Create a profile that triggers whenever you enter your home location (and/or\n   exit it).\n\n![Tasker screenshot showing an At Home/Outside Home pair of\nprofiles](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/tasker-screenshot-1.png)\n\n4. Leverage the [HTTP\n   Request](https://tasker.joaoapps.com/userguide/en/help/ah_http_request.html)\n   Tasker action to send a request to your Platypush API to trigger the routine.\n\n### The _Execute_ tab\n\nThe Web interface also provides an _Execute_ tab under the menu sidebar. You\ncan use this tab to dynamically discover the actions exposed by various plugins\n(and also your own procedures):\n\n![Screenshot of the Execute tab showing the autocomplete discovery of the\nactions](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/execute-panel-screenshot-1.jpg)\n\n![Screenshot of the Execute tab showing the automatically generated\ndocumentation for a given action and its\nparameters](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/execute-panel-screenshot-2.jpg)\n\n![Screenshot of the Execute tab showing the output of an action being\nrun](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/execute-panel-screenshot-3.jpg)\n\n## Websocket API\n\n### Events\n\nYou can subscribe to events generated by the application over the `/ws/events`\nWebsocket endpoint, and send events to this endpoint too.\n\nThis is useful if you want to synchronize Platypush events with another client,\nor send custom events outside of those native to the application and build\ncustom automation hooks on them.\n\nSending events:\n\n```bash\n❯ wscat -H \"Authorization: Bearer $YOUR_TOKEN\" \\\n    -c \"ws://localhost:8008/ws/events\" \\\n    -w 1 \\\n    -x '\n{\n  \"type\": \"event\",\n  \"args\": {\n    \"type\": \"platypush.message.event.custom.CustomEvent\",\n    \"subtype\": \"foo\",\n    \"args\": {\n      \"bar\": \"baz\"\n    }\n  }\n}'\n```\n\nReceiving events:\n\n```bash\n❯ wscat -H \"Authorization: Bearer $YOUR_TOKEN\" -c \"ws://localhost:8008/ws/events\"\n```\n\n### Actions\n\nYou can also send requests to the `/ws/requests` Websocket endpoint, and get\nresponses asynchronously on the same channel:\n\n```bash\n❯ wscat -H \"Authorization: Bearer $YOUR_TOKEN\" \\\n    -c \"ws://localhost:8008/ws/requests\" \\\n    -w 1 \\\n    -x '{\"type\": \"requests\", \"action\": \"procedure.foo.bar\"}'\n```\n\n## Web hooks\n\nYou can use Platypush to expose your custom routines as dynamic Web hooks that\ncan be called by any client.\n\nAll you need is to register a listener for a\n[`WebhookEvent`](https://docs.platypush.tech/platypush/events/http.hook.html#platypush.message.event.http.hook.WebhookEvent)\n\n```python\nfrom platypush import run, when\nfrom platypush.events.http.hook import WebhookEvent\n\nhook_token = \"abcdefabcdef\"\n\n# Expose the hook under the /hook/at_home endpoint\n@when(WebhookEvent, hook=\"at_home\")\ndef at_home_webhook(event: WebhookEvent):\n    # Unlike the calls to /execute, custom web hooks are unauthenticated.\n    # If you want authentication, you'll need to implement your custom logic by\n    # parsing the event headers\n    if event.headers.get(\"X-Token\") != hook_token:\n        # Tuple with \u003cresponse, http-code, [response-headers]\u003e\n        event.send_response((\"Unauthorized\", 401))\n        return\n\n    run('procedure.at_home')\n\n    # Return anything back to the client\n    return {'status': 'ok'}\n```\n\nThen you can invoke your custom logic over HTTP:\n\n```bash\n❯ curl -H 'X-Token: abcdefabcdef' 'http://localhost:8008/hook/at_home'\n```\n\n## Entities\n\nEntities are another building block of Platypush. Many integrations will store\ntheir state or connected devices in the form of entities - e.g. the sensors\ndetected by the Z-Wave/Zigbee/Bluetooth integration, or the lights connected to\na Hue bridge, or your cloud nodes, or your custom Arduino/ESP machinery, and so\non.\n\nEntities provide a consistent interface to interact with your integrations\nregardless of their type and the plugin that handles them. For instance, all\ntemperature sensors will expose the same interface, regardless if they are\nBluetooth or Zigbee sensors, and all the media plugins will expose the same\ninterface, regardless if they manage Chromecasts, Kodi, Plex, Jellyfin or a\nlocal VLC player.\n\nOnce you enable the HTTP backend and a few integrations that export entities\nand register a user, you can query the detected entities via:\n\n```shell\ncurl -XPOST -H 'Content-Type: application/json' \\\n    -H \"Authorization: Bearer $YOUR_TOKEN\" \\\n    -d '{\"type\":\"request\", \"action\":\"entities.get\"}' \\\n    http://localhost:8008/execute\n```\n\nAll the entities expose the same interface and can be manipulated through the\nsame API. Also, when an entity is updated it always emits an\n[`EntityUpdateEvent`](https://docs.platypush.tech/platypush/events/entities.html#platypush.message.event.entities.EntityUpdateEvent),\nso you can easily create hooks that react to these events and act on multiple\ntypes of entities.\n\nIf you enabled the HTTP backend, then you can also access all the entities from\nthe home panel of the Web UI.\n\n![Screenshot of the entities UI](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/Entities-screenshot-1.png)\n\n![Screenshot of the entities UI](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/Entities-screenshot-2.png)\n\n![Screenshot of the application main\npanel, showing the Bluetooth, Serial, SmartThings and System integrations](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/main-panel-screenshot-1.png)\n\n## Configuration\n\n### Configuration file\n\nYou can use the [default\n`config.yaml`](https://git.platypush.tech/platypush/platypush/src/branch/master/platypush/config/config.yaml)\nas a template/reference.\n\nThe location of the `config.yaml` to be used by the application is determined\nin the following way:\n\n1. It can be passed through the command-line `-c`/`--config` argument.\n2. If not specified via `-c`, it will be read from the `PLATYPUSH_CONFIG`\n   environment variable.\n3. If not specified, use `./config.yaml` if available.\n4. If not available, and you are running Platypush within a Docker container,\n   or as a privileged user (and usually you shouldn't), or as a systemd service\n   created by a supported package manager, then `/etc/platypush/config.yaml`\n   will be used if available.\n5. Otherwise, if you are running Platypush as a non-privileged user or in a\n   virtual environment, `$XDG_CONFIG_HOME/platypush/config.yaml` will be used\n   (defaults to `~/.config/platypush/config.yaml`).\n\n#### Scripts directory\n\nBy default, any custom Python scripts will be searched under\n`\u003cCONFDIR\u003e/scripts`, where `\u003cCONFDIR\u003e` is the path to your `config.yaml`.\n\nYou can override it in your `config.yaml`:\n\n```yaml\nscripts_dir: /path/to/custom/scripts\n```\n\nSince everything under the scripts directory will be imported as a submodule,\nyou can create your own libraries of scripts that can import other scripts:\n\n```python\n# Content of scripts/music.py\n\nfrom platypush import run\n\ndef music_play(plugin='music.mopidy', resource=None):\n  run(f'{plugin}.play', resource)\n\n# Content of scripts/lights.py\n\nfrom platypush import run\n\ndef lights_toggle(plugin='light.hue', groups=('Living Room',)):\n  run(f'{plugin}.toggle', groups=groups)\n\n# Content of scripts/home.py\n\nfrom platypush import procedure\n\nfrom scripts.music import music_play\nfrom scripts.lights import lights_toggle\n\n@procedure\ndef at_home():\n  music_play()\n  lights_toggle()\n```\n\n#### Splitting configuration on multiple files\n\nThe `config.yaml` file can become very complex, especially if you embed many\nhooks and procedures in it in YAML format.\n\nTo make the configuration more maintainable, and also to isolate modules that\nyou can reuse across multiple instances, you can leverage the `include`\ndirective:\n\n```yaml\n# All paths are relative to config.yaml, or to the location of the current file\ninclude:\n  - assistant.yaml\n  - db.yaml\n  - media.yaml\n  - mqtt.yaml\n  - sensors.yaml\n  # ...\n```\n\n### Working directory\n\nThis is where the application will store its data and integration plugins will\nstore their data. The order of precedence is:\n\n* `-w`/`--workdir` command line argument.\n* The `PLATYPUSH_WORKDIR` environment variable.\n* The `workdir` field in the configuration file.\n* `$XDG_DATA_HOME/platypush` (default: `~/.local/share/platypush`) if launched\n  with a non-privileged user, `/var/lib/platypush` if launched as root or with\n  a system user.\n\n### Database\n\nThe application stores entities, variables, users, integrations state and more\non a database. The engine configuration supports the [SQLAlchemy engine\nsyntax](https://docs.sqlalchemy.org/en/20/core/engines.html).\n\n**Note**: The application uses a local SQLite database by default, which is\nnatively supported by SQLAlchemy. The application has also been tested against\nMySQL/MariaDB and Postgres, and should work fine with any modern relational\ndatabase supported by SQLAlchemy. However, any backend other than SQLite may\nrequire an additional Python dependency for the SQLAlchemy driver (for example\n[`pg8000`](https://pypi.org/project/pg8000/) for PostgreSQL).\n\nOrder of precedence for the engine:\n\n* `--main-db`/`--db` command line argument.\n* The `PLATYPUSH_DB` environment variable.\n* The `main.db` field in the configuration file.\n* `sqlite:///\u003cWORKDIR\u003e/main.db`\n\n### Device ID\n\nThe device ID is a unique identifier for a Platypush instance on a network and\nis used to reliably dispatch messages when multiple instances use a shared\nbackend.\n\nThe order of precedence is:\n\n* `--device-id` command line argument.\n* The `PLATYPUSH_DEVICE_ID` environment variable.\n* The `device_id` field in the configuration file.\n* The hostname of the machine.\n\n### systemd service\n\nIf you installed Platypush from a system package manager then you'll also have\na `systemd` service installed for it.\n\nYou can start/enable Platypush like any other `systemd` service:\n\n```\n# systemctl start platypush\n# systemctl enable platypush\n```\n\nOr, if you want to run the Platypush service as a generic user:\n\n```bash\n❯ systemctl --user start platypush\n❯ systemctl --user enable platypush\n```\n\nOtherwise, you can create your own `systemd` service copying the [provided\n`.service`\nfile](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/systemd/platypush.service)\nto e.g. `~/.config/systemd/user` or `/etc/systemd/system`.\n\n### Redis\n\nPlatypush uses Redis as a in-memory queue to deliver messages and as a pub/sub\nbus for inter-process communication.\n\nIf you installed Platypush through a package manager, then the Redis service\nwill automatically be installed and started if you launch the Platypush service\nas a privileged user.\n\nIf you run Platypush in a container then by default it'll start its own Redis\ninstance through the `--start-redis` command-line option.\n\nYou can customize the Redis configuration through the:\n\n1. `--redis-host`, `--redis-port` and `--redis-queue` command-line options.\n2. `PLATYPUSH_REDIS_HOST`, `PLATYPUSH_REDIS_PORT` and `PLATYPUSH_REDIS_QUEUE`\n   environment variables.\n3. Through your `config.yaml`:\n\n```yaml\n# See https://redis-py.readthedocs.io/en/latest/connections.html#redis.Redis\n# for the full list of supported parameters\nredis:\n  host: redis-host\n  port: 6379\n  username: redis-user\n  password: redis-pass\n```\n\nIf `--start-redis` is set, the application can be configured to start a custom\n`redis-server` executable through the:\n\n1. `--redis-bin` command-line option.\n2. `PLATYPUSH_REDIS_BIN` environment variable.\n\nAlternative drop-in implementations such as `keydb-server`, `valkey` or\n`redict` are also supported.\n\n### nginx\n\nIf you want to access your Platypush web panel outside your home network, it may\nbe a good idea to use an nginx/Apache reverse proxy with a valid SSL certificate\n(e.g. managed by certbot). A [sample an nginx\nconfiguration](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/nginx/nginx.sample.conf)\nis provided in the repository.\n\n## The Web interface\n\n### Other Web panels\n\nBesides the built-in panels that we've already seen in the other sections,\nSeveral integrations add their own feature-rich panels to the Web view, turning\nPlatypush into a gateway to all of your services - from Zigbee sensors, to\nmedia players and services, to your music cloud, and more.\n\nFor example, the music view is available to most of the `music` plugins.\n\n![Screenshot of one of the music\npanels](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/music-panel-screenshot-1.png)\n\n![Screenshot of the Snapcast panel, which can be used to synchronize your music\nstreams across multiple\ndevices](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/snapcast-panel-screenshot-1.png)\n\nAnother example is the camera panel, to monitor your cameras, get stand-alone\nfeed URLs, and take photos. This becomes available in the UI if you enable at\nleast a `camera` plugin.\n\n![Camera panel screenshot\n1](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/Camera-panel-screenshot-1.png)\n\nIf you enabled at least one local `media` plugin (like `media.vlc`,\n`media.mplayer` etc.) then you'll also unlock the media UI, which allows you to\nindex, search, view and cast media files under the configured `media_dirs`, and\nit also integrates with other configured/supported backends such as YouTube,\nPlex and Jellyfin.\n\n![Media panel screenshot\n1](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/Media-panel-screenshot-1.png)\n\n### Dashboards\n\nThe web service also provides means for the user to create [custom\ndashboards](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/conf/dashboard.xml)\nthat can be used to show information from multiple sources on a large screen.\n\n![Screenshot of a Platypush dashboard, showing a calendar widget, the current\nmusic state, weather, news from the RSS integration, and a carousel of custom\npictures.](https://blog.platypush.tech/img/dashboard-1.png)\n\n### PWA support\n\nNote that having the web application served over SSL is a requirement for the\nPWA (progressive web app) to work. The Platypush PWA allows you to install a\nPlatypush native-like client on your mobile devices if you don't want to use the\nfull Android app.\n\n## Two-factor authentication\n\nSupport for 2FA over OTP codes requires to enable the\n[`otp`](https://docs.platypush.tech/platypush/plugins/otp.html) and\n[`qrcode`](https://docs.platypush.tech/platypush/plugins/qrcode.html) plugins.\n\nAfter installing the dependencies, you can enable it by navigating to\n_Settings_ -\u003e _Users_ from the Web panel. Then select your user, choose _Set up\n2FA_ and proceed with the steps on screen to set up your authenticator.\n\n## Mobile app\n\nAn [official Android\napp](https://f-droid.org/en/packages/tech.platypush.platypush/) is provided on\nthe F-Droid store. It allows to easily discover and manage multiple Platypush\nservices on a network through the web interface, and it easily brings the power\nof Platypush to your fingertips.\n\n## Browser extension\n\nA [browser extension](https://git.platypush.tech/platypush/platypush-webext) is\navailable for [Chrome](https://git.platypush.tech/platypush/platypush-webext)\nand [Firefox](https://addons.mozilla.org/en-US/firefox/addon/platypush/).\n\nThe browser extension allows you to run Platypush actions and procedures\ndirectly from your browser, associate keybindings with them, so you can run\nyour favourite routines with a few keystrokes anywhere in your browser, and\nprovides an advanced API to interact with the Web pages you visit - for\nexample, you can build an action that gets the content of a page you're\nvisiting and uses Platypush to distill it in readable format, or send the URL\nto another service.\n\n## Tests\n\nTo run the tests simply run `pytest` either from the project root folder or the\n`tests/` folder.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblacklight%2Fplatypush","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblacklight%2Fplatypush","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblacklight%2Fplatypush/lists"}