Compare commits

..

No commits in common. "master" and "master" have entirely different histories.

1864 changed files with 52360 additions and 94484 deletions

View File

@ -1,6 +0,0 @@
**/.git
**/node_modules
**/__pycache__
**/venv
**/.mypy_cache
**/build

1175
.drone.yml

File diff suppressed because it is too large Load Diff

8
.gitignore vendored
View File

@ -10,7 +10,7 @@ package.sh
platypush/backend/http/static/resources/*
docs/build
.idea/
/config
config
platypush/backend/http/static/css/*/.sass-cache/
.vscode
platypush/backend/http/static/js/lib/vue.js
@ -22,9 +22,3 @@ platypush/requests
.coverage
coverage.xml
Session.vim
/jsconfig.json
/package.json
/Dockerfile
/docs/source/wiki
/.skipci
dump.rdb

72
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,72 @@
sync-to-github:
stage: build
script:
- echo "Synchronizing repo state to Github"
- export REPO_DIR="$(mktemp -d /tmp/platypush-XXXXX)"
- git clone git@git.platypush.tech:platypush/platypush.git "$REPO_DIR"
- cd "$REPO_DIR"
- git remote add github git@github.com:/BlackLight/platypush.git
- git checkout $CI_COMMIT_BRANCH
- git pull
- git push --mirror -v github
run-tests:
stage: test
script:
- ./.gitlab/run_ci_tests.sh
rebuild-docs:
stage: deploy
only:
- master
script:
- ./.gitlab/rebuild_docs.sh
update-aur-packages:
stage: deploy
only:
- master
- tags
script:
- echo "Updating AUR packages"
- export REPO_DIR="$(mktemp -d /tmp/platypush-distutils-XXXXX)"
- git clone git@fabiomanganiello.com:/home/git/platypush-distutils.git "$REPO_DIR"
- cd "$REPO_DIR"
- git submodule init
- git submodule update
- cd distro/arch/git
- git checkout master
- git pull --rebase
- cd ../../../
- cd distro/arch/stable
- git checkout master
- git pull --rebase
- cd ../../../
- ./update.sh
- cd distro/arch/git
- changes="$(git status --porcelain --untracked-files=no)"
- "[[ -n \"$changes\" ]] && git commit -a -m '[Automatic] Package updated' && git push || echo 'No changes'"
- cd ../../../
- cd distro/arch/stable
- changes="$(git status --porcelain --untracked-files=no)"
- "[[ -n \"$changes\" ]] && git commit -a -m '[Automatic] Package updated' && git push || echo 'No changes'"
upload-pip-package:
stage: deploy
only:
- tags
script:
# Update the CI/CD configuration
- cd ~/platypush-ci-cd
- git pull
- cd -
# Build the package
- rm -rf build dist *.egg-info
- export VERSION=$(grep -e '^\s*__version__\s*=' platypush/__init__.py | sed -r -e 's/^\s*__version__\s*=\s*.(.+?).\s*$/\1/')
- source ~/.credentials/pypi.env
- python setup.py sdist bdist_wheel
# Upload to PyPI
- twine upload --repository platypush ./dist/platypush-${VERSION}.tar.gz
# Upload to the local package repository
- TWINE_USERNAME=$LOCAL_TWINE_USERNAME TWINE_PASSWORD=$LOCAL_TWINE_PASSWORD twine upload --repository-url https://git.platypush.tech/api/v4/projects/3/packages/pypi dist/platypush-${VERSION}.tar.gz

33
.gitlab/rebuild_docs.sh Executable file
View File

@ -0,0 +1,33 @@
#!/bin/bash
LOGFILE="./docs.log"
STATUS_IMG_PATH="./docs-status.svg"
build_docs() {
cd ./docs || exit 1
make html 2>&1 | tee "../$LOGFILE"
ret=$?
cd .. || exit 1
return $?
}
########
# MAIN #
########
build_docs
ret=$?
log_base_path="$(date +/opt/tests/platypush/logs/docs/%Y-%m-%dT%H:%M:%S.%m)"
if [[ $ret == 0 ]]; then
wget -O "$STATUS_IMG_PATH" https://ci.platypush.tech/docs/passed.svg
cp "$LOGFILE" "${log_base_path}_PASSED.log"
else
wget -O "$STATUS_IMG_PATH" https://ci.platypush.tech/docs/failed.svg
cp "$LOGFILE" "${log_base_path}_FAILED.log"
fi
mv "$STATUS_IMG_PATH" /opt/tests/platypush/logs/docs/
mv "$LOGFILE" /opt/tests/platypush/logs/latest.log
cp -r docs/build/html /opt/repos/platypush/docs/build/
exit $ret

60
.gitlab/run_ci_tests.sh Executable file
View File

@ -0,0 +1,60 @@
#!/bin/bash
BASE_DIR="$(mktemp -d '/tmp/platypush-ci-tests-XXXXX')"
VENV_DIR="$BASE_DIR/venv"
TEST_LOG="./test.log"
STATUS_IMG_PATH="./status.svg"
cleanup() {
echo "Cleaning up environment"
rm -rf "$BASE_DIR"
}
prepare_venv() {
echo "Preparing virtual environment"
python -m venv "$VENV_DIR"
cd "$VENV_DIR" || exit 1
source ./bin/activate
cd - || exit 1
}
install_repo() {
echo "Installing latest version of the repository"
pip install '.[http]'
}
run_tests() {
echo "Running tests"
pytest 2>&1 | tee "$TEST_LOG"
deactivate
if grep -e '^FAILED ' "$TEST_LOG"; then
return 2
fi
return 0 # PASSED
}
########
# MAIN #
########
cleanup
prepare_venv
install_repo
run_tests
ret=$?
cleanup
log_base_path="$(date +/opt/tests/platypush/logs/%Y-%m-%dT%H:%M:%S.%m)"
if [[ $ret == 0 ]]; then
wget -O "$STATUS_IMG_PATH" https://ci.platypush.tech/passed.svg
cp "$TEST_LOG" "${log_base_path}_PASSED.log"
else
wget -O "$STATUS_IMG_PATH" https://ci.platypush.tech/failed.svg
cp "$TEST_LOG" "${log_base_path}_FAILED.log"
fi
mv "$STATUS_IMG_PATH" /opt/tests/platypush/logs/status.svg
mv "$TEST_LOG" /opt/tests/platypush/logs/latest.log
exit $ret

View File

@ -6,12 +6,11 @@ repos:
hooks:
# - id: trailing-whitespace
# - id: end-of-file-fixer
- id: check-yaml
- id: check-json
- id: check-xml
- id: check-symlinks
- id: check-added-large-files
args: ['--maxkb=1500']
- id: check-yaml
- id: check-json
- id: check-xml
- id: check-symlinks
- id: check-added-large-files
- repo: https://github.com/Lucas-C/pre-commit-hooks-nodejs
rev: v1.1.2

View File

@ -4,320 +4,12 @@ All notable changes to this project will be documented in this file.
Given the high speed of development in the first phase, changes are being
reported only starting from v0.20.2.
## [0.50.3] - 2023-07-22
### Added
- Added [XMPP plugin](https://git.platypush.tech/platypush/platypush/pulls/269).
## [0.50.2] - 2023-06-30
### Fixed
- A fix for the new `get_plugin` supported syntax. `get_plugin` now also
accepts a plugin class/type as an argument rather than a string, but the
previous logic didn't properly inspect the parent module.
## [0.50.0] - 2023-06-28
This should actually be a new big major release, but I'm holding on implementing
more features before a 1.0 tag.
### Added
- Migrated many integrations to the new [entities
framework](https://git.platypush.tech/platypush/platypush/pulls/230).
This is a very large change to the foundations of the platform. Many plugins
(and many others will follow) now publish and store their *entities* in a
standard format, so e.g. all the lights, switches, Bluetooth devices, cameras,
audio devices, media players and sensors are now supposed to expose the same
attributes and API regardless of the type of integration. This refactor also
includes a new default home panel, which includes all the entities detected by
the registered integrations. Many integrations have already been migrated to
the new framework. Among them (and many others are on their way):
- `arduino`
- `bluetooth`
- `light.hue`
- `linode`
- All the `sensor.*` plugins
- `serial`
- `smartthings`
- `switchbot`
- `system`
- `variable`
- `zigbee.mqtt`
- `zwave.mqtt`
- Added support for more complex filters on event hooks. Earlier filters could
only model key-value pair matches. The interface now supports more
sophisticated filters - among these, structured filters with partial matches
and relational filters. For example:
```python
from platypush.event.hook import hook
from platypush.message.event.sensor import SensorDataChangeEvent
@hook(SensorDataChangeEvent, data=1):
def hook_1(event):
"""
Triggered when event.data == 1
"""
@hook(SensorDataChangeEvent, data={'state': 1}):
def hook_2(event):
"""
Triggered when event.data['state'] == 1
"""
@hook(SensorDataChangeEvent, data={
'temperature': {'$gt': 25},
'humidity': {'$le': 15}
}):
def hook_3(event):
"""
Triggered when event.data['temperature'] > 25 and
event.data['humidity'] <= 15.
"""
```
The supported relational fields are the same supported by ElasticSearch - `$gt`
for greater than, `$lt` for lesser than, `$ge` for greater or equal, `$ne` for
not equal, etc.
This also means that the previous `SensorDataAboveThresholdEvent` and
`SensorDataBelowThresholdEvent` events are now deprecated, as the new hook API
makes it much easier and flexible to define custom threshold logic on any events
without having to pre-define thresholds in each backend's configuration.
- Added a Progressive WebApp (PWA) framework to the Vue webapp. It is now
possible to install Platypush as a stand-alone webapp directly from the web
panel if the panel is served over HTTPS. For now this only improves the user
experience, performance and it provides a more native-like experience on
mobile, but in the future the PWA background worker could be used to e.g.
deliver asynchronous events and notifications to the clients without keeping
the browser open.
- Added support for application database automatic migrations after an update by
using Alembic.
### Changed
- Tornado is now used as an HTTP engine by `backend.http`, instead of using
bare bone Flask with its inefficient Werkzeug server and an optional uwsgi
that required extra configuration (and an extra external service).
- All the streaming endpoints have been rewritten and adapted to work with
Tornado. This greatly improves performance, stability and ease of
configuration, while remaining back-compatible with the previous URL formats.
As a side note, all the streaming endpoints are now using Redis to stream
information across multiple worker processes, so make sure that you have a
version of Redis that supports pub/sub (most of the recent ones should do).
- The `bluetooth` plugin has been completely rewritten, merged with the (now
deprecated) `backend.bluetooth`. The previously separated low-energy/legacy
integrations have now been merged too. It now supports much more than passive
scanning, as it can recognize the information published by most of the device,
supports both legacy and low-energy connection/disconnection actions, and it
can detect most of the device classes, services and manufacturers. It also
supports parsing some standard features (like battery level, temperature,
state etc.) if they are published according to some convention supported by
*TheengsGateway*. The `switchbot.bluetooth` integration has now also been
merged into `bluetooth`.
- The `sound` plugin has been completely rewritten. While it should still be
largely back-compatible with the previous implementation, you should probably
go and take a look at the new documentation to get a grasp of the new
features.
- The `camera.ffmpeg` plugin has received a big rewrite that has improved its
stability and robustness against several types of cameras. It is now the
recommended way of interfacing with general-purpose cameras, even for
PiCameras - the `camera.pi` integration is now largely deprecated, as the old
PiCamera API is deprecated as well, and `camera.ffmpeg` should now work out of
the box with a PiCamera if a reasonably recent version of ffmpeg is installed.
- `backend.websocket` has been **removed** and replaced by Tornado asynchronous
websocket URLs registered on the HTTP backend. The two new routes that
replace the websocket backend are:
- `/ws/events`: subscribe to this websocket to receive any asynchronous
events forwarded by the application.
- `/ws/requests`: you can send request messages to this endpoints, and the
responses will be received asynchronously on the same channel.
- The `inspect` plugin has been largely improved.
- Its performance is now much snappier, as it scans for all the available
integrations by searching for manifest files instead of scanning each
single source file. Documentation about specific plugins and actions is
fetched lazily when requested by the user.
- It now also caches results by looking at the last modified date of the
source file, so it won't have to re-scan source files that haven't been
modified.
- Its detection of RST constructs has also been improved, so most of the code
blocks, schemas, return types and references to other objects are now
rendered in the plugin UI.
- Added `variable.delete` action. The existing `variable.unset` action will now
only set a variable to null if it exists, while `variable.delete` will
actually remove it from the database.
- `backend.sensor.distance` and `gpio.sensor.distance` have been removed and
migrated instead to a new `sensor.hcsr04` plugin, since the existing logic
actually only applies to HC-SR04-like distance sensors.
- `backend.sensor.dht` and `gpio.sensor.dht` have been removed and
migrated to a new `sensor.dht` plugin.
- `backend.sensor.accelerometer` and `gpio.sensor.accelerometer` have been
removed and migrated to a new `sensor.lis3dh` plugin, since the existing
accelerometer logic only works with these sensors.
- `backend.sensor.motion.pwm3901` and `gpio.sensor.motion.pwm3901` have been
removed and migrated to a new `sensor.pwm3901` plugin.
accelerometer logic only works with these sensors.
- `backend.sensor.envirophat` and `gpio.sensor.envirophat` have been removed and
migrated to a new `sensor.envirophat` plugin.
- `backend.sensor.ltr559` and `gpio.sensor.ltr559` have been removed and
migrated to a new `sensor.ltr559` plugin.
- `backend.sensor.bme280` and `gpio.sensor.bme280` have been removed and
migrated to a new `sensor.bme280` plugin.
- `backend.sensor.distance.vl53l1x` and `gpio.sensor.distance.vl53l1x` have been
removed and migrated to a new `sensor.vl53l1x` plugin.
- `backend.serial` has been removed and merged into the `serial` plugin.
- `backend.switch.wemo` has been removed and merged into the `switch.wemo`
plugin.
- `backend.switch.tplink` has been removed and merged into the `switch.tplink`
plugin.
- `backend.zigbee.mqtt` has been removed and merged into the `zigbee.mqtt`
plugin.
- `backend.zwave.mqtt` has been removed and merged into the `zwave.mqtt` plugin.
### Fixed
- Notable performance improvements for the UI (like -50% on the load time and
memory usage in some cases). Recursive/reflective Vue components now use
`shallowRef`, so complex UI models won't have to be fully loaded at page
start.
- Fixed compatibility with SQLAlchemy 2.
- Migrated the `clipboard` integration from `pyperclip` to `pyclip` (see
[#240](https://git.platypush.tech/platypush/platypush/issues/240)).
`pyperclip` is unmaintained and largely broken, and `pyclip` seems to be a
viable drop-in alternative.
- Better implementation of the UI modals - added close buttons and trigger
closure when Esc is pressed.
### Removed
- Removed SSL configuration from `backend.http`. Configuring SSL on
Flask+Tornado is messy, and it won't end up with a good user experience.
Instead, you should consider using a reverse proxy (e.g. nginx or Apache) if
you want to make the Platypush web interface available over HTTPS. A sample
nginx configuration has been added under `examples/nginx`. Note that running
the web panel over HTTPS is a requirement if you want to leverage the PWA
features, as a PWA can only be served over HTTPS.
- Removed the Bluetooth file server integration. It is still possible to send
files over Bluetooth (the feature has now been merged into the `bluetooth`
plugin, under `bluetooth.send_file`), but all the server features rely on
features of PyOBEX that are now very broken on recent versions of Python (the
project itself hasn't been updated in years).
- Removed or deprecated all the `backend.sensor.*` backends. Their logic has now
been merged into their associated plugins, and the plugins will have the
ability to run in the background too.
- Removed `backend.sensor.battery`. It has now been merged into the `system`
plugin.
- Removed `gpio.sensor` plugin. It was never really fully implemented, and it
was probably impossible to implement with an interface that could work with
any sensor-like device connected over GPIO.
## [0.24.5] - 2023-02-22
### Added
- Added `hid` plugin to support discoverability and data interaction with
generic HID devices - like Bluetooth/USB peripherals, joysticks, dongles and
any other type of devices that supports the HID interface.
- Added `timeout` parameter to `websocket.send` to prevent messages sent on a
non-responsive websocket from getting the websocket loop stuck
### Fixed
- Running the Zeroconf registration logic in another thread in `backend.http`,
so failures in the Zeroconf logic don't affect the startup of the web server.
- (Temporarily) introduced `sqlalchemy < 2.0.0` as a requirement - a PR with a
migration to the new stable version of SQLAlchemy is in TODO.
## [0.24.4] - 2022-12-20
### Fixed
- Fixed cronjobs potentially being triggered even if it wasn't their slot in
case of clock synchronization events.
## [0.24.3] - 2022-12-17
### Added
- Added `[-v|--verbose]` command-line option to override the default logging
configuration and enable debug logging.
- Added `--version` command-line option to print the current version and exit.
- [[#236](https://git.platypush.tech/platypush/platypush/issues/236)] Added
support for `author` and `tags` attributes on feed entries.
## [0.24.2] - 2022-12-10
### Fixed
- The `main.db` configuration should use the configured `workdir` when no
values are specified.
- The `zwave.mqtt` is now compatible both with older (i.e. `zwavejs2mqtt`) and
newer (i.e. `ZwaveJS`) versions of the backend.
## [0.24.1] - 2022-12-08
### Fixed
- Removed a parenthesized context manager that broke compatibility with
Python &lt; 3.10.
## [0.24.0] - 2022-11-22
## [Unreleased]
### Added
- Added [Wallabag integration](https://git.platypush.tech/platypush/platypush/issues/224).
- Added [Mimic3 TTS integration](https://git.platypush.tech/platypush/platypush/issues/226).
- Added `qos` attribute to `mqtt.publish` and all the plugins derived from `mqtt`.
### Changed
- Replaced PyJWT dependency with the Python-native `rsa` package. This will
make the installation much lighter, compatible with more systems and less
dependent on the platform-specific libraries required by `cryptography`.
> **NOTE**: This is a breaking change for those who use the `backend.http` API
> with JWT tokens. The new logic encrypts and encodes the payload in a
> different format, therefore previously generated tokens are no longer
> compatible.
## [0.23.6] - 2022-09-19

View File

@ -1,6 +1,4 @@
recursive-include platypush/backend/http/webapp/dist *
recursive-include platypush/install *
include platypush/plugins/http/webpage/mercury-parser.js
include platypush/config/*.yaml
global-include manifest.yaml
global-include components.json.gz

738
README.md
View File

@ -1,59 +1,69 @@
Platypush
=========
[![Build Status](https://ci-cd.platypush.tech/api/badges/platypush/platypush/status.svg)](https://ci-cd.platypush.tech/platypush/platypush)
[![Build Status](https://ci.platypush.tech/status.svg)](https://ci.platypush.tech/latest.log)
[![Documentation Status](https://ci.platypush.tech/docs/status.svg)](https://ci.platypush.tech/docs/latest.log)
[![pip version](https://img.shields.io/pypi/v/platypush.svg?style=flat)](https://pypi.python.org/pypi/platypush/)
[![License](https://img.shields.io/github/license/BlackLight/platypush.svg)](https://git.platypush.tech/platypush/platypush/src/branch/master/LICENSE.txt)
[![Last Commit](https://img.shields.io/github/last-commit/BlackLight/platypush.svg)](https://git.platypush.tech/platypush/platypush/commits/branch/master)
[![License](https://img.shields.io/github/license/BlackLight/platypush.svg)](https://git.platypush.tech/platypush/platypush/-/blob/master/LICENSE.txt)
[![Last Commit](https://img.shields.io/github/last-commit/BlackLight/platypush.svg)](https://git.platypush.tech/platypush/platypush/-/commits/master/)
[![Join chat on Matrix](https://img.shields.io/matrix/:platypush?server_fqdn=matrix.platypush.tech)](https://matrix.to/#/#platypush:matrix.platypush.tech)
[![Contributions](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://git.platypush.tech/platypush/platypush/src/branch/master/CONTRIBUTING.md)
[![Contributions](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://git.platypush.tech/platypush/platypush/-/blob/master/CONTRIBUTING.md)
[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/BlackLight/platypush.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/BlackLight/platypush/context:python)
[![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/BlackLight/platypush.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/BlackLight/platypush/context:javascript)
<!-- toc -->
- [Introduction](#introduction)
+ [What it can do](#what-it-can-do)
- [Installation](#installation)
* [Prerequisites](#prerequisites)
+ [Docker installation](#docker-installation)
+ [Use an external service](#use-an-external-service)
+ [Manual installation](#manual-installation)
* [Install through `pip`](#install-through-pip)
* [Install through a system package manager](#install-through-a-system-package-manager)
* [Install from sources](#install-from-sources)
* [Installing the dependencies for your extensions](#installing-the-dependencies-for-your-extensions)
+ [Install via `extras` name](#install-via-extras-name)
+ [Install via `manifest.yaml`](#install-via-manifestyaml)
+ [Check the instructions reported in the documentation](#check-the-instructions-reported-in-the-documentation)
* [Virtual environment installation](#virtual-environment-installation)
* [Docker installation](#docker-installation-1)
- [Architecture](#architecture)
* [Plugins](#plugins)
* [Actions](#actions)
* [Backends](#backends)
* [Events](#events)
* [Hooks](#hooks)
+ [More complex filters](#more-complex-filters)
* [Procedures](#procedures)
* [Cronjobs](#cronjobs)
* [Entities](#entities)
* [The web interface](#the-web-interface)
+ [The main web panel](#the-main-web-panel)
+ [The execution panel](#the-execution-panel)
+ [Other web panels](#other-web-panels)
+ [Dashboards](#dashboards)
* [Running in production mode](#running-in-production-mode)
+ [PWA support](#pwa-support)
- [Installation](#installation)
* [System installation](#system-installation)
+ [Install through `pip`](#install-through-pip)
+ [Install through a system package manager](#install-through-a-system-package-manager)
+ [Install from sources](#install-from-sources)
* [Installing the dependencies for your extensions](#installing-the-dependencies-for-your-extensions)
+ [Install via `extras` name](#install-via-extras-name)
+ [Install via `manifest.yaml`](#install-via-manifestyaml)
+ [Check the instructions reported in the documentation](#check-the-instructions-reported-in-the-documentation)
* [Virtual environment installation](#virtual-environment-installation)
* [Docker installation](#docker-installation)
- [Mobile app](#mobile-app)
- [Tests](#tests)
- [Useful links](#useful-links)
- [Funding](#funding)
<!-- tocstop -->
## Introduction
- Recommended read: [**Getting started with Platypush**](https://blog.platypush.tech/article/Ultimate-self-hosted-automation-with-Platypush).
Platypush is a general-purpose extensible platform for automation across
multiple services and devices.
- The [blog](https://blog.platypush.tech) is in general a good place to get
more insights on what you can build with it and inspiration about possible
usages.
- The [wiki](https://git.platypush.tech/platypush/platypush/wiki) also
contains many resources on getting started.
- Extensive documentation for all the available integrations and messages [is
available](https://docs.platypush.tech/).
- If you have issues/feature requests/enhancement ideas please [create an
issue](https://git.platypush.tech/platypush/platypush/-/issues).
- A [Reddit channel](https://www.reddit.com/r/platypush) is also available for
more general questions.
- A [Matrix instance](https://matrix.to/#/#platypush:matrix.platypush.tech) is
also available if you are looking for more interactive support.
---
Platypush is a general-purpose extensible platform for automation and
integration across multiple services and devices.
It enables users to create their own self-hosted pieces of automation based on
events (*if this happens then do that*)
@ -62,15 +72,16 @@ everything you need to visualize and control under one roof.
It takes some concepts from [IFTTT](https://ifttt.com),
[Tasker](https://tasker.joaoapps.com/), [Microsoft
Flow](https://flow.microsoft.com) and [Home
Assistant](https://www.home-assistant.io/) to provide an environment where the
user can easily connect things together.
Flow](https://flow.microsoft.com), [PushBullet](https://pushbullet.com) and
[Home Assistant](https://www.home-assistant.io/) to provide an environment
where the user can easily connect things together.
It's built with compatibility and flexibility in mind, and it can easily run on
any device that can run a Python interpreter - from a Raspberry Pi zero, to an
old smartphone, to a beefy server.
#### What it can do
Its ideal home is a single-board computer like a RaspberryPi that you can
configure to orchestrate any home automation and cloud automation in your own
living room or garage, but it can easily run on any device that can run a
Python interpreter, and the bar for the hardware requirements is very low as
well - I use it to run pieces of automation on devices as powerful as a
RaspberryPi Zero or an old Nokia N900 with Linux.
You can use Platypush to do things like:
@ -101,254 +112,13 @@ You can use Platypush to do things like:
- [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)
- Build your own web dashboard with calendar, weather, news and music controls
(basically, anything that has a Platypush web widget)
- ...and much more (basically, anything that comes with a [Platypush plugin](https://docs.platypush.tech))
## Installation
### Prerequisites
Platypush uses [Redis](https://redis.io/) to dispatch requests, responses,
events and custom messages across several processes and integrations.
#### Docker installation
You can run Redis on the fly on your local machine using a Docker image:
```bash
# Expose a Redis server on port 6379 (default)
docker run --rm -p 6379:6379 --name redis redis
```
#### Use an external service
You can let Platypush use an external Redis service, if you wish to avoid
running one on the same machine.
In such scenario, simply start the application by passing custom values for
`--redis-host` and `--redis-port`, or configure these values in its
configuration file:
```yaml
redis:
host: some-ip
port: some-port
```
If you wish to run multiple instances that use the same Redis server, you may
also want to customize the name of the default queue that they use
(`--redis-queue` command-line option) in order to avoid conflicts.
#### Manual installation
Unless you are running Platypush in a Docker container, or you are running
Redis in a Docker container, or you want to use a remote Redis service, the
Redis server should be installed on the same machine where Platypush runs:
```bash
# On Debian-based distributions
sudo apt install redis-server
# On Arch-based distributions
# The hiredis package is also advised
sudo pacman -S redis
# On MacOS
brew install redis
```
Once Redis is installed, you have two options:
1. Run it a separate service. This depends on your operating system and
supervisor/service controller. For example, on systemd:
```bash
# Enable and start the service
sudo systemctl enable redis
sudo systemctl start redis
```
2. Let Platypush run and control the Redis service. This is a good option if
you want Platypush to run its own service, separate from any other one
running on the same machine, and terminate it as soon as the application
ends. In this case, simply launch the application with the `--start-redis`
option (and optionally `--redis-port <any-num>` to customize the listen
port).
### Install through `pip`
```bash
[sudo] pip install platypush
```
### Install through a system package manager
Note: currently only Arch Linux and derived distributions are supported.
You can either install the
[`platypush`](https://aur.archlinux.org/packages/platypush) package (for the
latest stable version) or the
[`platypush-git`](https://aur.archlinux.org/packages/platypush-git) package
(for the latest git version) through your favourite AUR package manager. For
example, using `yay`:
```bash
yay platypush
# Or
yay platypush-git
```
The Arch Linux packages on AUR are automatically updated upon new git commits
or tags.
### Install from sources
```shell
git clone https://git.platypush.tech/platypush/platypush.git
cd platypush
[sudo] pip install .
```
### Installing the dependencies for your extensions
After installing the base platform, you may want to check the dependencies and
configuration required by the extensions that you wish to use. There are a few
ways to check the dependencies required by an extension:
#### Install via `extras` name
All the extensions that require extra dependencies are listed in the
[`extras_require` section under
`setup.py`](https://git.platypush.tech/platypush/platypush/src/branch/master/setup.py#L84).
#### Install via `manifest.yaml`
All the plugins and backends have a `manifest.yaml` file in their source folder.
Any extra dependencies are listed there
If you followed the `extras` or `manifest.yaml` way to discover the
dependencies, then you can install them in two ways:
1. `pip` installation:
```shell
[sudo] pip3 install 'platypush[extra1,extra2,extra3]'
```
2. Sources installation:
```shell
cd $DIR_TO_PLATYPUSH
[sudo] pip3 install '.[extra1,extra2,extra3]'
```
#### Check the instructions reported in the documentation
If you follow this route then simply run the commands listed in the
[plugin/backend documentation](https://docs.platypush.tech) to get the
dependencies installed.
After installing the dependencies, create a configuration file under
`~/.config/platypush/config.yaml` (the application can load the configuration
from another location through the `-c` option) containing the configuration of
the backend and plugins that you want to use, and add any hooks and procedures
for your use case.
You can then start the service by simply running:
```shell
platypush
```
See `platypush --help` for a full list of options.
It's advised to run it as a systemd service though - simply copy the provided
[`.service`
file](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/systemd/platypush.service)
to `~/.config/systemd/user`, check if the path of `platypush` matches the path
where it's installed on your system, and start the service via `systemctl`:
```shell
systemctl --user start platypush
```
### Virtual environment installation
Platypush provides a script named `platyvenv` that can parse a `config.yaml`
and automatically create a virtual environment (under
`~/.local/share/platypush/venv/<device_id>`) with all the dependencies required
by the configured integrations.
1. Create the environment from a configuration file:
```shell
platyvenv build -c /path/to/config.yaml
```
2. Start the service from the virtual environment:
```shell
# device_id matches either the hostname or the device_id in config.yaml
platyvenv start device_id
```
3. Stop the instance:
```shell
platyvenv stop device_id
```
4. Remove the instance:
```shell
platyvenv rm device_id
```
[Wiki instructions](https://git.platypush.tech/platypush/platypush/wiki/Run-platypush-in-a-virtual-environment)
### Docker installation
You can also install Platypush in a container - the application provides a
script named `platydock` that automatically creates a container instance from a
`config.yaml`:
1. Create the container from a configuration file:
```shell
platydock build -c /path/to/config.yaml
```
2. Start the container:
```shell
# device_id matches either the hostname or the device_id in config.yaml
platydock start device_id
```
3. Stop the instance:
```shell
platydock stop device_id
```
4. Remove the instance:
```shell
platydock rm device_id
```
Note that both the virtual environment and Docker container option offer the
possibility to include extra YAML configuration files in the main `config.yaml`
through the `include` directive (as long as they are in the same folder as the
main `config.yaml`), as well as external Python scripts in a `scripts`
directory in the same folder as the `config.yaml`.
[Wiki instructions](https://git.platypush.tech/platypush/platypush/wiki/Run-platypush-in-a-container)
- ...and much more (basically, anything that comes with a [Platypush plugin](https://docs.platypush.tech/en/latest/plugins.html))
## Architecture
The architecture of Platypush consists of a few simple pieces, orchestrated by
a configuration file stored by default under
[`~/.config/platypush/config.yaml`](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/conf/config.yaml):
[`~/.config/platypush/config.yaml`](https://git.platypush.tech/platypush/platypush/-/blob/master/examples/conf/config.yaml):
### Plugins
@ -413,36 +183,57 @@ as simple JSON messages:
[Full list](https://docs.platypush.tech/en/latest/backends.html)
They are background services that listen for messages on channels (like
They are background services that either listen for messages on channels (like
an [HTTP
backend](https://docs.platypush.tech/en/latest/platypush/backend/http.html), an
[MQTT
instance](https://docs.platypush.tech/en/latest/platypush/backend/mqtt.html), a
[Kafka
instance](https://docs.platypush.tech/en/latest/platypush/backend/kafka.html).
instance](https://docs.platypush.tech/en/latest/platypush/backend/kafka.html),
a [Websocket
service](https://docs.platypush.tech/en/latest/platypush/backend/websocket.html),
[Pushbullet](https://docs.platypush.tech/en/latest/platypush/backend/pushbullet.html)
etc.) or monitor a device or a service for events (like a
[sensor](https://docs.platypush.tech/en/latest/platypush/backend/sensor.html),
a custom [voice
assistant](https://docs.platypush.tech/en/latest/platypush/backend/assistant.google.html),
a bridge running on a
[Zigbee](https://docs.platypush.tech/en/latest/platypush/backend/zigbee.mqtt.html)
or
[Z-Wave](https://docs.platypush.tech/en/latest/platypush/backend/zwave.html),
an [NFC card
reader](https://docs.platypush.tech/en/latest/platypush/backend/nfc.html), a
[MIDI
device](https://docs.platypush.tech/en/latest/platypush/backend/midi.html), a
[Telegram
channel](https://docs.platypush.tech/en/latest/platypush/backend/chat.telegram.html),
a [Bluetooth
scanner](https://docs.platypush.tech/en/latest/platypush/backend/bluetooth.scanner.ble.html)
etc.).
If a backend supports the execution of requests (e.g. HTTP, MQTT, Kafka,
Websocket and TCP) then you can send requests to these services in JSON format.
For example, in the case of the HTTP backend:
```shell
# Get a token
# Get a token
curl -XPOST -H 'Content-Type: application/json' -d '
{
"username": "$YOUR_USER",
"password": "$YOUR_PASSWORD"
}' http://host:8008/auth
{
"username": "$YOUR_USER",
"password": "$YOUR_PASSWORD"
}' http://host:8008/auth
# Execute a request
# Execute a request
curl -XPOST -H 'Content-Type: application/json' \
-H "Authorization: Bearer $YOUR_TOKEN" -d '
{
"type": "request",
"action": "tts.say",
"args": {
"text": "This is a test"
}
}' http://host:8008/execute
{
"type": "request",
"action": "tts.say",
"args": {
"text": "This is a test"
}
}' http://host:8008/execute
```
### Events
@ -478,7 +269,7 @@ triggered. Hooks are the glue that connects events to actions, exposing a
paradigm similar to IFTTT (_if a certain event happens then run these
actions_). They can declared as:
- Sections of the [`config.yaml`](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/conf/config.yaml).
- Sections of the [`config.yaml`](https://git.platypush.tech/platypush/platypush/-/blob/master/examples/conf/config.yaml).
Example:
```yaml
@ -502,7 +293,7 @@ event.hook.SearchSongVoiceCommand:
- Stand-alone Python scripts stored under `~/.config/platypush/scripts` and
will be dynamically imported at start time.
[Example](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/conf/hook.py):
[Example](https://git.platypush.tech/platypush/platypush/-/blob/master/examples/conf/hook.py):
```python
from platypush.event.hook import hook
@ -520,43 +311,6 @@ def on_music_play_command(event, title=None, artist=None, **context):
run('music.mpd.play', results[0]['file'])
```
#### More complex filters
Your event hooks can include more complex filters too. Structured filters
against partial event arguments are also possible, and relational operators are
supported as well. For example:
```python
from platypush.event.hook import hook
from platypush.message.event.sensor import SensorDataChangeEvent
@hook(SensorDataChangeEvent, data=1):
def hook_1(event):
"""
Triggered when event.data == 1
"""
@hook(SensorDataChangeEvent, data={'state': 1}):
def hook_2(event):
"""
Triggered when event.data['state'] == 1
"""
@hook(SensorDataChangeEvent, data={
'temperature': {'$gt': 25},
'humidity': {'$le': 15}
}):
def hook_3(event):
"""
Triggered when event.data['temperature'] > 25 and
event.data['humidity'] <= 15.
"""
```
The supported relational fields are the same supported by ElasticSearch - `$gt`
for greater than, `$lt` for lesser than, `$ge` for greater or equal, `$ne` for
not equal, etc.
### Procedures
Procedures are pieces of custom logic that can be executed as atomic actions
@ -592,7 +346,7 @@ procedure.at_home:
Python example:
```python
# Content of ~/.config/platypush/scripts/home.py
# Content of ~/.config/platypush/scripts/home.py
from platypush.procedure import procedure
from platypush.utils import run
@ -612,10 +366,10 @@ action request message to a backend - for example, over the HTTP backend:
```shell
curl -XPOST -H 'Content-Type: application/json' \
-H "Authorization: Bearer $YOUR_TOKEN" -d '
{
"type": "request",
"action": "procedure.at_home"
}' http://host:8008/execute
{
"type": "request",
"action": "procedure.at_home"
}' http://host:8008/execute
```
### Cronjobs
@ -650,7 +404,7 @@ cron.check_bt_device:
Python example:
```python
# Content of ~/.config/platypush/scripts/bt_cron.py
# Content of ~/.config/platypush/scripts/bt_cron.py
from platypush.cron import cron
from platypush.utils import run
@ -663,37 +417,6 @@ def check_bt_device(**context):
# on_device_off logic here
```
### Entities
Entities are a fundamental building block of Platypush. Most of the
integrations will store their state or connected devices in the form of
entities - e.g. the sensors detected by the Z-Wave/Zigbee/Bluetooth
integration, or the lights connected to a Hue bridge, or your cloud nodes, or
your custom Arduino/ESP machinery, and so on.
Entities provide a consistent interface to interact with your integrations
regardless of their type and the plugin that handles them. For instance, all
temperature sensors will expose the same interface, regardless if they are
Bluetooth or Zigbee sensors, and all the media plugins will expose the same
interface, regardless if they manage Chromecasts, Kodi, Plex, Jellyfin or a
local VLC player.
Once you enable the HTTP backend and a few integrations that export entities
and register a user, you can query the detected entities via:
```shell
curl -XPOST -H 'Content-Type: application/json' \
-H "Authorization: Bearer $YOUR_TOKEN" \
-d '{"type":"request", "action":"entities.get"}' \
http://localhost:8008/execute
```
All the entities expose the same interface and can be manipulated through the
same API. Also, when an entity is updated it always emits an
[`EntityUpdateEvent`](https://docs.platypush.tech/platypush/events/entities.html#platypush.message.event.entities.EntityUpdateEvent),
so you can easily create hooks that react to these events and act on multiple
types of entities.
### The web interface
If
@ -705,71 +428,194 @@ groups together the controls for most of the plugins - e.g. sensors, switches,
music controls and search, media library and torrent management, lights,
Zigbee/Z-Wave devices and so on. The UI is responsive and mobile-friendly.
#### The main web panel
This is the default panel available at `http://<host>:<port>` after
registration/login. It provides all the entities published by the integrations
under one view, with custom grouping and filtering options.
![Screenshot of the application main
panel, showing the Bluetooth, Serial, SmartThings and System integrations](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/main-panel-screenshot-1.png)
![Screenshot of the application main
panel, showing the Philips Hue, Zigbee, SmartThings and some sensors integrations](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/main-panel-screenshot-2.png)
#### The execution panel
The web interface provides an `execute` panel as well. You can use this panel to
interactively inspect the available integrations and their actions, together
with their documentation and parameters, run requests directly from the web
interface, and inspect the JSON responses.
![Screenshot of the execution panel, showing the actions autocomplete
form](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/execute-panel-screenshot-1.png)
![Screenshot of the execution panel, showing an action's automatically generated
documentation and its parsed attributes](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/execute-panel-screenshot-2.png)
#### Other web panels
Several integrations add their own feature-rich panels to the web view, turning
Platypush into a gateway to all of your services - from Zigbee sensors, to media
players and services, to your music cloud, and more.
![Screenshot of the media panel, showing search results from multiple sources
and several supported types of streaming services](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/media-panel-screenshot-1.png)
![Screenshot of one of the music
panels](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/music-panel-screenshot-1.png)
![Screenshot of the Snapcast panel, which can be used to synchronize your music
streams across multiple
devices](https://platypush-static.s3.nl-ams.scw.cloud/screenshots/snapcast-panel-screenshot-1.png)
#### Dashboards
The web service also provides means for the user to create [custom
dashboards](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/conf/dashboard.xml)
dashboards](https://git.platypush.tech/platypush/platypush/-/blob/master/examples/conf/dashboard.xml)
that can be used to show information from multiple sources on a large screen.
![Screenshot of a Platypush dashboard, showing a calendar widget, the current
music state, weather, news from the RSS integration, and a carousel of custom
pictures.](https://blog.platypush.tech/img/dashboard-1.png)
## Installation
### Running in production mode
### System installation
If you want to access your Platypush web panel outside your home network, it may
be a good idea to use an nginx/Apache reverse proxy with a valid SSL certificate
(e.g. managed by certbot). A [sample an nginx
configuration](https://git.platypush.tech/platypush/platypush/src/branch/master/examples/nginx/nginx.sample.conf)
is provided in the repository.
Platypush uses Redis to deliver and store requests and temporary messages:
#### PWA support
```yaml
# Example for Debian-based distributions
[sudo] apt-get install redis-server
Note that having the web application served over SSL is a requirement for the
PWA (progressive web app) to work. The Platypush PWA allows you to install a
Platypush native-like client on your mobile devices if you don't want to use the
full Android app.
# Enable and start the service
[sudo] systemctl enable redis
[sudo] systemctl start redis
```
#### Install through `pip`
```shell
[sudo] pip3 install platypush
```
#### Install through a system package manager
Note: currently only Arch Linux and derived distributions are supported.
You can either install the
[`platypush`](https://aur.archlinux.org/packages/platypush) package (for the
latest stable version) or the
[`platypush-git`](https://aur.archlinux.org/packages/platypush-git) package
(for the latest git version) through your favourite AUR package manager. For
example, using `yay`:
```shell
yay platypush
# Or
yay platypush-git
```
The Arch Linux packages on AUR are automatically updated upon new git commits
or tags.
#### Install from sources
```shell
git clone https://git.platypush.tech/platypush/platypush.git
cd platypush
[sudo] pip install .
# Or
[sudo] python3 setup.py install
```
### Installing the dependencies for your extensions
After installing the base platform, you may want to check the dependencies and
configuration required by the extensions that you wish to use. There are a few
ways to check the dependencies required by an extension:
#### Install via `extras` name
All the extensions that require extra dependencies are listed in the
[`extras_require` section under
`setup.py`](https://git.platypush.tech/platypush/platypush/-/blob/master/setup.py#L72).
#### Install via `manifest.yaml`
All the plugins and backends have a `manifest.yaml` file in their source folder.
Any extra dependencies are listed there
If you followed the `extras` or `manifest.yaml` way to discover the
dependencies, then you can install them in two ways:
1. `pip` installation:
```shell
[sudo] pip3 install 'platypush[extra1,extra2,extra3]'
```
2. Sources installation:
```shell
cd $DIR_TO_PLATYPUSH
[sudo] pip3 install '.[extra1,extra2,extra3]'
```
#### Check the instructions reported in the documentation
If you follow this route then simply run the commands listed in the
[plugin/backend documentation](https://docs.platypush.tech) to get the
dependencies installed.
After installing the dependencies, create a configuration file under
`~/.config/platypush/config.yaml` (the application can load the configuration
from another location through the `-c` option) containing the configuration of
the backend and plugins that you want to use, and add any hooks and procedures
for your use case.
You can then start the service by simply running:
```shell
platypush
```
It's advised to run it as a systemd service though - simply copy the provided
[`.service`
file](https://git.platypush.tech/platypush/platypush/-/blob/master/examples/systemd/platypush.service)
to `~/.config/systemd/user`, check if the path of `platypush` matches the path
where it's installed on your system, and start the service via `systemctl`:
```shell
systemctl --user start platypush
```
### Virtual environment installation
Platypush provides a script named `platyvenv` that can parse a `config.yaml`
and automatically create a virtual environment (under
`~/.local/share/platypush/venv/<device_id>`) with all the dependencies required
by the configured integrations.
1. Create the environment from a configuration file:
```shell
platyvenv build -c /path/to/config.yaml
```
2. Start the service from the virtual environment:
```shell
# device_id matches either the hostname or the device_id in config.yaml
platyvenv start device_id
```
3. Stop the instance:
```shell
platyvenv stop device_id
```
4. Remove the instance:
```shell
platyvenv rm device_id
```
[Wiki instructions](https://git.platypush.tech/platypush/platypush/wiki/Run-platypush-in-a-virtual-environment)
### Docker installation
You can also install Platypush in a container - the application provides a
script named `platydock` that automatically creates a container instance from a
`config.yaml`:
1. Create the container from a configuration file:
```shell
platydock build -c /path/to/config.yaml
```
2. Start the container:
```shell
# device_id matches either the hostname or the device_id in config.yaml
platydock start device_id
```
3. Stop the instance:
```shell
platydock stop device_id
```
4. Remove the instance:
```shell
platydock rm device_id
```
Note that both the virtual environment and Docker container option offer the
possibility to include extra YAML configuration files in the main `config.yaml`
through the `include` directive (as long as they are in the same folder as the
main `config.yaml`), as well as external Python scripts in a `scripts`
directory in the same folder as the `config.yaml`.
[Wiki instructions](https://git.platypush.tech/platypush/platypush/wiki/Run-platypush-in-a-container)
## Mobile app
@ -782,31 +628,11 @@ of Platypush to your fingertips.
## Tests
To run the tests simply run `pytest` either from the project root folder or the
`tests/` folder.
`tests/` folder. Or run the following command from the project root folder:
## Useful links
- Recommended read: [**Getting started with Platypush**](https://blog.platypush.tech/article/Ultimate-self-hosted-automation-with-Platypush).
- The [blog](https://blog.platypush.tech) is a good place to get more insights
and inspiration on what you can build.
- The [wiki](https://git.platypush.tech/platypush/platypush/wiki) also
contains many resources on getting started.
- Extensive documentation for all the available integrations and messages [is
available](https://docs.platypush.tech/).
- If you have issues/feature requests/enhancements please [create an
issue](https://git.platypush.tech/platypush/platypush/issues).
- A [Matrix instance](https://matrix.to/#/#platypush:matrix.platypush.tech) is
available if you are looking for interactive support.
- An IRC channel is also available at `#platypush@irc.platypush.tech:6697` (SSL
only).
- A [Lemmy instance](https://lemmy.platypush.tech/c/platypush) is available for
general questions.
```shell
python -m tests
```
---

9
bin/platypush Executable file
View File

@ -0,0 +1,9 @@
#!python3
from platypush import main
if __name__ == '__main__':
main()
# vim:sw=4:ts=4:et:

249
bin/platyvenv Executable file
View File

@ -0,0 +1,249 @@
#!/bin/bash
##############################################################################
# This script allows you to easily manage Platypush instances through Python #
# virtual environment. You can build environments from a config.yaml file #
# and automatically managed the required dependencies, as well as start, #
# stop and remove them #
# #
# @author: Fabio Manganiello <fabio@platypush.tech> #
# @licence: MIT #
##############################################################################
workdir="$HOME/.local/share/platypush/venv"
function build {
cfgfile=
while getopts ':c:' opt; do
case ${opt} in
c)
cfgfile=$OPTARG;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1;;
:)
echo "Option -$OPTARG requires the path to a Platypush configuration file" >&2
exit 1;;
esac
done
if [[ -z "$cfgfile" ]]; then
echo "Usage: $0 build -c <path-to-platypush-config-file>" >&2
exit 1
fi
echo "Parsing configuration file"
pip_cmd=
pkg_cmd=
includes=()
cmd_exec=()
while read -r line; do
if echo "$line" | grep -E "^pip:\s*"; then
pip_cmd="$(echo "$line" | sed -r -e 's/^pip:\s*(.*)'/\\1/)"
elif echo "$line" | grep -E "^packages:\s*"; then
pkg_cmd="$(echo "$line" | sed -r -e 's/^packages:\s*(.*)'/\\1/)"
elif echo "$line" | grep -E "^exec:\s*"; then
cmd_exec+=("$(echo "$line" | sed -r -e 's/^exec:\s*(.*)'/\\1/)")
elif echo "$line" | grep -E "^include:\s*"; then
includes+=("$(echo "$line" | sed -r -e 's/^include:\s*(.*)'/\\1/)")
elif echo "$line" | grep -E "^device_id:\s*"; then
device_id="$(echo "$line" | sed -r -e 's/^device_id:\s*(.*)'/\\1/)"
fi
done <<< "$(python <<EOF
from platypush.config import Config
from platypush.utils.manifest import get_install_commands_from_conf
deps = get_install_commands_from_conf('$(realpath "${cfgfile}")')
print(f'device_id: {Config.get("device_id")}')
if deps.get('pip'):
print(f'pip: {deps["pip"]}')
if deps.get('packages'):
print(f'packages: {deps["packages"]}')
for cmd in deps.get('exec', []):
print(f'exec: {cmd}')
for include in Config._included_files:
print(f'include: {include}')
EOF
)"
envdir="${workdir}/${device_id}"
etcdir="${envdir}/etc/platypush"
echo "Preparing virtual environment for device $device_id"
mkdir -p "$envdir"
mkdir -p "$etcdir"
srcdir=$(dirname "$cfgfile")
for ((i=0; i < ${#includes[@]}; i++)); do
incdir=$(dirname "${includes[$i]}")
incdir=$(realpath --relative-to="$srcdir" "$incdir")
destdir="$etcdir/$incdir"
mkdir -p "$destdir"
cp "${includes[$i]}" "$destdir"
done
cp "$cfgfile" "$etcdir/config.yaml"
cfgfile="${etcdir}/config.yaml"
python3 -m venv "${envdir}"
cd "${envdir}" || exit 1
source "${envdir}/bin/activate"
echo "Installing required dependencies"
# shellcheck disable=SC2086
[ -n "${pkg_cmd}" ] && sudo ${pkg_cmd}
[ -n "${pip_cmd}" ] && ${pip_cmd}
for ((i=0; i < ${#cmd_exec[@]}; i++)); do
${cmd_exec[$i]}
done
pip install --upgrade git+https://git.platypush.tech/platypush/platypush.git
echo "Platypush virtual environment prepared under $envdir"
}
function start {
if [[ -z "$1" ]]; then
echo "Usage: $0 start <env-name>" >&2
exit 1
fi
env=$1
envdir="${workdir}/${env}"
rundir="${envdir}/var/run"
pidfile="${rundir}/platypush.pid"
cfgfile="${envdir}/etc/platypush/config.yaml"
if [[ ! -d "$envdir" ]]; then
echo "No such directory: $envdir" >&2
exit 1
fi
mkdir -p "${rundir}"
if [[ -f "$pidfile" ]]; then
if pgrep -F "${pidfile}"; then
echo "Another instance (PID $(cat "${pidfile}")) is running, please stop that instance first"
exit 1
fi
echo "A PID file was found but the process does not seem to be running, starting anyway"
rm -f "$pidfile"
fi
python3 -m venv "${envdir}"
cd "${envdir}" || exit 1
source bin/activate
bin/platypush -c "$cfgfile" -P "$pidfile" &
start_time=$(date +'%s')
timeout=30
while :; do
[[ -f "$pidfile" ]] && break
now=$(date +'%s')
elapsed=$(( now-start_time ))
if (( elapsed >= timeout )); then
echo "Platypush instance '$env' did not start within $timeout seconds" >&2
exit 1
fi
echo -n '.'
sleep 1
done
pid=$(cat "$pidfile")
echo
echo "Platypush environment $env started with PID $pid"
wait "${pid}"
echo "Platypush environment $env terminated"
}
function stop {
if [[ -z "$1" ]]; then
echo "Usage: $0 stop <env-name>" >&2
exit 1
fi
env=$1
envdir="${workdir}/${env}"
rundir="${envdir}/var/run"
pidfile="${rundir}/platypush.pid"
if [[ ! -d "$envdir" ]]; then
echo "No such directory: $envdir" >&2
exit 1
fi
if [[ ! -f "$pidfile" ]]; then
echo "No pidfile found for instance \"${env}\""
exit 1
fi
pid=$(cat "$pidfile")
pids="$pid $(ps --no-headers -o pid= --ppid "$pid")"
# shellcheck disable=SC2086
kill -9 ${pids}
rm -f "$pidfile"
echo "Instance '$env' with PID $pid stopped"
}
function rme {
if [[ -z "$1" ]]; then
echo "Usage: $0 rm <env-name>" >&2
exit 1
fi
envdir="${workdir}/$1"
rundir="${envdir}/var/run"
pidfile="${rundir}/platypush.pid"
if [[ ! -d "$envdir" ]]; then
echo "No such directory: $envdir" >&2
exit 1
fi
if [[ -f "$pidfile" ]]; then
if pgrep -F "${pidfile}"; then
echo "Another instance (PID $(cat "$pidfile")) is running, please stop that instance first"
exit 1
fi
echo "A PID file was found but the process does not seem to be running, removing anyway"
fi
echo "WARNING: This operation will permanently remove the Platypush environment $1"
echo -n "Are you sure you want to continue? (y/N) "
IFS= read -r answer
echo "$answer" | grep -E '^[yY]' >/dev/null || exit 0
rm -rf "$envdir"
echo "$envdir removed"
}
function usage {
echo "Usage: $0 <build|start|stop|rm> [options]" >&2
exit 1
}
if (( $# < 1 )); then
usage
fi
action=$1
shift
mkdir -p "${workdir}"
# shellcheck disable=SC2048,SC2086
case ${action} in
'build') build $*;;
'start') start $*;;
'stop') stop $*;;
'rm') rme $*;;
*) usage;;
esac

View File

@ -1,186 +0,0 @@
import inspect
import os
import re
import sys
import textwrap as tw
from sphinx.application import Sphinx
base_path = os.path.abspath(
os.path.join(os.path.dirname(os.path.relpath(__file__)), '..', '..', '..')
)
sys.path.insert(0, base_path)
from platypush.common.reflection import Integration # noqa: E402
from platypush.utils import get_plugin_name_by_class # noqa: E402
from platypush.utils.mock import auto_mocks # noqa: E402
class IntegrationEnricher:
@staticmethod
def add_events(source: list[str], manifest: Integration, idx: int) -> int:
if not manifest.events:
return idx
source.insert(
idx,
'Triggered events\n----------------\n\n'
+ '\n'.join(
f'\t- :class:`{event.__module__}.{event.__qualname__}`'
for event in manifest.events
)
+ '\n\n',
)
return idx + 1
@staticmethod
def add_actions(source: list[str], manifest: Integration, idx: int) -> int:
if not (manifest.actions and manifest.cls):
return idx
source.insert(
idx,
'Actions\n-------\n\n'
+ '\n'.join(
f'\t- `{get_plugin_name_by_class(manifest.cls)}.{action} '
+ f'<#{manifest.cls.__module__}.{manifest.cls.__qualname__}.{action}>`_'
for action in sorted(manifest.actions.keys())
)
+ '\n\n',
)
return idx + 1
@staticmethod
def _shellify(title: str, cmd: str) -> str:
return (
f'**{title}**\n\n'
+ '.. code-block:: bash\n\n'
+ tw.indent(cmd, '\t')
+ '\n\n'
)
@classmethod
def add_install_deps(
cls, source: list[str], manifest: Integration, idx: int
) -> int:
deps = manifest.deps
parsed_deps = {
'before': deps.before,
'pip': deps.pip,
'after': deps.after,
}
if not (any(parsed_deps.values()) or deps.by_pkg_manager):
return idx
source.insert(idx, 'Dependencies\n------------\n\n')
idx += 1
if parsed_deps['before']:
source.insert(idx, cls._shellify('Pre-install', '\n'.join(deps.before)))
idx += 1
if parsed_deps['pip']:
source.insert(
idx, cls._shellify('pip', 'pip install ' + ' '.join(deps.pip))
)
idx += 1
for pkg_manager, sys_deps in deps.by_pkg_manager.items():
if not sys_deps:
continue
source.insert(
idx,
cls._shellify(
pkg_manager.value.default_os.value.description,
pkg_manager.value.install_doc + ' ' + ' '.join(sys_deps),
),
)
idx += 1
if parsed_deps['after']:
source.insert(idx, cls._shellify('Post-install', '\n'.join(deps.after)))
idx += 1
return idx
@classmethod
def add_description(cls, source: list[str], manifest: Integration, idx: int) -> int:
docs = (
doc
for doc in (
inspect.getdoc(manifest.cls) or '',
manifest.constructor.doc if manifest.constructor else '',
)
if doc
)
if not docs:
return idx
docstring = '\n\n'.join(docs)
source.insert(idx, f"Description\n-----------\n\n{docstring}\n\n")
return idx + 1
@classmethod
def add_conf_snippet(
cls, source: list[str], manifest: Integration, idx: int
) -> int:
source.insert(
idx,
tw.dedent(
f"""
Configuration
-------------
.. code-block:: yaml
{tw.indent(manifest.config_snippet, ' ')}
"""
),
)
return idx + 1
def __call__(self, _: Sphinx, doc: str, source: list[str]):
if not (source and re.match(r'^platypush/(backend|plugins)/.*', doc)):
return
src = [src.split('\n') for src in source][0]
if len(src) < 3:
return
manifest_file = os.path.join(
base_path,
*doc.split(os.sep)[:-1],
*doc.split(os.sep)[-1].split('.'),
'manifest.yaml',
)
if not os.path.isfile(manifest_file):
return
with auto_mocks():
manifest = Integration.from_manifest(manifest_file)
idx = self.add_description(src, manifest, idx=3)
idx = self.add_conf_snippet(src, manifest, idx=idx)
idx = self.add_install_deps(src, manifest, idx=idx)
idx = self.add_events(src, manifest, idx=idx)
idx = self.add_actions(src, manifest, idx=idx)
src.insert(idx, '\n\nModule reference\n----------------\n\n')
source[0] = '\n'.join(src)
def setup(app: Sphinx):
app.connect('source-read', IntegrationEnricher())
return {
'version': '0.1',
'parallel_read_safe': True,
'parallel_write_safe': True,
}

View File

@ -1,196 +0,0 @@
const processList = (list, level, addTitle) => {
const title = list.parentElement.querySelector('a')
list.classList.add('grid')
if (addTitle)
title.classList.add('grid-title')
list.querySelectorAll(`li.toctree-l${level}`).forEach((item) => {
const link = item.querySelector('a')
if (link) {
item.style.cursor = 'pointer'
item.addEventListener('click', () => link.click())
}
const name = item.querySelector('a').innerText
const img = document.createElement('img')
img.src = `https://static.platypush.tech/icons/${name.toLowerCase()}-64.png`
img.alt = ' '
item.prepend(img)
})
}
const addClipboard = (parent) => {
const pre = parent.tagName === 'PRE' ? parent : parent.querySelector('pre')
if (!pre)
return
const clipboard = document.createElement('i')
const setClipboard = (img, text) => {
clipboard.innerHTML = `<img src="https://static.platypush.tech/icons/${img}-64.png" alt="${text}">`
}
clipboard.classList.add('clipboard')
setClipboard('clipboard-bw', 'Copy')
clipboard.onclick = () => {
if (navigator && navigator.clipboard && navigator.clipboard.writeText) {
setClipboard('ok', 'Copied!')
setTimeout(() => setClipboard('clipboard-bw', 'Copy'), 2000)
return navigator.clipboard.writeText(pre.innerText.trim())
}
return Promise.reject('The Clipboard API is not available.');
}
pre.style.position = 'relative'
pre.appendChild(clipboard)
}
const Tabs = () => {
let selectedTab = null
let parent = null
let data = {}
const init = (obj) => {
data = obj
if (Object.keys(data).length && selectedTab == null)
selectedTab = Object.keys(data)[0]
}
const select = (name) => {
if (!parent) {
console.warn('Cannot select tab: parent not set')
return
}
if (!data[name]) {
console.warn(`Cannot select tab: invalid name: ${name}`)
return
}
const tabsBody = parent.querySelector('.body')
selectedTab = name
tabsBody.innerHTML = data[selectedTab]
parent.querySelectorAll('.tabs li').forEach(
(tab) => tab.classList.remove('selected')
)
const tab = [...parent.querySelectorAll('.tabs li')].find(
(t) => t.innerText === name
)
if (!tab) {
console.warn(`Cannot select tab: invalid name: ${name}`)
return
}
addClipboard(tabsBody)
tab.classList.add('selected')
}
const mount = (p) => {
const tabs = document.createElement('div')
tabs.classList.add('tabs')
parent = p
const tabsList = document.createElement('ul')
Object.keys(data).forEach((title) => {
const tab = document.createElement('li')
tab.innerText = title
tab.onclick = (event) => {
event.stopPropagation()
select(title)
},
tabsList.appendChild(tab)
})
const tabsBody = document.createElement('div')
tabsBody.classList.add('body')
tabs.appendChild(tabsList)
tabs.appendChild(tabsBody)
parent.innerHTML = ''
parent.appendChild(tabs)
select(selectedTab)
}
return {
init,
select,
mount,
}
}
const depsTabs = Tabs()
const convertDepsToTabs = () => {
const depsContainer = document.getElementById('dependencies')
if (!depsContainer)
return
const blocks = [...depsContainer.querySelectorAll('.highlight-bash')].map((block) => block.outerHTML)
const titles = [...depsContainer.querySelectorAll('p strong')].map((title) => title.innerText)
if (!(blocks.length && titles.length && blocks.length === titles.length))
return
const title = depsContainer.querySelector('h2')
const tabsData = titles.reduce((obj, title, i) => {
obj[title] = blocks[i]
return obj
}, {})
depsTabs.init(tabsData)
depsTabs.mount(depsContainer)
depsContainer.prepend(title)
}
const generateComponentsGrid = () => {
const tocWrappers = document.querySelectorAll('.toctree-wrapper.compound')
if (!tocWrappers.length) {
return
}
if (window.location.pathname.endsWith('/index.html')) {
if (tocWrappers.length < 2) {
return
}
const referenceLists = [
...tocWrappers[1].querySelectorAll('ul li.toctree-l1 ul')
].slice(0, 4)
referenceLists.forEach((list) => processList(list, 2, true))
} else if (window.location.pathname.endsWith('/plugins.html') || window.location.pathname.endsWith('/backends.html')) {
if (tocWrappers.length < 1) {
return
}
const list = tocWrappers[0].querySelector('ul')
if (list)
processList(list, 1, false)
}
}
const addClipboardToCodeBlocks = () => {
document.querySelectorAll('pre').forEach((pre) => addClipboard(pre))
}
const renderActionsList = () => {
const actionsList = document.getElementById('actions')?.querySelector('ul')
if (!actionsList)
return
[...actionsList.querySelectorAll('li')].forEach((li) => {
const link = li.querySelector('a')
link.innerHTML = `<code class="docutils literal notranslate"><span class="pre">${link.innerText}</span></code>`
})
}
document.addEventListener("DOMContentLoaded", function() {
generateComponentsGrid()
convertDepsToTabs()
addClipboardToCodeBlocks()
renderActionsList()
})

View File

@ -1,130 +0,0 @@
a, a:visited {
/* Don't change the color for visited links */
color: var(--pst-color-link) !important;
}
ul.grid {
display: grid;
@media screen and (max-width: 500px) {
grid-template-columns: repeat(1, 1fr);
}
@media screen and (min-width: 501px) and (max-width: 699px) {
grid-template-columns: repeat(2, 1fr);
}
@media screen and (min-width: 700px) {
grid-template-columns: repeat(3, 1fr);
}
}
a.grid-title {
width: 100%;
display: block;
margin: 1.5em 0;
font-size: 1.5em !important;
border-bottom: 1px solid #ccc;
}
ul.grid li {
display: flex;
align-items: center;
margin: 0 10px 10px 0;
padding: 10px;
border: 1px solid #ccc;
border-radius: 15px;
}
ul.grid img {
width: 32px;
margin-right: 5px;
}
ul.grid li code {
width: 100%;
}
ul.grid li code .pre {
width: 100%;
display: block;
white-space: pre-wrap;
}
ul.grid li:hover {
background: linear-gradient(0deg, #e0ffe8, #e3ffff);
}
ul.grid li a {
width: calc(100% - 35px);
display: flex;
justify-content: center;
}
ul.grid li a code {
background: none;
border: none;
}
ul.grid .icon {
width: 32px;
}
/* Clipboard button */
.clipboard {
position: absolute;
display: inline-block;
width: 32px;
top: 0.5em;
right: 0.5em;
cursor: pointer;
}
/* Tabs */
.tabs {
margin: 0 0 1em 0;
padding: 0;
list-style: none;
}
.tabs ul {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin: 0 0 1em 0;
padding: 0;
list-style: none;
border-bottom: 1px solid #ccc;
}
.tabs ul li {
display: inline-flex;
max-width: 25%;
margin: 0;
padding: 0.25em 0.5em;
list-style: none;
cursor: pointer;
flex-grow: 1;
justify-content: center;
align-items: center;
border-radius: 0.75em 0.75em 0 0;
border: 1px solid #ddd;
}
.tabs ul li.selected {
background: rgb(200,255,208);
}
.tabs ul li:hover {
background: rgb(190,246,218);
}
.tabs .body {
margin-top: -1em;
padding: 1em;
border: 1px solid #ccc;
border-top: none;
border-radius: 0 0 0.75em 0.75em;
}

View File

@ -6,10 +6,74 @@ Backends
:maxdepth: 1
:caption: Backends:
platypush/backend/adafruit.io.rst
platypush/backend/alarm.rst
platypush/backend/assistant.google.rst
platypush/backend/assistant.snowboy.rst
platypush/backend/bluetooth.fileserver.rst
platypush/backend/bluetooth.pushserver.rst
platypush/backend/bluetooth.scanner.rst
platypush/backend/bluetooth.scanner.ble.rst
platypush/backend/button.flic.rst
platypush/backend/camera.pi.rst
platypush/backend/chat.telegram.rst
platypush/backend/covid19.rst
platypush/backend/file.monitor.rst
platypush/backend/foursquare.rst
platypush/backend/github.rst
platypush/backend/google.fit.rst
platypush/backend/google.pubsub.rst
platypush/backend/gps.rst
platypush/backend/http.rst
platypush/backend/http.poll.rst
platypush/backend/inotify.rst
platypush/backend/joystick.rst
platypush/backend/joystick.jstest.rst
platypush/backend/joystick.linux.rst
platypush/backend/kafka.rst
platypush/backend/light.hue.rst
platypush/backend/linode.rst
platypush/backend/log.http.rst
platypush/backend/mail.rst
platypush/backend/midi.rst
platypush/backend/mqtt.rst
platypush/backend/music.mopidy.rst
platypush/backend/music.mpd.rst
platypush/backend/music.snapcast.rst
platypush/backend/music.spotify.rst
platypush/backend/nextcloud.rst
platypush/backend/nfc.rst
platypush/backend/nodered.rst
platypush/backend/ping.rst
platypush/backend/pushbullet.rst
platypush/backend/redis.rst
platypush/backend/scard.rst
platypush/backend/sensor.accelerometer.rst
platypush/backend/sensor.arduino.rst
platypush/backend/sensor.battery.rst
platypush/backend/sensor.bme280.rst
platypush/backend/sensor.dht.rst
platypush/backend/sensor.distance.rst
platypush/backend/sensor.distance.vl53l1x.rst
platypush/backend/sensor.envirophat.rst
platypush/backend/sensor.ir.zeroborg.rst
platypush/backend/sensor.leap.rst
platypush/backend/sensor.ltr559.rst
platypush/backend/sensor.mcp3008.rst
platypush/backend/sensor.motion.pmw3901.rst
platypush/backend/sensor.serial.rst
platypush/backend/stt.deepspeech.rst
platypush/backend/stt.picovoice.hotword.rst
platypush/backend/stt.picovoice.speech.rst
platypush/backend/tcp.rst
platypush/backend/todoist.rst
platypush/backend/travisci.rst
platypush/backend/trello.rst
platypush/backend/weather.buienradar.rst
platypush/backend/weather.darksky.rst
platypush/backend/weather.openweathermap.rst
platypush/backend/websocket.rst
platypush/backend/wiimote.rst
platypush/backend/zigbee.mqtt.rst
platypush/backend/zwave.rst
platypush/backend/zwave.mqtt.rst

View File

@ -15,14 +15,17 @@ import sys
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath("./_ext"))
# -- Project information -----------------------------------------------------
project = 'Platypush'
copyright = '2017-2023, Fabio Manganiello'
author = 'Fabio Manganiello <fabio@manganiello.tech>'
copyright = '2017-2021, Fabio Manganiello'
author = 'Fabio Manganiello'
# The short X.Y version
version = ''
@ -40,7 +43,6 @@ release = ''
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'myst_parser',
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.todo',
@ -50,7 +52,6 @@ extensions = [
'sphinx.ext.githubpages',
'sphinx_rtd_theme',
'sphinx_marshmallow',
'add_dependencies',
]
# Add any paths that contain templates here, relative to this directory.
@ -59,8 +60,8 @@ templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
source_suffix = ['.rst', '.md']
# source_suffix = '.rst'
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
@ -102,7 +103,6 @@ html_domain_indices = True
html_theme_options = {
'toc_title': 'Platypush documentation',
'repository_url': 'https://git.platypush.tech/platypush/platypush',
'repository_provider': 'github',
'use_repository_button': True,
'use_issues_button': True,
'use_fullscreen_button': True,
@ -112,14 +112,7 @@ html_theme_options = {
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_css_files = [
'styles/custom.css',
]
html_js_files = [
'scripts/custom.js',
]
# html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
@ -171,9 +164,9 @@ latex_documents = [
man_pages = [(master_doc, 'platypush', 'platypush Documentation', [author], 1)]
# -- Options for TexInfo output ----------------------------------------------
# -- Options for Texinfo output ----------------------------------------------
# Grouping the document tree into TexInfo files. List of tuples
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
@ -183,7 +176,7 @@ texinfo_documents = [
'platypush Documentation',
author,
'platypush',
'A general-purpose platform for automation.',
'One line description of project.',
'Miscellaneous',
),
]
@ -194,32 +187,128 @@ texinfo_documents = [
# -- Options for intersphinx extension ---------------------------------------
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}
intersphinx_mapping = {'https://docs.python.org/': None}
# -- Options for todo extension ----------------------------------------------
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True
autodoc_default_options = {
'members': True,
'show-inheritance': True,
}
autodoc_mock_imports = [
'googlesamples.assistant.grpc.audio_helpers',
'google.assistant.embedded',
'google.assistant.library',
'google.assistant.library.event',
'google.assistant.library.file_helpers',
'google.oauth2.credentials',
'oauth2client',
'apiclient',
'tenacity',
'smartcard',
'Leap',
'oauth2client',
'rtmidi',
'bluetooth',
'gevent.wsgi',
'Adafruit_IO',
'pyperclip',
'pydbus',
'inputs',
'inotify',
'omxplayer',
'plexapi',
'cwiid',
'sounddevice',
'soundfile',
'numpy',
'cv2',
'nfc',
'ndef',
'bcrypt',
'google',
'feedparser',
'kafka',
'googlesamples',
'icalendar',
'httplib2',
'mpd',
'serial',
'pyHS100',
'grpc',
'envirophat',
'gps',
'picamera',
'pmw3901',
'PIL',
'croniter',
'pyaudio',
'avs',
'PyOBEX',
'todoist',
'trello',
'telegram',
'telegram.ext',
'pyfirmata2',
'cups',
'graphyte',
'cpuinfo',
'psutil',
'openzwave',
'deepspeech',
'wave',
'pvporcupine ',
'pvcheetah',
'pyotp',
'linode_api4',
'pyzbar',
'tensorflow',
'keras',
'pandas',
'samsungtvws',
'paramiko',
'luma',
'zeroconf',
'dbus',
'gi',
'gi.repository',
'twilio',
'Adafruit_Python_DHT',
'RPi.GPIO',
'RPLCD',
'imapclient',
'pysmartthings',
'aiohttp',
'watchdog',
'pyngrok',
'irc',
'irc.bot',
'irc.strings',
'irc.client',
'irc.connection',
'irc.events',
'defusedxml',
'nio',
'aiofiles',
'aiofiles.os',
'async_lru',
]
sys.path.insert(0, os.path.abspath('../..'))
from platypush.utils.mock.modules import mock_imports # noqa
autodoc_mock_imports = [*mock_imports]
# _ = app
# __ = what
# ___ = obj
# ____ = options
def _skip(_, __, name, ___, skip, ____):
def skip(app, what, name, obj, skip, options):
if name == "__init__":
return False
return skip
def setup(app):
app.connect("autodoc-skip-member", _skip)
app.connect("autodoc-skip-member", skip)
# vim:sw=4:ts=4:et:

View File

@ -11,15 +11,16 @@ Events
platypush/events/application.rst
platypush/events/assistant.rst
platypush/events/bluetooth.rst
platypush/events/button.flic.rst
platypush/events/camera.rst
platypush/events/chat.slack.rst
platypush/events/chat.telegram.rst
platypush/events/clipboard.rst
platypush/events/covid19.rst
platypush/events/custom.rst
platypush/events/dbus.rst
platypush/events/distance.rst
platypush/events/entities.rst
platypush/events/file.rst
platypush/events/flic.rst
platypush/events/foursquare.rst
platypush/events/geo.rst
platypush/events/github.rst
@ -29,7 +30,6 @@ Events
platypush/events/gotify.rst
platypush/events/gpio.rst
platypush/events/gps.rst
platypush/events/hid.rst
platypush/events/http.rst
platypush/events/http.hook.rst
platypush/events/http.rss.rst
@ -65,9 +65,10 @@ Events
platypush/events/sound.rst
platypush/events/stt.rst
platypush/events/sun.rst
platypush/events/telegram.rst
platypush/events/tensorflow.rst
platypush/events/todoist.rst
platypush/events/torrent.rst
platypush/events/travisci.rst
platypush/events/trello.rst
platypush/events/video.rst
platypush/events/weather.rst
@ -75,7 +76,6 @@ Events
platypush/events/web.widget.rst
platypush/events/websocket.rst
platypush/events/wiimote.rst
platypush/events/xmpp.rst
platypush/events/zeroborg.rst
platypush/events/zeroconf.rst
platypush/events/zigbee.mqtt.rst

View File

@ -1,51 +1,23 @@
Platypush
#########
Description
===========
Welcome to the Platypush reference of available plugins, backends and event types.
This is the main documentation hub for Platypush. It includes both the wiki and
the complete reference of the available integrations.
For more information on Platypush check out:
Platypush is a general-purpose automation framework that can be used to cover
all the cases where you'd use a home automation hub, a media center, a smart
assistant, some IFTTT recipes, and a variety of other products and services.
* The `main page`_ of the project
* The `Gitea page`_ of the project
* The `online wiki`_ for quickstart and examples
* The `Blog articles`_ for inspiration on use-cases possible projects
It draws inspiration from the following projects, and it aims to cover all of
their use-cases:
* `Home Assistant <https://www.home-assistant.io/>`_
* `Homebridge <https://homebridge.io/>`_
* `OpenHAB <https://www.openhab.org/>`_
* `IFTTT <https://ifttt.com/>`_
* `Tasker <https://tasker.joaoapps.com/>`_
Useful links
============
* The `main page <https://platypush.tech>`_ of the project.
* The `Gitea page <https://git.platypush.tech/platypush/platypush>`_.
* The `blog <https://blog.platypush.tech>`_, for articles showing how to use
Platypush in real-world scenarios.
Wiki
====
.. toctree::
:maxdepth: 3
wiki/index
wiki/Installation
wiki/Configuration
wiki/Installing-extensions
wiki/A-configuration-example
wiki/The-Web-interface
Reference
=========
.. _main page: https://platypush.tech
.. _Gitea page: https://git.platypush.tech/platypush/platypush
.. _online wiki: https://git.platypush.tech/platypush/platypush/wiki
.. _Blog articles: https://blog.platypush.tech
.. toctree::
:maxdepth: 2
:caption: Contents:
backends
plugins

View File

@ -0,0 +1,6 @@
``adafruit.io``
=================================
.. automodule:: platypush.backend.adafruit.io
:members:

View File

@ -0,0 +1,5 @@
``alarm``
===========================
.. automodule:: platypush.backend.alarm
:members:

View File

@ -0,0 +1,6 @@
``assistant.google``
======================================
.. automodule:: platypush.backend.assistant.google
:members:

View File

@ -0,0 +1,6 @@
``assistant.snowboy``
=======================================
.. automodule:: platypush.backend.assistant.snowboy
:members:

View File

@ -0,0 +1,6 @@
``bluetooth.fileserver``
==========================================
.. automodule:: platypush.backend.bluetooth.fileserver
:members:

View File

@ -0,0 +1,6 @@
``bluetooth.pushserver``
==========================================
.. automodule:: platypush.backend.bluetooth.pushserver
:members:

View File

@ -0,0 +1,5 @@
``bluetooth.scanner.ble``
===========================================
.. automodule:: platypush.backend.bluetooth.scanner.ble
:members:

View File

@ -0,0 +1,5 @@
``bluetooth.scanner``
=======================================
.. automodule:: platypush.backend.bluetooth.scanner
:members:

View File

@ -0,0 +1,6 @@
``button.flic``
=================================
.. automodule:: platypush.backend.button.flic
:members:

View File

@ -0,0 +1,6 @@
``camera.pi``
===============================
.. automodule:: platypush.backend.camera.pi
:members:

View File

@ -0,0 +1,5 @@
``chat.telegram``
===================================
.. automodule:: platypush.backend.chat.telegram
:members:

View File

@ -0,0 +1,5 @@
``covid19``
=============================
.. automodule:: platypush.backend.covid19
:members:

View File

@ -0,0 +1,5 @@
``file.monitor``
==================================
.. automodule:: platypush.backend.file.monitor
:members:

View File

@ -0,0 +1,5 @@
``foursquare``
================================
.. automodule:: platypush.backend.foursquare
:members:

View File

@ -0,0 +1,5 @@
``github``
============================
.. automodule:: platypush.backend.github
:members:

View File

@ -0,0 +1,6 @@
``google.fit``
================================
.. automodule:: platypush.backend.google.fit
:members:

View File

@ -0,0 +1,5 @@
``google.pubsub``
===================================
.. automodule:: platypush.backend.google.pubsub
:members:

View File

@ -0,0 +1,6 @@
``gps``
=========================
.. automodule:: platypush.backend.gps
:members:

View File

@ -0,0 +1,6 @@
``http.poll``
===============================
.. automodule:: platypush.backend.http.poll
:members:

View File

@ -0,0 +1,6 @@
``inotify``
=============================
.. automodule:: platypush.backend.inotify
:members:

View File

@ -0,0 +1,5 @@
``joystick.jstest``
=====================================
.. automodule:: platypush.backend.joystick.jstest
:members:

View File

@ -0,0 +1,5 @@
``joystick.linux``
====================================
.. automodule:: platypush.backend.joystick.linux
:members:

View File

@ -0,0 +1,6 @@
``joystick``
==============================
.. automodule:: platypush.backend.joystick
:members:

View File

@ -0,0 +1,6 @@
``kafka``
===========================
.. automodule:: platypush.backend.kafka
:members:

View File

@ -0,0 +1,6 @@
``light.hue``
===============================
.. automodule:: platypush.backend.light.hue
:members:

View File

@ -0,0 +1,5 @@
``linode``
============================
.. automodule:: platypush.backend.linode
:members:

View File

@ -0,0 +1,5 @@
``log.http``
==============================
.. automodule:: platypush.backend.log.http
:members:

View File

@ -0,0 +1,5 @@
``mail``
==========================
.. automodule:: platypush.backend.mail
:members:

View File

@ -0,0 +1,6 @@
``mqtt``
==========================
.. automodule:: platypush.backend.mqtt
:members:

View File

@ -0,0 +1,6 @@
``music.mopidy``
==================================
.. automodule:: platypush.backend.music.mopidy
:members:

View File

@ -0,0 +1,6 @@
``music.mpd``
===============================
.. automodule:: platypush.backend.music.mpd
:members:

View File

@ -0,0 +1,6 @@
``music.snapcast``
====================================
.. automodule:: platypush.backend.music.snapcast
:members:

View File

@ -0,0 +1,5 @@
``music.spotify``
===================================
.. automodule:: platypush.backend.music.spotify
:members:

View File

@ -0,0 +1,5 @@
``nextcloud``
===============================
.. automodule:: platypush.backend.nextcloud
:members:

View File

@ -0,0 +1,6 @@
``nfc``
=========================
.. automodule:: platypush.backend.nfc
:members:

View File

@ -0,0 +1,5 @@
``ping``
==========================
.. automodule:: platypush.backend.ping
:members:

View File

@ -0,0 +1,6 @@
``pushbullet``
================================
.. automodule:: platypush.backend.pushbullet
:members:

View File

@ -0,0 +1,6 @@
``scard``
===========================
.. automodule:: platypush.backend.scard
:members:

View File

@ -0,0 +1,6 @@
``sensor.accelerometer``
==========================================
.. automodule:: platypush.backend.sensor.accelerometer
:members:

View File

@ -0,0 +1,5 @@
``sensor.arduino``
====================================
.. automodule:: platypush.backend.sensor.arduino
:members:

View File

@ -0,0 +1,5 @@
``sensor.battery``
====================================
.. automodule:: platypush.backend.sensor.battery
:members:

View File

@ -0,0 +1,6 @@
``sensor.bme280``
===================================
.. automodule:: platypush.backend.sensor.bme280
:members:

View File

@ -0,0 +1,5 @@
``sensor.dht``
================================
.. automodule:: platypush.backend.sensor.dht
:members:

View File

@ -0,0 +1,5 @@
``sensor.distance``
=====================================
.. automodule:: platypush.backend.sensor.distance
:members:

View File

@ -0,0 +1,6 @@
``sensor.distance.vl53l1x``
=============================================
.. automodule:: platypush.backend.sensor.distance.vl53l1x
:members:

View File

@ -0,0 +1,6 @@
``sensor.envirophat``
=======================================
.. automodule:: platypush.backend.sensor.envirophat
:members:

View File

@ -0,0 +1,6 @@
``sensor.ir.zeroborg``
========================================
.. automodule:: platypush.backend.sensor.ir.zeroborg
:members:

View File

@ -0,0 +1,7 @@
``sensor.leap``
=================================
.. automodule:: platypush.backend.sensor.leap
:members:

View File

@ -0,0 +1,6 @@
``sensor.ltr559``
===================================
.. automodule:: platypush.backend.sensor.ltr559
:members:

View File

@ -0,0 +1,8 @@
``sensor.mcp3008``
====================================
.. automodule:: platypush.backend.sensor.mcp3008
:members:

View File

@ -0,0 +1,5 @@
``sensor.motion.pmw3901``
=========================
.. automodule:: platypush.backend.sensor.motion.pmw3901
:members:

View File

@ -0,0 +1,6 @@
``sensor.serial``
===================================
.. automodule:: platypush.backend.sensor.serial
:members:

View File

@ -0,0 +1,5 @@
``stt.deepspeech``
====================================
.. automodule:: platypush.backend.stt.deepspeech
:members:

View File

@ -0,0 +1,5 @@
``todoist``
=============================
.. automodule:: platypush.backend.todoist
:members:

View File

@ -0,0 +1,5 @@
``travisci``
==============================
.. automodule:: platypush.backend.travisci
:members:

View File

@ -0,0 +1,5 @@
``trello``
============================
.. automodule:: platypush.backend.trello
:members:

View File

@ -0,0 +1,5 @@
``weather.buienradar``
========================================
.. automodule:: platypush.backend.weather.buienradar
:members:

View File

@ -0,0 +1,5 @@
``weather.darksky``
=====================================
.. automodule:: platypush.backend.weather.darksky
:members:

View File

@ -0,0 +1,5 @@
``weather.openweathermap``
============================================
.. automodule:: platypush.backend.weather.openweathermap
:members:

View File

@ -0,0 +1,6 @@
``websocket``
===============================
.. automodule:: platypush.backend.websocket
:members:

View File

@ -0,0 +1,6 @@
``wiimote``
=============================
.. automodule:: platypush.backend.wiimote
:members:

View File

@ -0,0 +1,5 @@
``zigbee.mqtt``
=================================
.. automodule:: platypush.backend.zigbee.mqtt
:members:

View File

@ -0,0 +1,5 @@
``zwave.mqtt``
================================
.. automodule:: platypush.backend.zwave.mqtt
:members:

View File

@ -0,0 +1,5 @@
``zwave``
===========================
.. automodule:: platypush.backend.zwave
:members:

View File

@ -0,0 +1,6 @@
``button.flic``
=======================================
.. automodule:: platypush.message.event.button.flic
:members:

View File

@ -0,0 +1,5 @@
``chat.telegram``
=========================================
.. automodule:: platypush.message.event.chat.telegram
:members:

View File

@ -0,0 +1,5 @@
``covid19``
===================================
.. automodule:: platypush.message.event.covid19
:members:

View File

@ -1,5 +0,0 @@
``entities``
============
.. automodule:: platypush.message.event.entities
:members:

View File

@ -1,5 +0,0 @@
``flic``
========
.. automodule:: platypush.message.event.flic
:members:

View File

@ -1,5 +0,0 @@
``hid``
=======
.. automodule:: platypush.message.event.hid
:members:

View File

@ -1,5 +0,0 @@
``telegram``
============
.. automodule:: platypush.message.event.telegram
:members:

View File

@ -0,0 +1,5 @@
``todoist``
===================================
.. automodule:: platypush.message.event.todoist
:members:

View File

@ -0,0 +1,5 @@
``travisci``
====================================
.. automodule:: platypush.message.event.travisci
:members:

View File

@ -1,5 +0,0 @@
``xmpp``
========
.. automodule:: platypush.message.event.xmpp
:members:

View File

@ -1,5 +0,0 @@
``application``
===============
.. automodule:: platypush.plugins.application
:members:

View File

@ -0,0 +1,6 @@
``assistant.echo``
====================================
.. automodule:: platypush.plugins.assistant.echo
:members:

View File

@ -0,0 +1,6 @@
``assistant.google.pushtotalk``
=================================================
.. automodule:: platypush.plugins.assistant.google.pushtotalk
:members:

View File

@ -0,0 +1,6 @@
``bluetooth.ble``
===================================
.. automodule:: platypush.plugins.bluetooth.ble
:members:

View File

@ -1,5 +0,0 @@
``camera.pi.legacy``
====================
.. automodule:: platypush.plugins.camera.pi.legacy
:members:

View File

@ -0,0 +1,5 @@
``chat.irc``
============
.. automodule:: platypush.plugins.chat.irc
:members:

View File

@ -0,0 +1,5 @@
``chat.telegram``
===================================
.. automodule:: platypush.plugins.chat.telegram
:members:

Some files were not shown because too many files have changed in this diff Show More