forked from platypush/platypush
Compare commits
201 Commits
Author | SHA1 | Date |
---|---|---|
Fabio Manganiello | 99de5318ff | |
Fabio Manganiello | b3bab9b1d8 | |
Fabio Manganiello | 7e4877c793 | |
Fabio Manganiello | 55602cc282 | |
Fabio Manganiello | d2053a012a | |
snyk-bot | 3d5fc9a10b | |
snyk-bot | be4dd48d76 | |
snyk-bot | bd21779a17 | |
snyk-bot | 58afc1090c | |
Fabio Manganiello | 7c87238fec | |
Fabio Manganiello | cbf8ba7fdd | |
Fabio Manganiello | c6c7128099 | |
Fabio Manganiello | 1a316bc3a6 | |
Fabio Manganiello | 5966566d54 | |
Fabio Manganiello | 8d26c8634d | |
Fabio Manganiello | 1da17fca35 | |
Fabio Manganiello | 35cb72f5aa | |
Fabio Manganiello | 115bed7d8b | |
Fabio Manganiello | 3d22d6b082 | |
Fabio Manganiello | 5971ec32c8 | |
Fabio Manganiello | 7e31ac6ed8 | |
Fabio Manganiello | c9f435a6cb | |
Fabio Manganiello | cb7021152f | |
Fabio Manganiello | d3f4865395 | |
Fabio Manganiello | f080478385 | |
Fabio Manganiello | b857ce60a7 | |
Fabio Manganiello | af483cade3 | |
Fabio Manganiello | 8be515c17b | |
Fabio Manganiello | 239025290d | |
Fabio Manganiello | 2e2169544d | |
Fabio Manganiello | 7a0e39111d | |
Fabio Manganiello | 2cd7ae9513 | |
Fabio Manganiello | 55958c1b57 | |
Fabio Manganiello | e9454b0c0f | |
Fabio Manganiello | ba23eb7280 | |
Fabio Manganiello | 41d0725ebf | |
Fabio Manganiello | 820a1c8184 | |
dependabot[bot] | 5929602c15 | |
Fabio Manganiello | fee5fc4ae0 | |
Fabio Manganiello | 371fd7e46b | |
Fabio Manganiello | da73a5f1b9 | |
Fabio Manganiello | a80adc996f | |
Fabio Manganiello | 12887b61fe | |
Fabio Manganiello | ca25607262 | |
Fabio Manganiello | 1b30bfc454 | |
Fabio Manganiello | 486801653a | |
Fabio Manganiello | f7c594cc3f | |
Fabio Manganiello | b1491b8048 | |
Fabio Manganiello | 96a2d8bef0 | |
Fabio Manganiello | e261dcc27a | |
Fabio Manganiello | d0790aaba3 | |
Fabio Manganiello | bb28617cc9 | |
Fabio Manganiello | e1e6da9307 | |
Fabio Manganiello | f6ce0d7200 | |
Fabio Manganiello | ed5f7070a2 | |
Fabio Manganiello | 5ee47902f4 | |
Fabio Manganiello | 128b45686a | |
Fabio Manganiello | 3d192a9733 | |
Fabio Manganiello | 08acaad218 | |
Fabio Manganiello | 385914c04a | |
dependabot[bot] | b72c9a19ae | |
Fabio Manganiello | 2e33d3b3c5 | |
Fabio Manganiello | c5395cc9e5 | |
Fabio Manganiello | 88846aa8f8 | |
Fabio Manganiello | ffd23cf04d | |
Fabio Manganiello | 34e1e673e8 | |
Fabio Manganiello | c3934e2a7e | |
Fabio Manganiello | b3b2a7a805 | |
Fabio Manganiello | 747e7f3e5d | |
Fabio Manganiello | fdf6d8fb4e | |
Fabio Manganiello | 7c9e9d284d | |
Fabio Manganiello | 19a1e9c626 | |
Fabio Manganiello | c0039c3f87 | |
Fabio Manganiello | 0d0797a465 | |
Fabio Manganiello | 0b293ff214 | |
Fabio Manganiello | 75ad537155 | |
dependabot[bot] | 0324eb9f6b | |
Fabio Manganiello | e3f67766a3 | |
Fabio Manganiello | 1933ec709f | |
Fabio Manganiello | 71cb73cf63 | |
Fabio Manganiello | 94bb3e0541 | |
Fabio Manganiello | 29a7eff15a | |
Fabio Manganiello | d13e4fc271 | |
Fabio Manganiello | 6e0c249b7e | |
Fabio Manganiello | 2944a77f93 | |
dependabot[bot] | 5b666814d5 | |
dependabot[bot] | 21ad599a08 | |
Fabio Manganiello | 782c198311 | |
Fabio Manganiello | 08b3cddb7b | |
Fabio Manganiello | 530245733c | |
dependabot[bot] | 1662873e54 | |
Fabio Manganiello | 42ee149b95 | |
Fabio Manganiello | 1038090ffd | |
Fabio Manganiello | 786286eac6 | |
Fabio Manganiello | 1914322fda | |
Fabio Manganiello | e4eb12fa6d | |
Fabio Manganiello | c534adf31f | |
Fabio Manganiello | 0c423e3809 | |
Fabio Manganiello | 6656bb4ce5 | |
Fabio Manganiello | f3be4a50d8 | |
Fabio Manganiello | a6b552504e | |
Fabio Manganiello | 833e1c49be | |
Fabio Manganiello | a46ce79f0a | |
Fabio Manganiello | e9f6d9a8bc | |
Fabio Manganiello | 3e4b91cd6c | |
Fabio Manganiello | e242dc53bf | |
Fabio Manganiello | ee0b6d237a | |
Fabio Manganiello | 9ba2c18595 | |
Fabio Manganiello | 0a3fd4065a | |
Fabio Manganiello | e94d338de5 | |
Fabio Manganiello | 081da3eb84 | |
Fabio Manganiello | 1569f940c6 | |
Fabio Manganiello | 6df9cbcf3c | |
Fabio Manganiello | e98aa63110 | |
Fabio Manganiello | fa0f4925ed | |
Fabio Manganiello | fa708663e1 | |
Fabio Manganiello | 20fc3d91fc | |
Fabio Manganiello | 2560bfa03f | |
Fabio Manganiello | 46d8d575ba | |
Fabio Manganiello | f478e1ff40 | |
Fabio Manganiello | 6023fd3db3 | |
Fabio Manganiello | f6057274a0 | |
Fabio Manganiello | 2d9dff7d4c | |
Fabio Manganiello | f74ca28382 | |
Fabio Manganiello | e615891bf3 | |
Fabio Manganiello | 02b5ec1d38 | |
Fabio Manganiello | 2914a74b75 | |
Fabio Manganiello | 1e1bf46f32 | |
Fabio Manganiello | 848b736d6e | |
Fabio Manganiello | f9f9c38a8b | |
Fabio Manganiello | 518d9f20c6 | |
Fabio Manganiello | 40903393df | |
Fabio Manganiello | d5cddc23fa | |
Fabio Manganiello | ea3b49a17f | |
Fabio Manganiello | adb9672989 | |
Fabio Manganiello | b432488876 | |
Fabio Manganiello | 65d4740cd7 | |
Fabio Manganiello | 6ba3128ac4 | |
Fabio Manganiello | 82fe4d93f3 | |
Fabio Manganiello | d7b273434b | |
dependabot[bot] | 5491682543 | |
Fabio Manganiello | 3ef602cc0b | |
Fabio Manganiello | 195ae5c488 | |
Fabio Manganiello | de25719563 | |
Fabio Manganiello | e86c61a44d | |
Fabio Manganiello | acdc636b1f | |
Fabio Manganiello | 6db070db1c | |
Fabio Manganiello | 952a2a9379 | |
Fabio Manganiello | 49676fcc7f | |
Fabio Manganiello | 6c0a8bf259 | |
Fabio Manganiello | 1906876969 | |
Fabio Manganiello | f9ce03919b | |
Fabio Manganiello | c3681e7b2a | |
Fabio Manganiello | 144700b693 | |
Fabio Manganiello | 4a5bb766af | |
Fabio Manganiello | cb4cfa40d8 | |
Fabio Manganiello | 8c339d0d55 | |
Fabio Manganiello | 1962a8c4de | |
Fabio Manganiello | c664796733 | |
Fabio Manganiello | 64c402b1c0 | |
Fabio Manganiello | a5f1dc2638 | |
Fabio Manganiello | 0e27c8f68a | |
Fabio Manganiello | 31ef9515f8 | |
Fabio Manganiello | d844890ab2 | |
Fabio Manganiello | ee35ea995b | |
Fabio Manganiello | 04a5480d19 | |
Fabio Manganiello | e3f0219554 | |
Fabio Manganiello | fa17011b24 | |
Fabio Manganiello | c12c83b386 | |
Fabio Manganiello | 229d05a40f | |
Fabio Manganiello | c4bd854be2 | |
Fabio Manganiello | f856ae69e1 | |
Fabio Manganiello | 68831e9e81 | |
Fabio Manganiello | d18245b15f | |
Fabio Manganiello | b961ef0424 | |
Fabio Manganiello | cb0638fe19 | |
Fabio Manganiello | 98cb216ba7 | |
Fabio Manganiello | f147c44a8a | |
Fabio Manganiello | f720e7fc7f | |
Fabio Manganiello | 10e11d66dc | |
Fabio Manganiello | a1cd25fe5a | |
Fabio Manganiello | 1a314ffd6b | |
Fabio Manganiello | 85af031c26 | |
Fabio Manganiello | 7b8938cb12 | |
Fabio Manganiello | 8c31905534 | |
Fabio Manganiello | a2f5755496 | |
Fabio Manganiello | fa11b13638 | |
Fabio Manganiello | 2b5698bdfe | |
Fabio Manganiello | 3bfc5b83ef | |
Fabio Manganiello | ac0dd95bcc | |
Fabio Manganiello | 87b70716c1 | |
Fabio Manganiello | a8064d2add | |
Fabio Manganiello | d086da64f6 | |
Fabio Manganiello | 90ec108580 | |
Fabio Manganiello | 286bab7489 | |
Fabio Manganiello | 0f37102ce4 | |
Fabio Manganiello | 8e2d4d0bce | |
Fabio Manganiello | 550fd3abe9 | |
Fabio Manganiello | 2fc7327788 | |
Fabio Manganiello | 371dd6da0a | |
Fabio Manganiello | 47228f2432 |
|
@ -19,3 +19,6 @@ platypush/requests
|
|||
/http-client.env.json
|
||||
/platypush/backend/http/static/css/dist
|
||||
/tests/etc/dashboards
|
||||
.coverage
|
||||
coverage.xml
|
||||
Session.vim
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,32 @@
|
|||
# See https://pre-commit.com for more information
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.1.0
|
||||
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
|
||||
|
||||
- repo: https://github.com/Lucas-C/pre-commit-hooks-nodejs
|
||||
rev: v1.1.2
|
||||
hooks:
|
||||
- id: markdown-toc
|
||||
|
||||
- repo: https://github.com/pycqa/flake8
|
||||
rev: 4.0.1
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies:
|
||||
- flake8-bugbear
|
||||
- flake8-comprehensions
|
||||
- flake8-simplify
|
||||
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 22.3.0
|
||||
hooks:
|
||||
- id: black
|
235
CHANGELOG.md
235
CHANGELOG.md
|
@ -5,27 +5,248 @@ Given the high speed of development in the first phase, changes are being report
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
- Removed `clipboard` backend. Enabling the `clipboard` plugin will also enable
|
||||
clipboard monitoring, with no need for an additional backend.
|
||||
|
||||
## [0.23.3] - 2022-06-01
|
||||
|
||||
### Added
|
||||
|
||||
- Added `ntfy` integration (see #219).
|
||||
- Support for a default `config.yaml` if one isn't specified in the default
|
||||
locations.
|
||||
|
||||
### Changed
|
||||
|
||||
- The HTTP server dependencies are now marked as required, since the default
|
||||
`config.yaml` will have the HTTP backend enabled by default in order to allow
|
||||
the creation of a first user.
|
||||
- Updated Vue.js frontend dependencies to the latest version.
|
||||
- Removed bulma from the frontend dependencies, making the frontend much
|
||||
lighter and loading times much faster.
|
||||
- Other UI improvements.
|
||||
|
||||
### Fixed
|
||||
|
||||
- More reliable cronjobs in case of DST change or any clock changes in general
|
||||
(see #217).
|
||||
- Fixed `--redis-queue` argument.
|
||||
|
||||
## [0.23.2] - 2022-03-27
|
||||
|
||||
### Added
|
||||
|
||||
- Support for asynchronous events over GPIO PINs. It is now possible to specify
|
||||
a list of `monitored_pins` in the [`gpio`
|
||||
plugin](https://git.platypush.tech/platypush/platypush/-/blob/master/platypush/plugins/gpio/__init__.py)
|
||||
configuration. A change in the value on those GPIO PINs (caused by e.g. a
|
||||
button, a binary sensor or a probe) will trigger a
|
||||
`platypush.message.event.gpio.GPIOEvent` that you can use in your automation
|
||||
scripts.
|
||||
|
||||
- Simplified script API to interact with platform variables
|
||||
(closes [#206](https://git.platypush.tech/platypush/platypush/-/issues/206)).
|
||||
You can now read and write stored variables in your Platypush scripts through
|
||||
a much more intuitive interface compared to explicitly using the `variable`
|
||||
plugin explicitly:
|
||||
|
||||
```python
|
||||
from platypush.context import Variable
|
||||
|
||||
# ...
|
||||
|
||||
my_var = Variable.get('my_var')
|
||||
my_var = int(my_var) + 1
|
||||
Variable.set(my_var=my_var)
|
||||
```
|
||||
|
||||
## [0.23.0] - 2022-03-01
|
||||
|
||||
### Added
|
||||
|
||||
- Added [Jellyfin integration](https://git.platypush.tech/platypush/platypush/-/issues/208).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Merged several PRs from `dependabot`.
|
||||
|
||||
- Fixed management of the `CN` field in the `calendar.ical` plugin.
|
||||
|
||||
## [0.22.10] - 2022-02-07
|
||||
|
||||
### Added
|
||||
|
||||
- Refactored the `dbus` integration. The plugin and backend have been merged into a
|
||||
single plugin component, and the ability to subscribe to custom signals has been
|
||||
added.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Proper support for empty payloads on the integrations that trigger a `SensorDataChangeEvent`.
|
||||
- Fixed possible infinite recursion on the Pushbullet integration in case of errors where the
|
||||
error and close handlers keep calling each other in a loop.
|
||||
|
||||
## [0.22.9] - 2022-01-06
|
||||
|
||||
### Added
|
||||
|
||||
- Added `rss` integration (replaces the cumbersome and deprecated `backend.http.poll`).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed timezone handling in calendar integrations.
|
||||
- Fixed handling of ignored directories in the `file.monitor` backend.
|
||||
|
||||
## [0.22.8] - 2021-12-13
|
||||
|
||||
### Added
|
||||
|
||||
- Added support for audio tracks in Plex integration.
|
||||
|
||||
### Changed
|
||||
|
||||
- Web server uWSGI wrapper changed from `uwsgi` to `gunicorn`.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed client ID assignment logic in MQTT backends to prevent client ID clashes and reconnections
|
||||
(closes #205).
|
||||
- Updated LTR559 integration to be compatible with the new API.
|
||||
- Updated Chromecast integration to be compatible with `pychromecast >= 10`.
|
||||
- Better handling of media errors.
|
||||
|
||||
## [0.22.6] - 2021-11-27
|
||||
|
||||
### Added
|
||||
|
||||
- Added support for converting webpages to markdown in `http.webpage.simplify`
|
||||
even if no `outfile` is specified.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Improved robustness of the ICal calendar parser in case some fields (e.g. `*status`)
|
||||
are not defined.
|
||||
|
||||
## [0.22.5] - 2021-11-15
|
||||
|
||||
### Added
|
||||
|
||||
- Added `mastodon` plugin.
|
||||
- Added `chat.irc` plugin.
|
||||
- Added `mailgun` plugin.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed `switchbot.status` method in case of virtual devices.
|
||||
- Fixed `platypush[alexa]` optional package installation.
|
||||
|
||||
## [0.22.4] - 2021-10-19
|
||||
|
||||
### Added
|
||||
|
||||
- Support for IR virtual devices in Switchbot plugin.
|
||||
- Added [`google.maps.get_travel_time`](https://docs.platypush.tech/platypush/plugins/google.maps.html#platypush.plugins.google.maps.GoogleMapsPlugin.get_travel_time)
|
||||
method (closes #115).
|
||||
- Support for custom YouTube video/audio formats on media plugins.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Responses for requests received over an MQTT backend are now delivered to the right topic
|
||||
(`<device_base_topic>/responses/<msg_id>`).
|
||||
- Various fixes on media plugins.
|
||||
|
||||
## [0.22.3] - 2021-10-01
|
||||
|
||||
### Added
|
||||
|
||||
- `gotify` integration (see #198).
|
||||
|
||||
## [0.22.2] - 2021-09-25
|
||||
|
||||
### Added
|
||||
|
||||
- `ngrok` integration (see #196).
|
||||
|
||||
## [0.22.1] - 2021-09-22
|
||||
|
||||
### Fixed
|
||||
|
||||
- `zigbee.mqtt` backend now no longer requires the MQTT backend/plugin to be enabled.
|
||||
|
||||
- Fixed bug on empty popcorn API responses.
|
||||
|
||||
### Changed
|
||||
|
||||
- Created CI Gitlab pipeline to replace the Platypush event-based pre-existing pipeline.
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed docs references to removed/abstract integrations.
|
||||
|
||||
## [0.22.0] - 2021-09-16
|
||||
|
||||
### Changed
|
||||
|
||||
- Platypush now uses manifest files to describe plugins and backends. Each extension is now
|
||||
expected to provide a `manifest.yaml` file in its folder, reporting its package name, pip
|
||||
dependencies, required system packages and optional extra installation commands.
|
||||
|
||||
- Refactored `platyvenv`, `platydock`, documentation generation and plugin management engine.
|
||||
They are now both faster and more robust, since they can rely on the manifest definition to
|
||||
operate instead of pydoc strings conventions or `config.yaml` conventions.
|
||||
|
||||
- `platyvenv start` now starts the environment process synchronously and it prints
|
||||
stdout/stderr instead of redirecting it to the logs dir (previous behaviour:
|
||||
`platyvenv start` used to start the process asynchronously and the logs were stored
|
||||
to `~/.local/share/platypush/venv/<env>/logs/<stdout|stderr>.log`).
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed `Homeseer` integration - it was based on a Python integration that has now been
|
||||
pulled out of PyPI and GitHub. A new integration may come in the future if there is enough
|
||||
demand for it.
|
||||
|
||||
## [0.21.4] - 2021-08-24
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed JWT token generation, since python-jwt >= 2.0 always returns strings (not bytes) upon `jwt.encode`.
|
||||
|
||||
## [0.21.3] - 2021-07-28
|
||||
|
||||
### Added
|
||||
|
||||
- Added `sun` plugin for sunrise/sunset events.
|
||||
|
||||
- Added `slack` integration.
|
||||
|
||||
## [0.21.2] - 2021-07-20
|
||||
|
||||
### Added
|
||||
|
||||
- Added `music.spotify` backend to emulate a Spotify Connect receiver through Platypush.
|
||||
|
||||
- Added `music.spotify` plugin.
|
||||
|
||||
- Added `music.spotify` UI integration.
|
||||
|
||||
## [0.21.1] - 2021-06-22
|
||||
|
||||
### Added
|
||||
|
||||
- Added `switchbot` plugin to interact with Switchbot devices over the cloud API instead of
|
||||
directly accessing the device's Bluetooth interface.
|
||||
|
||||
|
||||
- Added `marshmallow` dependency - it will be used from now own to dump and document schemas
|
||||
and responses instead of the currently mixed approach with `Response` objects and plain
|
||||
dictionaries and lists.
|
||||
|
||||
|
||||
- Support for custom MQTT timeout on all the `zwavejs2mqtt` calls.
|
||||
|
||||
- Added generic joystick backend `backend.joystick.jstest` which uses `jstest` from the
|
||||
standard `joystick` system package to read the state of joysticks not compatible with
|
||||
`python-inputs`.
|
||||
|
||||
|
||||
- Added PWM PCA9685 plugin.
|
||||
|
||||
- Added Linux native joystick plugin, ``backend.joystick.linux``, for the cases where
|
||||
|
@ -82,7 +303,7 @@ Given the high speed of development in the first phase, changes are being report
|
|||
|
||||
- Added `<Camera>` dashboard widget.
|
||||
|
||||
- Added support for custom dashboard widgets with customized (see https://git.platypush.tech/platypush/platypush/-/wikis/Backends#creating-custom-widgets).
|
||||
- Added support for custom dashboard widgets with customized (see https://git.platypush.tech/platypush/platypush/wiki/Backends#creating-custom-widgets).
|
||||
|
||||
- Added support for controls on `music.mpd` dashboard widget.
|
||||
|
||||
|
@ -129,7 +350,7 @@ Given the high speed of development in the first phase, changes are being report
|
|||
|
||||
- Added support for a static list of devices to actively scan to the `bluetooth.scanner` backend
|
||||
(see [#174](https://git.platypush.tech/platypush/platypush/-/issues/174)).
|
||||
|
||||
|
||||
- Added `weather.openweathermap` plugin and backend, which replaces `weather.darksky`, since the
|
||||
Darksky API will be completely shut down by the end of 2021.
|
||||
|
||||
|
@ -137,14 +358,14 @@ Given the high speed of development in the first phase, changes are being report
|
|||
|
||||
- Cron expressions should adhere to the UNIX cronjob standard and use the machine local time,
|
||||
not UTC, as a reference (closes [#173](https://git.platypush.tech/platypush/platypush/-/issues/173)).
|
||||
|
||||
|
||||
- Better management of Z-Wave values types from the UI.
|
||||
|
||||
- Disable logging for `ZwaveValueEvent` events - they tend to be very verbose and
|
||||
can impact the performance on slower devices. They will still be published to the
|
||||
websocket clients though, so you can still debug Z-Wave values issues from the browser
|
||||
developer console (enable debug traces).
|
||||
|
||||
|
||||
- Added suffix to the `zigbee.mqtt` backend default `client_id` to prevent clashes with
|
||||
the default `mqtt` backend `client_id`.
|
||||
|
||||
|
|
|
@ -29,9 +29,11 @@ Guidelines:
|
|||
|
||||
- If the feature requires an optional dependency then make sure to document it:
|
||||
|
||||
- In the class docstring (see other plugins and backends for examples)
|
||||
- In the class docstring (see other plugins and backends for examples).
|
||||
- In [`setup.py`](https://git.platypush.tech/platypush/platypush/-/blob/master/setup.py#L72) as
|
||||
an `extras_require` entry
|
||||
- In [`requirements.txt`](https://git.platypush.tech/platypush/platypush/-/blob/master/requirements.txt) -
|
||||
if the feature is optional then leave it commented and add a one-line comment to explain which
|
||||
plugin or backend requires it.
|
||||
an `extras_require` entry.
|
||||
- In the plugin/backend class pydoc string.
|
||||
- In the `manifest.yaml` - refer to the Wiki (how to write
|
||||
[plugins](https://git.platypush.tech/platypush/platypush/wiki/Writing-your-own-plugins)
|
||||
and [backends](https://git.platypush.tech/platypush/platypush/wiki/Writing-your-own-backends))
|
||||
for examples on how to write an extension manifest file.
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
recursive-include platypush/backend/http/webapp/dist *
|
||||
include platypush/plugins/http/webpage/mercury-parser.js
|
||||
include platypush/config/*.yaml
|
||||
global-include manifest.yaml
|
||||
|
|
507
README.md
507
README.md
|
@ -6,39 +6,82 @@ Platypush
|
|||
[![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/-/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/-/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 -->
|
||||
|
||||
- [Architecture](#architecture)
|
||||
* [Plugins](#plugins)
|
||||
* [Actions](#actions)
|
||||
* [Backends](#backends)
|
||||
* [Events](#events)
|
||||
* [Hooks](#hooks)
|
||||
* [Procedures](#procedures)
|
||||
* [Cronjobs](#cronjobs)
|
||||
* [The web interface](#the-web-interface)
|
||||
- [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)
|
||||
- [Funding](#funding)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
- Recommended read: [**Getting started with Platypush**](https://blog.platypush.tech/article/Ultimate-self-hosted-automation-with-Platypush).
|
||||
|
||||
- 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 [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/-/wikis/home) also contains many resources on getting started.
|
||||
- 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/).
|
||||
- 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).
|
||||
- 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 [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.
|
||||
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*)
|
||||
and it provides a comprehensive and customizable user interface that collects everything you need to visualize and
|
||||
control under one roof.
|
||||
It enables users to create their own self-hosted pieces of automation based on
|
||||
events (*if this happens then do that*)
|
||||
and it provides a comprehensive and customizable user interface that collects
|
||||
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), [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 takes some concepts from [IFTTT](https://ifttt.com),
|
||||
[Tasker](https://tasker.joaoapps.com/), [Microsoft
|
||||
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.
|
||||
|
||||
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.
|
||||
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:
|
||||
|
||||
|
@ -47,8 +90,10 @@ You can use Platypush to do things like:
|
|||
- [Create custom and privacy-secure voice assistants that run custom hooks on your phrases](https://blog.platypush.tech/article/Build-custom-voice-assistants)
|
||||
- Build integrations between [sensors](https://docs.platypush.tech/en/latest/platypush/backend/sensor.html),
|
||||
[cameras](https://docs.platypush.tech/en/latest/platypush/plugins/camera.pi.html),
|
||||
[microphones](https://docs.platypush.tech/en/latest/platypush/plugins/sound.html) and
|
||||
[machine learning models](https://docs.platypush.tech/en/latest/platypush/plugins/tensorflow.html) to create smart
|
||||
[microphones](https://docs.platypush.tech/en/latest/platypush/plugins/sound.html)
|
||||
and [machine learning
|
||||
models](https://docs.platypush.tech/en/latest/platypush/plugins/tensorflow.html)
|
||||
to create smart
|
||||
pieces of automation for e.g.
|
||||
[people detection](https://blog.platypush.tech/article/Detect-people-with-a-RaspberryPi-a-thermal-camera-Platypush-and-a-pinch-of-machine-learning)
|
||||
or [sound detection](https://blog.platypush.tech/article/Create-your-smart-baby-monitor-with-Platypush-and-Tensorflow)
|
||||
|
@ -60,35 +105,53 @@ You can use Platypush to do things like:
|
|||
- [Control your smart switches](https://docs.platypush.tech/en/latest/platypush/plugins/switch.html)
|
||||
- [Implement automated custom text-to-speech routines](https://docs.platypush.tech/en/latest/platypush/plugins/tts.html)
|
||||
- [Build any kind of interactions and automation routines with your Android device using Tasker](https://blog.platypush.tech/article/How-to-build-your-personal-infrastructure-for-data-collection-and-visualization)
|
||||
- Play [local videos](https://docs.platypush.tech/en/latest/platypush/plugins/media.mpv.html), YouTube videos and torrent media from any device and service, to any device
|
||||
- Play [local
|
||||
videos](https://docs.platypush.tech/en/latest/platypush/plugins/media.mpv.html),
|
||||
YouTube videos and torrent media from any device and service, to any device
|
||||
- [Get weather forecast events for your location and build automation routines on them](https://docs.platypush.tech/en/latest/platypush/plugins/weather.darksky.html)
|
||||
- [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)
|
||||
- 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/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/-/blob/master/examples/conf/config.yaml):
|
||||
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/-/blob/master/examples/conf/config.yaml):
|
||||
|
||||
### [Plugins](https://docs.platypush.tech/en/latest/plugins.html)
|
||||
### Plugins
|
||||
|
||||
They are integrations that do things - like
|
||||
[modify files](https://docs.platypush.tech/en/latest/platypush/plugins/file.html),
|
||||
[train and evaluate machine learning models](https://docs.platypush.tech/en/latest/platypush/plugins/tensorflow.html),
|
||||
[control cameras](https://docs.platypush.tech/en/latest/platypush/plugins/camera.pi.html),
|
||||
[read sensors](https://docs.platypush.tech/en/latest/platypush/plugins/gpio.sensor.dht.html),
|
||||
[parse a web page](https://docs.platypush.tech/en/latest/platypush/plugins/http.webpage.html),
|
||||
[control lights](https://docs.platypush.tech/en/latest/platypush/plugins/light.hue.html),
|
||||
[send emails](https://docs.platypush.tech/en/latest/platypush/plugins/mail.smtp.html),
|
||||
[control Chromecasts](https://docs.platypush.tech/en/latest/platypush/plugins/media.chromecast.html),
|
||||
[run voice queries](https://docs.platypush.tech/en/latest/platypush/plugins/assistant.google.html),
|
||||
[handle torrent transfers](https://docs.platypush.tech/en/latest/platypush/plugins/torrent.html) or
|
||||
control [Zigbee](https://docs.platypush.tech/en/latest/platypush/plugins/zigbee.mqtt.html) or
|
||||
[Z-Wave](https://docs.platypush.tech/en/latest/platypush/plugins/zwave.html) devices.
|
||||
[Full list](https://docs.platypush.tech/en/latest/plugins.html)
|
||||
|
||||
The configuration of a plugin matches one-on-one that of its documented class constructor, so it's very straightforward
|
||||
to write a configuration for a plugin by reading its documentation:
|
||||
Plugins are integrations that do things - like [modify
|
||||
files](https://docs.platypush.tech/en/latest/platypush/plugins/file.html),
|
||||
[train and evaluate machine learning
|
||||
models](https://docs.platypush.tech/en/latest/platypush/plugins/tensorflow.html),
|
||||
[control
|
||||
cameras](https://docs.platypush.tech/en/latest/platypush/plugins/camera.pi.html),
|
||||
[read
|
||||
sensors](https://docs.platypush.tech/en/latest/platypush/plugins/gpio.sensor.dht.html),
|
||||
[parse a web
|
||||
page](https://docs.platypush.tech/en/latest/platypush/plugins/http.webpage.html),
|
||||
[control
|
||||
lights](https://docs.platypush.tech/en/latest/platypush/plugins/light.hue.html),
|
||||
[send
|
||||
emails](https://docs.platypush.tech/en/latest/platypush/plugins/mail.smtp.html),
|
||||
[control
|
||||
Chromecasts](https://docs.platypush.tech/en/latest/platypush/plugins/media.chromecast.html),
|
||||
[run voice
|
||||
queries](https://docs.platypush.tech/en/latest/platypush/plugins/assistant.google.html),
|
||||
[handle torrent
|
||||
transfers](https://docs.platypush.tech/en/latest/platypush/plugins/torrent.html)
|
||||
or control
|
||||
[Zigbee](https://docs.platypush.tech/en/latest/platypush/plugins/zigbee.mqtt.html)
|
||||
or [Z-Wave](https://docs.platypush.tech/en/latest/platypush/plugins/zwave.html)
|
||||
devices.
|
||||
|
||||
The configuration of a plugin matches one-on-one that of its documented class
|
||||
constructor, so it's very straightforward to write a configuration for a plugin
|
||||
by reading its documentation:
|
||||
|
||||
```yaml
|
||||
light.hue:
|
||||
|
@ -100,9 +163,11 @@ light.hue:
|
|||
|
||||
### Actions
|
||||
|
||||
Plugins expose *actions*, that match one-on-one the plugin class methods denoted by `@action`, so it's very
|
||||
straightforward to invoke plugin actions by just reading the plugin documentation. They can be invoked directly from
|
||||
your own scripts or they can be sent to the platform through any supported channel as simple JSON messages:
|
||||
Plugins expose *actions*, that match one-on-one the plugin class methods
|
||||
denoted by `@action`, so it's very straightforward to invoke plugin actions by
|
||||
just reading the plugin documentation. They can be invoked directly from your
|
||||
own scripts or they can be sent to the platform through any supported channel
|
||||
as simple JSON messages:
|
||||
|
||||
```json
|
||||
{
|
||||
|
@ -114,37 +179,54 @@ your own scripts or they can be sent to the platform through any supported chann
|
|||
}
|
||||
```
|
||||
|
||||
### [Backends](https://docs.platypush.tech/en/latest/backends.html)
|
||||
### Backends
|
||||
|
||||
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), 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.).
|
||||
[Full list](https://docs.platypush.tech/en/latest/backends.html)
|
||||
|
||||
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:
|
||||
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),
|
||||
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
|
||||
|
||||
# Execute a request
|
||||
# Execute a request
|
||||
|
||||
curl -XPOST -H 'Content-Type: application/json' -H "Authorization: Bearer $YOUR_TOKEN" -d '
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-H "Authorization: Bearer $YOUR_TOKEN" -d '
|
||||
{
|
||||
"type": "request",
|
||||
"action": "tts.say",
|
||||
|
@ -154,33 +236,38 @@ curl -XPOST -H 'Content-Type: application/json' -H "Authorization: Bearer $YOUR_
|
|||
}' http://host:8008/execute
|
||||
```
|
||||
|
||||
### [Events](https://docs.platypush.tech/en/latest/events.html)
|
||||
### Events
|
||||
|
||||
When a certain event occurs (e.g. a JSON request is received, or a
|
||||
[Bluetooth device is connected](https://docs.platypush.tech/en/latest/platypush/events/bluetooth.html#platypush.message.event.bluetooth.BluetoothDeviceConnectedEvent),
|
||||
or a
|
||||
[Flic button is pressed](https://docs.platypush.tech/en/latest/platypush/events/button.flic.html#platypush.message.event.button.flic.FlicButtonEvent),
|
||||
or some
|
||||
[speech is detected on the voice assistant service](https://docs.platypush.tech/en/latest/platypush/events/assistant.html#platypush.message.event.assistant.SpeechRecognizedEvent),
|
||||
or an
|
||||
[RSS feed has new items](https://docs.platypush.tech/en/latest/platypush/events/http.rss.html#platypush.message.event.http.rss.NewFeedEvent),
|
||||
or a
|
||||
[new email is received](https://docs.platypush.tech/en/latest/platypush/events/mail.html#platypush.message.event.mail.MailReceivedEvent),
|
||||
or a
|
||||
[new track is played](https://docs.platypush.tech/en/latest/platypush/events/music.html#platypush.message.event.music.NewPlayingTrackEvent),
|
||||
or an
|
||||
[NFC tag is detected](https://docs.platypush.tech/en/latest/platypush/events/nfc.html#platypush.message.event.nfc.NFCTagDetectedEvent),
|
||||
or
|
||||
[new sensor data is available](https://docs.platypush.tech/en/latest/platypush/events/sensor.html#platypush.message.event.sensor.SensorDataChangeEvent),
|
||||
or
|
||||
[a value of a Zigbee device changes](https://docs.platypush.tech/en/latest/platypush/events/zigbee.mqtt.html#platypush.message.event.zigbee.mqtt.ZigbeeMqttDevicePropertySetEvent),
|
||||
etc.), the associated backend will trigger an [event](https://docs.platypush.tech/en/latest/events.html).
|
||||
[Full list](https://docs.platypush.tech/en/latest/events.html)
|
||||
|
||||
When a certain event occurs (e.g. a JSON request is received, or a [Bluetooth
|
||||
device is
|
||||
connected](https://docs.platypush.tech/en/latest/platypush/events/bluetooth.html#platypush.message.event.bluetooth.BluetoothDeviceConnectedEvent),
|
||||
or a [Flic button is
|
||||
pressed](https://docs.platypush.tech/en/latest/platypush/events/button.flic.html#platypush.message.event.button.flic.FlicButtonEvent),
|
||||
or some [speech is detected on the voice assistant
|
||||
service](https://docs.platypush.tech/en/latest/platypush/events/assistant.html#platypush.message.event.assistant.SpeechRecognizedEvent),
|
||||
or an [RSS feed has new
|
||||
items](https://docs.platypush.tech/en/latest/platypush/events/http.rss.html#platypush.message.event.http.rss.NewFeedEvent),
|
||||
or a [new email is
|
||||
received](https://docs.platypush.tech/en/latest/platypush/events/mail.html#platypush.message.event.mail.MailReceivedEvent),
|
||||
or a [new track is
|
||||
played](https://docs.platypush.tech/en/latest/platypush/events/music.html#platypush.message.event.music.NewPlayingTrackEvent),
|
||||
or an [NFC tag is
|
||||
detected](https://docs.platypush.tech/en/latest/platypush/events/nfc.html#platypush.message.event.nfc.NFCTagDetectedEvent),
|
||||
or [new sensor data is
|
||||
available](https://docs.platypush.tech/en/latest/platypush/events/sensor.html#platypush.message.event.sensor.SensorDataChangeEvent),
|
||||
or [a value of a Zigbee device
|
||||
changes](https://docs.platypush.tech/en/latest/platypush/events/zigbee.mqtt.html#platypush.message.event.zigbee.mqtt.ZigbeeMqttDevicePropertySetEvent),
|
||||
etc.), the associated backend will trigger an
|
||||
[event](https://docs.platypush.tech/en/latest/events.html).
|
||||
|
||||
### Hooks
|
||||
|
||||
Event hooks are custom pieces of logic that will be run when a certain event is 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:
|
||||
Event hooks are custom pieces of logic that will be run when a certain event is
|
||||
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/-/blob/master/examples/conf/config.yaml).
|
||||
Example:
|
||||
|
@ -204,9 +291,10 @@ event.hook.SearchSongVoiceCommand:
|
|||
resource: ${output[0]['file']}
|
||||
```
|
||||
|
||||
- Stand-alone Python scripts stored under `~/.config/platypush/scripts` and will be dynamically imported at start time.
|
||||
- Stand-alone Python scripts stored under `~/.config/platypush/scripts` and
|
||||
will be dynamically imported at start time.
|
||||
[Example](https://git.platypush.tech/platypush/platypush/-/blob/master/examples/conf/hook.py):
|
||||
|
||||
|
||||
```python
|
||||
from platypush.event.hook import hook
|
||||
from platypush.utils import run
|
||||
|
@ -225,13 +313,17 @@ def on_music_play_command(event, title=None, artist=None, **context):
|
|||
|
||||
### Procedures
|
||||
|
||||
Procedures are pieces of custom logic that can be executed as atomic actions using `procedure.<name>` as an action name.
|
||||
They can be defined either in the `config.yaml` or as Python scripts stored under `~/.config/platypush/scripts` -
|
||||
provided that the procedure is also imported in `~/.config/platypush/scripts/__init__.py` so it can be discovered by
|
||||
the service.
|
||||
Procedures are pieces of custom logic that can be executed as atomic actions
|
||||
using `procedure.<name>` as an action name.
|
||||
|
||||
YAML example for a procedure that can be executed when we arrive home and turns on the lights if the luminosity is lower
|
||||
that a certain thresholds, says a welcome home message using the TTS engine and starts playing the music:
|
||||
They can be defined either in the `config.yaml` or as Python scripts stored
|
||||
under `~/.config/platypush/scripts` - provided that the procedure is also
|
||||
imported in `~/.config/platypush/scripts/__init__.py` so it can be discovered
|
||||
by the service.
|
||||
|
||||
YAML example for a procedure that can be executed when we arrive home and turns
|
||||
on the lights if the luminosity is lower that a certain thresholds, says a
|
||||
welcome home message using the TTS engine and starts playing the music:
|
||||
|
||||
```yaml
|
||||
procedure.at_home:
|
||||
|
@ -254,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
|
||||
|
||||
|
@ -268,11 +360,12 @@ def at_home(**context):
|
|||
run('music.mpd.play')
|
||||
```
|
||||
|
||||
In either case, you can easily trigger the at-home procedure by sending an action request message to a backend - for
|
||||
example, over the HTTP backend:
|
||||
In either case, you can easily trigger the at-home procedure by sending an
|
||||
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 '
|
||||
curl -XPOST -H 'Content-Type: application/json' \
|
||||
-H "Authorization: Bearer $YOUR_TOKEN" -d '
|
||||
{
|
||||
"type": "request",
|
||||
"action": "procedure.at_home"
|
||||
|
@ -281,15 +374,18 @@ curl -XPOST -H 'Content-Type: application/json' -H "Authorization: Bearer $YOUR_
|
|||
|
||||
### Cronjobs
|
||||
|
||||
Cronjobs are pieces of logic that will be run at regular intervals, expressed in crontab-compatible syntax.
|
||||
They can be defined either in the `config.yaml` or as Python scripts stored under `~/.config/platypush/scripts` as
|
||||
functions labelled by the `@cron` decorator.
|
||||
Cronjobs are pieces of logic that will be run at regular intervals, expressed
|
||||
in crontab-compatible syntax. They can be defined either in the `config.yaml`
|
||||
or as Python scripts stored under `~/.config/platypush/scripts` as functions
|
||||
labelled by the `@cron` decorator.
|
||||
|
||||
Note that seconds are also supported (unlike the standard crontab definition), but, for back-compatibility with the
|
||||
standard crontab format, they are at the end of the cron expression, so the expression is actually in the format
|
||||
Note that seconds are also supported (unlike the standard crontab definition),
|
||||
but, for back-compatibility with the standard crontab format, they are at the
|
||||
end of the cron expression, so the expression is actually in the format
|
||||
`<minute> <hour> <day_of_month> <month> <day_of_week> <second>`.
|
||||
|
||||
YAML example for a cronjob that is executed every 30 seconds and checks if a Bluetooth device is nearby:
|
||||
YAML example for a cronjob that is executed every 30 seconds and checks if a
|
||||
Bluetooth device is nearby:
|
||||
|
||||
```yaml
|
||||
cron.check_bt_device:
|
||||
|
@ -308,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
|
||||
|
||||
|
@ -323,15 +419,18 @@ def check_bt_device(**context):
|
|||
|
||||
### The web interface
|
||||
|
||||
If [`backend.http`](https://docs.platypush.tech/en/latest/platypush/backend/http.html) is enabled then a web interface
|
||||
will be provided by default on `http://host:8008/`. Besides using the `/execute` endpoint for running requests, the
|
||||
built-in web server also provides a full-featured interface that 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.
|
||||
If
|
||||
[`backend.http`](https://docs.platypush.tech/en/latest/platypush/backend/http.html)
|
||||
is enabled then a web interface will be provided by default on
|
||||
`http://host:8008/`. Besides using the `/execute` endpoint for running
|
||||
requests, the built-in web server also provides a full-featured interface that
|
||||
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 web service also provides means for the user to create
|
||||
[custom 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.
|
||||
The web service also provides means for the user to create [custom
|
||||
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.
|
||||
|
||||
## Installation
|
||||
|
||||
|
@ -340,36 +439,69 @@ be used to show information from multiple sources on a large screen.
|
|||
Platypush uses Redis to deliver and store requests and temporary messages:
|
||||
|
||||
```yaml
|
||||
# Example for Debian-based distributions
|
||||
# Example for Debian-based distributions
|
||||
[sudo] apt-get install redis-server
|
||||
|
||||
# Enable and start the service
|
||||
# Enable and start the service
|
||||
[sudo] systemctl enable redis
|
||||
[sudo] systemctl start redis
|
||||
```
|
||||
|
||||
To install the core platform:
|
||||
|
||||
* The `pip` way:
|
||||
#### Install through `pip`
|
||||
|
||||
```shell
|
||||
[sudo] pip3 install platypush
|
||||
```
|
||||
|
||||
* The sources way:
|
||||
#### 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
|
||||
```
|
||||
|
||||
Then install the extensions that you wish to use. There are a few ways to check the dependencies required by an
|
||||
extension:
|
||||
### Installing the dependencies for your extensions
|
||||
|
||||
#### Check their `extras` name in [`extras_require` under `setup.py`](https://git.platypush.tech/platypush/platypush/-/blob/master/setup.py#L72).
|
||||
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:
|
||||
|
||||
If you follow this route then you can install the extra dependencies in one of the following ways:
|
||||
#### 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:
|
||||
|
||||
|
@ -383,25 +515,18 @@ If you follow this route then you can install the extra dependencies in one of t
|
|||
cd $DIR_TO_PLATYPUSH
|
||||
[sudo] pip3 install '.[extra1,extra2,extra3]'
|
||||
```
|
||||
|
||||
#### Check the dependencies/installation instructions reported under the plugin/backend documentation.
|
||||
|
||||
If you follow this route then simply run the commands listed in the plugin/backend documentation to get the dependencies
|
||||
installed.
|
||||
#### Check the instructions reported in the documentation
|
||||
|
||||
#### Check/uncomment the associated lines in [`requirements.txt`](https://git.platypush.tech/platypush/platypush/-/blob/master/requirements.txt).
|
||||
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.
|
||||
|
||||
If you follow this route then uncomment the lines in
|
||||
[`requirements.txt`](https://git.platypush.tech/platypush/platypush/-/blob/master/requirements.txt) associated to the
|
||||
plugins/backends that you want to use and run:
|
||||
|
||||
```shell
|
||||
[sudo] pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
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.
|
||||
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:
|
||||
|
||||
|
@ -410,85 +535,100 @@ 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`:
|
||||
[`.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](https://git.platypush.tech/platypush/platypush/-/wikis/Run-platypush-in-a-virtual-environment)
|
||||
### 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.
|
||||
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
|
||||
```
|
||||
```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
|
||||
```
|
||||
```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
|
||||
```
|
||||
```shell
|
||||
platyvenv stop device_id
|
||||
```
|
||||
|
||||
4. Remove the instance:
|
||||
|
||||
```shell
|
||||
platyvenv rm device_id
|
||||
```
|
||||
```shell
|
||||
platyvenv rm device_id
|
||||
```
|
||||
|
||||
### [Docker installation](https://git.platypush.tech/platypush/platypush/-/wikis/Run-platypush-in-a-container)
|
||||
[Wiki instructions](https://git.platypush.tech/platypush/platypush/wiki/Run-platypush-in-a-virtual-environment)
|
||||
|
||||
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`:
|
||||
### 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
|
||||
```
|
||||
```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
|
||||
```
|
||||
```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
|
||||
```
|
||||
```shell
|
||||
platydock stop device_id
|
||||
```
|
||||
|
||||
4. Remove the instance:
|
||||
|
||||
```shell
|
||||
platydock rm device_id
|
||||
```
|
||||
```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
|
||||
|
||||
An [official Android app](https://f-droid.org/en/packages/tech.platypush.platypush/) is provided on the F-Droid store.
|
||||
It allows to easily discover and manage multiple Platypush services on a network through the web interface, and it
|
||||
easily brings the power of Platypush to your fingertips.
|
||||
An [official Android
|
||||
app](https://f-droid.org/en/packages/tech.platypush.platypush/) is provided on
|
||||
the F-Droid store. It allows to easily discover and manage multiple Platypush
|
||||
services on a network through the web interface, and it easily brings the power
|
||||
of Platypush to your fingertips.
|
||||
|
||||
## Tests
|
||||
|
||||
To run the tests simply run `pytest` either from the project root folder or the `tests/` folder.
|
||||
Or run the following command from the project root folder:
|
||||
To run the tests simply run `pytest` either from the project root folder or the
|
||||
`tests/` folder. Or run the following command from the project root folder:
|
||||
|
||||
```shell
|
||||
python -m tests
|
||||
|
@ -500,10 +640,11 @@ python -m tests
|
|||
|
||||
If you use and love Platypush, please consider [buying me a coffee/beer](https://paypal.me/fabiomanganiello).
|
||||
|
||||
I've been working on Platypush all by myself in my spare time for the past few years, and I've made sure that it remains
|
||||
open and free.
|
||||
I've been working on Platypush all by myself in my spare time for the past few
|
||||
years, and I've made sure that it remains open and free.
|
||||
|
||||
If you like this product, please consider supporting - I'm definitely not planning to get rich with this project, but
|
||||
I'd love to have at least the costs for the server covered by users.
|
||||
If you like this product, please consider supporting - I'm definitely not
|
||||
planning to get rich with this project, but I'd love to have at least the costs
|
||||
for the server covered by users.
|
||||
|
||||
Issues and requests opened by donors will also be given priority over others.
|
||||
|
|
176
bin/platyvenv
176
bin/platyvenv
|
@ -6,12 +6,12 @@
|
|||
# and automatically managed the required dependencies, as well as start, #
|
||||
# stop and remove them #
|
||||
# #
|
||||
# @author: Fabio Manganiello <blacklight86@gmail.com> #
|
||||
# @author: Fabio Manganiello <fabio@platypush.tech> #
|
||||
# @licence: MIT #
|
||||
##############################################################################
|
||||
|
||||
|
||||
workdir=$HOME/.local/share/platypush/venv
|
||||
workdir="$HOME/.local/share/platypush/venv"
|
||||
|
||||
function build {
|
||||
cfgfile=
|
||||
|
@ -35,88 +35,74 @@ function build {
|
|||
fi
|
||||
|
||||
echo "Parsing configuration file"
|
||||
deps=()
|
||||
pip_cmd=
|
||||
pkg_cmd=
|
||||
includes=()
|
||||
cmd_exec=()
|
||||
|
||||
while read -r line; do
|
||||
echo ${line} | egrep '``pip install .+?``' > /dev/null 2>&1
|
||||
if (( $? != 0 )); then
|
||||
continue
|
||||
fi
|
||||
|
||||
dep=$(echo ${line} | sed -r -e 's/.*``pip install (.+?)``.*/\1/')
|
||||
deps+=("$dep")
|
||||
done <<< $(python <<EOF
|
||||
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.context import get_plugin, get_backend, register_backends
|
||||
from platypush.utils.manifest import get_install_commands_from_conf
|
||||
|
||||
Config.init('`realpath ${cfgfile}`')
|
||||
register_backends()
|
||||
backend_config = Config.get_backends()
|
||||
deps = get_install_commands_from_conf('$(realpath "${cfgfile}")')
|
||||
print(f'device_id: {Config.get("device_id")}')
|
||||
|
||||
for name in Config.get_backends().keys():
|
||||
backend = get_backend(name)
|
||||
print(backend.__doc__)
|
||||
if deps.get('pip'):
|
||||
print(f'pip: {deps["pip"]}')
|
||||
|
||||
for name in Config.get_plugins().keys():
|
||||
try:
|
||||
plugin = get_plugin(name)
|
||||
print(plugin.__doc__)
|
||||
except:
|
||||
pass
|
||||
EOF
|
||||
)
|
||||
if deps.get('packages'):
|
||||
print(f'packages: {deps["packages"]}')
|
||||
|
||||
while read -r include; do
|
||||
includes+=(${include})
|
||||
done <<< $(python <<EOF
|
||||
from platypush.config import Config
|
||||
from platypush.context import get_plugin, get_backend, register_backends
|
||||
|
||||
Config.init('`realpath ${cfgfile}`')
|
||||
for cmd in deps.get('exec', []):
|
||||
print(f'exec: {cmd}')
|
||||
|
||||
for include in Config._included_files:
|
||||
print(include)
|
||||
print(f'include: {include}')
|
||||
EOF
|
||||
)
|
||||
)"
|
||||
|
||||
device_id=$(python <<EOF
|
||||
from platypush.config import Config
|
||||
|
||||
Config.init('`realpath ${cfgfile}`')
|
||||
print(Config.get('device_id'))
|
||||
EOF
|
||||
)
|
||||
|
||||
envdir=${workdir}/${device_id}
|
||||
etcdir=${envdir}/etc/platypush
|
||||
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"`
|
||||
srcdir=$(dirname "$cfgfile")
|
||||
|
||||
for ((i=0; $i < ${#includes[@]}; i++)); do
|
||||
incdir=`dirname "${includes[$i]}"`
|
||||
incdir=`realpath --relative-to="$srcdir" "$incdir"`
|
||||
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
|
||||
cfgfile="${etcdir}/config.yaml"
|
||||
|
||||
python3 -m venv ${envdir}
|
||||
cd ${envdir}
|
||||
source ${envdir}/bin/activate
|
||||
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 < ${#deps[@]}; i++)); do
|
||||
echo ${deps[$i]}
|
||||
done | sort -u | while read dep; do
|
||||
pip install ${dep}
|
||||
for ((i=0; i < ${#cmd_exec[@]}; i++)); do
|
||||
${cmd_exec[$i]}
|
||||
done
|
||||
|
||||
pip install --upgrade git+https://git.platypush.tech/platypush/platypush.git
|
||||
|
@ -130,44 +116,41 @@ function start {
|
|||
fi
|
||||
|
||||
env=$1
|
||||
envdir=${workdir}/${env}
|
||||
logsdir=${envdir}/var/log/platypush
|
||||
rundir=${envdir}/var/run
|
||||
pidfile=${rundir}/platypush.pid
|
||||
cfgfile=${envdir}/etc/platypush/config.yaml
|
||||
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 ${logsdir}
|
||||
mkdir -p ${rundir}
|
||||
mkdir -p "${rundir}"
|
||||
|
||||
if [[ -f "$pidfile" ]]; then
|
||||
pid=`cat "$pidfile"`
|
||||
if ps -p ${pid} | grep platypush; then
|
||||
echo "Another instance (PID $pid) is running, please stop that instance first"
|
||||
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 doesn't seem to be running, starting anyway"
|
||||
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}
|
||||
python3 -m venv "${envdir}"
|
||||
cd "${envdir}" || exit 1
|
||||
source bin/activate
|
||||
bin/platypush -c "$cfgfile" -P "$pidfile" > ${logsdir}/stdout.log 2> ${logsdir}/stderr.log &
|
||||
start_time=`date +'%s'`
|
||||
bin/platypush -c "$cfgfile" -P "$pidfile" &
|
||||
start_time=$(date +'%s')
|
||||
timeout=30
|
||||
|
||||
while :; do
|
||||
[[ -f "$pidfile" ]] && break
|
||||
now=`date +'%s'`
|
||||
let elapsed=$now-$start_time
|
||||
if (( ${elapsed} >= ${timeout} )); then
|
||||
echo "Platypush instance '$env' didn't start within $timeout seconds" >&2
|
||||
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
|
||||
|
||||
|
@ -175,9 +158,11 @@ function start {
|
|||
sleep 1
|
||||
done
|
||||
|
||||
pid=`cat "$pidfile"`
|
||||
pid=$(cat "$pidfile")
|
||||
echo
|
||||
echo "Platypush environment $env started with PID $pid, logs dir: $logsdir"
|
||||
echo "Platypush environment $env started with PID $pid"
|
||||
wait "${pid}"
|
||||
echo "Platypush environment $env terminated"
|
||||
}
|
||||
|
||||
function stop {
|
||||
|
@ -187,9 +172,9 @@ function stop {
|
|||
fi
|
||||
|
||||
env=$1
|
||||
envdir=${workdir}/${env}
|
||||
rundir=${envdir}/var/run
|
||||
pidfile=${rundir}/platypush.pid
|
||||
envdir="${workdir}/${env}"
|
||||
rundir="${envdir}/var/run"
|
||||
pidfile="${rundir}/platypush.pid"
|
||||
|
||||
if [[ ! -d "$envdir" ]]; then
|
||||
echo "No such directory: $envdir" >&2
|
||||
|
@ -197,12 +182,13 @@ function stop {
|
|||
fi
|
||||
|
||||
if [[ ! -f "$pidfile" ]]; then
|
||||
echo "No pidfile found for instance "${env}""
|
||||
echo "No pidfile found for instance \"${env}\""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pid=`cat "$pidfile"`
|
||||
pids="$pid `ps --no-headers -o pid= --ppid $pid`"
|
||||
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"
|
||||
|
@ -214,9 +200,9 @@ function rme {
|
|||
exit 1
|
||||
fi
|
||||
|
||||
envdir=${workdir}/$1
|
||||
rundir=${envdir}/var/run
|
||||
pidfile=${rundir}/platypush.pid
|
||||
envdir="${workdir}/$1"
|
||||
rundir="${envdir}/var/run"
|
||||
pidfile="${rundir}/platypush.pid"
|
||||
|
||||
if [[ ! -d "$envdir" ]]; then
|
||||
echo "No such directory: $envdir" >&2
|
||||
|
@ -224,14 +210,18 @@ function rme {
|
|||
fi
|
||||
|
||||
if [[ -f "$pidfile" ]]; then
|
||||
if ps -p `cat "$pidfile"` | grep platypush; then
|
||||
echo "Another instance (PID $pidfile) is running, please stop that instance first"
|
||||
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 doesn't seem to be running, removing anyway"
|
||||
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"
|
||||
}
|
||||
|
@ -247,13 +237,13 @@ fi
|
|||
|
||||
action=$1
|
||||
shift
|
||||
mkdir -p ${workdir}
|
||||
mkdir -p "${workdir}"
|
||||
|
||||
# shellcheck disable=SC2048,SC2086
|
||||
case ${action} in
|
||||
'build') build;;
|
||||
'build') build $*;;
|
||||
'start') start $*;;
|
||||
'stop') stop $*;;
|
||||
'rm') rme $*;;
|
||||
*) usage;;
|
||||
esac
|
||||
|
||||
|
|
|
@ -3,10 +3,12 @@ import json
|
|||
import os
|
||||
import re
|
||||
import sys
|
||||
from random import randint
|
||||
from typing import Union, List
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import Directive
|
||||
from marshmallow import fields
|
||||
|
||||
|
||||
class SchemaDirective(Directive):
|
||||
|
@ -22,10 +24,36 @@ class SchemaDirective(Directive):
|
|||
|
||||
sys.path.insert(0, _schemas_path)
|
||||
|
||||
@staticmethod
|
||||
def _get_field_value(field) -> str:
|
||||
@classmethod
|
||||
def _get_field_value(cls, field):
|
||||
metadata = getattr(field, 'metadata', {})
|
||||
return metadata.get('example', metadata.get('description', str(field.__class__.__name__).lower()))
|
||||
if metadata.get('example'):
|
||||
return metadata['example']
|
||||
if metadata.get('description'):
|
||||
return metadata['description']
|
||||
|
||||
if isinstance(field, fields.Number):
|
||||
return randint(1, 99)
|
||||
if isinstance(field, fields.Boolean):
|
||||
return bool(randint(0, 1))
|
||||
if isinstance(field, fields.URL):
|
||||
return 'https://example.org'
|
||||
if isinstance(field, fields.List):
|
||||
return [cls._get_field_value(field.inner)]
|
||||
if isinstance(field, fields.Dict):
|
||||
return {
|
||||
cls._get_field_value(field.key_field) if field.key_field else 'key':
|
||||
cls._get_field_value(field.value_field) if field.value_field else 'value'
|
||||
}
|
||||
if isinstance(field, fields.Nested):
|
||||
ret = {
|
||||
name: cls._get_field_value(f)
|
||||
for name, f in field.nested().fields.items()
|
||||
}
|
||||
|
||||
return [ret] if field.many else ret
|
||||
|
||||
return str(field.__class__.__name__).lower()
|
||||
|
||||
def _parse_schema(self) -> Union[dict, List[dict]]:
|
||||
m = self._schema_regex.match('\n'.join(self.content))
|
||||
|
|
|
@ -8,10 +8,8 @@ Backends
|
|||
|
||||
platypush/backend/adafruit.io.rst
|
||||
platypush/backend/alarm.rst
|
||||
platypush/backend/assistant.rst
|
||||
platypush/backend/assistant.google.rst
|
||||
platypush/backend/assistant.snowboy.rst
|
||||
platypush/backend/bluetooth.rst
|
||||
platypush/backend/bluetooth.fileserver.rst
|
||||
platypush/backend/bluetooth.pushserver.rst
|
||||
platypush/backend/bluetooth.scanner.rst
|
||||
|
@ -19,9 +17,7 @@ Backends
|
|||
platypush/backend/button.flic.rst
|
||||
platypush/backend/camera.pi.rst
|
||||
platypush/backend/chat.telegram.rst
|
||||
platypush/backend/clipboard.rst
|
||||
platypush/backend/covid19.rst
|
||||
platypush/backend/dbus.rst
|
||||
platypush/backend/file.monitor.rst
|
||||
platypush/backend/foursquare.rst
|
||||
platypush/backend/github.rst
|
||||
|
@ -52,7 +48,6 @@ Backends
|
|||
platypush/backend/pushbullet.rst
|
||||
platypush/backend/redis.rst
|
||||
platypush/backend/scard.rst
|
||||
platypush/backend/sensor.rst
|
||||
platypush/backend/sensor.accelerometer.rst
|
||||
platypush/backend/sensor.arduino.rst
|
||||
platypush/backend/sensor.battery.rst
|
||||
|
@ -65,9 +60,8 @@ Backends
|
|||
platypush/backend/sensor.leap.rst
|
||||
platypush/backend/sensor.ltr559.rst
|
||||
platypush/backend/sensor.mcp3008.rst
|
||||
platypush/backend/sensor.motion.pwm3901.rst
|
||||
platypush/backend/sensor.motion.pmw3901.rst
|
||||
platypush/backend/sensor.serial.rst
|
||||
platypush/backend/stt.rst
|
||||
platypush/backend/stt.deepspeech.rst
|
||||
platypush/backend/stt.picovoice.hotword.rst
|
||||
platypush/backend/stt.picovoice.speech.rst
|
||||
|
@ -75,7 +69,6 @@ Backends
|
|||
platypush/backend/todoist.rst
|
||||
platypush/backend/travisci.rst
|
||||
platypush/backend/trello.rst
|
||||
platypush/backend/weather.rst
|
||||
platypush/backend/weather.buienradar.rst
|
||||
platypush/backend/weather.darksky.rst
|
||||
platypush/backend/weather.openweathermap.rst
|
||||
|
|
|
@ -195,6 +195,10 @@ intersphinx_mapping = {'https://docs.python.org/': None}
|
|||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
||||
|
||||
autodoc_default_options = {
|
||||
'inherited-members': True,
|
||||
}
|
||||
|
||||
autodoc_mock_imports = ['googlesamples.assistant.grpc.audio_helpers',
|
||||
'google.assistant.embedded',
|
||||
'google.assistant.library',
|
||||
|
@ -212,7 +216,7 @@ autodoc_mock_imports = ['googlesamples.assistant.grpc.audio_helpers',
|
|||
'gevent.wsgi',
|
||||
'Adafruit_IO',
|
||||
'pyperclip',
|
||||
'dbus',
|
||||
'pydbus',
|
||||
'inputs',
|
||||
'inotify',
|
||||
'omxplayer',
|
||||
|
@ -238,7 +242,7 @@ autodoc_mock_imports = ['googlesamples.assistant.grpc.audio_helpers',
|
|||
'envirophat',
|
||||
'gps',
|
||||
'picamera',
|
||||
'pwm3901',
|
||||
'pmw3901',
|
||||
'PIL',
|
||||
'croniter',
|
||||
'pyaudio',
|
||||
|
@ -272,7 +276,6 @@ autodoc_mock_imports = ['googlesamples.assistant.grpc.audio_helpers',
|
|||
'gi',
|
||||
'gi.repository',
|
||||
'twilio',
|
||||
'pytz',
|
||||
'Adafruit_Python_DHT',
|
||||
'RPi.GPIO',
|
||||
'RPLCD',
|
||||
|
@ -280,15 +283,25 @@ autodoc_mock_imports = ['googlesamples.assistant.grpc.audio_helpers',
|
|||
'pysmartthings',
|
||||
'aiohttp',
|
||||
'watchdog',
|
||||
'pyngrok',
|
||||
'irc',
|
||||
'irc.bot',
|
||||
'irc.strings',
|
||||
'irc.client',
|
||||
'irc.connection',
|
||||
'irc.events',
|
||||
'defusedxml',
|
||||
]
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../..'))
|
||||
|
||||
|
||||
def skip(app, what, name, obj, skip, options):
|
||||
if name == "__init__":
|
||||
return False
|
||||
return skip
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.connect("autodoc-skip-member", skip)
|
||||
|
||||
|
|
|
@ -13,10 +13,12 @@ Events
|
|||
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/file.rst
|
||||
platypush/events/foursquare.rst
|
||||
|
@ -25,11 +27,14 @@ Events
|
|||
platypush/events/google.rst
|
||||
platypush/events/google.fit.rst
|
||||
platypush/events/google.pubsub.rst
|
||||
platypush/events/gotify.rst
|
||||
platypush/events/gpio.rst
|
||||
platypush/events/gps.rst
|
||||
platypush/events/http.rst
|
||||
platypush/events/http.hook.rst
|
||||
platypush/events/http.rss.rst
|
||||
platypush/events/inotify.rst
|
||||
platypush/events/irc.rst
|
||||
platypush/events/joystick.rst
|
||||
platypush/events/kafka.rst
|
||||
platypush/events/light.rst
|
||||
|
@ -43,9 +48,12 @@ Events
|
|||
platypush/events/music.snapcast.rst
|
||||
platypush/events/nextcloud.rst
|
||||
platypush/events/nfc.rst
|
||||
platypush/events/ngrok.rst
|
||||
platypush/events/ntfy.rst
|
||||
platypush/events/ping.rst
|
||||
platypush/events/pushbullet.rst
|
||||
platypush/events/qrcode.rst
|
||||
platypush/events/rss.rst
|
||||
platypush/events/scard.rst
|
||||
platypush/events/sensor.rst
|
||||
platypush/events/sensor.ir.rst
|
||||
|
@ -54,6 +62,7 @@ Events
|
|||
platypush/events/serial.rst
|
||||
platypush/events/sound.rst
|
||||
platypush/events/stt.rst
|
||||
platypush/events/sun.rst
|
||||
platypush/events/tensorflow.rst
|
||||
platypush/events/todoist.rst
|
||||
platypush/events/torrent.rst
|
||||
|
|
|
@ -6,13 +6,13 @@ Welcome to the Platypush reference of available plugins, backends and event type
|
|||
For more information on Platypush check out:
|
||||
|
||||
* The `main page`_ of the project
|
||||
* The `Gitlab 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
|
||||
|
||||
.. _main page: https://platypush.tech
|
||||
.. _Gitlab page: https://git.platypush.tech/platypush/platypush
|
||||
.. _online wiki: https://git.platypush.tech/platypush/platypush/-/wikis/home
|
||||
.. _Gitea page: https://git.platypush.tech/platypush/platypush
|
||||
.. _online wiki: https://git.platypush.tech/platypush/platypush/wiki
|
||||
.. _Blog articles: https://blog.platypush.tech
|
||||
|
||||
.. toctree::
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
``assistant``
|
||||
===============================
|
||||
|
||||
.. automodule:: platypush.backend.assistant
|
||||
:members:
|
|
@ -1,5 +0,0 @@
|
|||
``bluetooth``
|
||||
===============================
|
||||
|
||||
.. automodule:: platypush.backend.bluetooth
|
||||
:members:
|
|
@ -1,5 +0,0 @@
|
|||
``clipboard``
|
||||
===============================
|
||||
|
||||
.. automodule:: platypush.backend.clipboard
|
||||
:members:
|
|
@ -1,5 +0,0 @@
|
|||
``dbus``
|
||||
==========================
|
||||
|
||||
.. automodule:: platypush.backend.dbus
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``sensor.motion.pmw3901``
|
||||
=========================
|
||||
|
||||
.. automodule:: platypush.backend.sensor.motion.pmw3901
|
||||
:members:
|
|
@ -1,5 +0,0 @@
|
|||
``sensor.motion.pwm3901``
|
||||
===========================================
|
||||
|
||||
.. automodule:: platypush.backend.sensor.motion.pwm3901
|
||||
:members:
|
|
@ -1,6 +0,0 @@
|
|||
``sensor``
|
||||
============================
|
||||
|
||||
.. automodule:: platypush.backend.sensor
|
||||
:members:
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
``stt``
|
||||
=========================
|
||||
|
||||
.. automodule:: platypush.backend.stt
|
||||
:members:
|
|
@ -1,5 +0,0 @@
|
|||
``weather``
|
||||
=============================
|
||||
|
||||
.. automodule:: platypush.backend.weather
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``chat.slack``
|
||||
==============
|
||||
|
||||
.. automodule:: platypush.message.event.chat.slack
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``dbus``
|
||||
========
|
||||
|
||||
.. automodule:: platypush.message.event.dbus
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``gotify``
|
||||
==========
|
||||
|
||||
.. automodule:: platypush.message.event.gotify
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``gpio``
|
||||
========
|
||||
|
||||
.. automodule:: platypush.message.event.gpio
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``irc``
|
||||
=======
|
||||
|
||||
.. automodule:: platypush.message.event.irc
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``ngrok``
|
||||
=========
|
||||
|
||||
.. automodule:: platypush.message.event.ngrok
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``ntfy``
|
||||
========
|
||||
|
||||
.. automodule:: platypush.message.event.ntfy
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``rss``
|
||||
=======
|
||||
|
||||
.. automodule:: platypush.message.event.rss
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``sun``
|
||||
=======
|
||||
|
||||
.. automodule:: platypush.message.event.sun
|
||||
:members:
|
|
@ -1,5 +0,0 @@
|
|||
``assistant``
|
||||
===============================
|
||||
|
||||
.. automodule:: platypush.plugins.assistant
|
||||
:members:
|
|
@ -1,6 +0,0 @@
|
|||
``camera``
|
||||
============================
|
||||
|
||||
.. automodule:: platypush.plugins.camera
|
||||
:members:
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
``chat.irc``
|
||||
============
|
||||
|
||||
.. automodule:: platypush.plugins.chat.irc
|
||||
:members:
|
|
@ -1,7 +0,0 @@
|
|||
``google``
|
||||
============================
|
||||
|
||||
.. automodule:: platypush.plugins.google
|
||||
:members:
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
``gotify``
|
||||
==========
|
||||
|
||||
.. automodule:: platypush.plugins.gotify
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``gpio.sensor.motion.pmw3901``
|
||||
==============================
|
||||
|
||||
.. automodule:: platypush.plugins.gpio.sensor.motion.pmw3901
|
||||
:members:
|
|
@ -1,6 +0,0 @@
|
|||
``gpio.sensor.motion.pwm3901``
|
||||
================================================
|
||||
|
||||
.. automodule:: platypush.plugins.gpio.sensor.motion.pwm3901
|
||||
:members:
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
``gpio.sensor``
|
||||
=================================
|
||||
|
||||
.. automodule:: platypush.plugins.gpio.sensor
|
||||
:members:
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
``homeseer``
|
||||
==============================
|
||||
|
||||
.. automodule:: platypush.plugins.homeseer
|
||||
:members:
|
||||
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
``lcd``
|
||||
=========================
|
||||
|
||||
.. automodule:: platypush.plugins.lcd
|
||||
:members:
|
|
@ -1,6 +0,0 @@
|
|||
``light``
|
||||
===========================
|
||||
|
||||
.. automodule:: platypush.plugins.light
|
||||
:members:
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
``mail``
|
||||
==========================
|
||||
|
||||
.. automodule:: platypush.plugins.mail
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``mailgun``
|
||||
===========
|
||||
|
||||
.. automodule:: platypush.plugins.mailgun
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``mastodon``
|
||||
============
|
||||
|
||||
.. automodule:: platypush.plugins.mastodon
|
||||
:members:
|
|
@ -0,0 +1,6 @@
|
|||
``media.jellyfin``
|
||||
==================
|
||||
|
||||
.. automodule:: platypush.plugins.media.jellyfin
|
||||
:members:
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
``media``
|
||||
===========================
|
||||
|
||||
.. automodule:: platypush.plugins.media
|
||||
:members:
|
|
@ -1,5 +0,0 @@
|
|||
``music``
|
||||
===========================
|
||||
|
||||
.. automodule:: platypush.plugins.music
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``ngrok``
|
||||
=========
|
||||
|
||||
.. automodule:: platypush.plugins.ngrok
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``ntfy``
|
||||
========
|
||||
|
||||
.. automodule:: platypush.plugins.ntfy
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``rss``
|
||||
=======
|
||||
|
||||
.. automodule:: platypush.plugins.rss
|
||||
:members:
|
|
@ -1,5 +0,0 @@
|
|||
``sensor``
|
||||
============================
|
||||
|
||||
.. automodule:: platypush.plugins.sensor
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``slack``
|
||||
=========
|
||||
|
||||
.. automodule:: platypush.plugins.slack
|
||||
:members:
|
|
@ -1,5 +0,0 @@
|
|||
``stt``
|
||||
=========================
|
||||
|
||||
.. automodule:: platypush.plugins.stt
|
||||
:members:
|
|
@ -0,0 +1,5 @@
|
|||
``sun``
|
||||
=======
|
||||
|
||||
.. automodule:: platypush.plugins.sun
|
||||
:members:
|
|
@ -1,6 +0,0 @@
|
|||
``switch``
|
||||
============================
|
||||
|
||||
.. automodule:: platypush.plugins.switch
|
||||
:members:
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
``weather``
|
||||
=============================
|
||||
|
||||
.. automodule:: platypush.plugins.weather
|
||||
:members:
|
|
@ -1,5 +0,0 @@
|
|||
``zwave._base``
|
||||
=================================
|
||||
|
||||
.. automodule:: platypush.plugins.zwave._base
|
||||
:members:
|
|
@ -9,7 +9,6 @@ Plugins
|
|||
platypush/plugins/adafruit.io.rst
|
||||
platypush/plugins/alarm.rst
|
||||
platypush/plugins/arduino.rst
|
||||
platypush/plugins/assistant.rst
|
||||
platypush/plugins/assistant.echo.rst
|
||||
platypush/plugins/assistant.google.rst
|
||||
platypush/plugins/assistant.google.pushtotalk.rst
|
||||
|
@ -18,13 +17,13 @@ Plugins
|
|||
platypush/plugins/bluetooth.ble.rst
|
||||
platypush/plugins/calendar.rst
|
||||
platypush/plugins/calendar.ical.rst
|
||||
platypush/plugins/camera.rst
|
||||
platypush/plugins/camera.android.ipcam.rst
|
||||
platypush/plugins/camera.cv.rst
|
||||
platypush/plugins/camera.ffmpeg.rst
|
||||
platypush/plugins/camera.gstreamer.rst
|
||||
platypush/plugins/camera.ir.mlx90640.rst
|
||||
platypush/plugins/camera.pi.rst
|
||||
platypush/plugins/chat.irc.rst
|
||||
platypush/plugins/chat.telegram.rst
|
||||
platypush/plugins/clipboard.rst
|
||||
platypush/plugins/config.rst
|
||||
|
@ -37,7 +36,6 @@ Plugins
|
|||
platypush/plugins/ffmpeg.rst
|
||||
platypush/plugins/file.rst
|
||||
platypush/plugins/foursquare.rst
|
||||
platypush/plugins/google.rst
|
||||
platypush/plugins/google.calendar.rst
|
||||
platypush/plugins/google.drive.rst
|
||||
platypush/plugins/google.fit.rst
|
||||
|
@ -46,8 +44,8 @@ Plugins
|
|||
platypush/plugins/google.pubsub.rst
|
||||
platypush/plugins/google.translate.rst
|
||||
platypush/plugins/google.youtube.rst
|
||||
platypush/plugins/gotify.rst
|
||||
platypush/plugins/gpio.rst
|
||||
platypush/plugins/gpio.sensor.rst
|
||||
platypush/plugins/gpio.sensor.accelerometer.rst
|
||||
platypush/plugins/gpio.sensor.bme280.rst
|
||||
platypush/plugins/gpio.sensor.dht.rst
|
||||
|
@ -56,10 +54,9 @@ Plugins
|
|||
platypush/plugins/gpio.sensor.envirophat.rst
|
||||
platypush/plugins/gpio.sensor.ltr559.rst
|
||||
platypush/plugins/gpio.sensor.mcp3008.rst
|
||||
platypush/plugins/gpio.sensor.motion.pwm3901.rst
|
||||
platypush/plugins/gpio.sensor.motion.pmw3901.rst
|
||||
platypush/plugins/gpio.zeroborg.rst
|
||||
platypush/plugins/graphite.rst
|
||||
platypush/plugins/homeseer.rst
|
||||
platypush/plugins/http.request.rst
|
||||
platypush/plugins/http.request.rss.rst
|
||||
platypush/plugins/http.webpage.rst
|
||||
|
@ -68,20 +65,19 @@ Plugins
|
|||
platypush/plugins/inspect.rst
|
||||
platypush/plugins/kafka.rst
|
||||
platypush/plugins/lastfm.rst
|
||||
platypush/plugins/lcd.rst
|
||||
platypush/plugins/lcd.gpio.rst
|
||||
platypush/plugins/lcd.i2c.rst
|
||||
platypush/plugins/light.rst
|
||||
platypush/plugins/light.hue.rst
|
||||
platypush/plugins/linode.rst
|
||||
platypush/plugins/logger.rst
|
||||
platypush/plugins/luma.oled.rst
|
||||
platypush/plugins/mail.rst
|
||||
platypush/plugins/mail.imap.rst
|
||||
platypush/plugins/mail.smtp.rst
|
||||
platypush/plugins/media.rst
|
||||
platypush/plugins/mailgun.rst
|
||||
platypush/plugins/mastodon.rst
|
||||
platypush/plugins/media.chromecast.rst
|
||||
platypush/plugins/media.gstreamer.rst
|
||||
platypush/plugins/media.jellyfin.rst
|
||||
platypush/plugins/media.kodi.rst
|
||||
platypush/plugins/media.mplayer.rst
|
||||
platypush/plugins/media.mpv.rst
|
||||
|
@ -94,12 +90,13 @@ Plugins
|
|||
platypush/plugins/ml.cv.rst
|
||||
platypush/plugins/mobile.join.rst
|
||||
platypush/plugins/mqtt.rst
|
||||
platypush/plugins/music.rst
|
||||
platypush/plugins/music.mpd.rst
|
||||
platypush/plugins/music.snapcast.rst
|
||||
platypush/plugins/music.spotify.rst
|
||||
platypush/plugins/nextcloud.rst
|
||||
platypush/plugins/ngrok.rst
|
||||
platypush/plugins/nmap.rst
|
||||
platypush/plugins/ntfy.rst
|
||||
platypush/plugins/otp.rst
|
||||
platypush/plugins/pihole.rst
|
||||
platypush/plugins/ping.rst
|
||||
|
@ -108,18 +105,18 @@ Plugins
|
|||
platypush/plugins/pwm.pca9685.rst
|
||||
platypush/plugins/qrcode.rst
|
||||
platypush/plugins/redis.rst
|
||||
platypush/plugins/rss.rst
|
||||
platypush/plugins/rtorrent.rst
|
||||
platypush/plugins/sensor.rst
|
||||
platypush/plugins/serial.rst
|
||||
platypush/plugins/shell.rst
|
||||
platypush/plugins/slack.rst
|
||||
platypush/plugins/smartthings.rst
|
||||
platypush/plugins/sound.rst
|
||||
platypush/plugins/ssh.rst
|
||||
platypush/plugins/stt.rst
|
||||
platypush/plugins/stt.deepspeech.rst
|
||||
platypush/plugins/stt.picovoice.hotword.rst
|
||||
platypush/plugins/stt.picovoice.speech.rst
|
||||
platypush/plugins/switch.rst
|
||||
platypush/plugins/sun.rst
|
||||
platypush/plugins/switch.tplink.rst
|
||||
platypush/plugins/switch.wemo.rst
|
||||
platypush/plugins/switchbot.rst
|
||||
|
@ -139,7 +136,6 @@ Plugins
|
|||
platypush/plugins/user.rst
|
||||
platypush/plugins/utils.rst
|
||||
platypush/plugins/variable.rst
|
||||
platypush/plugins/weather.rst
|
||||
platypush/plugins/weather.buienradar.rst
|
||||
platypush/plugins/weather.darksky.rst
|
||||
platypush/plugins/weather.openweathermap.rst
|
||||
|
@ -148,5 +144,4 @@ Plugins
|
|||
platypush/plugins/zeroconf.rst
|
||||
platypush/plugins/zigbee.mqtt.rst
|
||||
platypush/plugins/zwave.rst
|
||||
platypush/plugins/zwave._base.rst
|
||||
platypush/plugins/zwave.mqtt.rst
|
||||
|
|
|
@ -1,22 +1,41 @@
|
|||
import os
|
||||
|
||||
from platypush.backend import Backend
|
||||
from platypush.context import get_plugin
|
||||
from platypush.plugins import Plugin
|
||||
from platypush.utils.manifest import get_manifests
|
||||
|
||||
|
||||
def _get_inspect_plugin():
|
||||
p = get_plugin('inspect')
|
||||
assert p, 'Could not load the `inspect` plugin'
|
||||
return p
|
||||
|
||||
|
||||
def get_all_plugins():
|
||||
return get_plugin('inspect').get_all_plugins().output
|
||||
manifests = {mf.component_name for mf in get_manifests(Plugin)}
|
||||
return {
|
||||
plugin_name: plugin_info
|
||||
for plugin_name, plugin_info in _get_inspect_plugin().get_all_plugins().output.items()
|
||||
if plugin_name in manifests
|
||||
}
|
||||
|
||||
|
||||
def get_all_backends():
|
||||
return get_plugin('inspect').get_all_backends().output
|
||||
manifests = {mf.component_name for mf in get_manifests(Backend)}
|
||||
return {
|
||||
backend_name: backend_info
|
||||
for backend_name, backend_info in _get_inspect_plugin().get_all_backends().output.items()
|
||||
if backend_name in manifests
|
||||
}
|
||||
|
||||
|
||||
def get_all_events():
|
||||
return get_plugin('inspect').get_all_events().output
|
||||
return _get_inspect_plugin().get_all_events().output
|
||||
|
||||
|
||||
def get_all_responses():
|
||||
return get_plugin('inspect').get_all_responses().output
|
||||
return _get_inspect_plugin().get_all_responses().output
|
||||
|
||||
|
||||
# noinspection DuplicatedCode
|
||||
|
@ -87,16 +106,17 @@ Backends
|
|||
|
||||
# noinspection DuplicatedCode
|
||||
def generate_events_doc():
|
||||
from platypush.message import event as event_module
|
||||
events_index = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'docs', 'source', 'events.rst')
|
||||
events_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'docs', 'source', 'platypush', 'events')
|
||||
all_events = sorted(event for event in get_all_events().keys())
|
||||
all_events = sorted(event for event in get_all_events().keys() if event)
|
||||
|
||||
for event in all_events:
|
||||
event_file = os.path.join(events_dir, event[len('platypush.message.event.'):] + '.rst')
|
||||
event_file = os.path.join(events_dir, event + '.rst')
|
||||
if not os.path.exists(event_file):
|
||||
header = '``{}``'.format(event)
|
||||
divider = '=' * len(header)
|
||||
body = '\n.. automodule:: {}\n :members:\n'.format(event)
|
||||
body = '\n.. automodule:: {}.{}\n :members:\n'.format(event_module.__name__, event)
|
||||
out = '\n'.join([header, divider, body])
|
||||
|
||||
with open(event_file, 'w') as f:
|
||||
|
@ -114,21 +134,22 @@ Events
|
|||
''')
|
||||
|
||||
for event in all_events:
|
||||
f.write(' platypush/events/' + event[len('platypush.message.event.'):] + '.rst\n')
|
||||
f.write(' platypush/events/' + event + '.rst\n')
|
||||
|
||||
|
||||
# noinspection DuplicatedCode
|
||||
def generate_responses_doc():
|
||||
from platypush.message import response as response_module
|
||||
responses_index = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'docs', 'source', 'responses.rst')
|
||||
responses_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'docs', 'source', 'platypush', 'responses')
|
||||
all_responses = sorted(response for response in get_all_responses().keys())
|
||||
all_responses = sorted(response for response in get_all_responses().keys() if response)
|
||||
|
||||
for response in all_responses:
|
||||
response_file = os.path.join(responses_dir, response[len('platypush.message.response.'):] + '.rst')
|
||||
response_file = os.path.join(responses_dir, response + '.rst')
|
||||
if not os.path.exists(response_file):
|
||||
header = '``{}``'.format(response)
|
||||
divider = '=' * len(header)
|
||||
body = '\n.. automodule:: {}\n :members:\n'.format(response)
|
||||
body = '\n.. automodule:: {}.{}\n :members:\n'.format(response_module.__name__, response)
|
||||
out = '\n'.join([header, divider, body])
|
||||
|
||||
with open(response_file, 'w') as f:
|
||||
|
@ -146,7 +167,7 @@ Responses
|
|||
''')
|
||||
|
||||
for response in all_responses:
|
||||
f.write(' platypush/responses/' + response[len('platypush.message.response.'):] + '.rst\n')
|
||||
f.write(' platypush/responses/' + response + '.rst\n')
|
||||
|
||||
|
||||
generate_plugins_doc()
|
||||
|
|
|
@ -12,7 +12,7 @@ import sys
|
|||
|
||||
from .bus.redis import RedisBus
|
||||
from .config import Config
|
||||
from .context import register_backends
|
||||
from .context import register_backends, register_plugins
|
||||
from .cron.scheduler import CronScheduler
|
||||
from .event.processor import EventProcessor
|
||||
from .logger import Logger
|
||||
|
@ -20,17 +20,16 @@ from .message.event import Event
|
|||
from .message.event.application import ApplicationStartedEvent
|
||||
from .message.request import Request
|
||||
from .message.response import Response
|
||||
from .utils import set_thread_name
|
||||
|
||||
from .utils import set_thread_name, get_enabled_plugins
|
||||
|
||||
__author__ = 'Fabio Manganiello <info@fabiomanganiello.com>'
|
||||
__version__ = '0.21.1'
|
||||
__version__ = '0.23.3'
|
||||
|
||||
logger = logging.getLogger('platypush')
|
||||
|
||||
|
||||
class Daemon:
|
||||
""" Main class for the Platypush daemon """
|
||||
"""Main class for the Platypush daemon"""
|
||||
|
||||
# Configuration file (default: either ~/.config/platypush/config.yaml or
|
||||
# /etc/platypush/config.yaml
|
||||
|
@ -52,8 +51,15 @@ class Daemon:
|
|||
# number of executions retries before a request fails
|
||||
n_tries = 2
|
||||
|
||||
def __init__(self, config_file=None, pidfile=None, requests_to_process=None,
|
||||
no_capture_stdout=False, no_capture_stderr=False, redis_queue=None):
|
||||
def __init__(
|
||||
self,
|
||||
config_file=None,
|
||||
pidfile=None,
|
||||
requests_to_process=None,
|
||||
no_capture_stdout=False,
|
||||
no_capture_stderr=False,
|
||||
redis_queue=None,
|
||||
):
|
||||
"""
|
||||
Constructor
|
||||
Params:
|
||||
|
@ -81,8 +87,11 @@ class Daemon:
|
|||
logging.basicConfig(**Config.get('logging'))
|
||||
|
||||
redis_conf = Config.get('backend.redis') or {}
|
||||
self.bus = RedisBus(redis_queue=self.redis_queue, on_message=self.on_message(),
|
||||
**redis_conf.get('redis_args', {}))
|
||||
self.bus = RedisBus(
|
||||
redis_queue=self.redis_queue,
|
||||
on_message=self.on_message(),
|
||||
**redis_conf.get('redis_args', {})
|
||||
)
|
||||
|
||||
self.no_capture_stdout = no_capture_stdout
|
||||
self.no_capture_stderr = no_capture_stderr
|
||||
|
@ -99,33 +108,59 @@ class Daemon:
|
|||
args -- Your sys.argv[1:] [List of strings]
|
||||
"""
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--config', '-c', dest='config', required=False,
|
||||
default=None, help=cls.config_file.__doc__)
|
||||
parser.add_argument('--pidfile', '-P', dest='pidfile', required=False,
|
||||
default=None, help="File where platypush will " +
|
||||
"store its PID, useful if you're planning to " +
|
||||
"integrate it in a service")
|
||||
parser.add_argument('--no-capture-stdout', dest='no_capture_stdout',
|
||||
required=False, action='store_true',
|
||||
help="Set this flag if you have max stack depth " +
|
||||
"exceeded errors so stdout won't be captured by " +
|
||||
"the logging system")
|
||||
parser.add_argument('--no-capture-stderr', dest='no_capture_stderr',
|
||||
required=False, action='store_true',
|
||||
help="Set this flag if you have max stack depth " +
|
||||
"exceeded errors so stderr won't be captured by " +
|
||||
"the logging system")
|
||||
parser.add_argument('--redis-queue', dest='redis_queue',
|
||||
required=False, action='store_true',
|
||||
default=cls._default_redis_queue,
|
||||
help="Name of the Redis queue to be used to internally deliver messages "
|
||||
"(default: platypush/bus)")
|
||||
parser.add_argument(
|
||||
'--config',
|
||||
'-c',
|
||||
dest='config',
|
||||
required=False,
|
||||
default=None,
|
||||
help=cls.config_file.__doc__,
|
||||
)
|
||||
parser.add_argument(
|
||||
'--pidfile',
|
||||
'-P',
|
||||
dest='pidfile',
|
||||
required=False,
|
||||
default=None,
|
||||
help="File where platypush will "
|
||||
+ "store its PID, useful if you're planning to "
|
||||
+ "integrate it in a service",
|
||||
)
|
||||
parser.add_argument(
|
||||
'--no-capture-stdout',
|
||||
dest='no_capture_stdout',
|
||||
required=False,
|
||||
action='store_true',
|
||||
help="Set this flag if you have max stack depth "
|
||||
+ "exceeded errors so stdout won't be captured by "
|
||||
+ "the logging system",
|
||||
)
|
||||
parser.add_argument(
|
||||
'--no-capture-stderr',
|
||||
dest='no_capture_stderr',
|
||||
required=False,
|
||||
action='store_true',
|
||||
help="Set this flag if you have max stack depth "
|
||||
+ "exceeded errors so stderr won't be captured by "
|
||||
+ "the logging system",
|
||||
)
|
||||
parser.add_argument(
|
||||
'--redis-queue',
|
||||
dest='redis_queue',
|
||||
required=False,
|
||||
default=cls._default_redis_queue,
|
||||
help="Name of the Redis queue to be used to internally deliver messages "
|
||||
"(default: platypush/bus)",
|
||||
)
|
||||
|
||||
opts, args = parser.parse_known_args(args)
|
||||
return cls(config_file=opts.config, pidfile=opts.pidfile,
|
||||
no_capture_stdout=opts.no_capture_stdout,
|
||||
no_capture_stderr=opts.no_capture_stderr,
|
||||
redis_queue=opts.redis_queue)
|
||||
return cls(
|
||||
config_file=opts.config,
|
||||
pidfile=opts.pidfile,
|
||||
no_capture_stdout=opts.no_capture_stdout,
|
||||
no_capture_stderr=opts.no_capture_stderr,
|
||||
redis_queue=opts.redis_queue,
|
||||
)
|
||||
|
||||
def on_message(self):
|
||||
"""
|
||||
|
@ -146,8 +181,10 @@ class Daemon:
|
|||
logger.info('Dropped unauthorized request: {}'.format(msg))
|
||||
|
||||
self.processed_requests += 1
|
||||
if self.requests_to_process \
|
||||
and self.processed_requests >= self.requests_to_process:
|
||||
if (
|
||||
self.requests_to_process
|
||||
and self.processed_requests >= self.requests_to_process
|
||||
):
|
||||
self.stop_app()
|
||||
elif isinstance(msg, Response):
|
||||
logger.info('Received response: {}'.format(msg))
|
||||
|
@ -159,16 +196,22 @@ class Daemon:
|
|||
return _f
|
||||
|
||||
def stop_app(self):
|
||||
""" Stops the backends and the bus """
|
||||
"""Stops the backends and the bus"""
|
||||
from .plugins import RunnablePlugin
|
||||
|
||||
for backend in self.backends.values():
|
||||
backend.stop()
|
||||
|
||||
for plugin in get_enabled_plugins().values():
|
||||
if isinstance(plugin, RunnablePlugin):
|
||||
plugin.stop()
|
||||
|
||||
self.bus.stop()
|
||||
if self.cron_scheduler:
|
||||
self.cron_scheduler.stop()
|
||||
|
||||
def run(self):
|
||||
""" Start the daemon """
|
||||
"""Start the daemon"""
|
||||
if not self.no_capture_stdout:
|
||||
sys.stdout = Logger(logger.info)
|
||||
if not self.no_capture_stderr:
|
||||
|
@ -184,6 +227,9 @@ class Daemon:
|
|||
for backend in self.backends.values():
|
||||
backend.start()
|
||||
|
||||
# Initialize the plugins
|
||||
register_plugins(bus=self.bus)
|
||||
|
||||
# Start the cron scheduler
|
||||
if Config.get_cronjobs():
|
||||
self.cron_scheduler = CronScheduler(jobs=Config.get_cronjobs())
|
||||
|
|
|
@ -12,6 +12,7 @@ from threading import Thread, Event as ThreadEvent, get_ident
|
|||
from typing import Optional, Dict
|
||||
|
||||
from platypush.bus import Bus
|
||||
from platypush.common import ExtensionWithManifest
|
||||
from platypush.config import Config
|
||||
from platypush.context import get_backend
|
||||
from platypush.message.event.zeroconf import ZeroconfServiceAddedEvent, ZeroconfServiceRemovedEvent
|
||||
|
@ -26,7 +27,7 @@ from platypush.message.request import Request
|
|||
from platypush.message.response import Response
|
||||
|
||||
|
||||
class Backend(Thread, EventGenerator):
|
||||
class Backend(Thread, EventGenerator, ExtensionWithManifest):
|
||||
"""
|
||||
Parent class for backends.
|
||||
|
||||
|
@ -53,6 +54,7 @@ class Backend(Thread, EventGenerator):
|
|||
|
||||
self._thread_name = self.__class__.__name__
|
||||
EventGenerator.__init__(self)
|
||||
ExtensionWithManifest.__init__(self)
|
||||
Thread.__init__(self, name=self._thread_name, daemon=True)
|
||||
|
||||
# If no bus is specified, create an internal queue where
|
||||
|
@ -97,6 +99,7 @@ class Backend(Thread, EventGenerator):
|
|||
if self._is_expected_response(msg):
|
||||
# Expected response, trigger the response handler
|
||||
clear_timeout()
|
||||
# pylint: disable=unsubscriptable-object
|
||||
self._request_context['on_response'](msg)
|
||||
self.stop()
|
||||
return
|
||||
|
@ -108,12 +111,13 @@ class Backend(Thread, EventGenerator):
|
|||
""" Internal only - returns true if we are expecting for a response
|
||||
and msg is that response """
|
||||
|
||||
# pylint: disable=unsubscriptable-object
|
||||
return self._request_context \
|
||||
and isinstance(msg, Response) \
|
||||
and msg.id == self._request_context['request'].id
|
||||
|
||||
def _get_backend_config(self):
|
||||
config_name = 'backend.' + self.__class__.__name__.split('Backend')[0].lower()
|
||||
config_name = 'backend.' + self.__class__.__name__.split('Backend', maxsplit=1)[0].lower()
|
||||
return Config.get(config_name)
|
||||
|
||||
def _setup_response_handler(self, request, on_response, response_timeout):
|
||||
|
@ -194,7 +198,7 @@ class Backend(Thread, EventGenerator):
|
|||
|
||||
self.send_message(response, **kwargs)
|
||||
|
||||
def send_message(self, msg, queue_name=None, **kwargs):
|
||||
def send_message(self, msg, queue_name=None, **_):
|
||||
"""
|
||||
Sends a platypush.message.Message to a node.
|
||||
To be implemented in the derived classes. By default, if the Redis
|
||||
|
@ -211,8 +215,10 @@ class Backend(Thread, EventGenerator):
|
|||
if not redis:
|
||||
raise KeyError()
|
||||
except KeyError:
|
||||
self.logger.warning("Backend {} does not implement send_message " +
|
||||
"and the fallback Redis backend isn't configured")
|
||||
self.logger.warning((
|
||||
"Backend {} does not implement send_message "
|
||||
"and the fallback Redis backend isn't configured"
|
||||
).format(self.__class__.__name__))
|
||||
return
|
||||
|
||||
redis.send_message(msg, queue_name=queue_name)
|
||||
|
@ -231,6 +237,7 @@ class Backend(Thread, EventGenerator):
|
|||
|
||||
while not self.should_stop() and not has_error:
|
||||
try:
|
||||
# pylint: disable=not-callable
|
||||
self.loop()
|
||||
except Exception as e:
|
||||
has_error = True
|
||||
|
@ -257,7 +264,6 @@ class Backend(Thread, EventGenerator):
|
|||
|
||||
def on_stop(self):
|
||||
""" Callback invoked when the process stops """
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
""" Stops the backend thread by sending a STOP event on its bus """
|
||||
|
@ -279,7 +285,7 @@ class Backend(Thread, EventGenerator):
|
|||
|
||||
redis_backend = get_backend('redis')
|
||||
if not redis_backend:
|
||||
self.logger.warning('Redis backend not configured - some ' +
|
||||
self.logger.warning('Redis backend not configured - some '
|
||||
'web server features may not be working properly')
|
||||
redis_args = {}
|
||||
else:
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from typing import Optional
|
||||
|
||||
from platypush.backend import Backend
|
||||
from platypush.context import get_plugin
|
||||
from platypush.message.event.adafruit import ConnectedEvent, DisconnectedEvent, \
|
||||
|
@ -30,8 +32,9 @@ class AdafruitIoBackend(Backend):
|
|||
"""
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
from Adafruit_IO import MQTTClient
|
||||
self.feeds = feeds
|
||||
self._client = None
|
||||
self._client: Optional[MQTTClient] = None
|
||||
|
||||
def _init_client(self):
|
||||
if self._client:
|
||||
|
@ -57,12 +60,12 @@ class AdafruitIoBackend(Backend):
|
|||
return _handler
|
||||
|
||||
def on_disconnect(self):
|
||||
def _handler(client):
|
||||
def _handler(*_, **__):
|
||||
self.bus.post(DisconnectedEvent())
|
||||
|
||||
return _handler
|
||||
|
||||
def on_message(self, msg):
|
||||
def on_message(self, *_, **__):
|
||||
# noinspection PyUnusedLocal
|
||||
def _handler(client, feed, data):
|
||||
try:
|
||||
|
@ -83,7 +86,9 @@ class AdafruitIoBackend(Backend):
|
|||
while not self.should_stop():
|
||||
try:
|
||||
self._init_client()
|
||||
# noinspection PyUnresolvedReferences
|
||||
self._client.connect()
|
||||
# noinspection PyUnresolvedReferences
|
||||
self._client.loop_blocking()
|
||||
except Exception as e:
|
||||
self.logger.exception(e)
|
|
@ -0,0 +1,12 @@
|
|||
manifest:
|
||||
events:
|
||||
platypush.message.event.adafruit.ConnectedEvent: when thebackend connects to the
|
||||
Adafruit queue
|
||||
platypush.message.event.adafruit.DisconnectedEvent: when thebackend disconnects
|
||||
from the Adafruit queue
|
||||
platypush.message.event.adafruit.FeedUpdateEvent: when anupdate event is received
|
||||
on a monitored feed
|
||||
install:
|
||||
pip: []
|
||||
package: platypush.backend.adafruit.io
|
||||
type: backend
|
|
@ -0,0 +1,10 @@
|
|||
manifest:
|
||||
events:
|
||||
platypush.message.event.alarm.AlarmDismissedEvent: when an alarm is dismissed.
|
||||
platypush.message.event.alarm.AlarmSnoozedEvent: when an alarm is snoozed.
|
||||
platypush.message.event.alarm.AlarmStartedEvent: when an alarm starts.
|
||||
platypush.message.event.alarm.AlarmTimeoutEvent: when an alarm times out.
|
||||
install:
|
||||
pip: []
|
||||
package: platypush.backend.alarm
|
||||
type: backend
|
|
@ -1,3 +1,4 @@
|
|||
from abc import ABC
|
||||
import threading
|
||||
from typing import Optional, Dict, Any, Tuple
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
manifest:
|
||||
events:
|
||||
platypush.message.event.assistant.AlarmEndEvent: when an alarm ends
|
||||
platypush.message.event.assistant.AlarmStartedEvent: when an alarm starts
|
||||
platypush.message.event.assistant.ConversationEndEvent: when a new conversation
|
||||
ends
|
||||
platypush.message.event.assistant.ConversationStartEvent: when a new conversation
|
||||
starts
|
||||
platypush.message.event.assistant.ConversationTimeoutEvent: when a conversation
|
||||
times out
|
||||
platypush.message.event.assistant.MicMutedEvent: when the microphone is muted.
|
||||
platypush.message.event.assistant.MicUnmutedEvent: when the microphone is un-muted.
|
||||
platypush.message.event.assistant.NoResponse: when a conversation returned no
|
||||
response
|
||||
platypush.message.event.assistant.ResponseEvent: when the assistant is speaking
|
||||
a response
|
||||
platypush.message.event.assistant.SpeechRecognizedEvent: when a new voice command
|
||||
is recognized
|
||||
platypush.message.event.assistant.TimerEndEvent: when a timer ends
|
||||
platypush.message.event.assistant.TimerStartedEvent: when a timer starts
|
||||
install:
|
||||
pip:
|
||||
- google-assistant-library
|
||||
- google-assistant-sdk[samples]
|
||||
package: platypush.backend.assistant.google
|
||||
type: backend
|
|
@ -0,0 +1,9 @@
|
|||
manifest:
|
||||
events:
|
||||
platypush.message.event.assistant.HotwordDetectedEvent: whenever the hotword has
|
||||
been detected
|
||||
install:
|
||||
pip:
|
||||
- snowboy
|
||||
package: platypush.backend.assistant.snowboy
|
||||
type: backend
|
|
@ -83,7 +83,7 @@ class BluetoothBackend(Backend, Server):
|
|||
self.connect(connection, request)
|
||||
self.bus.post(BluetoothDeviceConnectedEvent(address=address[0], port=address[1]))
|
||||
elif isinstance(request, requests.Disconnect):
|
||||
self.disconnect(connection)
|
||||
self.disconnect(connection, request)
|
||||
self.bus.post(BluetoothDeviceDisconnectedEvent(address=address[0], port=address[1]))
|
||||
elif isinstance(request, requests.Put):
|
||||
self.bus.post(BluetoothFilePutRequestEvent(address=address[0], port=address[1]))
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
manifest:
|
||||
events: {}
|
||||
install:
|
||||
pip:
|
||||
- pybluez
|
||||
- pyobex
|
||||
package: platypush.backend.bluetooth.fileserver
|
||||
type: backend
|
|
@ -0,0 +1,8 @@
|
|||
manifest:
|
||||
events: {}
|
||||
install:
|
||||
pip:
|
||||
- pybluez
|
||||
- pyobex
|
||||
package: platypush.backend.bluetooth.pushserver
|
||||
type: backend
|
|
@ -84,7 +84,9 @@ class BluetoothScannerBackend(SensorBackend):
|
|||
with self._bt_lock:
|
||||
return super().get_measurement()
|
||||
|
||||
def process_data(self, data: Dict[str, dict], new_data: Dict[str, dict]):
|
||||
def process_data( # lgtm [py/inheritance/signature-mismatch]
|
||||
self, data: Dict[str, dict], new_data: Optional[Dict[str, dict]] = None, **_
|
||||
):
|
||||
for addr, dev in data.items():
|
||||
self._add_last_seen_device(dev)
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
manifest:
|
||||
events:
|
||||
platypush.message.event.bluetooth.BluetoothDeviceFoundEvent: when a new bluetooth
|
||||
device is found.
|
||||
platypush.message.event.bluetooth.BluetoothDeviceLostEvent: when a bluetooth device
|
||||
is lost.
|
||||
install:
|
||||
pip: []
|
||||
package: platypush.backend.bluetooth.scanner.ble
|
||||
type: backend
|
|
@ -0,0 +1,10 @@
|
|||
manifest:
|
||||
events:
|
||||
platypush.message.event.bluetooth.BluetoothDeviceFoundEvent: when a new bluetooth
|
||||
device is found.
|
||||
platypush.message.event.bluetooth.BluetoothDeviceLostEvent: when a bluetooth device
|
||||
is lost.
|
||||
install:
|
||||
pip: []
|
||||
package: platypush.backend.bluetooth.scanner
|
||||
type: backend
|
|
@ -1,6 +1,3 @@
|
|||
import importlib
|
||||
|
||||
from enum import Enum
|
||||
from threading import Timer
|
||||
from time import time
|
||||
|
||||
|
@ -17,11 +14,14 @@ class ButtonFlicBackend(Backend):
|
|||
|
||||
Triggers:
|
||||
|
||||
* :class:`platypush.message.event.button.flic.FlicButtonEvent` when a button is pressed. The event will also contain the press sequence (e.g. ``["ShortPressEvent", "LongPressEvent", "ShortPressEvent"]``)
|
||||
* :class:`platypush.message.event.button.flic.FlicButtonEvent` when a button is pressed.
|
||||
The event will also contain the press sequence
|
||||
(e.g. ``["ShortPressEvent", "LongPressEvent", "ShortPressEvent"]``)
|
||||
|
||||
Requires:
|
||||
|
||||
* **fliclib** (https://github.com/50ButtonsEach/fliclib-linux-hci). For the backend to work properly you need to have the ``flicd`` daemon from the fliclib running, and you have to first pair the buttons with your device using any of the scanners provided by the library.
|
||||
|
||||
"""
|
||||
|
||||
_long_press_timeout = 0.3
|
||||
|
@ -87,6 +87,7 @@ class ButtonFlicBackend(Backend):
|
|||
return _f
|
||||
|
||||
def _on_event(self):
|
||||
# noinspection PyUnusedLocal
|
||||
def _f(bd_addr, channel, click_type, was_queued, time_diff):
|
||||
if was_queued:
|
||||
return
|
||||
|
|
|
@ -15,6 +15,7 @@ from enum import Enum
|
|||
from collections import namedtuple
|
||||
import struct
|
||||
import itertools
|
||||
import threading
|
||||
|
||||
|
||||
class CreateConnectionChannelError(Enum):
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
manifest:
|
||||
events:
|
||||
platypush.message.event.button.flic.FlicButtonEvent: when a button is pressed.The
|
||||
event will also contain the press sequence(e.g. ``["ShortPressEvent", "LongPressEvent",
|
||||
"ShortPressEvent"]``)
|
||||
install:
|
||||
pip: []
|
||||
package: platypush.backend.button.flic
|
||||
type: backend
|
|
@ -18,7 +18,6 @@ class CameraPiBackend(Backend):
|
|||
Requires:
|
||||
|
||||
* **picamera** (``pip install picamera``)
|
||||
* **redis** (``pip install redis``) for inter-process communication with the camera process
|
||||
|
||||
This backend is **DEPRECATED**. Use the plugin :class:`platypush.plugins.camera.pi.CameraPiPlugin` instead to run
|
||||
Pi camera actions. If you want to start streaming the camera on application start then simply create an event hook
|
||||
|
@ -59,7 +58,7 @@ class CameraPiBackend(Backend):
|
|||
self.bind_address = bind_address
|
||||
self.listen_port = listen_port
|
||||
self.server_socket = socket.socket()
|
||||
self.server_socket.bind((self.bind_address, self.listen_port))
|
||||
self.server_socket.bind((self.bind_address, self.listen_port)) # lgtm [py/bind-socket-all-network-interfaces]
|
||||
self.server_socket.listen(0)
|
||||
|
||||
import picamera
|
|
@ -0,0 +1,7 @@
|
|||
manifest:
|
||||
events: {}
|
||||
install:
|
||||
pip:
|
||||
- picamera
|
||||
package: platypush.backend.camera.pi
|
||||
type: backend
|
|
@ -0,0 +1,19 @@
|
|||
manifest:
|
||||
events:
|
||||
platypush.message.event.chat.telegram.CommandMessageEvent: when a command message
|
||||
is received.
|
||||
platypush.message.event.chat.telegram.ContactMessageEvent: when a contact is received.
|
||||
platypush.message.event.chat.telegram.DocumentMessageEvent: when a document is
|
||||
received.
|
||||
platypush.message.event.chat.telegram.GroupCreatedEvent: when the bot is invited
|
||||
to a new group.
|
||||
platypush.message.event.chat.telegram.LocationMessageEvent: when a location is
|
||||
received.
|
||||
platypush.message.event.chat.telegram.PhotoMessageEvent: when a photo is received.
|
||||
platypush.message.event.chat.telegram.TextMessageEvent: when a text message is
|
||||
received.
|
||||
platypush.message.event.chat.telegram.VideoMessageEvent: when a video is received.
|
||||
install:
|
||||
pip: []
|
||||
package: platypush.backend.chat.telegram
|
||||
type: backend
|
|
@ -1,40 +0,0 @@
|
|||
import time
|
||||
from typing import Optional
|
||||
|
||||
import pyperclip
|
||||
|
||||
from platypush.backend import Backend
|
||||
from platypush.message.event.clipboard import ClipboardEvent
|
||||
|
||||
|
||||
class ClipboardBackend(Backend):
|
||||
"""
|
||||
This backend monitors for changes in the clipboard and generates even when the user copies a new text.
|
||||
|
||||
Requires:
|
||||
|
||||
- **pyperclip** (``pip install pyperclip``)
|
||||
|
||||
Triggers:
|
||||
|
||||
- :class:`platypush.message.event.clipboard.ClipboardEvent` on clipboard update.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._last_text: Optional[str] = None
|
||||
|
||||
def run(self):
|
||||
self.logger.info('Started clipboard monitor backend')
|
||||
while not self.should_stop():
|
||||
text = pyperclip.paste()
|
||||
if text and text != self._last_text:
|
||||
self.bus.post(ClipboardEvent(text=text))
|
||||
|
||||
self._last_text = text
|
||||
time.sleep(0.1)
|
||||
|
||||
self.logger.info('Stopped clipboard monitor backend')
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
|
@ -0,0 +1,7 @@
|
|||
manifest:
|
||||
events:
|
||||
platypush.message.event.covid19.Covid19UpdateEvent: when new data is available.
|
||||
install:
|
||||
pip: []
|
||||
package: platypush.backend.covid19
|
||||
type: backend
|
|
@ -1,86 +0,0 @@
|
|||
from typing import Union
|
||||
|
||||
# noinspection PyPackageRequirements,PyUnresolvedReferences
|
||||
from gi.repository import GLib
|
||||
|
||||
import dbus
|
||||
import dbus.service
|
||||
import dbus.mainloop.glib
|
||||
|
||||
from platypush.backend import Backend
|
||||
from platypush.context import get_bus
|
||||
from platypush.message import Message
|
||||
from platypush.message.event import Event
|
||||
from platypush.message.request import Request
|
||||
from platypush.utils import run
|
||||
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
class DBusService(dbus.service.Object):
|
||||
@classmethod
|
||||
def _parse_msg(cls, msg: Union[dict, list]):
|
||||
import json
|
||||
return Message.build(json.loads(json.dumps(msg)))
|
||||
|
||||
@dbus.service.method('org.platypush.MessageBusInterface', in_signature='a{sv}', out_signature='v')
|
||||
def Post(self, msg: dict):
|
||||
"""
|
||||
This method accepts a message as a dictionary (either representing a valid request or an event) and either
|
||||
executes it (request) or forwards it to the application bus (event).
|
||||
|
||||
:param msg: Request or event, as a dictionary.
|
||||
:return: The return value of the request, or 0 if the message is an event.
|
||||
"""
|
||||
msg = self._parse_msg(msg)
|
||||
if isinstance(msg, Request):
|
||||
ret = run(msg.action, **msg.args)
|
||||
if ret is None:
|
||||
ret = '' # DBus doesn't like None return types
|
||||
|
||||
return ret
|
||||
elif isinstance(msg, Event):
|
||||
get_bus().post(msg)
|
||||
return 0
|
||||
|
||||
|
||||
class DbusBackend(Backend):
|
||||
"""
|
||||
This backend acts as a proxy that receives messages (requests or events) on the DBus and forwards them to the
|
||||
application bus.
|
||||
|
||||
The name of the messaging interface exposed by Platypush is ``org.platypush.MessageBusInterface`` and it exposes
|
||||
``Post`` method, which accepts a dictionary representing a valid Platypush message (either a request or an event)
|
||||
and either executes it or forwards it to the application bus.
|
||||
|
||||
Requires:
|
||||
|
||||
* **dbus-python** (``pip install dbus-python``)
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, bus_name='org.platypush.Bus', service_path='/MessageService', *args, **kwargs):
|
||||
"""
|
||||
:param bus_name: Name of the bus where the application will listen for incoming messages (default:
|
||||
``org.platypush.Bus``).
|
||||
:param service_path: Path to the service exposed by the app (default: ``/MessageService``).
|
||||
"""
|
||||
super().__init__(*args, **kwargs)
|
||||
self.bus_name = bus_name
|
||||
self.service_path = service_path
|
||||
|
||||
def run(self):
|
||||
super().run()
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||||
bus = dbus.SessionBus()
|
||||
name = dbus.service.BusName(self.bus_name, bus)
|
||||
srv = DBusService(bus, self.service_path)
|
||||
|
||||
loop = GLib.MainLoop()
|
||||
# noinspection PyProtectedMember
|
||||
self.logger.info('Starting DBus main loop - bus name: {}, service: {}'.format(name._name, srv._object_path))
|
||||
loop.run()
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
|
@ -33,10 +33,10 @@ class FileMonitorBackend(Backend):
|
|||
if isinstance(resource, str):
|
||||
resource = MonitoredResource(resource)
|
||||
elif isinstance(resource, dict):
|
||||
if 'patterns' in resource or 'ignore_patterns' in resource:
|
||||
resource = MonitoredPattern(**resource)
|
||||
elif 'regexes' in resource or 'ignore_regexes' in resource:
|
||||
if 'regexes' in resource or 'ignore_regexes' in resource:
|
||||
resource = MonitoredRegex(**resource)
|
||||
elif 'patterns' in resource or 'ignore_patterns' in resource or 'ignore_directories' in resource:
|
||||
resource = MonitoredPattern(**resource)
|
||||
else:
|
||||
resource = MonitoredResource(**resource)
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import os
|
||||
import re
|
||||
|
||||
from watchdog.events import FileSystemEventHandler, PatternMatchingEventHandler, RegexMatchingEventHandler
|
||||
|
||||
|
@ -16,14 +17,50 @@ class EventHandler(FileSystemEventHandler):
|
|||
resource.path = os.path.expanduser(resource.path)
|
||||
self.resource = resource
|
||||
|
||||
def _should_ignore_event(self, event) -> bool:
|
||||
ignore_dirs = [
|
||||
os.path.expanduser(
|
||||
_dir if os.path.expanduser(_dir).strip('/').startswith(self.resource.path)
|
||||
else os.path.join(self.resource.path, _dir)
|
||||
)
|
||||
for _dir in getattr(self.resource, 'ignore_directories', [])
|
||||
]
|
||||
|
||||
ignore_patterns = getattr(self.resource, 'ignore_patterns', None)
|
||||
ignore_regexes = getattr(self.resource, 'ignore_regexes', None)
|
||||
|
||||
if ignore_dirs and any(
|
||||
event.src_path.startswith(ignore_dir) for ignore_dir in ignore_dirs
|
||||
):
|
||||
return True
|
||||
|
||||
if ignore_patterns and any(
|
||||
re.match(r'^{}$'.format(pattern.replace('*', '.*')), event.src_path)
|
||||
for pattern in ignore_patterns
|
||||
):
|
||||
return True
|
||||
|
||||
if ignore_regexes and any(
|
||||
re.match(regex, event.src_path)
|
||||
for regex in ignore_patterns
|
||||
):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _on_event(self, event, output_event_type):
|
||||
if self._should_ignore_event(event):
|
||||
return
|
||||
get_bus().post(output_event_type(path=event.src_path, is_directory=event.is_directory))
|
||||
|
||||
def on_created(self, event):
|
||||
get_bus().post(FileSystemCreateEvent(path=event.src_path, is_directory=event.is_directory))
|
||||
self._on_event(event, FileSystemCreateEvent)
|
||||
|
||||
def on_deleted(self, event):
|
||||
get_bus().post(FileSystemDeleteEvent(path=event.src_path, is_directory=event.is_directory))
|
||||
self._on_event(event, FileSystemDeleteEvent)
|
||||
|
||||
def on_modified(self, event):
|
||||
get_bus().post(FileSystemModifyEvent(path=event.src_path, is_directory=event.is_directory))
|
||||
self._on_event(event, FileSystemModifyEvent)
|
||||
|
||||
def on_moved(self, event):
|
||||
pass
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
manifest:
|
||||
events:
|
||||
platypush.message.event.file.FileSystemCreateEvent: if a resource is created.
|
||||
platypush.message.event.file.FileSystemDeleteEvent: if a resource is removed.
|
||||
platypush.message.event.file.FileSystemModifyEvent: if a resource is modified.
|
||||
install:
|
||||
pip:
|
||||
- watchdog
|
||||
package: platypush.backend.file.monitor
|
||||
type: backend
|
|
@ -0,0 +1,8 @@
|
|||
manifest:
|
||||
events:
|
||||
platypush.message.event.foursquare.FoursquareCheckinEvent: when a new check-in
|
||||
occurs.
|
||||
install:
|
||||
pip: []
|
||||
package: platypush.backend.foursquare
|
||||
type: backend
|
|
@ -4,7 +4,6 @@ import threading
|
|||
|
||||
from typing import Optional, List
|
||||
|
||||
import pytz
|
||||
import requests
|
||||
from sqlalchemy import create_engine, Column, String, DateTime
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
@ -129,7 +128,7 @@ class GithubBackend(Backend):
|
|||
def _get_last_event_time(self, uri: str):
|
||||
with self.db_lock:
|
||||
record = self._get_or_create_resource(uri=uri, session=Session())
|
||||
return record.last_updated_at.replace(tzinfo=pytz.UTC) if record.last_updated_at else None
|
||||
return record.last_updated_at.replace(tzinfo=datetime.timezone.utc) if record.last_updated_at else None
|
||||
|
||||
def _update_last_event_time(self, uri: str, last_updated_at: datetime.datetime):
|
||||
with self.db_lock:
|
|
@ -0,0 +1,32 @@
|
|||
manifest:
|
||||
events:
|
||||
platypush.message.event.github.GithubCommitCommentEvent: when a new commit comment
|
||||
is created.
|
||||
platypush.message.event.github.GithubCreateEvent: when a tag or branch is created.
|
||||
platypush.message.event.github.GithubDeleteEvent: when a tag or branch is deleted.
|
||||
platypush.message.event.github.GithubEvent: for any event that doesn't fall in
|
||||
the above categories(``event_type`` will be set accordingly).
|
||||
platypush.message.event.github.GithubForkEvent: when a user forks a repository.
|
||||
platypush.message.event.github.GithubIssueCommentEvent: when new activity happens
|
||||
on an issue comment.
|
||||
platypush.message.event.github.GithubIssueEvent: when new repository issue activity
|
||||
happens.
|
||||
platypush.message.event.github.GithubMemberEvent: when new repository collaborators
|
||||
activity happens.
|
||||
platypush.message.event.github.GithubPublicEvent: when a repository goes public.
|
||||
platypush.message.event.github.GithubPullRequestEvent: when new pull request related
|
||||
activity happens.
|
||||
platypush.message.event.github.GithubPullRequestReviewCommentEvent: when activity
|
||||
happens on a pullrequest commit.
|
||||
platypush.message.event.github.GithubPushEvent: when a new push is created.
|
||||
platypush.message.event.github.GithubReleaseEvent: when a new release happens.
|
||||
platypush.message.event.github.GithubSponsorshipEvent: when new sponsorship related
|
||||
activity happens.
|
||||
platypush.message.event.github.GithubWatchEvent: when someone stars/starts watching
|
||||
a repository.
|
||||
platypush.message.event.github.GithubWikiEvent: when new activity happens on a
|
||||
repository wiki.
|
||||
install:
|
||||
pip: []
|
||||
package: platypush.backend.github
|
||||
type: backend
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue