Compare commits

..

9 Commits

1829 changed files with 51159 additions and 75918 deletions

View File

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

View File

@ -1,386 +0,0 @@
---
kind: pipeline
type: docker
name: default
volumes:
- name: docs
host:
path: /opt/docs/platypush
- name: repos
host:
path: /opt/repos/platypush
steps:
###
### Mirror the current repository state to Github
###
- name: github-mirror
image: alpine
environment:
SSH_PUBKEY:
from_secret: ssh_pubkey
SSH_PRIVKEY:
from_secret: ssh_privkey
commands:
- . .drone/github-mirror.sh
###
### Rebuild the docs
###
- name: docs
image: alpine
volumes:
- name: docs
path: /docs
commands:
- . .drone/rebuild-docs.sh
when:
event:
- tag
###
### Run the tests
###
- name: tests
image: alpine
commands:
- . .drone/run-tests.sh
###
### Rebuild the UI files
###
- name: build-ui
image: node:current-alpine3.18
environment:
SSH_PUBKEY:
from_secret: ssh_pubkey
SSH_PRIVKEY:
from_secret: ssh_privkey
PGP_KEY:
from_secret: pgp_key
PGP_KEY_ID:
from_secret: pgp_key_id
when:
branch:
- master
event:
- push
depends_on:
- tests
commands:
- . .drone/build-ui.sh
###
### Regenerate the components.json cache
###
- name: update-components-cache
image: alpine
environment:
SSH_PUBKEY:
from_secret: ssh_pubkey
SSH_PRIVKEY:
from_secret: ssh_privkey
PGP_KEY:
from_secret: pgp_key
PGP_KEY_ID:
from_secret: pgp_key_id
when:
branch:
- master
event:
- push
depends_on:
- build-ui
commands:
- . .drone/update-components-cache.sh
###
### Update the Arch packages
###
- name: update-arch-packages
image: python:3.11-alpine
environment:
WORKDIR: /tmp/workdir
SSH_PUBKEY:
from_secret: ssh_pubkey
SSH_PRIVKEY:
from_secret: ssh_privkey
when:
branch:
- master
event:
- push
depends_on:
- update-components-cache
commands:
- . .drone/update-arch-packages.sh
###
### Update the Debian (stable) packages
###
- name: update-debian-stable-packages
image: debian:stable
volumes:
- name: repos
path: /repos
environment:
DEB_VERSION: stable
WORKDIR: /tmp/workdir
APT_ROOT: /repos/apt
PKG_NAME: platypush
when:
branch:
- master
event:
- push
depends_on:
- update-components-cache
commands:
- . .drone/update-deb-packages.sh
###
### Update the Debian (oldstable) packages
###
- name: update-debian-oldstable-packages
image: debian:oldstable
volumes:
- name: repos
path: /repos
environment:
DEB_VERSION: oldstable
WORKDIR: /tmp/workdir
APT_ROOT: /repos/apt
PKG_NAME: platypush
when:
branch:
- master
event:
- push
depends_on:
- update-components-cache
commands:
- . .drone/update-deb-packages.sh
###
### Update the Ubuntu (latest) packages
###
- name: update-ubuntu-packages
image: ubuntu:latest
volumes:
- name: repos
path: /repos
environment:
DEB_VERSION: ubuntu
WORKDIR: /tmp/workdir
APT_ROOT: /repos/apt
PKG_NAME: platypush
when:
branch:
- master
event:
- push
depends_on:
- update-components-cache
commands:
- . .drone/update-deb-packages.sh
###
### Updates the APT repository after new packages have been pushed
###
- name: update-apt-repo
image: debian:stable
volumes:
- name: repos
path: /repos
environment:
REPOS_ROOT: /repos
APT_ROOT: /repos/apt
PGP_PUBKEY:
from_secret: apt_pgp_pub_key
PGP_PRIVKEY:
from_secret: apt_pgp_priv_key
when:
branch:
- master
event:
- push
depends_on:
- update-debian-stable-packages
- update-debian-oldstable-packages
- update-ubuntu-packages
commands:
- . .drone/update-apt-repo.sh
###
### Update the RPM (stable) packages
###
- name: update-rpm-repo
image: fedora
volumes:
- name: repos
path: /repos
environment:
RPM_VERSION: stable
REPOS_ROOT: /repos
RPM_ROOT: /repos/rpm
WORKDIR: /tmp/workdir
PKG_NAME: platypush
PGP_PUBKEY:
from_secret: rpm_pgp_pub_key
PGP_PRIVKEY:
from_secret: rpm_pgp_priv_key
when:
branch:
- master
event:
- push
depends_on:
- update-components-cache
commands:
- . .drone/update-rpm-repo.sh
###
### Updates the pip package upon new releases
###
- name: update-pip-package
image: alpine
environment:
TWINE_USERNAME:
from_secret: pypi_user
TWINE_PASSWORD:
from_secret: pypi_pass
when:
event:
- tag
depends_on:
- tests
- docs
commands:
- . .drone/update-pip-package.sh
###
### Checkpoint step that waits for all the package update
### steps to complete before proceeding to the next steps.
###
- name: wait-pkg-update
image: alpine
when:
branch:
- master
event:
- push
depends_on:
- update-arch-packages
- update-rpm-repo
- update-apt-repo
commands:
- echo "All packages have been successfully updated"
###
### Notifies about a new release
###
- name: notify-release
image: python:3.11-alpine
environment:
WORKER_RPC_SECRET:
from_secret: worker_rpc_secret
when:
event:
- tag
depends_on:
- update-pip-package
commands:
- apk add --update --no-cache curl
- |
curl --silent -XPOST \
-H "X-Token: $WORKER_RPC_SECRET" \
"https://worker.ci-cd.platypush.tech/hook/notify-platypush-release?version=$(python setup.py --version)"
###
### Notifies about a change in the CI/CD build status
###
- name: notify-build-status
image: alpine
environment:
WORKER_RPC_SECRET:
from_secret: worker_rpc_secret
when:
branch:
- master
event:
- push
status:
- success
- failure
depends_on:
- wait-pkg-update
commands:
- apk add --update --no-cache curl
- |
curl --silent -XPOST \
-H "X-Token: $WORKER_RPC_SECRET" \
"https://worker.ci-cd.platypush.tech/hook/notify-platypush-build?status=$DRONE_BUILD_STATUS"

View File

@ -1,46 +0,0 @@
#!/bin/sh
export SRCDIR="$PWD"
export WEBAPP_DIR="$SRCDIR/platypush/backend/http/webapp"
export SKIPCI="$PWD/.skipci"
rm -rf "$SKIPCI"
. .drone/macros/configure-git.sh
cd "$WEBAPP_DIR"
if [ $(git log --pretty=oneline $DRONE_COMMIT_AFTER...$DRONE_COMMIT_BEFORE . | wc -l) -eq 0 ]; then
echo "No UI changes detected, skipping build"
exit 0
fi
if [ "$(git log --pretty=format:%s HEAD...HEAD~1 | head -1)" == "[Automatic] Updated UI files" ]; then
echo "UI changes have already been committed, skipping build"
exit 0
fi
rm -rf dist node_modules
npm install
npm run build
if [ $(git status --porcelain dist | wc -l) -eq 0 ]; then
echo "No build files have been changed"
exit 0
fi
# Create a .skipci file to mark the fact that the next steps should be skipped
# (we're going to do another push anyway, so another pipeline will be triggered)
touch "$SKIPCI"
cd "$SRCDIR"
. .drone/macros/configure-ssh.sh
. .drone/macros/configure-gpg.sh
git add "${WEBAPP_DIR}/dist"
git commit "${WEBAPP_DIR}/dist" -S -m "[Automatic] Updated UI files" --no-verify
git remote rm origin
git remote add origin git@git.platypush.tech:platypush/platypush.git
git push -f origin master
# Restore the original git configuration
mv "$TMP_GIT_CONF" "$GIT_CONF"

View File

@ -1,13 +0,0 @@
#!/bin/sh
. .drone/macros/configure-git.sh
. .drone/macros/configure-ssh.sh
ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null
# Clone the repository
git remote add github git@github.com:/BlackLight/platypush.git
git pull --rebase github "$(git branch | head -1 | awk '{print $2}')" || echo "No such branch on Github"
# Push the changes to the GitHub mirror
git push --all -v github

View File

@ -1,29 +0,0 @@
#!/bin/sh
# Install git
if [ -z "$(which git)" ]; then
if [ -n "$(which apt-get)" ]; then
apt-get update
apt-get install -y git
elif [ -n "$(which apk)" ]; then
apk add --update --no-cache git
elif [ -n "$(which yum)" ]; then
yum install -y git
elif [ -n "$(which dnf)" ]; then
dnf install -y git
elif [ -n "$(which pacman)" ]; then
pacman -Sy --noconfirm git
else
echo "Could not find a package manager to install git"
exit 1
fi
fi
# Backup the original git configuration before changing attributes
export GIT_CONF="$PWD/.git/config"
export TMP_GIT_CONF=/tmp/git.config.orig
cp "$GIT_CONF" "$TMP_GIT_CONF"
git config --global --add safe.directory "$PWD"
git config user.name "Platypush CI/CD Automation"
git config user.email "admin@platypush.tech"

View File

@ -1,30 +0,0 @@
#!/bin/sh
[ -z "$PGP_KEY" ] && echo "PGP_KEY is not set" && exit 1
[ -z "$PGP_KEY_ID" ] && echo "PGP_KEY_ID is not set" && exit 1
# Install gpg
if [ -z "$(which gpg)" ]; then
if [ -n "$(which apt-get)" ]; then
apt-get update
apt-get install -y gnupg
elif [ -n "$(which apk)" ]; then
apk add --update --no-cache bash gnupg
elif [ -n "$(which yum)" ]; then
yum install -y gnupg
elif [ -n "$(which dnf)" ]; then
dnf install -y gnupg
elif [ -n "$(which pacman)" ]; then
pacman -Sy --noconfirm gnupg
else
echo "Could not find a package manager to install gnupg"
exit 1
fi
fi
cat <<EOF | gpg --import --armor
$PGP_KEY
EOF
git config commit.gpgsign true
git config user.signingkey "$PGP_KEY_ID"

View File

@ -1,35 +0,0 @@
#!/bin/sh
if [ -z "$SSH_PUBKEY" ] || [ -z "$SSH_PRIVKEY" ]; then
echo "SSH_PUBKEY and SSH_PRIVKEY environment variables must be set"
exit 1
fi
# Install ssh
if [ -z "$(which ssh)" ]; then
if [ -n "$(which apt-get)" ]; then
apt-get update
apt-get install -y openssh
elif [ -n "$(which apk)" ]; then
apk add --update --no-cache openssh
elif [ -n "$(which yum)" ]; then
yum install -y openssh
elif [ -n "$(which dnf)" ]; then
dnf install -y openssh
elif [ -n "$(which pacman)" ]; then
pacman -Sy --noconfirm openssh
else
echo "Could not find a package manager to install openssh"
exit 1
fi
fi
mkdir -p ~/.ssh
echo $SSH_PUBKEY > ~/.ssh/id_rsa.pub
cat <<EOF > ~/.ssh/id_rsa
$SSH_PRIVKEY
EOF
chmod 0600 ~/.ssh/id_rsa
ssh-keyscan git.platypush.tech >> ~/.ssh/known_hosts 2>/dev/null

View File

@ -1,27 +0,0 @@
#!/bin/sh
echo "Installing required build dependencies"
apk add --update --no-cache git make py3-sphinx py3-myst-parser py3-pip $(cat platypush/install/requirements/alpine.txt)
pip install -U sphinx-rtd-theme sphinx-book-theme --break-system-packages
pip install . --break-system-packages
mkdir -p /docs/current
export APPDIR="$PWD"
rm -rf "$APPDIR/docs/build"
echo "Building the updated documentation"
cd "$APPDIR/docs/source"
git clone 'https://git.platypush.tech/platypush/platypush.wiki.git' wiki
echo "Linking the wiki to the Sphinx index"
cd wiki
cd "$APPDIR/docs"
make html
rm -f config*.yaml
cd "$APPDIR"
echo "Copying the new documentation files to the target folder"
mv -v "$APPDIR/docs/build" /docs/new
cd /docs
mv current old
mv new current
rm -rf old

View File

@ -1,6 +0,0 @@
#!/bin/sh
apk add --update --no-cache $(cat platypush/install/requirements/alpine.txt)
pip install . --break-system-packages
pip install -r requirements-tests.txt --break-system-packages
pytest tests

View File

@ -1,169 +0,0 @@
#!/bin/sh
[ -f .skipci ] && exit 0
echo "-- Installing dependencies"
apt update
apt install -y dpkg-dev gpg
echo "-- Creating a new apt root folder"
export TMP_APT_ROOT="/tmp/apt"
cp -r "$APT_ROOT" "$TMP_APT_ROOT"
echo "-- Cleaning up older apt releases"
find "$TMP_APT_ROOT/pool" -mindepth 2 -maxdepth 2 -type d | while read reldir; do
pkg_to_remove=$(( $(ls "$reldir"/*.deb | wc -l) - 1 ))
[ $pkg_to_remove -le 0 ] && continue
ls "$reldir"/*.deb | sort -V | head -n$pkg_to_remove | xargs rm -f
done
echo "-- Updating Packages files"
echo "stable\noldstable\nubuntu" | while read distro; do
echo "main\ndev" | while read branch; do
branch_dir="$TMP_APT_ROOT/pool/$distro/$branch"
echo "Checking pool folder: $branch_dir"
[ -d "$branch_dir" ] || mkdir -p "$branch_dir"
dist_dir="$TMP_APT_ROOT/dists/$distro/$branch/all"
mkdir -p "$dist_dir"
pkg_file="$dist_dir/Packages"
dpkg-scanpackages --arch all "$branch_dir" > "$pkg_file"
sed -i "$pkg_file" -re "s|^Filename: $TMP_APT_ROOT/|Filename: |"
cat "$pkg_file" | gzip -9 > "$pkg_file.gz"
echo "Generated Packages file: $pkg_file"
cat "$pkg_file"
done
done
echo "-- Updating Release files"
add_hashes() {
dist_dir=$1
hash_cmd=$2
hash_label=$3
echo "$hash_label:"
find "$dist_dir" -name 'Packages*' | while read file; do
basename="$(echo "$file" | sed -r -e "s|^$dist_dir/||")"
hash="$($hash_cmd "$file" | cut -d" " -f1)"
size="$(wc -c < $file)"
echo " $hash $size $basename"
echo " $hash $size $(echo $basename | sed -re 's|/all/|/binary-i386/|')"
echo " $hash $size $(echo $basename | sed -re 's|/all/|/binary-amd64/|')"
echo " $hash $size $(echo $basename | sed -re 's|/all/|/binary-armel/|')"
echo " $hash $size $(echo $basename | sed -re 's|/all/|/binary-armhf/|')"
echo " $hash $size $(echo $basename | sed -re 's|/all/|/binary-arm64/|')"
done
}
echo "stable\noldstable\nubuntu" | while read distro; do
dist_dir="$TMP_APT_ROOT/dists/$distro"
components=$(find "$dist_dir" -name Packages | awk -F '/' '{print $(NF-2)}' | uniq | tr '\n' ' ')
release_file="$dist_dir/Release"
cat <<EOF > "$release_file"
Origin: Platypush repository
Label: Platypush
Suite: $distro
Codename: $distro
Architectures: i386 amd64 armel armhf arm64
Components: $components
Description: The official APT repository for Platypush
Date: $(date -Ru)
EOF
add_hashes "$dist_dir" "md5sum" "MD5Sum" >> "$release_file"
add_hashes "$dist_dir" "sha1sum" "SHA1" >> "$release_file"
add_hashes "$dist_dir" "sha256sum" "SHA256" >> "$release_file"
done
echo "-- Generating list files"
mkdir -p "$TMP_APT_ROOT/lists"
for distro in stable oldstable ubuntu; do
for branch in main dev; do
echo "deb https://apt.platypush.tech/ $distro $branch" > "$TMP_APT_ROOT/lists/platypush-$distro-$branch.list"
done
done
echo "-- Updating index file"
cat <<EOF > "$TMP_APT_ROOT/index.txt"
Welcome to the Platypush APT repository!
Project homepage: https://platypush.tech
Source code: https://git.platypush.tech/platypush/platypush
Documentation / API reference: https://docs.platypush.tech
You can use this APT repository to install Platypush on Debian, Ubuntu or any
Debian-based distro.
Steps:
1. Add this repository's PGP key to your apt keyring
====================================================
# wget -q -O \\\
/etc/apt/trusted.gpg.d/platypush.asc \\\
https://apt.platypush.tech/pubkey.txt
2. Add the repository to your sources
=====================================
# wget -q -O \\\
/etc/apt/sources.list.d/platypush.list \\\
https://apt.platypush.tech/lists/platypush-<deb_version>-<branch>.list
Where:
- deb_version can be:
- *stable* - current Debian stable version
- *oldstable* - previous Debian stable version
- *ubuntu* - latest Ubuntu version
- branch can be either:
- *main* - latest stable release
- *dev* a package always in sync with the git version
For example, to install the latest stable tags on Debian stable:
# wget -q -O \\\
/etc/apt/sources.list.d/platypush.list \\\
https://apt.platypush.tech/lists/platypush-stable-main.list
3. Update your repos
====================
# apt update
4. Install Platypush
====================
# apt install platypush
EOF
echo "-- Importing and refreshing PGP key"
echo "$PGP_PUBKEY" > "$TMP_APT_ROOT/pubkey.txt"
export PGP_KEYID=$(echo "$PGP_PUBKEY" | gpg --with-colons --import-options show-only --import --fingerprint | grep -e '^fpr:' | head -1 | awk -F ':' '{print $(NF - 1)}')
cat <<EOF | gpg --import --armor
$PGP_PRIVKEY
EOF
echo "-- Signing Release files"
find "$TMP_APT_ROOT/dists" -type f -name Release | while read file; do
dirname="$(dirname "$file")"
cat "$file" | gpg -q --default-key "$PGP_KEYID" -abs > "$file.gpg"
cat "$file" | gpg -q --default-key "$PGP_KEYID" -abs --clearsign > "$dirname/InRelease"
done
echo "-- Updating the apt repo root"
export OLD_APT_ROOT="$REPOS_ROOT/oldapt"
rm -rf "$OLD_APT_ROOT"
mv "$APT_ROOT" "$OLD_APT_ROOT"
mv "$TMP_APT_ROOT" "$APT_ROOT"
chmod -R a+r "$APT_ROOT"
chmod a+x "$APT_ROOT"

View File

@ -1,67 +0,0 @@
#!/bin/sh
[ -f .skipci ] && exit 0
apk add --update --no-cache curl pacman sudo
. .drone/macros/configure-ssh.sh
. .drone/macros/configure-git.sh
git pull --rebase origin master --tags
export VERSION=$(python setup.py --version)
export HEAD=$(git log --pretty=format:%h HEAD...HEAD~1 | head -1)
export GIT_VERSION="$VERSION.r$(git log --pretty=oneline HEAD...v$VERSION | wc -l).g${HEAD}"
export TAG_URL="https://git.platypush.tech/platypush/platypush/archive/v$VERSION.tar.gz"
ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts 2>/dev/null
adduser -u 1000 -D build
mkdir -p "$WORKDIR"
echo "--- Updating Arch git version"
export PKGDIR=$WORKDIR/git
git clone ssh://aur@aur.archlinux.org/platypush-git.git "$PKGDIR"
git config --global --add safe.directory "$PKGDIR"
chown -R build "$PKGDIR"
cd "$PKGDIR"
sed -i 'PKGBUILD' -r \
-e "s/^pkgver=.*/pkgver=$GIT_VERSION/" \
-e "s/^pkgrel=.*/pkgrel=1/" \
sudo -u build makepkg --printsrcinfo > .SRCINFO
export FILES_CHANGED=$(git status --porcelain --untracked-files=no | wc -l)
if [ $FILES_CHANGED -gt 0 ]; then
echo "--- Pushing git package version $GIT_VERSION"
git commit -a -m '[Automatic] Package update'
git push origin master
fi
echo "--- Updating Arch stable version"
export PKGDIR="$WORKDIR/stable"
git clone ssh://aur@aur.archlinux.org/platypush.git "$PKGDIR"
git config --global --add safe.directory "$PKGDIR"
chown -R build "$PKGDIR"
cd "$PKGDIR"
export RELEASED_VERSION=$(grep -e '^pkgver=' PKGBUILD | sed -r -e 's/^pkgver=(.*)\s*/\1/')
if [ "$RELEASED_VERSION" == "$VERSION" ]; then
exit 0
fi
export TAG_CHECKSUM=$(curl --silent "$TAG_URL" | sha512sum | awk '{print $1}')
sed -i 'PKGBUILD' -r \
-e "s/^pkgver=.*/pkgver=$VERSION/" \
-e "s/^pkgrel=.*/pkgrel=1/" \
-e "s/^sha512sums=.*/sha512sums=('$TAG_CHECKSUM')/"
sudo -u build makepkg --printsrcinfo > .SRCINFO
export FILES_CHANGED=$(git status --porcelain --untracked-files=no | wc -l)
if [ $FILES_CHANGED -gt 0 ]; then
echo "--- Pushing stable package version $VERSION"
git commit -a -m '[Automatic] Package update'
git push origin master
fi

View File

@ -1,46 +0,0 @@
#!/bin/sh
export SKIPCI="$PWD/.skipci"
export CACHEFILE="$PWD/platypush/components.json.gz"
[ -f "$SKIPCI" ] && exit 0
# Backup the original git configuration before changing attributes
export GIT_CONF="$PWD/.git/config"
export TMP_GIT_CONF="/tmp/git.config.orig"
cp "$GIT_CONF" "$TMP_GIT_CONF"
. .drone/macros/configure-git.sh
# Only regenerate the components cache if either the plugins, backends,
# events or schemas folders have some changes (excluding the webapp files).
if [ -z "$(git log --pretty=oneline $DRONE_COMMIT_AFTER...$DRONE_COMMIT_BEFORE -- platypush/backend platypush/plugins platypush/schemas platypush/message/event ':(exclude)platypush/backend/http/webapp')" ]; then
echo 'No changes to the components file'
exit 0
fi
. .drone/macros/configure-ssh.sh
. .drone/macros/configure-gpg.sh
echo 'Updating components cache'
apk add --update --no-cache $(cat platypush/install/requirements/alpine.txt)
pip install . --break-system-packages
python - <<EOF
from platypush import get_plugin
get_plugin('inspect').refresh_cache(force=True)
EOF
# Create a .skipci file to mark the fact that the next steps should be skipped
# (we're going to do another push anyway, so another pipeline will be triggered)
touch "$SKIPCI"
git add "$CACHEFILE"
git commit "$CACHEFILE" -S -m "[Automatic] Updated components cache" --no-verify
git remote rm origin
git remote add origin git@git.platypush.tech:platypush/platypush.git
git push -f origin master
# Restore the original git configuration
mv "$TMP_GIT_CONF" "$GIT_CONF"

View File

@ -1,103 +0,0 @@
#!/bin/sh
[ -f .skipci ] && exit 0
echo "-- Copying source directory"
mkdir -p "$WORKDIR/src"
export SRCDIR="$WORKDIR/src/$DEB_VERSION"
cp -r "$PWD" "$SRCDIR"
cd "$SRCDIR"
echo "-- Installing dependencies"
export DEBIAN_FRONTEND=noninteractive
apt update
apt install -y curl dpkg-dev gpg git python3 python3-pip python3-setuptools
echo "--- Parsing metadata"
git config --global --add safe.directory "$PWD"
git pull --rebase origin master --tags
export VERSION=$(python3 setup.py --version)
export GIT_VERSION="$VERSION-$(git log --pretty=oneline HEAD...v$VERSION | wc -l)"
export GIT_BUILD_DIR="$WORKDIR/${PKG_NAME}_${GIT_VERSION}_all"
export GIT_DEB="$WORKDIR/${PKG_NAME}_${GIT_VERSION}_all.deb"
export POOL_PATH="$APT_ROOT/pool/$DEB_VERSION/dev"
echo "--- Building git package"
pip install --prefix="$GIT_BUILD_DIR/usr" --no-cache --no-deps .
find "$GIT_BUILD_DIR" -name "site-packages" | while read dir; do
base="$(dirname "$dir")"
mv "$dir" "$base/dist-packages"
done
install -m755 -d "${GIT_BUILD_DIR}/usr/lib/systemd/system"
install -m755 -d "${GIT_BUILD_DIR}/usr/lib/systemd/user"
install -m750 -d "${GIT_BUILD_DIR}/var/lib/platypush"
install -m750 -d "${GIT_BUILD_DIR}/etc/platypush/scripts"
install -m644 "${SRCDIR}/platypush/config/config.yaml" "${GIT_BUILD_DIR}/etc/platypush/config.yaml"
install -m644 "${SRCDIR}/platypush/config/systemd/platypush.service" "${GIT_BUILD_DIR}/usr/lib/systemd/user/platypush.service"
install -m644 "${SRCDIR}/platypush/config/systemd/platypush.service" "${GIT_BUILD_DIR}/usr/lib/systemd/system/platypush.service"
sed -i "${GIT_BUILD_DIR}/usr/lib/systemd/system/platypush.service" -r \
-e 's/^#\s*Requires=(.*)/Requires=\1/' \
-e 's/^\[Service\]$/\[Service\]\
User=platypush\
Group=platypush\
WorkingDirectory=\/var\/lib\/platypush\
Environment="PLATYPUSH_CONFIG=\/etc\/platypush\/config.yaml"\
Environment="PLATYPUSH_WORKDIR=\/var\/lib\/platypush"/'
mkdir -p "$GIT_BUILD_DIR/DEBIAN"
cat <<EOF > "$GIT_BUILD_DIR/DEBIAN/control"
Package: $PKG_NAME
Version: $GIT_VERSION
Maintainer: Fabio Manganiello <fabio@platypush.tech>
Depends: $(cat platypush/install/requirements/debian.txt | tr '\n' ',' | sed -re 's/,$//' -e 's/,/, /g')
Architecture: all
Homepage: https://platypush.tech
Description: Universal command executor and automation hub.
EOF
cat <<EOF > "$GIT_BUILD_DIR/DEBIAN/postinst" && chmod +x "$GIT_BUILD_DIR/DEBIAN/postinst"
#!/bin/sh
set -e
if [ "\$1" = "configure" ]; then
grep -e '^platypush:' /etc/passwd 2>/dev/null || useradd -U -r -s /bin/false -d /var/lib/platypush platypush
mkdir -p /var/lib/platypush
chown -R platypush:platypush /var/lib/platypush
chown -R platypush:platypush /etc/platypush
if which systemctl; then systemctl daemon-reload; fi
fi
EOF
mkdir -p "$POOL_PATH"
rm -f "$POOL_PATH/"*.deb
dpkg --build "$GIT_BUILD_DIR"
echo "--- Copying $GIT_DEB to $POOL_PATH"
cp "$GIT_DEB" "$POOL_PATH"
# If main/all/Packages doesn't exist, then we should create the first main release
[ $(ls "$APT_ROOT/pool/$DEB_VERSION/main/${PKG_NAME}_${VERSION}-"*"_all.deb" 2>/dev/null | wc -l) -eq 0 ] && export UPDATE_STABLE_PKG=1
export PKGURL="https://apt.platypush.tech/dists/$DEB_VERSION/main/all/Packages"
[ -z "$UPDATE_STABLE_PKG" ] &&
curl -ILs -o /dev/null -w "%{http_code}" "$PKGURL" |
grep -e '^4' >/dev/null && export UPDATE_STABLE_PKG=1
# If the published release version differs from the current one, then we should publish a new main release
if [ -z "$UPDATE_STABLE_PKG" ]; then
RELEASED_VERSION=$(curl -s "$PKGURL" | grep -e '^Version: ' | head -1 | awk '{print $2}' | cut -d- -f 1)
[ "$RELEASED_VERSION" != "$VERSION" ] && export UPDATE_STABLE_PKG=1
fi
# Proceed and update the main release if the version number has changed
if [ -n "$UPDATE_STABLE_PKG" ]; then
echo "--- Updating main package"
mkdir -p "$APT_ROOT/pool/$DEB_VERSION/main"
cp "$GIT_DEB" "$APT_ROOT/pool/$DEB_VERSION/main/${PKG_NAME}_${VERSION}-1_all.deb"
fi

View File

@ -1,5 +0,0 @@
#!/bin/sh
apk add --update --no-cache py3-twine py3-setuptools py3-wheel py3-pip
python setup.py sdist bdist_wheel
twine upload dist/platypush-$(python setup.py --version).tar.gz

View File

@ -1,261 +0,0 @@
#!/bin/sh
[ -f .skipci ] && exit 0
echo "-- Installing dependencies"
yum install -y \
createrepo \
git \
gpg \
python \
python-pip \
python-setuptools \
rpm-build \
rpm-sign \
systemd-rpm-macros \
wget \
yum-utils \
echo "-- Copying source directory"
mkdir -p "$WORKDIR"
export SRCDIR="$WORKDIR/src"
cp -r "$PWD" "$SRCDIR"
cd "$SRCDIR"
mkdir -p "$RPM_ROOT"
echo "--- Parsing metadata"
git config --global --add safe.directory $PWD
git pull --rebase origin master --tags
export VERSION=$(python3 setup.py --version)
export RELNUM="$(git log --pretty=oneline HEAD...v$VERSION | wc -l)"
export SPECFILE="$WORKDIR/$PKG_NAME.spec"
export BUILD_DIR="$WORKDIR/build"
export TMP_RPM_ROOT="$WORKDIR/repo"
export SRC_URL="https://git.platypush.tech/platypush/platypush/archive/master.tar.gz"
echo "--- Creating git package spec"
cat <<EOF > $SPECFILE
Summary: Universal command executor and automation hub.
Name: $PKG_NAME-git
Version: $VERSION
Release: $RELNUM
URL: https://platypush.tech
Group: System
License: MIT
Packager: Fabio Manganiello <fabio@platypush.tech>
Source: $SRC_URL
Requires: $(cat platypush/install/requirements/fedora.txt | tr '\n' ' ')
Conflicts: $PKG_NAME
Prefix: %{_prefix}
BuildRoot: %{_tmppath}/%{name}-root
BuildRequires: systemd-rpm-macros
%{?sysusers_requires_compat}
%description
Universal command executor and automation hub.
%install
mkdir -p %{buildroot}/
cp -r "$BUILD_DIR"/* %{buildroot}/
install -p -Dm0644 "${BUILD_DIR}/usr/lib/sysusers.d/platypush.conf" %{buildroot}%{_sysusersdir}/platypush.conf
%pre
%sysusers_create_compat "${BUILD_DIR}/usr/lib/sysusers.d/platypush.conf"
%clean
%files
%defattr(750,platypush,platypush,750)
%dir /etc/platypush
/etc/platypush/*
/usr/bin/*
/usr/lib/python$(python3 --version | awk '{print $2}' | cut -d. -f 1,2)/site-packages/platypush
/usr/lib/python$(python3 --version | awk '{print $2}' | cut -d. -f 1,2)/site-packages/platypush-$VERSION.dist-info
/usr/lib/systemd/system/*
/usr/lib/systemd/user/*
%defattr(750,platypush,platypush,750)
%dir /var/lib/platypush
%{_sysusersdir}/platypush.conf
%changelog
* $(date +'%a %b %d %Y') admin <admin@platypush.tech>
- [Automatic] Release $VERSION-$RELNUM
EOF
echo "--- Building git package"
mkdir -p "$BUILD_DIR"
pip install --prefix="$BUILD_DIR/usr" --no-cache --no-deps .
install -m755 -d "${BUILD_DIR}/usr/lib/systemd/system"
install -m755 -d "${BUILD_DIR}/usr/lib/systemd/user"
install -m755 -d "${BUILD_DIR}/usr/lib/sysusers.d"
install -m750 -d "${BUILD_DIR}/var/lib/platypush"
install -m750 -d "${BUILD_DIR}/etc/platypush/scripts"
install -m644 "${SRCDIR}/platypush/config/config.yaml" "${BUILD_DIR}/etc/platypush/config.yaml"
install -Dm644 "${SRCDIR}/platypush/config/systemd/platypush-sysusers.conf" "${BUILD_DIR}/usr/lib/sysusers.d/platypush.conf"
install -m644 "${SRCDIR}/platypush/config/systemd/platypush.service" "${BUILD_DIR}/usr/lib/systemd/user/platypush.service"
install -m644 "${SRCDIR}/platypush/config/systemd/platypush.service" "${BUILD_DIR}/usr/lib/systemd/system/platypush.service"
sed -i "${BUILD_DIR}/usr/lib/systemd/system/platypush.service" -r \
-e 's/^#\s*Requires=(.*)/Requires=\1/' \
-e 's/^\[Service\]$/\[Service\]\
User=platypush\
Group=platypush\
WorkingDirectory=\/var\/lib\/platypush\
Environment="PLATYPUSH_CONFIG=\/etc\/platypush\/config.yaml"\
Environment="PLATYPUSH_WORKDIR=\/var\/lib\/platypush"/'
rpmbuild --target "noarch" -bb "$SPECFILE"
echo "--- Copying the new RPM package"
mkdir -p "$TMP_RPM_ROOT"
cp "$HOME/rpmbuild/RPMS/noarch/$PKG_NAME-git-$VERSION-$RELNUM.noarch.rpm" "$TMP_RPM_ROOT"
echo "--- Checking the latest released stable version"
export LATEST_STABLE_PKG=$(ls -rt "$RPM_ROOT/$PKG_NAME"*.rpm 2>/dev/null | grep -v "$PKG_NAME-git" | tail -1)
if [ -z "$LATEST_STABLE_PKG" ]; then
# If not stable release is available, then create one
export UPDATE_STABLE_PKG=1
else
# Otherwise, create a new release if the reported version on the repo is different
# from the latest released version.
export LATEST_STABLE_VERSION=$(basename $LATEST_STABLE_PKG | cut -d- -f 2)
if [ "$VERSION" != "$LATEST_STABLE_VERSION" ]; then
export UPDATE_STABLE_PKG=1
else
# If the version has remained the same, then simply copy the existing RPM to the
# new repository directory.
echo "Copying the existing release $LATEST_STABLE_VERSION to the new repository"
cp "$LATEST_STABLE_PKG" "$TMP_RPM_ROOT"
fi
fi
# If a new stable release is required, build another RPM
if [ -n "$UPDATE_STABLE_PKG" ]; then
export RELNUM=1
export SRC_URL="https://git.platypush.tech/platypush/platypush/archive/v$VERSION.tar.gz"
cat <<EOF > $SPECFILE
Summary: Universal command executor and automation hub.
Name: $PKG_NAME
Version: $VERSION
Release: $RELNUM
URL: https://platypush.tech
Group: System
License: MIT
Packager: Fabio Manganiello <fabio@platypush.tech>
Source: $SRC_URL
Requires: $(cat platypush/install/requirements/fedora.txt | tr '\n' ' ')
Conflicts: $PKG_NAME-git
Prefix: %{_prefix}
BuildRoot: %{_tmppath}/%{name}-root
BuildRequires: systemd-rpm-macros
%{?sysusers_requires_compat}
%description
Universal command executor and automation hub.
%install
mkdir -p %{buildroot}/
cp -r "$BUILD_DIR"/* %{buildroot}/
install -p -Dm0644 "${BUILD_DIR}/usr/lib/sysusers.d/platypush.conf" %{buildroot}%{_sysusersdir}/platypush.conf
%pre
%sysusers_create_compat "${BUILD_DIR}/usr/lib/sysusers.d/platypush.conf"
%clean
%files
%defattr(750,platypush,platypush,750)
%dir /etc/platypush
/etc/platypush/*
/usr/bin/*
/usr/lib/python$(python3 --version | awk '{print $2}' | cut -d. -f 1,2)/site-packages/platypush
/usr/lib/python$(python3 --version | awk '{print $2}' | cut -d. -f 1,2)/site-packages/platypush-$VERSION.dist-info
/usr/lib/systemd/system/*
/usr/lib/systemd/user/*
%defattr(750,platypush,platypush,750)
%dir /var/lib/platypush
%{_sysusersdir}/platypush.conf
%changelog
* $(date +'%a %b %d %Y') admin <admin@platypush.tech>
- [Automatic] Release $VERSION-$RELNUM
EOF
echo "--- Building package for stable release $VERSION"
rpmbuild --target "noarch" -bb "$SPECFILE"
cp "$HOME/rpmbuild/RPMS/noarch/$PKG_NAME-$VERSION-$RELNUM.noarch.rpm" "$TMP_RPM_ROOT"
fi
echo "--- Importing the repository keys"
cat <<EOF | gpg --import --armor
$PGP_PRIVKEY
EOF
export PGP_KEYID=$(echo "$PGP_PUBKEY" | gpg --with-colons --import-options show-only --import --fingerprint | grep -e '^fpr:' | head -1 | awk -F ':' '{print $(NF - 1)}')
cat <<EOF > $HOME/.rpmmacros
%signature gpg
%_gpg_name $PGP_KEYID
EOF
echo "--- Signing the new RPM packages"
rpm --addsign "$TMP_RPM_ROOT"/*.rpm
echo "--- Creating a new copy of the RPM repository"
createrepo "$TMP_RPM_ROOT"
gpg --detach-sign --armor "$TMP_RPM_ROOT/repodata/repomd.xml"
cat <<EOF > "$TMP_RPM_ROOT/platypush.repo"
[platypush]
name=Platypush repository
baseurl=https://rpm.platypush.tech
enabled=1
type=rpm
gpgcheck=1
gpgkey=https://rpm.platypush.tech/pubkey.txt
EOF
cat <<EOF > "$TMP_RPM_ROOT/index.txt"
Welcome to the Platypush RPM repository!
Project homepage: https://platypush.tech
Source code: https://git.platypush.tech/platypush/platypush
Documentation / API reference: https://docs.platypush.tech
You can use this RPM repository to install Platypush on Fedora or other
RPM-based distros - as long as they are compatible with the latest Fedora
release.
Steps:
1. Add the repository to your sources
=====================================
# yum config-manager --add-repo https://rpm.platypush.tech/platypush.repo
2. Install Platypush
====================
# yum install platypush
Or, if you want to install a version always up-to-date with the git repo:
# yum install platypush-git
EOF
cat <<EOF > "$TMP_RPM_ROOT/pubkey.txt"
$PGP_PUBKEY
EOF
echo "--- Updating the repository"
export NEW_RPM_ROOT="$REPOS_ROOT/rpm_new"
export OLD_RPM_ROOT="$REPOS_ROOT/rpm_old"
cp -r "$TMP_RPM_ROOT" "$NEW_RPM_ROOT"
rm -rf "$TMP_RPM_ROOT"
mv "$RPM_ROOT" "$OLD_RPM_ROOT"
mv "$NEW_RPM_ROOT" "$RPM_ROOT"
rm -rf "$OLD_RPM_ROOT"

View File

@ -1,22 +0,0 @@
# The device ID is the unique identifier for the device that runs Platypush.
# You should make sure that it's unique at least within your local network,
# as it is used to identify the device in the MQTT topics, on the HTTP API
# and on the published ZeroConf services.
PLATYPUSH_DEVICE_ID=platypush
# Use an external Redis server for the message queue. By default, the Platypush
# container will run a Redis server on the same container. Also remove the
# `--start-redis` option from the `docker run` command if you want to use an
# external Redis server.
# PLATYPUSH_REDIS_HOST=localhost
# PLATYPUSH_REDIS_PORT=6379
# Custom location for the Platypush configuration file.
# PLATYPUSH_CONFIG=/etc/platypush/config.yaml
# Custom location for the Platypush working directory.
# PLATYPUSH_WORKDIR=/var/lib/platypush
# SQLAlchemy database URL. By default, the Platypush container will run on a
# SQLite database installed under <WORKDIR>/main.db. If you want
# PLATYPUSH_DB=sqlite:////var/lib/platypush/main.db

7
.gitignore vendored
View File

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

72
.gitlab-ci.yml Normal file
View File

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

33
.gitlab/rebuild_docs.sh Executable file
View File

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

60
.gitlab/run_ci_tests.sh Executable file
View File

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

View File

@ -1,424 +1,26 @@
# Changelog
All notable changes to this project will be documented in this file.
Given the high speed of development in the first phase, changes are being
reported only starting from v0.20.2.
## [Unreleased]
- [[#281](https://git.platypush.tech/platypush/platypush/issues/281)]
replaced `warnings.warn` with `logging.warning`, as there is no easy and
reliable way of routing `warnings.warn` to `logging`.
## [1.1.0] - 2024-06-06
- [[#405](https://git.platypush.tech/platypush/platypush/issues/405)] Fixed
timezone/timestamp rendering issues for `calendar.ical` events.
- [[#403]((https://git.platypush.tech/platypush/platypush/issues/403))]
Included inherited actions in plugins docs.
## [1.0.7] - 2024-06-02
- [[#384]((https://git.platypush.tech/platypush/platypush/issues/384))] Added
`assistant.openai` and `tts.openai` plugins.
## [1.0.6] - 2024-06-01
- 🐛 Bug fix on one of the entities modules that prevented the application from
loading when `.` is part of `PYTHONPATH`.
## [1.0.5] - 2024-06-01
- A proper solution for the `utcnow()` issue.
It was a bit trickier than expected to solve, but now Platypush uses a
`utcnow()` facade that always returns a UTC datetime in a timezone-aware
representation.
The code should however also handle the case of timestamps stored on the db in
the old format.
## [1.0.4] - 2024-05-31
- Fixed regression introduced by
[c18768e61fef62924f4c1fac3089ecfb83666dab](https://git.platypush.tech/platypush/platypush/commit/c18768e61fef62924f4c1fac3089ecfb83666dab).
Python seems to have introduced a breaking change from the version 3.12 -
`datetime.utcnow()` is not deprecated, but `datetime.UTC`, the suggested
alternative, isn't available on older versions of Python. Added a workaround
that makes Platypush compatible with both the implementations.
## [1.0.3] - 2024-05-31
- [[#368](https://git.platypush.tech/platypush/platypush/issues/368)] Added
Ubuntu packages.
- Fixed bug that didn't get hooks to match events imported through the new
`platypush.events` symlinked module.
## [1.0.2] - 2024-05-26
- Fixed regression introduced by the support of custom names through the
`@procedure` decorator.
## [1.0.0] - 2024-05-26
Many, many changes for the first major release of Platypush after so many
years.
- [!3](https://git.platypush.tech/platypush/platypush/milestone/3) All
backends, except for `http`, `nodered`, `redis` and `tcp`, are gone. Many
were already deprecated a while ago, but the change now applies to all of
them. Backends should only be components that actively listen for application
messages to process, not generic daemon threads for integrations. This had
been a source of confusion for a long time. Backends and plugins are now
merged, meaning that you won't need to configure two different sections
instead of one for many integrations (one for the stateless plugin, and one
for the background state listener). Please check the
[documentation](https://docs.platypush.tech) to verify the configuration
changes required by your integrations. This has been a long process that has
involved the rewrite of most of the integrations, and many bugs have been
fixed.
- Improved Docker support - now with a default `docker-compose.yml`, multiple
Dockerfiles for
[Alpine](https://git.platypush.tech/platypush/platypush/src/branch/master/platypush/install/docker/alpine.Dockerfile),
[Debian](https://git.platypush.tech/platypush/platypush/src/branch/master/platypush/install/docker/debian.Dockerfile),
[Ubuntu](https://git.platypush.tech/platypush/platypush/src/branch/master/platypush/install/docker/ubuntu.Dockerfile)
and
[Fedora](https://git.platypush.tech/platypush/platypush/src/branch/master/platypush/install/docker/fedora.Dockerfile)
base images. Many improvements on the `platydock` and `platyvenv` scripts
too, with better automated installation processes for optional dependencies.
- Added [official
packages](https://git.platypush.tech/platypush/platypush#system-package-manager-installation)
for
[Debian](https://git.platypush.tech/platypush/platypush#debian-ubuntu)
and [Fedora](https://git.platypush.tech/platypush/platypush#fedora).
- Added `--device-id`, `--workdir`, `--logsdir`, `--cachedir`, `--main-db`,
`--redis-host`, `--redis-port` and `--redis-queue` CLI arguments, along the
`PLATYPUSH_DEVICE_ID`, `PLATYPUSH_WORKDIR`, `PLATYPUSH_LOGSDIR`,
`PLATYPUSH_CACHEDIR`, `PLATYPUSH_DB`, `PLATYPUSH_REDIS_HOST`,
`PLATYPUSH_REDIS_PORT` and `PLATYPUSH_REDIS_QUEUE` environment variables.
- Added an _Extensions_ panel to the UI to dynamically:
- Install new dependencies directly from the Web view.
- Explore the documentation as well as the supported actions and events for
each plugin.
- Get ready-to-paste configuration snippets/templates.
- New, completely rewritten [documentation](https://docs.platypush.tech), which
now integrates the wiki, dynamically includes plugins configuration snippets
and dependencies, and adds a global filter bar for the integrations.
- [[#394](https://git.platypush.tech/platypush/platypush/issues/394)] A more
intuitive way of installing extra dependencies via `pip`. Instead of a static
list that the user should check inside of `setup.py`, the syntax `pip install
'platypush[plugin1,plugin2,...]'` is now supported.
- No more need to manually create `__init__.py` in each of the `scripts`
folders that you want to use to store your custom scripts. Automatic
discovery of scripts and creation of module files has been implemented. You
can now just drop a `.py` script with your procedures, hooks or crons in the
scripts folder and it should be picked up by the application.
- The _Execute_ Web panel now supports procedures too, as well as curl snippets.
- Removed all `Response` objects outside of the root type. They are now all
replaced by Marshmallow schemas with the structure automatically generated in
the documentation.
- [`alarm`] [[#340](https://git.platypush.tech/platypush/platypush/issues/340)]
Rewritten integration. It now includes a powerful UI panel to set up alarms
with custom procedures too.
- [`assistant.picovoice`]
[[#304](https://git.platypush.tech/platypush/platypush/issues/304)] New
all-in-one Picovoice integration that replaces the previous `stt.picovoice.*`
integrations.
- [`youtube`]
[[#337](https://git.platypush.tech/platypush/platypush/issues/337)] Full
rewrite of the plugin. It now supports Piped instances instead of the
official YouTube API. A new UI has also been designed to explore
subscriptions, playlists and channels.
- [`weather.*`]
[[#308](https://git.platypush.tech/platypush/platypush/issues/308)] Removed
the `weather.darksky` integration (it's now owned by Apple and the API is
basically dead) and enhanced the `weather.openweathermap` plugin instead.
- [`camera.pi*`] The old `camera.pi` integration based on the deprecated
`picamera` module has been moved to `camera.pi.legacy`. `camera.pi` is now a
new plugin which uses the new `picamera2` API (and it's so far only
compatible with recent versions on the Raspberry Pi OS).
- Dynamically auto-generate plugins documentation in the UI from the RST
docstrings.
- New design for the configuration panel.
- Better synchronization between processes on threads on application stop -
greatly reduced the risk of hanging processes on shutdown.
- Migrated all CI/CD pipelines to [Drone
CI](https://ci-cd.platypush.tech/platypush/platypush).
- Removed `google.fit` integration, as Google has deprecated the API.
- Removed `wiimote` integration: the `cwiid` library hasn't been updated in
years, it doesn't even work well with Python 3, and I'm not in the mood of
bringing it back from the dead.
- Removed `stt.deepspeech` integration. That project has been basically
abandoned by Mozilla, the libraries are very buggy and I don't think it's
going to see new developments any time soon.
- [[#297](https://git.platypush.tech/platypush/platypush/issues/297)] Removed
`spotify` backend integration based on Librespot. The project has gone
through a lot of changes, and I no longer have a Spotify premium account to
work on a new implementation. Open to contributions if somebody still wants
it.
## [0.50.3] - 2023-07-22
### Added
- Added [XMPP plugin](https://git.platypush.tech/platypush/platypush/pulls/269).
## [0.50.2] - 2023-06-30
### Fixed
- A fix for the new `get_plugin` supported syntax. `get_plugin` now also
accepts a plugin class/type as an argument rather than a string, but the
previous logic didn't properly inspect the parent module.
## [0.50.0] - 2023-06-28
This should actually be a new big major release, but I'm holding on implementing
more features before a 1.0 tag.
### Added
- Migrated many integrations to the new [entities
framework](https://git.platypush.tech/platypush/platypush/pulls/230).
This is a very large change to the foundations of the platform. Many plugins
(and many others will follow) now publish and store their *entities* in a
standard format, so e.g. all the lights, switches, Bluetooth devices, cameras,
audio devices, media players and sensors are now supposed to expose the same
attributes and API regardless of the type of integration. This refactor also
includes a new default home panel, which includes all the entities detected by
the registered integrations. Many integrations have already been migrated to
the new framework. Among them (and many others are on their way):
- `arduino`
- `bluetooth`
- `light.hue`
- `linode`
- All the `sensor.*` plugins
- `serial`
- `smartthings`
- `switchbot`
- `system`
- `variable`
- `zigbee.mqtt`
- `zwave.mqtt`
- Added support for more complex filters on event hooks. Earlier filters could
only model key-value pair matches. The interface now supports more
sophisticated filters - among these, structured filters with partial matches
and relational filters. For example:
```python
from platypush.event.hook import hook
from platypush.message.event.sensor import SensorDataChangeEvent
@hook(SensorDataChangeEvent, data=1):
def hook_1(event):
"""
Triggered when event.data == 1
"""
@hook(SensorDataChangeEvent, data={'state': 1}):
def hook_2(event):
"""
Triggered when event.data['state'] == 1
"""
@hook(SensorDataChangeEvent, data={
'temperature': {'$gt': 25},
'humidity': {'$le': 15}
}):
def hook_3(event):
"""
Triggered when event.data['temperature'] > 25 and
event.data['humidity'] <= 15.
"""
```
The supported relational fields are the same supported by ElasticSearch - `$gt`
for greater than, `$lt` for lesser than, `$ge` for greater or equal, `$ne` for
not equal, etc.
This also means that the previous `SensorDataAboveThresholdEvent` and
`SensorDataBelowThresholdEvent` events are now deprecated, as the new hook API
makes it much easier and flexible to define custom threshold logic on any events
without having to pre-define thresholds in each backend's configuration.
- Added a Progressive WebApp (PWA) framework to the Vue webapp. It is now
possible to install Platypush as a stand-alone webapp directly from the web
panel if the panel is served over HTTPS. For now this only improves the user
experience, performance and it provides a more native-like experience on
mobile, but in the future the PWA background worker could be used to e.g.
deliver asynchronous events and notifications to the clients without keeping
the browser open.
- Added support for application database automatic migrations after an update by
using Alembic.
### Changed
- Tornado is now used as an HTTP engine by `backend.http`, instead of using
bare bone Flask with its inefficient Werkzeug server and an optional uwsgi
that required extra configuration (and an extra external service).
- All the streaming endpoints have been rewritten and adapted to work with
Tornado. This greatly improves performance, stability and ease of
configuration, while remaining back-compatible with the previous URL formats.
As a side note, all the streaming endpoints are now using Redis to stream
information across multiple worker processes, so make sure that you have a
version of Redis that supports pub/sub (most of the recent ones should do).
- The `bluetooth` plugin has been completely rewritten, merged with the (now
deprecated) `backend.bluetooth`. The previously separated low-energy/legacy
integrations have now been merged too. It now supports much more than passive
scanning, as it can recognize the information published by most of the device,
supports both legacy and low-energy connection/disconnection actions, and it
can detect most of the device classes, services and manufacturers. It also
supports parsing some standard features (like battery level, temperature,
state etc.) if they are published according to some convention supported by
*TheengsGateway*. The `switchbot.bluetooth` integration has now also been
merged into `bluetooth`.
- The `sound` plugin has been completely rewritten. While it should still be
largely back-compatible with the previous implementation, you should probably
go and take a look at the new documentation to get a grasp of the new
features.
- The `camera.ffmpeg` plugin has received a big rewrite that has improved its
stability and robustness against several types of cameras. It is now the
recommended way of interfacing with general-purpose cameras, even for
PiCameras - the `camera.pi` integration is now largely deprecated, as the old
PiCamera API is deprecated as well, and `camera.ffmpeg` should now work out of
the box with a PiCamera if a reasonably recent version of ffmpeg is installed.
- `backend.websocket` has been **removed** and replaced by Tornado asynchronous
websocket URLs registered on the HTTP backend. The two new routes that
replace the websocket backend are:
- `/ws/events`: subscribe to this websocket to receive any asynchronous
events forwarded by the application.
- `/ws/requests`: you can send request messages to this endpoints, and the
responses will be received asynchronously on the same channel.
- The `inspect` plugin has been largely improved.
- Its performance is now much snappier, as it scans for all the available
integrations by searching for manifest files instead of scanning each
single source file. Documentation about specific plugins and actions is
fetched lazily when requested by the user.
- It now also caches results by looking at the last modified date of the
source file, so it won't have to re-scan source files that haven't been
modified.
- Its detection of RST constructs has also been improved, so most of the code
blocks, schemas, return types and references to other objects are now
rendered in the plugin UI.
- Added `variable.delete` action. The existing `variable.unset` action will now
only set a variable to null if it exists, while `variable.delete` will
actually remove it from the database.
- `backend.sensor.distance` and `gpio.sensor.distance` have been removed and
migrated instead to a new `sensor.hcsr04` plugin, since the existing logic
actually only applies to HC-SR04-like distance sensors.
- `backend.sensor.dht` and `gpio.sensor.dht` have been removed and
migrated to a new `sensor.dht` plugin.
- `backend.sensor.accelerometer` and `gpio.sensor.accelerometer` have been
removed and migrated to a new `sensor.lis3dh` plugin, since the existing
accelerometer logic only works with these sensors.
- `backend.sensor.motion.pwm3901` and `gpio.sensor.motion.pwm3901` have been
removed and migrated to a new `sensor.pwm3901` plugin.
accelerometer logic only works with these sensors.
- `backend.sensor.envirophat` and `gpio.sensor.envirophat` have been removed and
migrated to a new `sensor.envirophat` plugin.
- `backend.sensor.ltr559` and `gpio.sensor.ltr559` have been removed and
migrated to a new `sensor.ltr559` plugin.
- `backend.sensor.bme280` and `gpio.sensor.bme280` have been removed and
migrated to a new `sensor.bme280` plugin.
- `backend.sensor.distance.vl53l1x` and `gpio.sensor.distance.vl53l1x` have been
removed and migrated to a new `sensor.vl53l1x` plugin.
- `backend.serial` has been removed and merged into the `serial` plugin.
- `backend.switch.wemo` has been removed and merged into the `switch.wemo`
plugin.
- `backend.switch.tplink` has been removed and merged into the `switch.tplink`
plugin.
- `backend.zigbee.mqtt` has been removed and merged into the `zigbee.mqtt`
plugin.
- `backend.zwave.mqtt` has been removed and merged into the `zwave.mqtt` plugin.
This is a very large change to the foundations of the platform, and there's
still a lot of work in progress. A detailed description of all the changes
will follow shortly.
### Fixed
- Notable performance improvements for the UI (like -50% on the load time and
memory usage in some cases). Recursive/reflective Vue components now use
`shallowRef`, so complex UI models won't have to be fully loaded at page
start.
- Fixed compatibility with SQLAlchemy 2.
- Migrated the `clipboard` integration from `pyperclip` to `pyclip` (see
[#240](https://git.platypush.tech/platypush/platypush/issues/240)).
`pyperclip` is unmaintained and largely broken, and `pyclip` seems to be a
viable drop-in alternative.
- Better implementation of the UI modals - added close buttons and trigger
closure when Esc is pressed.
### Removed
- Removed SSL configuration from `backend.http`. Configuring SSL on
Flask+Tornado is messy, and it won't end up with a good user experience.
Instead, you should consider using a reverse proxy (e.g. nginx or Apache) if
you want to make the Platypush web interface available over HTTPS. A sample
nginx configuration has been added under `examples/nginx`. Note that running
the web panel over HTTPS is a requirement if you want to leverage the PWA
features, as a PWA can only be served over HTTPS.
- Removed the Bluetooth file server integration. It is still possible to send
files over Bluetooth (the feature has now been merged into the `bluetooth`
plugin, under `bluetooth.send_file`), but all the server features rely on
features of PyOBEX that are now very broken on recent versions of Python (the
project itself hasn't been updated in years).
- Removed or deprecated all the `backend.sensor.*` backends. Their logic has now
been merged into their associated plugins, and the plugins will have the
ability to run in the background too.
- Removed `backend.sensor.battery`. It has now been merged into the `system`
plugin.
- Removed `gpio.sensor` plugin. It was never really fully implemented, and it
was probably impossible to implement with an interface that could work with
any sensor-like device connected over GPIO.
## [0.24.5] - 2023-02-22
### Added

View File

@ -27,9 +27,13 @@ Guidelines:
you are changing some of the core entities (e.g. requests, events, procedures, hooks, crons
or the bus) then make sure to add tests and not to break the existing tests.
- If the feature requires an optional dependency then make sure to document it
in the `manifest.json` - 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.
- 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 [`setup.py`](https://git.platypush.tech/platypush/platypush/-/blob/master/setup.py#L72) as
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.

View File

@ -1 +0,0 @@
platypush/install/docker/alpine.Dockerfile

View File

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

1654
README.md

File diff suppressed because it is too large Load Diff

9
bin/platypush Executable file
View File

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

249
bin/platyvenv Executable file
View File

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

View File

@ -1,46 +0,0 @@
services:
platypush:
restart: "always"
command:
- platypush
# Comment --start-redis if you want to run an external Redis service
# In such case you'll also have to ensure that the appropriate Redis
# variables are set in the .env file, or the Redis configuration is
# passed in the config.yaml, or use the --redis-host and --redis-port
# command-line options
- --start-redis
# Custom list of host devices that should be accessible to the container -
# e.g. an Arduino, an ESP-compatible microcontroller, a joystick etc.
# devices:
# - /dev/ttyUSB0
# Uncomment if you need plugins that require access to low-level hardware
# (e.g. Bluetooth BLE or GPIO/SPI/I2C) if access to individual devices is
# not enough or isn't practical
# privileged: true
build:
context: .
# Alpine base image
dockerfile: ./platypush/install/docker/alpine.Dockerfile
# Debian base image
# dockerfile: ./platypush/install/docker/debian.Dockerfile
# Ubuntu base image
# dockerfile: ./platypush/install/docker/ubuntu.Dockerfile
# Fedora base image
# dockerfile: ./platypush/install/docker/fedora.Dockerfile
# Copy .env.example to .env and modify as needed
# env_file:
# - .env
ports:
# Comment if you don't have the HTTP backend enable or you don't want to
# expose it
- "8008:8008"
volumes:
- /path/to/your/config.yaml:/etc/platypush
- /path/to/a/workdir:/var/lib/platypush
# - /path/to/a/cachedir:/var/cache/platypush

View File

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

View File

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

View File

@ -1,188 +0,0 @@
a, a:visited {
/* Don't change the color for visited links */
color: var(--pst-color-link) !important;
}
ul.grid {
display: grid;
@media screen and (max-width: 500px) {
grid-template-columns: repeat(1, 1fr);
}
@media screen and (min-width: 501px) and (max-width: 699px) {
grid-template-columns: repeat(2, 1fr);
}
@media screen and (min-width: 700px) {
grid-template-columns: repeat(3, 1fr);
}
}
a.grid-title {
width: 100%;
display: block;
margin: 1.5em 0;
font-size: 1.5em !important;
border-bottom: 1px solid #ccc;
}
ul.grid li {
display: flex;
background: linear-gradient(0deg, #fff, #f9f9f9);
align-items: center;
justify-content: space-between;
margin: 0 10px 10px 0;
padding: 20px;
border: 1px solid #ccc;
border-radius: 15px;
flex-direction: column;
}
ul.grid img {
width: 48px;
margin-right: 5px;
}
ul.grid li code {
width: 100%;
}
ul.grid li code .pre {
width: 100%;
display: block;
white-space: pre-wrap;
}
ul.grid li:hover {
background: linear-gradient(0deg, #157765, #cbffd8) !important;
}
ul.grid li a {
width: 100%;
display: flex;
justify-content: center;
text-align: center;
margin-top: 0.5em;
}
ul.grid li:hover a,
ul.grid li:hover a > code {
color: white !important;
}
ul.grid li a code {
background: none;
border: none;
}
ul.grid .icon {
width: 32px;
}
/* Clipboard button */
.clipboard {
position: absolute;
display: inline-block;
width: 32px;
top: 0.5em;
right: 0.5em;
cursor: pointer;
}
/* Tabs */
.tabs {
margin: 0 0 1em 0;
padding: 0;
list-style: none;
}
.tabs ul {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin: 0 0 1em 0;
padding: 0;
list-style: none;
border-bottom: 1px solid #ccc;
}
.tabs ul li {
display: inline-flex;
max-width: 25%;
margin: 0;
padding: 0.25em 0.5em;
list-style: none;
cursor: pointer;
flex-grow: 1;
justify-content: center;
align-items: center;
border-radius: 0.75em 0.75em 0 0;
border: 1px solid #ddd;
}
.tabs ul li.selected {
background: rgb(200,255,208);
}
.tabs ul li:hover {
background: rgb(190,246,218);
}
.tabs .body {
margin-top: -1em;
padding: 1em;
border: 1px solid #ccc;
border-top: none;
border-radius: 0 0 0.75em 0.75em;
}
.bd-article-container {
position: relative;
}
.filter-bar {
width: 100%;
display: block;
font-size: 0.6em;
border: 1px solid #ccc;
border-radius: 0.75em;
margin: 0.5em 0;
padding: 0.25em;
}
#reference h2.fixed {
position: fixed;
top: 0;
background: white;
z-index: 1;
}
#reference h2.fixed .header-content {
display: none;
}
@media screen and (max-width: 768px) {
#reference h2.fixed {
width: 100%;
margin-left: -0.5em;
padding: 0.5em 0.5em 0 0.5em;
}
}
@media screen and (max-width: 959px) {
#reference h2.fixed {
width: 100%;
margin-left: -1em;
padding: 0.5em 0.5em 0 0.5em;
}
}
@media screen and (min-width: 960px) {
#reference h2.fixed {
width: 75%;
max-width: 800px;
padding-top: 0.5em;
}
}

View File

@ -6,7 +6,55 @@ Backends
:maxdepth: 1
:caption: Backends:
platypush/backend/adafruit.io.rst
platypush/backend/alarm.rst
platypush/backend/assistant.google.rst
platypush/backend/assistant.snowboy.rst
platypush/backend/button.flic.rst
platypush/backend/camera.pi.rst
platypush/backend/chat.telegram.rst
platypush/backend/covid19.rst
platypush/backend/file.monitor.rst
platypush/backend/foursquare.rst
platypush/backend/github.rst
platypush/backend/google.fit.rst
platypush/backend/google.pubsub.rst
platypush/backend/gps.rst
platypush/backend/http.rst
platypush/backend/http.poll.rst
platypush/backend/inotify.rst
platypush/backend/joystick.rst
platypush/backend/joystick.jstest.rst
platypush/backend/joystick.linux.rst
platypush/backend/kafka.rst
platypush/backend/light.hue.rst
platypush/backend/log.http.rst
platypush/backend/mail.rst
platypush/backend/midi.rst
platypush/backend/mqtt.rst
platypush/backend/music.mopidy.rst
platypush/backend/music.mpd.rst
platypush/backend/music.snapcast.rst
platypush/backend/music.spotify.rst
platypush/backend/nextcloud.rst
platypush/backend/nfc.rst
platypush/backend/nodered.rst
platypush/backend/ping.rst
platypush/backend/pushbullet.rst
platypush/backend/redis.rst
platypush/backend/scard.rst
platypush/backend/sensor.ir.zeroborg.rst
platypush/backend/sensor.leap.rst
platypush/backend/stt.deepspeech.rst
platypush/backend/stt.picovoice.hotword.rst
platypush/backend/stt.picovoice.speech.rst
platypush/backend/tcp.rst
platypush/backend/todoist.rst
platypush/backend/travisci.rst
platypush/backend/trello.rst
platypush/backend/weather.buienradar.rst
platypush/backend/weather.darksky.rst
platypush/backend/weather.openweathermap.rst
platypush/backend/wiimote.rst
platypush/backend/zwave.rst
platypush/backend/zwave.mqtt.rst

View File

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

View File

@ -11,19 +11,22 @@ Events
platypush/events/application.rst
platypush/events/assistant.rst
platypush/events/bluetooth.rst
platypush/events/button.flic.rst
platypush/events/camera.rst
platypush/events/chat.slack.rst
platypush/events/chat.telegram.rst
platypush/events/clipboard.rst
platypush/events/covid19.rst
platypush/events/custom.rst
platypush/events/dbus.rst
platypush/events/distance.rst
platypush/events/entities.rst
platypush/events/file.rst
platypush/events/flic.rst
platypush/events/foursquare.rst
platypush/events/geo.rst
platypush/events/github.rst
platypush/events/google.rst
platypush/events/google.fit.rst
platypush/events/google.pubsub.rst
platypush/events/gotify.rst
platypush/events/gpio.rst
@ -64,16 +67,17 @@ Events
platypush/events/sound.rst
platypush/events/stt.rst
platypush/events/sun.rst
platypush/events/telegram.rst
platypush/events/tensorflow.rst
platypush/events/todoist.rst
platypush/events/torrent.rst
platypush/events/travisci.rst
platypush/events/trello.rst
platypush/events/video.rst
platypush/events/weather.rst
platypush/events/web.rst
platypush/events/web.widget.rst
platypush/events/websocket.rst
platypush/events/xmpp.rst
platypush/events/wiimote.rst
platypush/events/zeroborg.rst
platypush/events/zeroconf.rst
platypush/events/zigbee.mqtt.rst

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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