From 3bfc5b83ef878105f2cb91400c4544238f0a9491 Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Thu, 16 Sep 2021 17:53:40 +0200 Subject: [PATCH] Moved to manifest files for describing plugins and backends and their dependencies --- MANIFEST.in | 1 + bin/platyvenv | 174 +++++----- docs/source/backends.rst | 5 - docs/source/conf.py | 2 +- docs/source/plugins.rst | 15 - generate_missing_docs.py | 17 +- platypush/backend/__init__.py | 4 +- .../adafruit/{io.py => io/__init__.py} | 11 +- platypush/backend/adafruit/io/manifest.yaml | 12 + .../backend/{alarm.py => alarm/__init__.py} | 0 platypush/backend/alarm/manifest.yaml | 10 + platypush/backend/assistant/__init__.py | 1 + .../{google.py => google/__init__.py} | 0 .../backend/assistant/google/manifest.yaml | 26 ++ .../backend/assistant/snowboy/manifest.yaml | 9 + platypush/backend/bluetooth/__init__.py | 2 +- .../{fileserver.py => fileserver/__init__.py} | 0 .../bluetooth/fileserver/manifest.yaml | 8 + .../{pushserver.py => pushserver/__init__.py} | 0 .../bluetooth/pushserver/manifest.yaml | 8 + .../scanner/{ble.py => ble/__init__.py} | 0 .../bluetooth/scanner/ble/manifest.yaml | 10 + .../backend/bluetooth/scanner/manifest.yaml | 10 + platypush/backend/button/flic/__init__.py | 9 +- .../backend/button/flic/fliclib/aioflic.py | 1 + platypush/backend/button/flic/manifest.yaml | 9 + .../backend/camera/{pi.py => pi/__init__.py} | 1 - platypush/backend/camera/pi/manifest.yaml | 7 + .../{telegram.py => telegram/__init__.py} | 0 platypush/backend/chat/telegram/manifest.yaml | 19 ++ .../{clipboard.py => clipboard/__init__.py} | 0 platypush/backend/clipboard/manifest.yaml | 8 + .../{covid19.py => covid19/__init__.py} | 0 platypush/backend/covid19/manifest.yaml | 7 + .../backend/{dbus.py => dbus/__init__.py} | 0 platypush/backend/dbus/manifest.yaml | 7 + platypush/backend/file/monitor/manifest.yaml | 10 + .../{foursquare.py => foursquare/__init__.py} | 0 platypush/backend/foursquare/manifest.yaml | 8 + .../backend/{github.py => github/__init__.py} | 0 platypush/backend/github/manifest.yaml | 32 ++ .../google/{fit.py => fit/__init__.py} | 0 platypush/backend/google/fit/manifest.yaml | 8 + .../google/{pubsub.py => pubsub/__init__.py} | 0 platypush/backend/google/pubsub/manifest.yaml | 9 + platypush/backend/{gps.py => gps/__init__.py} | 0 platypush/backend/gps/manifest.yaml | 16 + platypush/backend/http/__init__.py | 15 +- .../app/routes/plugins/camera/ir/mlx90640.py | 2 +- .../http/app/routes/plugins/camera/pi.py | 2 +- .../http/app/routes/plugins/media/__init__.py | 2 +- platypush/backend/http/manifest.yaml | 9 + .../backend/http/media/handlers/__init__.py | 3 +- platypush/backend/http/poll/__init__.py | 2 +- platypush/backend/http/poll/manifest.yaml | 6 + .../backend/http/request/ota/__init__.py | 0 .../http/request/ota/booking/__init__.py | 48 --- .../backend/http/request/rss/__init__.py | 5 +- .../{inotify.py => inotify/__init__.py} | 0 platypush/backend/inotify/manifest.yaml | 15 + .../{jstest.py => jstest/__init__.py} | 0 .../backend/joystick/jstest/manifest.yaml | 21 ++ .../joystick/{linux.py => linux/__init__.py} | 0 .../backend/joystick/linux/manifest.yaml | 16 + platypush/backend/joystick/manifest.yaml | 8 + platypush/backend/kafka/__init__.py | 1 - platypush/backend/kafka/manifest.yaml | 7 + .../backend/light/{hue.py => hue/__init__.py} | 0 platypush/backend/light/hue/manifest.yaml | 8 + .../backend/{linode.py => linode/__init__.py} | 0 platypush/backend/linode/manifest.yaml | 8 + .../backend/log/{http.py => http/__init__.py} | 0 platypush/backend/log/http/manifest.yaml | 8 + .../backend/{mail.py => mail/__init__.py} | 0 platypush/backend/mail/manifest.yaml | 10 + .../backend/{midi.py => midi/__init__.py} | 2 +- platypush/backend/midi/manifest.yaml | 8 + .../backend/{mqtt.py => mqtt/__init__.py} | 0 platypush/backend/mqtt/manifest.yaml | 9 + .../music/{mopidy.py => mopidy/__init__.py} | 7 +- platypush/backend/music/mopidy/manifest.yaml | 17 + platypush/backend/music/mpd/manifest.yaml | 16 + .../{snapcast.py => snapcast/__init__.py} | 0 .../backend/music/snapcast/manifest.yaml | 15 + platypush/backend/music/spotify/manifest.yaml | 21 ++ .../{nextcloud.py => nextcloud/__init__.py} | 0 platypush/backend/nextcloud/manifest.yaml | 10 + platypush/backend/{nfc.py => nfc/__init__.py} | 0 platypush/backend/nfc/manifest.yaml | 13 + platypush/backend/nodered/__init__.py | 1 + platypush/backend/nodered/manifest.yaml | 7 + .../backend/{ping.py => ping/__init__.py} | 0 platypush/backend/ping/manifest.yaml | 8 + platypush/backend/pushbullet/__init__.py | 45 +-- platypush/backend/pushbullet/manifest.yaml | 8 + .../backend/{redis.py => redis/__init__.py} | 5 - platypush/backend/redis/manifest.yaml | 6 + platypush/backend/scard/__init__.py | 15 +- platypush/backend/scard/manifest.yaml | 9 + platypush/backend/sensor/__init__.py | 1 + platypush/backend/sensor/accelerometer.py | 18 -- .../backend/sensor/accelerometer/__init__.py | 27 ++ .../sensor/accelerometer/manifest.yaml | 13 + platypush/backend/sensor/arduino.py | 18 -- platypush/backend/sensor/arduino/__init__.py | 26 ++ .../backend/sensor/arduino/manifest.yaml | 12 + .../{battery.py => battery/__init__.py} | 9 + .../backend/sensor/battery/manifest.yaml | 13 + .../sensor/{bme280.py => bme280/__init__.py} | 9 + platypush/backend/sensor/bme280/manifest.yaml | 13 + .../sensor/{dht.py => dht/__init__.py} | 8 + platypush/backend/sensor/dht/manifest.yaml | 13 + platypush/backend/sensor/distance/__init__.py | 9 + .../backend/sensor/distance/manifest.yaml | 13 + .../{vl53l1x.py => vl53l1x/__init__.py} | 9 + .../sensor/distance/vl53l1x/manifest.yaml | 14 + .../{envirophat.py => envirophat/__init__.py} | 9 + .../backend/sensor/envirophat/manifest.yaml | 13 + .../backend/sensor/ir/zeroborg/manifest.yaml | 8 + .../sensor/{leap.py => leap/__init__.py} | 0 platypush/backend/sensor/leap/manifest.yaml | 15 + .../sensor/{ltr559.py => ltr559/__init__.py} | 9 + platypush/backend/sensor/ltr559/manifest.yaml | 13 + .../{mcp3008.py => mcp3008/__init__.py} | 9 + .../backend/sensor/mcp3008/manifest.yaml | 13 + .../backend/sensor/motion/pmw3901/__init__.py | 33 ++ .../sensor/motion/pmw3901/manifest.yaml | 13 + platypush/backend/sensor/motion/pwm3901.py | 24 -- platypush/backend/sensor/serial.py | 18 -- platypush/backend/sensor/serial/__init__.py | 27 ++ platypush/backend/sensor/serial/manifest.yaml | 12 + .../{deepspeech.py => deepspeech/__init__.py} | 0 .../backend/stt/deepspeech/manifest.yaml | 6 + .../{hotword.py => hotword/__init__.py} | 0 .../stt/picovoice/hotword/manifest.yaml | 6 + .../{speech.py => speech/__init__.py} | 0 .../stt/picovoice/speech/manifest.yaml | 6 + platypush/backend/{tcp.py => tcp/__init__.py} | 0 platypush/backend/tcp/manifest.yaml | 6 + .../{todoist.py => todoist/__init__.py} | 1 - platypush/backend/todoist/manifest.yaml | 16 + .../{travisci.py => travisci/__init__.py} | 0 platypush/backend/travisci/manifest.yaml | 10 + .../backend/{trello.py => trello/__init__.py} | 2 - platypush/backend/trello/manifest.yaml | 10 + platypush/backend/weather/__init__.py | 3 +- .../{buienradar.py => buienradar/__init__.py} | 0 .../backend/weather/buienradar/manifest.yaml | 8 + .../{darksky.py => darksky/__init__.py} | 0 .../backend/weather/darksky/manifest.yaml | 8 + .../__init__.py} | 0 .../weather/openweathermap/manifest.yaml | 8 + .../{websocket.py => websocket/__init__.py} | 30 +- platypush/backend/websocket/manifest.yaml | 6 + .../{wiimote.py => wiimote/__init__.py} | 32 +- platypush/backend/wiimote/manifest.yaml | 8 + .../zigbee/{mqtt.py => mqtt/__init__.py} | 0 platypush/backend/zigbee/mqtt/manifest.yaml | 45 +++ platypush/backend/zwave/manifest.yaml | 48 +++ .../zwave/{mqtt.py => mqtt/__init__.py} | 0 platypush/backend/zwave/mqtt/manifest.yaml | 20 ++ platypush/bus/__init__.py | 2 +- platypush/common/__init__.py | 17 + platypush/config/__init__.py | 32 +- platypush/event/hook.py | 2 +- platypush/message/event/adafruit.py | 4 +- .../message/event/button/flic/__init__.py | 10 +- platypush/message/event/chat/slack.py | 6 +- platypush/message/event/joystick.py | 4 +- platypush/message/event/video/__init__.py | 1 - platypush/platydock/__init__.py | 201 +++++++----- platypush/plugins/__init__.py | 6 +- .../adafruit/{io.py => io/__init__.py} | 8 +- platypush/plugins/adafruit/io/manifest.yaml | 7 + .../plugins/{alarm.py => alarm/__init__.py} | 0 platypush/plugins/alarm/manifest.yaml | 6 + .../{arduino.py => arduino/__init__.py} | 0 platypush/plugins/arduino/manifest.yaml | 7 + .../plugins/assistant/echo/manifest.yaml | 13 + .../plugins/assistant/google/manifest.yaml | 6 + .../{pushtotalk.py => pushtotalk/__init__.py} | 0 .../assistant/google/pushtotalk/manifest.yaml | 14 + .../{autoremote.py => autoremote/__init__.py} | 14 +- platypush/plugins/autoremote/manifest.yaml | 6 + platypush/plugins/bluetooth/__init__.py | 2 + .../bluetooth/{ble.py => ble/__init__.py} | 0 platypush/plugins/bluetooth/ble/manifest.yaml | 8 + platypush/plugins/bluetooth/manifest.yaml | 8 + platypush/plugins/calendar/__init__.py | 3 - .../calendar/{ical.py => ical/__init__.py} | 21 +- platypush/plugins/calendar/ical/manifest.yaml | 7 + platypush/plugins/calendar/manifest.yaml | 6 + platypush/plugins/camera/__init__.py | 1 + .../android/{ipcam.py => ipcam/__init__.py} | 0 .../camera/android/ipcam/manifest.yaml | 6 + .../plugins/camera/{cv.py => cv/__init__.py} | 0 platypush/plugins/camera/cv/manifest.yaml | 8 + platypush/plugins/camera/ffmpeg/manifest.yaml | 9 + .../plugins/camera/gstreamer/__init__.py | 10 +- .../plugins/camera/gstreamer/manifest.yaml | 12 + .../plugins/camera/ir/mlx90640/manifest.yaml | 9 + platypush/plugins/camera/pi/manifest.yaml | 9 + .../{telegram.py => telegram/__init__.py} | 0 platypush/plugins/chat/telegram/manifest.yaml | 7 + .../{clipboard.py => clipboard/__init__.py} | 0 platypush/plugins/clipboard/manifest.yaml | 7 + .../plugins/{config.py => config/__init__.py} | 4 + platypush/plugins/config/manifest.yaml | 6 + .../{covid19.py => covid19/__init__.py} | 0 platypush/plugins/covid19/manifest.yaml | 6 + platypush/plugins/{csv.py => csv/__init__.py} | 5 +- platypush/plugins/csv/manifest.yaml | 6 + platypush/plugins/db/__init__.py | 28 +- platypush/plugins/db/manifest.yaml | 6 + .../plugins/{dbus.py => dbus/__init__.py} | 0 platypush/plugins/dbus/manifest.yaml | 7 + .../{dropbox.py => dropbox/__init__.py} | 0 platypush/plugins/dropbox/manifest.yaml | 7 + platypush/plugins/esp/__init__.py | 32 +- platypush/plugins/esp/manifest.yaml | 6 + .../plugins/{ffmpeg.py => ffmpeg/__init__.py} | 0 platypush/plugins/ffmpeg/manifest.yaml | 11 + .../plugins/{file.py => file/__init__.py} | 0 platypush/plugins/file/manifest.yaml | 6 + .../{foursquare.py => foursquare/__init__.py} | 0 platypush/plugins/foursquare/manifest.yaml | 6 + .../{calendar.py => calendar/__init__.py} | 8 +- .../plugins/google/calendar/manifest.yaml | 8 + .../google/{drive.py => drive/__init__.py} | 6 + platypush/plugins/google/drive/manifest.yaml | 8 + .../google/{fit.py => fit/__init__.py} | 10 +- platypush/plugins/google/fit/manifest.yaml | 8 + .../google/{mail.py => mail/__init__.py} | 6 + platypush/plugins/google/mail/manifest.yaml | 8 + .../google/{maps.py => maps/__init__.py} | 6 + platypush/plugins/google/maps/manifest.yaml | 8 + .../google/{pubsub.py => pubsub/__init__.py} | 3 + platypush/plugins/google/pubsub/manifest.yaml | 9 + .../{translate.py => translate/__init__.py} | 2 + .../plugins/google/translate/manifest.yaml | 9 + .../{youtube.py => youtube/__init__.py} | 8 +- .../plugins/google/youtube/manifest.yaml | 8 + platypush/plugins/gpio/__init__.py | 3 +- platypush/plugins/gpio/manifest.yaml | 7 + platypush/plugins/gpio/sensor/__init__.py | 2 +- .../gpio/sensor/accelerometer/__init__.py | 6 +- .../gpio/sensor/accelerometer/lib/LIS3DH.py | 2 +- .../gpio/sensor/accelerometer/manifest.yaml | 7 + .../sensor/{bme280.py => bme280/__init__.py} | 0 .../plugins/gpio/sensor/bme280/manifest.yaml | 7 + .../gpio/sensor/{dht.py => dht/__init__.py} | 3 +- .../plugins/gpio/sensor/dht/manifest.yaml | 7 + .../gpio/sensor/distance/manifest.yaml | 9 + .../{vl53l1x.py => vl53l1x/__init__.py} | 0 .../sensor/distance/vl53l1x/manifest.yaml | 8 + .../{envirophat.py => envirophat/__init__.py} | 0 .../gpio/sensor/envirophat/manifest.yaml | 7 + .../sensor/{ltr559.py => ltr559/__init__.py} | 0 .../plugins/gpio/sensor/ltr559/manifest.yaml | 7 + .../plugins/gpio/sensor/mcp3008/manifest.yaml | 7 + .../{pwm3901.py => pmw3901/__init__.py} | 6 +- .../gpio/sensor/motion/pmw3901/manifest.yaml | 7 + .../plugins/gpio/zeroborg/lib/__init__.py | 2 +- platypush/plugins/gpio/zeroborg/manifest.yaml | 8 + .../{graphite.py => graphite/__init__.py} | 1 + platypush/plugins/graphite/manifest.yaml | 6 + platypush/plugins/homeseer.py | 101 ------ platypush/plugins/http/request/__init__.py | 16 +- platypush/plugins/http/request/manifest.yaml | 6 + .../http/request/{rss.py => rss/__init__.py} | 0 .../plugins/http/request/rss/manifest.yaml | 7 + platypush/plugins/http/webpage/__init__.py | 7 +- platypush/plugins/http/webpage/manifest.yaml | 7 + .../plugins/{ifttt.py => ifttt/__init__.py} | 4 - platypush/plugins/ifttt/manifest.yaml | 6 + .../plugins/{inputs.py => inputs/__init__.py} | 0 platypush/plugins/inputs/manifest.yaml | 7 + .../{inspect.py => inspect/__init__.py} | 0 platypush/plugins/inspect/manifest.yaml | 7 + .../plugins/{kafka.py => kafka/__init__.py} | 0 platypush/plugins/kafka/manifest.yaml | 9 + platypush/plugins/lastfm/__init__.py | 31 +- platypush/plugins/lastfm/manifest.yaml | 7 + .../plugins/lcd/{gpio.py => gpio/__init__.py} | 0 platypush/plugins/lcd/gpio/manifest.yaml | 8 + .../plugins/lcd/{i2c.py => i2c/__init__.py} | 4 + platypush/plugins/lcd/i2c/manifest.yaml | 8 + platypush/plugins/light/__init__.py | 5 +- platypush/plugins/light/hue/manifest.yaml | 11 + .../plugins/{linode.py => linode/__init__.py} | 0 platypush/plugins/linode/manifest.yaml | 7 + .../plugins/{logger.py => logger/__init__.py} | 0 platypush/plugins/logger/manifest.yaml | 6 + .../luma/{oled.py => oled/__init__.py} | 4 +- platypush/plugins/luma/oled/manifest.yaml | 7 + platypush/plugins/mail/__init__.py | 7 +- .../mail/{imap.py => imap/__init__.py} | 0 platypush/plugins/mail/imap/manifest.yaml | 7 + .../mail/{smtp.py => smtp/__init__.py} | 0 platypush/plugins/mail/smtp/manifest.yaml | 6 + platypush/plugins/media/__init__.py | 25 +- .../{chromecast.py => chromecast/__init__.py} | 6 + .../plugins/media/chromecast/manifest.yaml | 7 + platypush/plugins/media/gstreamer/__init__.py | 19 +- .../plugins/media/gstreamer/manifest.yaml | 12 + .../media/{kodi.py => kodi/__init__.py} | 22 +- platypush/plugins/media/kodi/manifest.yaml | 7 + .../media/{mplayer.py => mplayer/__init__.py} | 14 +- platypush/plugins/media/mplayer/manifest.yaml | 9 + .../plugins/media/{mpv.py => mpv/__init__.py} | 0 platypush/plugins/media/mpv/manifest.yaml | 11 + .../{omxplayer.py => omxplayer/__init__.py} | 13 +- .../plugins/media/omxplayer/manifest.yaml | 9 + .../media/{plex.py => plex/__init__.py} | 2 +- platypush/plugins/media/plex/manifest.yaml | 7 + platypush/plugins/media/search/local.py | 4 - .../{subtitles.py => subtitles/__init__.py} | 2 +- .../plugins/media/subtitles/manifest.yaml | 8 + .../plugins/media/{vlc.py => vlc/__init__.py} | 0 platypush/plugins/media/vlc/manifest.yaml | 11 + .../{webtorrent.py => webtorrent/__init__.py} | 40 ++- .../plugins/media/webtorrent/manifest.yaml | 6 + .../plugins/{midi.py => midi/__init__.py} | 32 +- platypush/plugins/midi/manifest.yaml | 7 + .../plugins/ml/{cv.py => cv/__init__.py} | 0 platypush/plugins/ml/cv/manifest.yaml | 8 + platypush/plugins/mobile/join/__init__.py | 2 +- platypush/plugins/mobile/join/manifest.yaml | 6 + .../plugins/{mqtt.py => mqtt/__init__.py} | 2 +- platypush/plugins/mqtt/manifest.yaml | 7 + platypush/plugins/music/mpd/manifest.yaml | 7 + .../{snapcast.py => snapcast/__init__.py} | 3 +- .../plugins/music/snapcast/manifest.yaml | 6 + .../music/{spotify.py => spotify/__init__.py} | 0 platypush/plugins/music/spotify/manifest.yaml | 6 + .../{nextcloud.py => nextcloud/__init__.py} | 2 +- platypush/plugins/nextcloud/manifest.yaml | 7 + .../plugins/{nmap.py => nmap/__init__.py} | 0 platypush/plugins/nmap/manifest.yaml | 6 + platypush/plugins/{otp.py => otp/__init__.py} | 0 platypush/plugins/otp/manifest.yaml | 7 + .../plugins/{pihole.py => pihole/__init__.py} | 0 platypush/plugins/pihole/manifest.yaml | 6 + .../plugins/{ping.py => ping/__init__.py} | 0 platypush/plugins/ping/manifest.yaml | 6 + .../printer/{cups.py => cups/__init__.py} | 0 platypush/plugins/printer/cups/manifest.yaml | 7 + .../{pushbullet.py => pushbullet/__init__.py} | 4 +- platypush/plugins/pushbullet/manifest.yaml | 6 + .../pwm/{pca9685.py => pca9685/__init__.py} | 5 + platypush/plugins/pwm/pca9685/manifest.yaml | 7 + .../plugins/{qrcode.py => qrcode/__init__.py} | 10 +- platypush/plugins/qrcode/manifest.yaml | 10 + .../plugins/{redis.py => redis/__init__.py} | 4 - platypush/plugins/redis/manifest.yaml | 6 + .../{rtorrent.py => rtorrent/__init__.py} | 0 platypush/plugins/rtorrent/manifest.yaml | 23 ++ platypush/plugins/sensor/__init__.py | 6 +- platypush/plugins/serial/manifest.yaml | 6 + platypush/plugins/shell/manifest.yaml | 6 + .../plugins/{slack.py => slack/__init__.py} | 13 +- platypush/plugins/slack/manifest.yaml | 14 + .../__init__.py} | 0 platypush/plugins/smartthings/manifest.yaml | 7 + platypush/plugins/sound/__init__.py | 7 +- platypush/plugins/sound/core.py | 47 ++- platypush/plugins/sound/manifest.yaml | 15 + platypush/plugins/ssh/__init__.py | 9 +- platypush/plugins/ssh/manifest.yaml | 7 + .../{deepspeech.py => deepspeech/__init__.py} | 0 .../plugins/stt/deepspeech/manifest.yaml | 9 + .../{hotword.py => hotword/__init__.py} | 0 .../stt/picovoice/hotword/manifest.yaml | 7 + .../{speech.py => speech/__init__.py} | 0 .../stt/picovoice/speech/manifest.yaml | 7 + platypush/plugins/{sun.py => sun/__init__.py} | 0 platypush/plugins/sun/manifest.yaml | 8 + platypush/plugins/switch/__init__.py | 7 +- .../switch/{tplink.py => tplink/__init__.py} | 0 platypush/plugins/switch/tplink/manifest.yaml | 7 + platypush/plugins/switch/wemo/__init__.py | 4 - platypush/plugins/switch/wemo/manifest.yaml | 6 + .../{bluetooth.py => bluetooth/__init__.py} | 0 .../plugins/switchbot/bluetooth/manifest.yaml | 13 + platypush/plugins/switchbot/manifest.yaml | 6 + platypush/plugins/system/manifest.yaml | 8 + platypush/plugins/{tcp.py => tcp/__init__.py} | 0 platypush/plugins/tcp/manifest.yaml | 6 + platypush/plugins/tensorflow/manifest.yaml | 22 ++ .../{todoist.py => todoist/__init__.py} | 0 platypush/plugins/todoist/manifest.yaml | 7 + .../{torrent.py => torrent/__init__.py} | 4 +- platypush/plugins/torrent/manifest.yaml | 7 + .../{travisci.py => travisci/__init__.py} | 0 platypush/plugins/travisci/manifest.yaml | 6 + .../plugins/{trello.py => trello/__init__.py} | 0 platypush/plugins/trello/manifest.yaml | 7 + platypush/plugins/tts/__init__.py | 2 +- .../tts/{google.py => google/__init__.py} | 3 +- platypush/plugins/tts/google/manifest.yaml | 7 + platypush/plugins/tts/manifest.yaml | 6 + .../tv/samsung/{ws.py => ws/__init__.py} | 0 platypush/plugins/tv/samsung/ws/manifest.yaml | 7 + .../plugins/{twilio.py => twilio/__init__.py} | 0 platypush/plugins/twilio/manifest.yaml | 7 + platypush/plugins/{udp.py => udp/__init__.py} | 0 platypush/plugins/udp/manifest.yaml | 6 + .../plugins/{user.py => user/__init__.py} | 0 platypush/plugins/user/manifest.yaml | 6 + .../plugins/{utils.py => utils/__init__.py} | 0 platypush/plugins/utils/manifest.yaml | 6 + .../{variable.py => variable/__init__.py} | 5 - platypush/plugins/variable/manifest.yaml | 6 + platypush/plugins/weather/__init__.py | 3 +- .../{buienradar.py => buienradar/__init__.py} | 0 .../plugins/weather/buienradar/manifest.yaml | 7 + .../{darksky.py => darksky/__init__.py} | 0 .../plugins/weather/darksky/manifest.yaml | 6 + .../__init__.py} | 2 +- .../weather/openweathermap/manifest.yaml | 6 + .../{websocket.py => websocket/__init__.py} | 13 +- platypush/plugins/websocket/manifest.yaml | 6 + .../{wiimote.py => wiimote/__init__.py} | 0 platypush/plugins/wiimote/manifest.yaml | 6 + .../{zeroconf.py => zeroconf/__init__.py} | 0 platypush/plugins/zeroconf/manifest.yaml | 13 + .../zigbee/{mqtt.py => mqtt/__init__.py} | 0 platypush/plugins/zigbee/mqtt/manifest.yaml | 7 + platypush/plugins/zwave/_base.py | 70 +++- platypush/plugins/zwave/manifest.yaml | 7 + .../zwave/{mqtt.py => mqtt/__init__.py} | 0 platypush/plugins/zwave/mqtt/manifest.yaml | 7 + platypush/user/__init__.py | 21 +- platypush/utils/__init__.py | 14 +- platypush/utils/manifest.py | 200 ++++++++++++ requirements.txt | 305 +----------------- setup.py | 21 +- 437 files changed, 3139 insertions(+), 1121 deletions(-) rename platypush/backend/adafruit/{io.py => io/__init__.py} (90%) create mode 100644 platypush/backend/adafruit/io/manifest.yaml rename platypush/backend/{alarm.py => alarm/__init__.py} (100%) create mode 100644 platypush/backend/alarm/manifest.yaml rename platypush/backend/assistant/{google.py => google/__init__.py} (100%) create mode 100644 platypush/backend/assistant/google/manifest.yaml create mode 100644 platypush/backend/assistant/snowboy/manifest.yaml rename platypush/backend/bluetooth/{fileserver.py => fileserver/__init__.py} (100%) create mode 100644 platypush/backend/bluetooth/fileserver/manifest.yaml rename platypush/backend/bluetooth/{pushserver.py => pushserver/__init__.py} (100%) create mode 100644 platypush/backend/bluetooth/pushserver/manifest.yaml rename platypush/backend/bluetooth/scanner/{ble.py => ble/__init__.py} (100%) create mode 100644 platypush/backend/bluetooth/scanner/ble/manifest.yaml create mode 100644 platypush/backend/bluetooth/scanner/manifest.yaml create mode 100644 platypush/backend/button/flic/manifest.yaml rename platypush/backend/camera/{pi.py => pi/__init__.py} (98%) create mode 100644 platypush/backend/camera/pi/manifest.yaml rename platypush/backend/chat/{telegram.py => telegram/__init__.py} (100%) create mode 100644 platypush/backend/chat/telegram/manifest.yaml rename platypush/backend/{clipboard.py => clipboard/__init__.py} (100%) create mode 100644 platypush/backend/clipboard/manifest.yaml rename platypush/backend/{covid19.py => covid19/__init__.py} (100%) create mode 100644 platypush/backend/covid19/manifest.yaml rename platypush/backend/{dbus.py => dbus/__init__.py} (100%) create mode 100644 platypush/backend/dbus/manifest.yaml create mode 100644 platypush/backend/file/monitor/manifest.yaml rename platypush/backend/{foursquare.py => foursquare/__init__.py} (100%) create mode 100644 platypush/backend/foursquare/manifest.yaml rename platypush/backend/{github.py => github/__init__.py} (100%) create mode 100644 platypush/backend/github/manifest.yaml rename platypush/backend/google/{fit.py => fit/__init__.py} (100%) create mode 100644 platypush/backend/google/fit/manifest.yaml rename platypush/backend/google/{pubsub.py => pubsub/__init__.py} (100%) create mode 100644 platypush/backend/google/pubsub/manifest.yaml rename platypush/backend/{gps.py => gps/__init__.py} (100%) create mode 100644 platypush/backend/gps/manifest.yaml create mode 100644 platypush/backend/http/manifest.yaml create mode 100644 platypush/backend/http/poll/manifest.yaml delete mode 100644 platypush/backend/http/request/ota/__init__.py delete mode 100644 platypush/backend/http/request/ota/booking/__init__.py rename platypush/backend/{inotify.py => inotify/__init__.py} (100%) create mode 100644 platypush/backend/inotify/manifest.yaml rename platypush/backend/joystick/{jstest.py => jstest/__init__.py} (100%) create mode 100644 platypush/backend/joystick/jstest/manifest.yaml rename platypush/backend/joystick/{linux.py => linux/__init__.py} (100%) create mode 100644 platypush/backend/joystick/linux/manifest.yaml create mode 100644 platypush/backend/joystick/manifest.yaml create mode 100644 platypush/backend/kafka/manifest.yaml rename platypush/backend/light/{hue.py => hue/__init__.py} (100%) create mode 100644 platypush/backend/light/hue/manifest.yaml rename platypush/backend/{linode.py => linode/__init__.py} (100%) create mode 100644 platypush/backend/linode/manifest.yaml rename platypush/backend/log/{http.py => http/__init__.py} (100%) create mode 100644 platypush/backend/log/http/manifest.yaml rename platypush/backend/{mail.py => mail/__init__.py} (100%) create mode 100644 platypush/backend/mail/manifest.yaml rename platypush/backend/{midi.py => midi/__init__.py} (98%) create mode 100644 platypush/backend/midi/manifest.yaml rename platypush/backend/{mqtt.py => mqtt/__init__.py} (100%) create mode 100644 platypush/backend/mqtt/manifest.yaml rename platypush/backend/music/{mopidy.py => mopidy/__init__.py} (98%) create mode 100644 platypush/backend/music/mopidy/manifest.yaml create mode 100644 platypush/backend/music/mpd/manifest.yaml rename platypush/backend/music/{snapcast.py => snapcast/__init__.py} (100%) create mode 100644 platypush/backend/music/snapcast/manifest.yaml create mode 100644 platypush/backend/music/spotify/manifest.yaml rename platypush/backend/{nextcloud.py => nextcloud/__init__.py} (100%) create mode 100644 platypush/backend/nextcloud/manifest.yaml rename platypush/backend/{nfc.py => nfc/__init__.py} (100%) create mode 100644 platypush/backend/nfc/manifest.yaml create mode 100644 platypush/backend/nodered/manifest.yaml rename platypush/backend/{ping.py => ping/__init__.py} (100%) create mode 100644 platypush/backend/ping/manifest.yaml create mode 100644 platypush/backend/pushbullet/manifest.yaml rename platypush/backend/{redis.py => redis/__init__.py} (97%) create mode 100644 platypush/backend/redis/manifest.yaml create mode 100644 platypush/backend/scard/manifest.yaml delete mode 100644 platypush/backend/sensor/accelerometer.py create mode 100644 platypush/backend/sensor/accelerometer/__init__.py create mode 100644 platypush/backend/sensor/accelerometer/manifest.yaml delete mode 100644 platypush/backend/sensor/arduino.py create mode 100644 platypush/backend/sensor/arduino/__init__.py create mode 100644 platypush/backend/sensor/arduino/manifest.yaml rename platypush/backend/sensor/{battery.py => battery/__init__.py} (65%) create mode 100644 platypush/backend/sensor/battery/manifest.yaml rename platypush/backend/sensor/{bme280.py => bme280/__init__.py} (65%) create mode 100644 platypush/backend/sensor/bme280/manifest.yaml rename platypush/backend/sensor/{dht.py => dht/__init__.py} (64%) create mode 100644 platypush/backend/sensor/dht/manifest.yaml create mode 100644 platypush/backend/sensor/distance/manifest.yaml rename platypush/backend/sensor/distance/{vl53l1x.py => vl53l1x/__init__.py} (66%) create mode 100644 platypush/backend/sensor/distance/vl53l1x/manifest.yaml rename platypush/backend/sensor/{envirophat.py => envirophat/__init__.py} (76%) create mode 100644 platypush/backend/sensor/envirophat/manifest.yaml create mode 100644 platypush/backend/sensor/ir/zeroborg/manifest.yaml rename platypush/backend/sensor/{leap.py => leap/__init__.py} (100%) create mode 100644 platypush/backend/sensor/leap/manifest.yaml rename platypush/backend/sensor/{ltr559.py => ltr559/__init__.py} (60%) create mode 100644 platypush/backend/sensor/ltr559/manifest.yaml rename platypush/backend/sensor/{mcp3008.py => mcp3008/__init__.py} (54%) create mode 100644 platypush/backend/sensor/mcp3008/manifest.yaml create mode 100644 platypush/backend/sensor/motion/pmw3901/__init__.py create mode 100644 platypush/backend/sensor/motion/pmw3901/manifest.yaml delete mode 100644 platypush/backend/sensor/motion/pwm3901.py delete mode 100644 platypush/backend/sensor/serial.py create mode 100644 platypush/backend/sensor/serial/__init__.py create mode 100644 platypush/backend/sensor/serial/manifest.yaml rename platypush/backend/stt/{deepspeech.py => deepspeech/__init__.py} (100%) create mode 100644 platypush/backend/stt/deepspeech/manifest.yaml rename platypush/backend/stt/picovoice/{hotword.py => hotword/__init__.py} (100%) create mode 100644 platypush/backend/stt/picovoice/hotword/manifest.yaml rename platypush/backend/stt/picovoice/{speech.py => speech/__init__.py} (100%) create mode 100644 platypush/backend/stt/picovoice/speech/manifest.yaml rename platypush/backend/{tcp.py => tcp/__init__.py} (100%) create mode 100644 platypush/backend/tcp/manifest.yaml rename platypush/backend/{todoist.py => todoist/__init__.py} (98%) create mode 100644 platypush/backend/todoist/manifest.yaml rename platypush/backend/{travisci.py => travisci/__init__.py} (100%) create mode 100644 platypush/backend/travisci/manifest.yaml rename platypush/backend/{trello.py => trello/__init__.py} (98%) create mode 100644 platypush/backend/trello/manifest.yaml rename platypush/backend/weather/{buienradar.py => buienradar/__init__.py} (100%) create mode 100644 platypush/backend/weather/buienradar/manifest.yaml rename platypush/backend/weather/{darksky.py => darksky/__init__.py} (100%) create mode 100644 platypush/backend/weather/darksky/manifest.yaml rename platypush/backend/weather/{openweathermap.py => openweathermap/__init__.py} (100%) create mode 100644 platypush/backend/weather/openweathermap/manifest.yaml rename platypush/backend/{websocket.py => websocket/__init__.py} (89%) create mode 100644 platypush/backend/websocket/manifest.yaml rename platypush/backend/{wiimote.py => wiimote/__init__.py} (81%) create mode 100644 platypush/backend/wiimote/manifest.yaml rename platypush/backend/zigbee/{mqtt.py => mqtt/__init__.py} (100%) create mode 100644 platypush/backend/zigbee/mqtt/manifest.yaml create mode 100644 platypush/backend/zwave/manifest.yaml rename platypush/backend/zwave/{mqtt.py => mqtt/__init__.py} (100%) create mode 100644 platypush/backend/zwave/mqtt/manifest.yaml rename platypush/plugins/adafruit/{io.py => io/__init__.py} (97%) create mode 100644 platypush/plugins/adafruit/io/manifest.yaml rename platypush/plugins/{alarm.py => alarm/__init__.py} (100%) create mode 100644 platypush/plugins/alarm/manifest.yaml rename platypush/plugins/{arduino.py => arduino/__init__.py} (100%) create mode 100644 platypush/plugins/arduino/manifest.yaml create mode 100644 platypush/plugins/assistant/echo/manifest.yaml create mode 100644 platypush/plugins/assistant/google/manifest.yaml rename platypush/plugins/assistant/google/{pushtotalk.py => pushtotalk/__init__.py} (100%) create mode 100644 platypush/plugins/assistant/google/pushtotalk/manifest.yaml rename platypush/plugins/{autoremote.py => autoremote/__init__.py} (97%) create mode 100644 platypush/plugins/autoremote/manifest.yaml rename platypush/plugins/bluetooth/{ble.py => ble/__init__.py} (100%) create mode 100644 platypush/plugins/bluetooth/ble/manifest.yaml create mode 100644 platypush/plugins/bluetooth/manifest.yaml rename platypush/plugins/calendar/{ical.py => ical/__init__.py} (85%) create mode 100644 platypush/plugins/calendar/ical/manifest.yaml create mode 100644 platypush/plugins/calendar/manifest.yaml rename platypush/plugins/camera/android/{ipcam.py => ipcam/__init__.py} (100%) create mode 100644 platypush/plugins/camera/android/ipcam/manifest.yaml rename platypush/plugins/camera/{cv.py => cv/__init__.py} (100%) create mode 100644 platypush/plugins/camera/cv/manifest.yaml create mode 100644 platypush/plugins/camera/ffmpeg/manifest.yaml create mode 100644 platypush/plugins/camera/gstreamer/manifest.yaml create mode 100644 platypush/plugins/camera/ir/mlx90640/manifest.yaml create mode 100644 platypush/plugins/camera/pi/manifest.yaml rename platypush/plugins/chat/{telegram.py => telegram/__init__.py} (100%) create mode 100644 platypush/plugins/chat/telegram/manifest.yaml rename platypush/plugins/{clipboard.py => clipboard/__init__.py} (100%) create mode 100644 platypush/plugins/clipboard/manifest.yaml rename platypush/plugins/{config.py => config/__init__.py} (88%) create mode 100644 platypush/plugins/config/manifest.yaml rename platypush/plugins/{covid19.py => covid19/__init__.py} (100%) create mode 100644 platypush/plugins/covid19/manifest.yaml rename platypush/plugins/{csv.py => csv/__init__.py} (98%) create mode 100644 platypush/plugins/csv/manifest.yaml create mode 100644 platypush/plugins/db/manifest.yaml rename platypush/plugins/{dbus.py => dbus/__init__.py} (100%) create mode 100644 platypush/plugins/dbus/manifest.yaml rename platypush/plugins/{dropbox.py => dropbox/__init__.py} (100%) create mode 100644 platypush/plugins/dropbox/manifest.yaml create mode 100644 platypush/plugins/esp/manifest.yaml rename platypush/plugins/{ffmpeg.py => ffmpeg/__init__.py} (100%) create mode 100644 platypush/plugins/ffmpeg/manifest.yaml rename platypush/plugins/{file.py => file/__init__.py} (100%) create mode 100644 platypush/plugins/file/manifest.yaml rename platypush/plugins/{foursquare.py => foursquare/__init__.py} (100%) create mode 100644 platypush/plugins/foursquare/manifest.yaml rename platypush/plugins/google/{calendar.py => calendar/__init__.py} (85%) create mode 100644 platypush/plugins/google/calendar/manifest.yaml rename platypush/plugins/google/{drive.py => drive/__init__.py} (98%) create mode 100644 platypush/plugins/google/drive/manifest.yaml rename platypush/plugins/google/{fit.py => fit/__init__.py} (90%) create mode 100644 platypush/plugins/google/fit/manifest.yaml rename platypush/plugins/google/{mail.py => mail/__init__.py} (95%) create mode 100644 platypush/plugins/google/mail/manifest.yaml rename platypush/plugins/google/{maps.py => maps/__init__.py} (95%) create mode 100644 platypush/plugins/google/maps/manifest.yaml rename platypush/plugins/google/{pubsub.py => pubsub/__init__.py} (96%) create mode 100644 platypush/plugins/google/pubsub/manifest.yaml rename platypush/plugins/google/{translate.py => translate/__init__.py} (97%) create mode 100644 platypush/plugins/google/translate/manifest.yaml rename platypush/plugins/google/{youtube.py => youtube/__init__.py} (93%) create mode 100644 platypush/plugins/google/youtube/manifest.yaml create mode 100644 platypush/plugins/gpio/manifest.yaml create mode 100644 platypush/plugins/gpio/sensor/accelerometer/manifest.yaml rename platypush/plugins/gpio/sensor/{bme280.py => bme280/__init__.py} (100%) create mode 100644 platypush/plugins/gpio/sensor/bme280/manifest.yaml rename platypush/plugins/gpio/sensor/{dht.py => dht/__init__.py} (98%) create mode 100644 platypush/plugins/gpio/sensor/dht/manifest.yaml create mode 100644 platypush/plugins/gpio/sensor/distance/manifest.yaml rename platypush/plugins/gpio/sensor/distance/{vl53l1x.py => vl53l1x/__init__.py} (100%) create mode 100644 platypush/plugins/gpio/sensor/distance/vl53l1x/manifest.yaml rename platypush/plugins/gpio/sensor/{envirophat.py => envirophat/__init__.py} (100%) create mode 100644 platypush/plugins/gpio/sensor/envirophat/manifest.yaml rename platypush/plugins/gpio/sensor/{ltr559.py => ltr559/__init__.py} (100%) create mode 100644 platypush/plugins/gpio/sensor/ltr559/manifest.yaml create mode 100644 platypush/plugins/gpio/sensor/mcp3008/manifest.yaml rename platypush/plugins/gpio/sensor/motion/{pwm3901.py => pmw3901/__init__.py} (95%) create mode 100644 platypush/plugins/gpio/sensor/motion/pmw3901/manifest.yaml create mode 100644 platypush/plugins/gpio/zeroborg/manifest.yaml rename platypush/plugins/{graphite.py => graphite/__init__.py} (97%) create mode 100644 platypush/plugins/graphite/manifest.yaml delete mode 100644 platypush/plugins/homeseer.py create mode 100644 platypush/plugins/http/request/manifest.yaml rename platypush/plugins/http/request/{rss.py => rss/__init__.py} (100%) create mode 100644 platypush/plugins/http/request/rss/manifest.yaml create mode 100644 platypush/plugins/http/webpage/manifest.yaml rename platypush/plugins/{ifttt.py => ifttt/__init__.py} (96%) create mode 100644 platypush/plugins/ifttt/manifest.yaml rename platypush/plugins/{inputs.py => inputs/__init__.py} (100%) create mode 100644 platypush/plugins/inputs/manifest.yaml rename platypush/plugins/{inspect.py => inspect/__init__.py} (100%) create mode 100644 platypush/plugins/inspect/manifest.yaml rename platypush/plugins/{kafka.py => kafka/__init__.py} (100%) create mode 100644 platypush/plugins/kafka/manifest.yaml create mode 100644 platypush/plugins/lastfm/manifest.yaml rename platypush/plugins/lcd/{gpio.py => gpio/__init__.py} (100%) create mode 100644 platypush/plugins/lcd/gpio/manifest.yaml rename platypush/plugins/lcd/{i2c.py => i2c/__init__.py} (98%) create mode 100644 platypush/plugins/lcd/i2c/manifest.yaml create mode 100644 platypush/plugins/light/hue/manifest.yaml rename platypush/plugins/{linode.py => linode/__init__.py} (100%) create mode 100644 platypush/plugins/linode/manifest.yaml rename platypush/plugins/{logger.py => logger/__init__.py} (100%) create mode 100644 platypush/plugins/logger/manifest.yaml rename platypush/plugins/luma/{oled.py => oled/__init__.py} (99%) create mode 100644 platypush/plugins/luma/oled/manifest.yaml rename platypush/plugins/mail/{imap.py => imap/__init__.py} (100%) create mode 100644 platypush/plugins/mail/imap/manifest.yaml rename platypush/plugins/mail/{smtp.py => smtp/__init__.py} (100%) create mode 100644 platypush/plugins/mail/smtp/manifest.yaml rename platypush/plugins/media/{chromecast.py => chromecast/__init__.py} (99%) create mode 100644 platypush/plugins/media/chromecast/manifest.yaml create mode 100644 platypush/plugins/media/gstreamer/manifest.yaml rename platypush/plugins/media/{kodi.py => kodi/__init__.py} (96%) create mode 100644 platypush/plugins/media/kodi/manifest.yaml rename platypush/plugins/media/{mplayer.py => mplayer/__init__.py} (97%) create mode 100644 platypush/plugins/media/mplayer/manifest.yaml rename platypush/plugins/media/{mpv.py => mpv/__init__.py} (100%) create mode 100644 platypush/plugins/media/mpv/manifest.yaml rename platypush/plugins/media/{omxplayer.py => omxplayer/__init__.py} (96%) create mode 100644 platypush/plugins/media/omxplayer/manifest.yaml rename platypush/plugins/media/{plex.py => plex/__init__.py} (99%) create mode 100644 platypush/plugins/media/plex/manifest.yaml rename platypush/plugins/media/{subtitles.py => subtitles/__init__.py} (99%) create mode 100644 platypush/plugins/media/subtitles/manifest.yaml rename platypush/plugins/media/{vlc.py => vlc/__init__.py} (100%) create mode 100644 platypush/plugins/media/vlc/manifest.yaml rename platypush/plugins/media/{webtorrent.py => webtorrent/__init__.py} (94%) create mode 100644 platypush/plugins/media/webtorrent/manifest.yaml rename platypush/plugins/{midi.py => midi/__init__.py} (82%) create mode 100644 platypush/plugins/midi/manifest.yaml rename platypush/plugins/ml/{cv.py => cv/__init__.py} (100%) create mode 100644 platypush/plugins/ml/cv/manifest.yaml create mode 100644 platypush/plugins/mobile/join/manifest.yaml rename platypush/plugins/{mqtt.py => mqtt/__init__.py} (99%) create mode 100644 platypush/plugins/mqtt/manifest.yaml create mode 100644 platypush/plugins/music/mpd/manifest.yaml rename platypush/plugins/music/{snapcast.py => snapcast/__init__.py} (99%) create mode 100644 platypush/plugins/music/snapcast/manifest.yaml rename platypush/plugins/music/{spotify.py => spotify/__init__.py} (100%) create mode 100644 platypush/plugins/music/spotify/manifest.yaml rename platypush/plugins/{nextcloud.py => nextcloud/__init__.py} (99%) create mode 100644 platypush/plugins/nextcloud/manifest.yaml rename platypush/plugins/{nmap.py => nmap/__init__.py} (100%) create mode 100644 platypush/plugins/nmap/manifest.yaml rename platypush/plugins/{otp.py => otp/__init__.py} (100%) create mode 100644 platypush/plugins/otp/manifest.yaml rename platypush/plugins/{pihole.py => pihole/__init__.py} (100%) create mode 100644 platypush/plugins/pihole/manifest.yaml rename platypush/plugins/{ping.py => ping/__init__.py} (100%) create mode 100644 platypush/plugins/ping/manifest.yaml rename platypush/plugins/printer/{cups.py => cups/__init__.py} (100%) create mode 100644 platypush/plugins/printer/cups/manifest.yaml rename platypush/plugins/{pushbullet.py => pushbullet/__init__.py} (98%) create mode 100644 platypush/plugins/pushbullet/manifest.yaml rename platypush/plugins/pwm/{pca9685.py => pca9685/__init__.py} (98%) create mode 100644 platypush/plugins/pwm/pca9685/manifest.yaml rename platypush/plugins/{qrcode.py => qrcode/__init__.py} (93%) create mode 100644 platypush/plugins/qrcode/manifest.yaml rename platypush/plugins/{redis.py => redis/__init__.py} (97%) create mode 100644 platypush/plugins/redis/manifest.yaml rename platypush/plugins/{rtorrent.py => rtorrent/__init__.py} (100%) create mode 100644 platypush/plugins/rtorrent/manifest.yaml create mode 100644 platypush/plugins/serial/manifest.yaml create mode 100644 platypush/plugins/shell/manifest.yaml rename platypush/plugins/{slack.py => slack/__init__.py} (95%) create mode 100644 platypush/plugins/slack/manifest.yaml rename platypush/plugins/{smartthings.py => smartthings/__init__.py} (100%) create mode 100644 platypush/plugins/smartthings/manifest.yaml create mode 100644 platypush/plugins/sound/manifest.yaml create mode 100644 platypush/plugins/ssh/manifest.yaml rename platypush/plugins/stt/{deepspeech.py => deepspeech/__init__.py} (100%) create mode 100644 platypush/plugins/stt/deepspeech/manifest.yaml rename platypush/plugins/stt/picovoice/{hotword.py => hotword/__init__.py} (100%) create mode 100644 platypush/plugins/stt/picovoice/hotword/manifest.yaml rename platypush/plugins/stt/picovoice/{speech.py => speech/__init__.py} (100%) create mode 100644 platypush/plugins/stt/picovoice/speech/manifest.yaml rename platypush/plugins/{sun.py => sun/__init__.py} (100%) create mode 100644 platypush/plugins/sun/manifest.yaml rename platypush/plugins/switch/{tplink.py => tplink/__init__.py} (100%) create mode 100644 platypush/plugins/switch/tplink/manifest.yaml create mode 100644 platypush/plugins/switch/wemo/manifest.yaml rename platypush/plugins/switchbot/{bluetooth.py => bluetooth/__init__.py} (100%) create mode 100644 platypush/plugins/switchbot/bluetooth/manifest.yaml create mode 100644 platypush/plugins/switchbot/manifest.yaml create mode 100644 platypush/plugins/system/manifest.yaml rename platypush/plugins/{tcp.py => tcp/__init__.py} (100%) create mode 100644 platypush/plugins/tcp/manifest.yaml create mode 100644 platypush/plugins/tensorflow/manifest.yaml rename platypush/plugins/{todoist.py => todoist/__init__.py} (100%) create mode 100644 platypush/plugins/todoist/manifest.yaml rename platypush/plugins/{torrent.py => torrent/__init__.py} (99%) create mode 100644 platypush/plugins/torrent/manifest.yaml rename platypush/plugins/{travisci.py => travisci/__init__.py} (100%) create mode 100644 platypush/plugins/travisci/manifest.yaml rename platypush/plugins/{trello.py => trello/__init__.py} (100%) create mode 100644 platypush/plugins/trello/manifest.yaml rename platypush/plugins/tts/{google.py => google/__init__.py} (96%) create mode 100644 platypush/plugins/tts/google/manifest.yaml create mode 100644 platypush/plugins/tts/manifest.yaml rename platypush/plugins/tv/samsung/{ws.py => ws/__init__.py} (100%) create mode 100644 platypush/plugins/tv/samsung/ws/manifest.yaml rename platypush/plugins/{twilio.py => twilio/__init__.py} (100%) create mode 100644 platypush/plugins/twilio/manifest.yaml rename platypush/plugins/{udp.py => udp/__init__.py} (100%) create mode 100644 platypush/plugins/udp/manifest.yaml rename platypush/plugins/{user.py => user/__init__.py} (100%) create mode 100644 platypush/plugins/user/manifest.yaml rename platypush/plugins/{utils.py => utils/__init__.py} (100%) create mode 100644 platypush/plugins/utils/manifest.yaml rename platypush/plugins/{variable.py => variable/__init__.py} (97%) create mode 100644 platypush/plugins/variable/manifest.yaml rename platypush/plugins/weather/{buienradar.py => buienradar/__init__.py} (100%) create mode 100644 platypush/plugins/weather/buienradar/manifest.yaml rename platypush/plugins/weather/{darksky.py => darksky/__init__.py} (100%) create mode 100644 platypush/plugins/weather/darksky/manifest.yaml rename platypush/plugins/weather/{openweathermap.py => openweathermap/__init__.py} (98%) create mode 100644 platypush/plugins/weather/openweathermap/manifest.yaml rename platypush/plugins/{websocket.py => websocket/__init__.py} (91%) create mode 100644 platypush/plugins/websocket/manifest.yaml rename platypush/plugins/{wiimote.py => wiimote/__init__.py} (100%) create mode 100644 platypush/plugins/wiimote/manifest.yaml rename platypush/plugins/{zeroconf.py => zeroconf/__init__.py} (100%) create mode 100644 platypush/plugins/zeroconf/manifest.yaml rename platypush/plugins/zigbee/{mqtt.py => mqtt/__init__.py} (100%) create mode 100644 platypush/plugins/zigbee/mqtt/manifest.yaml create mode 100644 platypush/plugins/zwave/manifest.yaml rename platypush/plugins/zwave/{mqtt.py => mqtt/__init__.py} (100%) create mode 100644 platypush/plugins/zwave/mqtt/manifest.yaml create mode 100644 platypush/utils/manifest.py diff --git a/MANIFEST.in b/MANIFEST.in index ace9a1f59..e61e3251c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,3 @@ recursive-include platypush/backend/http/webapp/dist * include platypush/plugins/http/webpage/mercury-parser.js +global-include manifest.yaml diff --git a/bin/platyvenv b/bin/platyvenv index 7b69abc8a..4e1d33ab4 100755 --- a/bin/platyvenv +++ b/bin/platyvenv @@ -6,12 +6,12 @@ # and automatically managed the required dependencies, as well as start, # # stop and remove them # # # -# @author: Fabio Manganiello # +# @author: Fabio Manganiello # # @licence: MIT # ############################################################################## -workdir=$HOME/.local/share/platypush/venv +workdir="$HOME/.local/share/platypush/venv" function build { cfgfile= @@ -35,88 +35,74 @@ function build { fi echo "Parsing configuration file" - deps=() + pip_cmd= + pkg_cmd= includes=() + cmd_exec=() while read -r line; do - echo ${line} | egrep '``pip install .+?``' > /dev/null 2>&1 - if (( $? != 0 )); then - continue - fi - - dep=$(echo ${line} | sed -r -e 's/.*``pip install (.+?)``.*/\1/') - deps+=("$dep") - done <<< $(python <&2 exit 1 fi - mkdir -p ${logsdir} - mkdir -p ${rundir} + mkdir -p "${logsdir}" + mkdir -p "${rundir}" if [[ -f "$pidfile" ]]; then - pid=`cat "$pidfile"` - if ps -p ${pid} | grep platypush; then - echo "Another instance (PID $pid) is running, please stop that instance first" + if pgrep -F "${pidfile}"; then + echo "Another instance (PID $(cat "${pidfile}")) is running, please stop that instance first" exit 1 fi - echo "A PID file was found but the process doesn't seem to be running, starting anyway" + echo "A PID file was found but the process does not seem to be running, starting anyway" rm -f "$pidfile" fi - python3 -m venv ${envdir} - cd ${envdir} + python3 -m venv "${envdir}" + cd "${envdir}" || exit 1 source bin/activate - bin/platypush -c "$cfgfile" -P "$pidfile" > ${logsdir}/stdout.log 2> ${logsdir}/stderr.log & - start_time=`date +'%s'` + bin/platypush -c "$cfgfile" -P "$pidfile" > "${logsdir}/stdout.log" 2> "${logsdir}/stderr.log" & + start_time=$(date +'%s') timeout=30 while :; do [[ -f "$pidfile" ]] && break - now=`date +'%s'` - let elapsed=$now-$start_time - if (( ${elapsed} >= ${timeout} )); then - echo "Platypush instance '$env' didn't start within $timeout seconds" >&2 + now=$(date +'%s') + elapsed=$(( now-start_time )) + if (( elapsed >= timeout )); then + echo "Platypush instance '$env' did not start within $timeout seconds" >&2 exit 1 fi @@ -175,7 +160,7 @@ function start { sleep 1 done - pid=`cat "$pidfile"` + pid=$(cat "$pidfile") echo echo "Platypush environment $env started with PID $pid, logs dir: $logsdir" } @@ -187,9 +172,9 @@ function stop { fi env=$1 - envdir=${workdir}/${env} - rundir=${envdir}/var/run - pidfile=${rundir}/platypush.pid + envdir="${workdir}/${env}" + rundir="${envdir}/var/run" + pidfile="${rundir}/platypush.pid" if [[ ! -d "$envdir" ]]; then echo "No such directory: $envdir" >&2 @@ -197,12 +182,13 @@ function stop { fi if [[ ! -f "$pidfile" ]]; then - echo "No pidfile found for instance "${env}"" + echo "No pidfile found for instance \"${env}\"" exit 1 fi - pid=`cat "$pidfile"` - pids="$pid `ps --no-headers -o pid= --ppid $pid`" + pid=$(cat "$pidfile") + pids="$pid $(ps --no-headers -o pid= --ppid "$pid")" + # shellcheck disable=SC2086 kill -9 ${pids} rm -f "$pidfile" echo "Instance '$env' with PID $pid stopped" @@ -214,9 +200,9 @@ function rme { exit 1 fi - envdir=${workdir}/$1 - rundir=${envdir}/var/run - pidfile=${rundir}/platypush.pid + envdir="${workdir}/$1" + rundir="${envdir}/var/run" + pidfile="${rundir}/platypush.pid" if [[ ! -d "$envdir" ]]; then echo "No such directory: $envdir" >&2 @@ -224,14 +210,18 @@ function rme { fi if [[ -f "$pidfile" ]]; then - if ps -p `cat "$pidfile"` | grep platypush; then - echo "Another instance (PID $pidfile) is running, please stop that instance first" + if pgrep -F "${pidfile}"; then + echo "Another instance (PID $(cat "$pidfile")) is running, please stop that instance first" exit 1 fi - echo "A PID file was found but the process doesn't seem to be running, removing anyway" + echo "A PID file was found but the process does not seem to be running, removing anyway" fi + echo "WARNING: This operation will permanently remove the Platypush environment $1" + echo -n "Are you sure you want to continue? (y/N) " + IFS= read -r answer + echo "$answer" | grep -E '^[yY]' >/dev/null || exit 0 rm -rf "$envdir" echo "$envdir removed" } @@ -247,13 +237,13 @@ fi action=$1 shift -mkdir -p ${workdir} +mkdir -p "${workdir}" +# shellcheck disable=SC2048,SC2086 case ${action} in - 'build') build;; + 'build') build $*;; 'start') start $*;; 'stop') stop $*;; 'rm') rme $*;; *) usage;; esac - diff --git a/docs/source/backends.rst b/docs/source/backends.rst index 8ced60b2b..5e8930919 100644 --- a/docs/source/backends.rst +++ b/docs/source/backends.rst @@ -8,10 +8,8 @@ Backends platypush/backend/adafruit.io.rst platypush/backend/alarm.rst - platypush/backend/assistant.rst platypush/backend/assistant.google.rst platypush/backend/assistant.snowboy.rst - platypush/backend/bluetooth.rst platypush/backend/bluetooth.fileserver.rst platypush/backend/bluetooth.pushserver.rst platypush/backend/bluetooth.scanner.rst @@ -52,7 +50,6 @@ Backends platypush/backend/pushbullet.rst platypush/backend/redis.rst platypush/backend/scard.rst - platypush/backend/sensor.rst platypush/backend/sensor.accelerometer.rst platypush/backend/sensor.arduino.rst platypush/backend/sensor.battery.rst @@ -67,7 +64,6 @@ Backends platypush/backend/sensor.mcp3008.rst platypush/backend/sensor.motion.pwm3901.rst platypush/backend/sensor.serial.rst - platypush/backend/stt.rst platypush/backend/stt.deepspeech.rst platypush/backend/stt.picovoice.hotword.rst platypush/backend/stt.picovoice.speech.rst @@ -75,7 +71,6 @@ Backends platypush/backend/todoist.rst platypush/backend/travisci.rst platypush/backend/trello.rst - platypush/backend/weather.rst platypush/backend/weather.buienradar.rst platypush/backend/weather.darksky.rst platypush/backend/weather.openweathermap.rst diff --git a/docs/source/conf.py b/docs/source/conf.py index 36f73e349..2a7262c6e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -238,7 +238,7 @@ autodoc_mock_imports = ['googlesamples.assistant.grpc.audio_helpers', 'envirophat', 'gps', 'picamera', - 'pwm3901', + 'pmw3901', 'PIL', 'croniter', 'pyaudio', diff --git a/docs/source/plugins.rst b/docs/source/plugins.rst index 63d62fbbe..b05de1401 100644 --- a/docs/source/plugins.rst +++ b/docs/source/plugins.rst @@ -9,7 +9,6 @@ Plugins platypush/plugins/adafruit.io.rst platypush/plugins/alarm.rst platypush/plugins/arduino.rst - platypush/plugins/assistant.rst platypush/plugins/assistant.echo.rst platypush/plugins/assistant.google.rst platypush/plugins/assistant.google.pushtotalk.rst @@ -18,14 +17,12 @@ Plugins platypush/plugins/bluetooth.ble.rst platypush/plugins/calendar.rst platypush/plugins/calendar.ical.rst - platypush/plugins/camera.rst platypush/plugins/camera.android.ipcam.rst platypush/plugins/camera.cv.rst platypush/plugins/camera.ffmpeg.rst platypush/plugins/camera.gstreamer.rst platypush/plugins/camera.ir.mlx90640.rst platypush/plugins/camera.pi.rst - platypush/plugins/chat.rst platypush/plugins/chat.telegram.rst platypush/plugins/clipboard.rst platypush/plugins/config.rst @@ -38,7 +35,6 @@ Plugins platypush/plugins/ffmpeg.rst platypush/plugins/file.rst platypush/plugins/foursquare.rst - platypush/plugins/google.rst platypush/plugins/google.calendar.rst platypush/plugins/google.drive.rst platypush/plugins/google.fit.rst @@ -48,7 +44,6 @@ Plugins platypush/plugins/google.translate.rst platypush/plugins/google.youtube.rst platypush/plugins/gpio.rst - platypush/plugins/gpio.sensor.rst platypush/plugins/gpio.sensor.accelerometer.rst platypush/plugins/gpio.sensor.bme280.rst platypush/plugins/gpio.sensor.dht.rst @@ -69,18 +64,14 @@ Plugins platypush/plugins/inspect.rst platypush/plugins/kafka.rst platypush/plugins/lastfm.rst - platypush/plugins/lcd.rst platypush/plugins/lcd.gpio.rst platypush/plugins/lcd.i2c.rst - platypush/plugins/light.rst platypush/plugins/light.hue.rst platypush/plugins/linode.rst platypush/plugins/logger.rst platypush/plugins/luma.oled.rst - platypush/plugins/mail.rst platypush/plugins/mail.imap.rst platypush/plugins/mail.smtp.rst - platypush/plugins/media.rst platypush/plugins/media.chromecast.rst platypush/plugins/media.gstreamer.rst platypush/plugins/media.kodi.rst @@ -95,7 +86,6 @@ Plugins platypush/plugins/ml.cv.rst platypush/plugins/mobile.join.rst platypush/plugins/mqtt.rst - platypush/plugins/music.rst platypush/plugins/music.mpd.rst platypush/plugins/music.snapcast.rst platypush/plugins/music.spotify.rst @@ -110,19 +100,16 @@ Plugins platypush/plugins/qrcode.rst platypush/plugins/redis.rst platypush/plugins/rtorrent.rst - platypush/plugins/sensor.rst platypush/plugins/serial.rst platypush/plugins/shell.rst platypush/plugins/slack.rst platypush/plugins/smartthings.rst platypush/plugins/sound.rst platypush/plugins/ssh.rst - platypush/plugins/stt.rst platypush/plugins/stt.deepspeech.rst platypush/plugins/stt.picovoice.hotword.rst platypush/plugins/stt.picovoice.speech.rst platypush/plugins/sun.rst - platypush/plugins/switch.rst platypush/plugins/switch.tplink.rst platypush/plugins/switch.wemo.rst platypush/plugins/switchbot.rst @@ -142,7 +129,6 @@ Plugins platypush/plugins/user.rst platypush/plugins/utils.rst platypush/plugins/variable.rst - platypush/plugins/weather.rst platypush/plugins/weather.buienradar.rst platypush/plugins/weather.darksky.rst platypush/plugins/weather.openweathermap.rst @@ -151,5 +137,4 @@ Plugins platypush/plugins/zeroconf.rst platypush/plugins/zigbee.mqtt.rst platypush/plugins/zwave.rst - platypush/plugins/zwave._base.rst platypush/plugins/zwave.mqtt.rst diff --git a/generate_missing_docs.py b/generate_missing_docs.py index d302a7b8e..bce44186a 100644 --- a/generate_missing_docs.py +++ b/generate_missing_docs.py @@ -1,14 +1,27 @@ import os +from platypush.backend import Backend from platypush.context import get_plugin +from platypush.plugins import Plugin +from platypush.utils.manifest import get_manifests def get_all_plugins(): - return get_plugin('inspect').get_all_plugins().output + manifests = {mf.component_name for mf in get_manifests(Plugin)} + return { + plugin_name: plugin_info + for plugin_name, plugin_info in get_plugin('inspect').get_all_plugins().output.items() + if plugin_name in manifests + } def get_all_backends(): - return get_plugin('inspect').get_all_backends().output + manifests = {mf.component_name for mf in get_manifests(Backend)} + return { + backend_name: backend_info + for backend_name, backend_info in get_plugin('inspect').get_all_backends().output.items() + if backend_name in manifests + } def get_all_events(): diff --git a/platypush/backend/__init__.py b/platypush/backend/__init__.py index f69dcf09f..d0751fa9b 100644 --- a/platypush/backend/__init__.py +++ b/platypush/backend/__init__.py @@ -12,6 +12,7 @@ from threading import Thread, Event as ThreadEvent, get_ident from typing import Optional, Dict from platypush.bus import Bus +from platypush.common import ExtensionWithManifest from platypush.config import Config from platypush.context import get_backend from platypush.message.event.zeroconf import ZeroconfServiceAddedEvent, ZeroconfServiceRemovedEvent @@ -26,7 +27,7 @@ from platypush.message.request import Request from platypush.message.response import Response -class Backend(Thread, EventGenerator): +class Backend(Thread, EventGenerator, ExtensionWithManifest): """ Parent class for backends. @@ -53,6 +54,7 @@ class Backend(Thread, EventGenerator): self._thread_name = self.__class__.__name__ EventGenerator.__init__(self) + ExtensionWithManifest.__init__(self) Thread.__init__(self, name=self._thread_name, daemon=True) # If no bus is specified, create an internal queue where diff --git a/platypush/backend/adafruit/io.py b/platypush/backend/adafruit/io/__init__.py similarity index 90% rename from platypush/backend/adafruit/io.py rename to platypush/backend/adafruit/io/__init__.py index 478063418..a403ed868 100644 --- a/platypush/backend/adafruit/io.py +++ b/platypush/backend/adafruit/io/__init__.py @@ -1,3 +1,5 @@ +from typing import Optional + from platypush.backend import Backend from platypush.context import get_plugin from platypush.message.event.adafruit import ConnectedEvent, DisconnectedEvent, \ @@ -30,8 +32,9 @@ class AdafruitIoBackend(Backend): """ super().__init__(*args, **kwargs) + from Adafruit_IO import MQTTClient self.feeds = feeds - self._client = None + self._client: Optional[MQTTClient] = None def _init_client(self): if self._client: @@ -57,12 +60,12 @@ class AdafruitIoBackend(Backend): return _handler def on_disconnect(self): - def _handler(client): + def _handler(*_, **__): self.bus.post(DisconnectedEvent()) return _handler - def on_message(self, msg): + def on_message(self, *_, **__): # noinspection PyUnusedLocal def _handler(client, feed, data): try: @@ -83,7 +86,9 @@ class AdafruitIoBackend(Backend): while not self.should_stop(): try: self._init_client() + # noinspection PyUnresolvedReferences self._client.connect() + # noinspection PyUnresolvedReferences self._client.loop_blocking() except Exception as e: self.logger.exception(e) diff --git a/platypush/backend/adafruit/io/manifest.yaml b/platypush/backend/adafruit/io/manifest.yaml new file mode 100644 index 000000000..e019ab9cc --- /dev/null +++ b/platypush/backend/adafruit/io/manifest.yaml @@ -0,0 +1,12 @@ +manifest: + events: + platypush.message.event.adafruit.ConnectedEvent: when thebackend connects to the + Adafruit queue + platypush.message.event.adafruit.DisconnectedEvent: when thebackend disconnects + from the Adafruit queue + platypush.message.event.adafruit.FeedUpdateEvent: when anupdate event is received + on a monitored feed + install: + pip: [] + package: platypush.backend.adafruit.io + type: backend diff --git a/platypush/backend/alarm.py b/platypush/backend/alarm/__init__.py similarity index 100% rename from platypush/backend/alarm.py rename to platypush/backend/alarm/__init__.py diff --git a/platypush/backend/alarm/manifest.yaml b/platypush/backend/alarm/manifest.yaml new file mode 100644 index 000000000..51f4e0947 --- /dev/null +++ b/platypush/backend/alarm/manifest.yaml @@ -0,0 +1,10 @@ +manifest: + events: + platypush.message.event.alarm.AlarmDismissedEvent: when an alarm is dismissed. + platypush.message.event.alarm.AlarmSnoozedEvent: when an alarm is snoozed. + platypush.message.event.alarm.AlarmStartedEvent: when an alarm starts. + platypush.message.event.alarm.AlarmTimeoutEvent: when an alarm times out. + install: + pip: [] + package: platypush.backend.alarm + type: backend diff --git a/platypush/backend/assistant/__init__.py b/platypush/backend/assistant/__init__.py index 0d7aa308c..37589fd92 100644 --- a/platypush/backend/assistant/__init__.py +++ b/platypush/backend/assistant/__init__.py @@ -1,3 +1,4 @@ +from abc import ABC import threading from typing import Optional, Dict, Any, Tuple diff --git a/platypush/backend/assistant/google.py b/platypush/backend/assistant/google/__init__.py similarity index 100% rename from platypush/backend/assistant/google.py rename to platypush/backend/assistant/google/__init__.py diff --git a/platypush/backend/assistant/google/manifest.yaml b/platypush/backend/assistant/google/manifest.yaml new file mode 100644 index 000000000..1668b511c --- /dev/null +++ b/platypush/backend/assistant/google/manifest.yaml @@ -0,0 +1,26 @@ +manifest: + events: + platypush.message.event.assistant.AlarmEndEvent: when an alarm ends + platypush.message.event.assistant.AlarmStartedEvent: when an alarm starts + platypush.message.event.assistant.ConversationEndEvent: when a new conversation + ends + platypush.message.event.assistant.ConversationStartEvent: when a new conversation + starts + platypush.message.event.assistant.ConversationTimeoutEvent: when a conversation + times out + platypush.message.event.assistant.MicMutedEvent: when the microphone is muted. + platypush.message.event.assistant.MicUnmutedEvent: when the microphone is un-muted. + platypush.message.event.assistant.NoResponse: when a conversation returned no + response + platypush.message.event.assistant.ResponseEvent: when the assistant is speaking + a response + platypush.message.event.assistant.SpeechRecognizedEvent: when a new voice command + is recognized + platypush.message.event.assistant.TimerEndEvent: when a timer ends + platypush.message.event.assistant.TimerStartedEvent: when a timer starts + install: + pip: + - google-assistant-library + - google-assistant-sdk[samples] + package: platypush.backend.assistant.google + type: backend diff --git a/platypush/backend/assistant/snowboy/manifest.yaml b/platypush/backend/assistant/snowboy/manifest.yaml new file mode 100644 index 000000000..1a3fcebcd --- /dev/null +++ b/platypush/backend/assistant/snowboy/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: + platypush.message.event.assistant.HotwordDetectedEvent: whenever the hotword has + been detected + install: + pip: + - snowboy + package: platypush.backend.assistant.snowboy + type: backend diff --git a/platypush/backend/bluetooth/__init__.py b/platypush/backend/bluetooth/__init__.py index 4e67b955d..f62bdd4ce 100644 --- a/platypush/backend/bluetooth/__init__.py +++ b/platypush/backend/bluetooth/__init__.py @@ -83,7 +83,7 @@ class BluetoothBackend(Backend, Server): self.connect(connection, request) self.bus.post(BluetoothDeviceConnectedEvent(address=address[0], port=address[1])) elif isinstance(request, requests.Disconnect): - self.disconnect(connection) + self.disconnect(connection, request) self.bus.post(BluetoothDeviceDisconnectedEvent(address=address[0], port=address[1])) elif isinstance(request, requests.Put): self.bus.post(BluetoothFilePutRequestEvent(address=address[0], port=address[1])) diff --git a/platypush/backend/bluetooth/fileserver.py b/platypush/backend/bluetooth/fileserver/__init__.py similarity index 100% rename from platypush/backend/bluetooth/fileserver.py rename to platypush/backend/bluetooth/fileserver/__init__.py diff --git a/platypush/backend/bluetooth/fileserver/manifest.yaml b/platypush/backend/bluetooth/fileserver/manifest.yaml new file mode 100644 index 000000000..c47aa8560 --- /dev/null +++ b/platypush/backend/bluetooth/fileserver/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - pybluez + - pyobex + package: platypush.backend.bluetooth.fileserver + type: backend diff --git a/platypush/backend/bluetooth/pushserver.py b/platypush/backend/bluetooth/pushserver/__init__.py similarity index 100% rename from platypush/backend/bluetooth/pushserver.py rename to platypush/backend/bluetooth/pushserver/__init__.py diff --git a/platypush/backend/bluetooth/pushserver/manifest.yaml b/platypush/backend/bluetooth/pushserver/manifest.yaml new file mode 100644 index 000000000..4e5ef6313 --- /dev/null +++ b/platypush/backend/bluetooth/pushserver/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - pybluez + - pyobex + package: platypush.backend.bluetooth.pushserver + type: backend diff --git a/platypush/backend/bluetooth/scanner/ble.py b/platypush/backend/bluetooth/scanner/ble/__init__.py similarity index 100% rename from platypush/backend/bluetooth/scanner/ble.py rename to platypush/backend/bluetooth/scanner/ble/__init__.py diff --git a/platypush/backend/bluetooth/scanner/ble/manifest.yaml b/platypush/backend/bluetooth/scanner/ble/manifest.yaml new file mode 100644 index 000000000..65be3ca9b --- /dev/null +++ b/platypush/backend/bluetooth/scanner/ble/manifest.yaml @@ -0,0 +1,10 @@ +manifest: + events: + platypush.message.event.bluetooth.BluetoothDeviceFoundEvent: when a new bluetooth + device is found. + platypush.message.event.bluetooth.BluetoothDeviceLostEvent: when a bluetooth device + is lost. + install: + pip: [] + package: platypush.backend.bluetooth.scanner.ble + type: backend diff --git a/platypush/backend/bluetooth/scanner/manifest.yaml b/platypush/backend/bluetooth/scanner/manifest.yaml new file mode 100644 index 000000000..1a3c6c852 --- /dev/null +++ b/platypush/backend/bluetooth/scanner/manifest.yaml @@ -0,0 +1,10 @@ +manifest: + events: + platypush.message.event.bluetooth.BluetoothDeviceFoundEvent: when a new bluetooth + device is found. + platypush.message.event.bluetooth.BluetoothDeviceLostEvent: when a bluetooth device + is lost. + install: + pip: [] + package: platypush.backend.bluetooth.scanner + type: backend diff --git a/platypush/backend/button/flic/__init__.py b/platypush/backend/button/flic/__init__.py index bf9f1f670..3e9ef4d1e 100644 --- a/platypush/backend/button/flic/__init__.py +++ b/platypush/backend/button/flic/__init__.py @@ -1,6 +1,3 @@ -import importlib - -from enum import Enum from threading import Timer from time import time @@ -17,11 +14,14 @@ class ButtonFlicBackend(Backend): Triggers: - * :class:`platypush.message.event.button.flic.FlicButtonEvent` when a button is pressed. The event will also contain the press sequence (e.g. ``["ShortPressEvent", "LongPressEvent", "ShortPressEvent"]``) + * :class:`platypush.message.event.button.flic.FlicButtonEvent` when a button is pressed. + The event will also contain the press sequence + (e.g. ``["ShortPressEvent", "LongPressEvent", "ShortPressEvent"]``) Requires: * **fliclib** (https://github.com/50ButtonsEach/fliclib-linux-hci). For the backend to work properly you need to have the ``flicd`` daemon from the fliclib running, and you have to first pair the buttons with your device using any of the scanners provided by the library. + """ _long_press_timeout = 0.3 @@ -87,6 +87,7 @@ class ButtonFlicBackend(Backend): return _f def _on_event(self): + # noinspection PyUnusedLocal def _f(bd_addr, channel, click_type, was_queued, time_diff): if was_queued: return diff --git a/platypush/backend/button/flic/fliclib/aioflic.py b/platypush/backend/button/flic/fliclib/aioflic.py index 424fd11a8..9099c0f11 100644 --- a/platypush/backend/button/flic/fliclib/aioflic.py +++ b/platypush/backend/button/flic/fliclib/aioflic.py @@ -15,6 +15,7 @@ from enum import Enum from collections import namedtuple import struct import itertools +import threading class CreateConnectionChannelError(Enum): diff --git a/platypush/backend/button/flic/manifest.yaml b/platypush/backend/button/flic/manifest.yaml new file mode 100644 index 000000000..b95026b9e --- /dev/null +++ b/platypush/backend/button/flic/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: + platypush.message.event.button.flic.FlicButtonEvent: when a button is pressed.The + event will also contain the press sequence(e.g. ``["ShortPressEvent", "LongPressEvent", + "ShortPressEvent"]``) + install: + pip: [] + package: platypush.backend.button.flic + type: backend diff --git a/platypush/backend/camera/pi.py b/platypush/backend/camera/pi/__init__.py similarity index 98% rename from platypush/backend/camera/pi.py rename to platypush/backend/camera/pi/__init__.py index c68a94a63..87e8ec534 100644 --- a/platypush/backend/camera/pi.py +++ b/platypush/backend/camera/pi/__init__.py @@ -18,7 +18,6 @@ class CameraPiBackend(Backend): Requires: * **picamera** (``pip install picamera``) - * **redis** (``pip install redis``) for inter-process communication with the camera process This backend is **DEPRECATED**. Use the plugin :class:`platypush.plugins.camera.pi.CameraPiPlugin` instead to run Pi camera actions. If you want to start streaming the camera on application start then simply create an event hook diff --git a/platypush/backend/camera/pi/manifest.yaml b/platypush/backend/camera/pi/manifest.yaml new file mode 100644 index 000000000..b48cf3c6a --- /dev/null +++ b/platypush/backend/camera/pi/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - picamera + package: platypush.backend.camera.pi + type: backend diff --git a/platypush/backend/chat/telegram.py b/platypush/backend/chat/telegram/__init__.py similarity index 100% rename from platypush/backend/chat/telegram.py rename to platypush/backend/chat/telegram/__init__.py diff --git a/platypush/backend/chat/telegram/manifest.yaml b/platypush/backend/chat/telegram/manifest.yaml new file mode 100644 index 000000000..5d8d7ac2f --- /dev/null +++ b/platypush/backend/chat/telegram/manifest.yaml @@ -0,0 +1,19 @@ +manifest: + events: + platypush.message.event.chat.telegram.CommandMessageEvent: when a command message + is received. + platypush.message.event.chat.telegram.ContactMessageEvent: when a contact is received. + platypush.message.event.chat.telegram.DocumentMessageEvent: when a document is + received. + platypush.message.event.chat.telegram.GroupCreatedEvent: when the bot is invited + to a new group. + platypush.message.event.chat.telegram.LocationMessageEvent: when a location is + received. + platypush.message.event.chat.telegram.PhotoMessageEvent: when a photo is received. + platypush.message.event.chat.telegram.TextMessageEvent: when a text message is + received. + platypush.message.event.chat.telegram.VideoMessageEvent: when a video is received. + install: + pip: [] + package: platypush.backend.chat.telegram + type: backend diff --git a/platypush/backend/clipboard.py b/platypush/backend/clipboard/__init__.py similarity index 100% rename from platypush/backend/clipboard.py rename to platypush/backend/clipboard/__init__.py diff --git a/platypush/backend/clipboard/manifest.yaml b/platypush/backend/clipboard/manifest.yaml new file mode 100644 index 000000000..03eeb516d --- /dev/null +++ b/platypush/backend/clipboard/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.clipboard.ClipboardEvent: on clipboard update. + install: + pip: + - pyperclip + package: platypush.backend.clipboard + type: backend diff --git a/platypush/backend/covid19.py b/platypush/backend/covid19/__init__.py similarity index 100% rename from platypush/backend/covid19.py rename to platypush/backend/covid19/__init__.py diff --git a/platypush/backend/covid19/manifest.yaml b/platypush/backend/covid19/manifest.yaml new file mode 100644 index 000000000..e92909316 --- /dev/null +++ b/platypush/backend/covid19/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: + platypush.message.event.covid19.Covid19UpdateEvent: when new data is available. + install: + pip: [] + package: platypush.backend.covid19 + type: backend diff --git a/platypush/backend/dbus.py b/platypush/backend/dbus/__init__.py similarity index 100% rename from platypush/backend/dbus.py rename to platypush/backend/dbus/__init__.py diff --git a/platypush/backend/dbus/manifest.yaml b/platypush/backend/dbus/manifest.yaml new file mode 100644 index 000000000..0872acd93 --- /dev/null +++ b/platypush/backend/dbus/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - dbus-python + package: platypush.backend.dbus + type: backend diff --git a/platypush/backend/file/monitor/manifest.yaml b/platypush/backend/file/monitor/manifest.yaml new file mode 100644 index 000000000..92b066d18 --- /dev/null +++ b/platypush/backend/file/monitor/manifest.yaml @@ -0,0 +1,10 @@ +manifest: + events: + platypush.message.event.file.FileSystemCreateEvent: if a resource is created. + platypush.message.event.file.FileSystemDeleteEvent: if a resource is removed. + platypush.message.event.file.FileSystemModifyEvent: if a resource is modified. + install: + pip: + - watchdog + package: platypush.backend.file.monitor + type: backend diff --git a/platypush/backend/foursquare.py b/platypush/backend/foursquare/__init__.py similarity index 100% rename from platypush/backend/foursquare.py rename to platypush/backend/foursquare/__init__.py diff --git a/platypush/backend/foursquare/manifest.yaml b/platypush/backend/foursquare/manifest.yaml new file mode 100644 index 000000000..0690cc930 --- /dev/null +++ b/platypush/backend/foursquare/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.foursquare.FoursquareCheckinEvent: when a new check-in + occurs. + install: + pip: [] + package: platypush.backend.foursquare + type: backend diff --git a/platypush/backend/github.py b/platypush/backend/github/__init__.py similarity index 100% rename from platypush/backend/github.py rename to platypush/backend/github/__init__.py diff --git a/platypush/backend/github/manifest.yaml b/platypush/backend/github/manifest.yaml new file mode 100644 index 000000000..18eced00d --- /dev/null +++ b/platypush/backend/github/manifest.yaml @@ -0,0 +1,32 @@ +manifest: + events: + platypush.message.event.github.GithubCommitCommentEvent: when a new commit comment + is created. + platypush.message.event.github.GithubCreateEvent: when a tag or branch is created. + platypush.message.event.github.GithubDeleteEvent: when a tag or branch is deleted. + platypush.message.event.github.GithubEvent: for any event that doesn't fall in + the above categories(``event_type`` will be set accordingly). + platypush.message.event.github.GithubForkEvent: when a user forks a repository. + platypush.message.event.github.GithubIssueCommentEvent: when new activity happens + on an issue comment. + platypush.message.event.github.GithubIssueEvent: when new repository issue activity + happens. + platypush.message.event.github.GithubMemberEvent: when new repository collaborators + activity happens. + platypush.message.event.github.GithubPublicEvent: when a repository goes public. + platypush.message.event.github.GithubPullRequestEvent: when new pull request related + activity happens. + platypush.message.event.github.GithubPullRequestReviewCommentEvent: when activity + happens on a pullrequest commit. + platypush.message.event.github.GithubPushEvent: when a new push is created. + platypush.message.event.github.GithubReleaseEvent: when a new release happens. + platypush.message.event.github.GithubSponsorshipEvent: when new sponsorship related + activity happens. + platypush.message.event.github.GithubWatchEvent: when someone stars/starts watching + a repository. + platypush.message.event.github.GithubWikiEvent: when new activity happens on a + repository wiki. + install: + pip: [] + package: platypush.backend.github + type: backend diff --git a/platypush/backend/google/fit.py b/platypush/backend/google/fit/__init__.py similarity index 100% rename from platypush/backend/google/fit.py rename to platypush/backend/google/fit/__init__.py diff --git a/platypush/backend/google/fit/manifest.yaml b/platypush/backend/google/fit/manifest.yaml new file mode 100644 index 000000000..7a5b3ef0e --- /dev/null +++ b/platypush/backend/google/fit/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.google.fit.GoogleFitEvent: when a newdata point is received + on one of the registered streams. + install: + pip: [] + package: platypush.backend.google.fit + type: backend diff --git a/platypush/backend/google/pubsub.py b/platypush/backend/google/pubsub/__init__.py similarity index 100% rename from platypush/backend/google/pubsub.py rename to platypush/backend/google/pubsub/__init__.py diff --git a/platypush/backend/google/pubsub/manifest.yaml b/platypush/backend/google/pubsub/manifest.yaml new file mode 100644 index 000000000..c7fd5c41d --- /dev/null +++ b/platypush/backend/google/pubsub/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: + platypush.message.event.google.pubsub.GooglePubsubMessageEvent: when a new message + is received ona subscribed topic. + install: + pip: + - google-cloud-pubsub + package: platypush.backend.google.pubsub + type: backend diff --git a/platypush/backend/gps.py b/platypush/backend/gps/__init__.py similarity index 100% rename from platypush/backend/gps.py rename to platypush/backend/gps/__init__.py diff --git a/platypush/backend/gps/manifest.yaml b/platypush/backend/gps/manifest.yaml new file mode 100644 index 000000000..f4d1dedf5 --- /dev/null +++ b/platypush/backend/gps/manifest.yaml @@ -0,0 +1,16 @@ +manifest: + events: + platypush.message.event.gps.GPSDeviceEvent: when a GPS device is connected or + updated + platypush.message.event.gps.GPSUpdateEvent: when a GPS device has new data + platypush.message.event.gps.GPSVersionEvent: when a GPS device advertises its + version data + install: + pip: + - gps + pacman: + - gpsd + apt: + - gpsd + package: platypush.backend.gps + type: backend diff --git a/platypush/backend/http/__init__.py b/platypush/backend/http/__init__.py index c898ab20e..27336cfbe 100644 --- a/platypush/backend/http/__init__.py +++ b/platypush/backend/http/__init__.py @@ -4,6 +4,11 @@ import threading from multiprocessing import Process +try: + from websockets.exceptions import ConnectionClosed +except ImportError: + from websockets import ConnectionClosed + from platypush.backend import Backend from platypush.backend.http.app import application from platypush.context import get_or_create_event_loop @@ -146,9 +151,7 @@ class HttpBackend(Backend): Requires: * **flask** (``pip install flask``) - * **redis** (``pip install redis``) - * **websockets** (``pip install websockets``) - * **python-dateutil** (``pip install python-dateutil``) + * **bcrypt** (``pip install bcrypt``) * **magic** (``pip install python-magic``), optional, for MIME type support if you want to enable media streaming * **uwsgi** (``pip install uwsgi`` plus uwsgi server installed on your @@ -328,8 +331,6 @@ class HttpBackend(Backend): def notify_web_clients(self, event): """ Notify all the connected web clients (over websocket) of a new event """ - import websockets - async def send_event(ws): try: self._acquire_websocket_lock(ws) @@ -345,7 +346,7 @@ class HttpBackend(Backend): for _ws in wss: try: loop.run_until_complete(send_event(_ws)) - except websockets.exceptions.ConnectionClosed: + except ConnectionClosed: self.logger.warning('Websocket client {} connection lost'.format(_ws.remote_address)) self.active_websockets.remove(_ws) if _ws.remote_address in self._websocket_locks: @@ -365,7 +366,7 @@ class HttpBackend(Backend): try: await websocket.recv() - except websockets.exceptions.ConnectionClosed: + except ConnectionClosed: self.logger.info('Websocket client {} closed connection'.format(address)) self.active_websockets.remove(websocket) if address in self._websocket_locks: diff --git a/platypush/backend/http/app/routes/plugins/camera/ir/mlx90640.py b/platypush/backend/http/app/routes/plugins/camera/ir/mlx90640.py index 9dce0a446..eada98492 100644 --- a/platypush/backend/http/app/routes/plugins/camera/ir/mlx90640.py +++ b/platypush/backend/http/app/routes/plugins/camera/ir/mlx90640.py @@ -4,7 +4,7 @@ from platypush.backend.http.app import template_folder from platypush.backend.http.app.routes.plugins.camera import get_photo, get_video from platypush.backend.http.app.utils import authenticate -camera_ir_mlx90640 = Blueprint('camera.ir.mlx90640', __name__, template_folder=template_folder) +camera_ir_mlx90640 = Blueprint('camera-ir-mlx90640', __name__, template_folder=template_folder) # Declare routes list __routes__ = [ diff --git a/platypush/backend/http/app/routes/plugins/camera/pi.py b/platypush/backend/http/app/routes/plugins/camera/pi.py index aff9405e6..0e3c2234d 100644 --- a/platypush/backend/http/app/routes/plugins/camera/pi.py +++ b/platypush/backend/http/app/routes/plugins/camera/pi.py @@ -8,7 +8,7 @@ from platypush.backend.http.app.utils import authenticate, send_request from platypush.config import Config from platypush.plugins.camera.pi import CameraPiPlugin -camera_pi = Blueprint('camera.pi', __name__, template_folder=template_folder) +camera_pi = Blueprint('camera-pi', __name__, template_folder=template_folder) # Declare routes list __routes__ = [ diff --git a/platypush/backend/http/app/routes/plugins/media/__init__.py b/platypush/backend/http/app/routes/plugins/media/__init__.py index d160af40e..67d82ca61 100644 --- a/platypush/backend/http/app/routes/plugins/media/__init__.py +++ b/platypush/backend/http/app/routes/plugins/media/__init__.py @@ -2,7 +2,7 @@ import hashlib import json import threading -from flask import Response, render_template +from flask import Response from platypush.backend.http.app.utils import get_remote_base_url, logger, \ send_message diff --git a/platypush/backend/http/manifest.yaml b/platypush/backend/http/manifest.yaml new file mode 100644 index 000000000..5215fbd33 --- /dev/null +++ b/platypush/backend/http/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: {} + install: + pip: + - flask + - bcrypt + - python-magic + package: platypush.backend.http + type: backend diff --git a/platypush/backend/http/media/handlers/__init__.py b/platypush/backend/http/media/handlers/__init__.py index 8c1f05e83..f6e8b8e32 100644 --- a/platypush/backend/http/media/handlers/__init__.py +++ b/platypush/backend/http/media/handlers/__init__.py @@ -1,5 +1,6 @@ import logging + class MediaHandler: """ Abstract class to manage media handlers that can be streamed over the HTTP @@ -57,7 +58,7 @@ class MediaHandler: for attr in ['name', 'source', 'mime_type', 'url', 'subtitles', 'prefix_handlers', 'media_id']: if hasattr(self, attr): - yield (attr, getattr(self, attr)) + yield attr, getattr(self, attr) from .file import FileHandler diff --git a/platypush/backend/http/poll/__init__.py b/platypush/backend/http/poll/__init__.py index facef9a83..2c39678c9 100644 --- a/platypush/backend/http/poll/__init__.py +++ b/platypush/backend/http/poll/__init__.py @@ -34,7 +34,7 @@ class HttpPollBackend(Backend): - # Poll for updates on an RSS feed type: platypush.backend.http.request.rss.RssUpdates - url: http://www.theguardian.com/rss/world + url: https://www.theguardian.com/rss/world title: The Guardian - World News poll_seconds: 120 max_entries: 10 diff --git a/platypush/backend/http/poll/manifest.yaml b/platypush/backend/http/poll/manifest.yaml new file mode 100644 index 000000000..fb5b0a2d3 --- /dev/null +++ b/platypush/backend/http/poll/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.backend.http.poll + type: backend diff --git a/platypush/backend/http/request/ota/__init__.py b/platypush/backend/http/request/ota/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/platypush/backend/http/request/ota/booking/__init__.py b/platypush/backend/http/request/ota/booking/__init__.py deleted file mode 100644 index ea92e5455..000000000 --- a/platypush/backend/http/request/ota/booking/__init__.py +++ /dev/null @@ -1,48 +0,0 @@ -import datetime -import dateutil.parser -import json - -from platypush.backend.http.request import JsonHttpRequest -from platypush.message.event.http.ota.booking import NewReservationEvent - - -class GetReservationUpdates(JsonHttpRequest): - """ Gets the reservation updates """ - def __init__(self, hotel_id, token, *args, **kwargs): - self.hotel_id = hotel_id - self.token = token - self.seen_entries = set() - self.last_update = None - - args = { - 'method': 'get', - 'url': 'https://hub-api.booking.com/v1/hotels/{}/reservations'.format(self.hotel_id), - 'headers': { 'X-Booking-Auth-Token': self.token }, - 'params': { 'updatedSince': datetime.date.today().isoformat() } - } - - super().__init__(args=args, **kwargs) - - - def get_new_items(self, response): - response = response.json() - entries = [] - - for entry in response: - update_timestamp = dateutil.parser.parse(entry['updateDate']) - last_update_timestamp = dateutil.parser.parse(self.last_update['updateDate']) \ - if self.last_update else None - - if self.last_update is None \ - or (update_timestamp > last_update_timestamp - and not ( - entry['booker']['email'] == self.last_update['booker']['email'] - and entry['status'] == self.last_update['status'])): - self.last_update = entry - entries.append(entry) - - return NewReservationEvent(dict(self), entries) - - -# vim:sw=4:ts=4:et: - diff --git a/platypush/backend/http/request/rss/__init__.py b/platypush/backend/http/request/rss/__init__.py index 276d8cf01..b16565dc5 100644 --- a/platypush/backend/http/request/rss/__init__.py +++ b/platypush/backend/http/request/rss/__init__.py @@ -239,7 +239,10 @@ class RssUpdates(HttpRequest): f.write(content) elif self.digest_format == 'pdf': from weasyprint import HTML, CSS - from weasyprint.fonts import FontConfiguration + try: + from weasyprint.fonts import FontConfiguration + except ImportError: + from weasyprint.document import FontConfiguration body_style = 'body { ' + self.body_style + ' }' font_config = FontConfiguration() diff --git a/platypush/backend/inotify.py b/platypush/backend/inotify/__init__.py similarity index 100% rename from platypush/backend/inotify.py rename to platypush/backend/inotify/__init__.py diff --git a/platypush/backend/inotify/manifest.yaml b/platypush/backend/inotify/manifest.yaml new file mode 100644 index 000000000..d25b42472 --- /dev/null +++ b/platypush/backend/inotify/manifest.yaml @@ -0,0 +1,15 @@ +manifest: + events: + platypush.message.event.inotify.InotifyAccessEvent: if a resource is accessed + platypush.message.event.inotify.InotifyCloseEvent: if a resource is closed + platypush.message.event.inotify.InotifyCreateEvent: if a resource is created + platypush.message.event.inotify.InotifyDeleteEvent: if a resource is removed + platypush.message.event.inotify.InotifyModifyEvent: if a resource is modified + platypush.message.event.inotify.InotifyOpenEvent: if a resource is opened + platypush.message.event.inotify.InotifyPermissionsChangeEvent: if the permissions + of a resource are changed + install: + pip: + - inotify + package: platypush.backend.inotify + type: backend diff --git a/platypush/backend/joystick/jstest.py b/platypush/backend/joystick/jstest/__init__.py similarity index 100% rename from platypush/backend/joystick/jstest.py rename to platypush/backend/joystick/jstest/__init__.py diff --git a/platypush/backend/joystick/jstest/manifest.yaml b/platypush/backend/joystick/jstest/manifest.yaml new file mode 100644 index 000000000..8e97424b1 --- /dev/null +++ b/platypush/backend/joystick/jstest/manifest.yaml @@ -0,0 +1,21 @@ +manifest: + events: + platypush.message.event.joystick.JoystickAxisEvent: when an axis value of the + joystick changes. + platypush.message.event.joystick.JoystickButtonPressedEvent: when a joystick button + is pressed. + platypush.message.event.joystick.JoystickButtonReleasedEvent: when a joystick + button is released. + platypush.message.event.joystick.JoystickConnectedEvent: when the joystick is + connected. + platypush.message.event.joystick.JoystickDisconnectedEvent: when the joystick + is disconnected. + platypush.message.event.joystick.JoystickStateEvent: when the state of the joystick + (i.e. some of itsaxes or buttons values) changes. + install: + apt: + - joystick + pacman: + - jsutils + package: platypush.backend.joystick.jstest + type: backend diff --git a/platypush/backend/joystick/linux.py b/platypush/backend/joystick/linux/__init__.py similarity index 100% rename from platypush/backend/joystick/linux.py rename to platypush/backend/joystick/linux/__init__.py diff --git a/platypush/backend/joystick/linux/manifest.yaml b/platypush/backend/joystick/linux/manifest.yaml new file mode 100644 index 000000000..227b328a5 --- /dev/null +++ b/platypush/backend/joystick/linux/manifest.yaml @@ -0,0 +1,16 @@ +manifest: + events: + platypush.message.event.joystick.JoystickAxisEvent: when an axis value of the + joystick changes. + platypush.message.event.joystick.JoystickButtonPressedEvent: when a joystick button + is pressed. + platypush.message.event.joystick.JoystickButtonReleasedEvent: when a joystick + button is released. + platypush.message.event.joystick.JoystickConnectedEvent: when the joystick is + connected. + platypush.message.event.joystick.JoystickDisconnectedEvent: when the joystick + is disconnected. + install: + pip: [] + package: platypush.backend.joystick.linux + type: backend diff --git a/platypush/backend/joystick/manifest.yaml b/platypush/backend/joystick/manifest.yaml new file mode 100644 index 000000000..c3fb77fe5 --- /dev/null +++ b/platypush/backend/joystick/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.joystick.JoystickEvent: when a new joystick event is received + install: + pip: + - inputs + package: platypush.backend.joystick + type: backend diff --git a/platypush/backend/kafka/__init__.py b/platypush/backend/kafka/__init__.py index 050d39e68..bd4af2c9d 100644 --- a/platypush/backend/kafka/__init__.py +++ b/platypush/backend/kafka/__init__.py @@ -1,4 +1,3 @@ -import json import logging import time diff --git a/platypush/backend/kafka/manifest.yaml b/platypush/backend/kafka/manifest.yaml new file mode 100644 index 000000000..e836bf917 --- /dev/null +++ b/platypush/backend/kafka/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - kafka + package: platypush.backend.kafka + type: backend diff --git a/platypush/backend/light/hue.py b/platypush/backend/light/hue/__init__.py similarity index 100% rename from platypush/backend/light/hue.py rename to platypush/backend/light/hue/__init__.py diff --git a/platypush/backend/light/hue/manifest.yaml b/platypush/backend/light/hue/manifest.yaml new file mode 100644 index 000000000..5d5e4ed03 --- /dev/null +++ b/platypush/backend/light/hue/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.light.LightStatusChangeEvent: when thestatus of a lightbulb + changes + install: + pip: [] + package: platypush.backend.light.hue + type: backend diff --git a/platypush/backend/linode.py b/platypush/backend/linode/__init__.py similarity index 100% rename from platypush/backend/linode.py rename to platypush/backend/linode/__init__.py diff --git a/platypush/backend/linode/manifest.yaml b/platypush/backend/linode/manifest.yaml new file mode 100644 index 000000000..8777eb55f --- /dev/null +++ b/platypush/backend/linode/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.linode.LinodeInstanceStatusChanged: when the status of + an instance changes. + install: + pip: [] + package: platypush.backend.linode + type: backend diff --git a/platypush/backend/log/http.py b/platypush/backend/log/http/__init__.py similarity index 100% rename from platypush/backend/log/http.py rename to platypush/backend/log/http/__init__.py diff --git a/platypush/backend/log/http/manifest.yaml b/platypush/backend/log/http/manifest.yaml new file mode 100644 index 000000000..ddf01ec19 --- /dev/null +++ b/platypush/backend/log/http/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.log.http.HttpLogEvent: when a new log line is created. + install: + pip: + - watchdog + package: platypush.backend.log.http + type: backend diff --git a/platypush/backend/mail.py b/platypush/backend/mail/__init__.py similarity index 100% rename from platypush/backend/mail.py rename to platypush/backend/mail/__init__.py diff --git a/platypush/backend/mail/manifest.yaml b/platypush/backend/mail/manifest.yaml new file mode 100644 index 000000000..a471c6649 --- /dev/null +++ b/platypush/backend/mail/manifest.yaml @@ -0,0 +1,10 @@ +manifest: + events: + platypush.message.event.mail.MailFlaggedEvent: when a message is marked as flagged/starred. + platypush.message.event.mail.MailReceivedEvent: when a new message is received. + platypush.message.event.mail.MailSeenEvent: when a message is marked as seen. + platypush.message.event.mail.MailUnflaggedEvent: when a message is marked as unflagged/unstarred. + install: + pip: [] + package: platypush.backend.mail + type: backend diff --git a/platypush/backend/midi.py b/platypush/backend/midi/__init__.py similarity index 98% rename from platypush/backend/midi.py rename to platypush/backend/midi/__init__.py index 13551814f..30db06ac0 100644 --- a/platypush/backend/midi.py +++ b/platypush/backend/midi/__init__.py @@ -120,7 +120,7 @@ class MidiBackend(Backend): self.logger.exception(e) if self.midi: - self.midi.close_port(self.port_number) + self.midi.close_port() self.midi = None diff --git a/platypush/backend/midi/manifest.yaml b/platypush/backend/midi/manifest.yaml new file mode 100644 index 000000000..246262ab7 --- /dev/null +++ b/platypush/backend/midi/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.midi.MidiMessageEvent: when a new MIDI event is received + install: + pip: + - rtmidi + package: platypush.backend.midi + type: backend diff --git a/platypush/backend/mqtt.py b/platypush/backend/mqtt/__init__.py similarity index 100% rename from platypush/backend/mqtt.py rename to platypush/backend/mqtt/__init__.py diff --git a/platypush/backend/mqtt/manifest.yaml b/platypush/backend/mqtt/manifest.yaml new file mode 100644 index 000000000..d2bc08f49 --- /dev/null +++ b/platypush/backend/mqtt/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: + platypush.message.event.mqtt.MQTTMessageEvent: when a newmessage is received on + one of the custom listeners + install: + pip: + - paho-mqtt + package: platypush.backend.mqtt + type: backend diff --git a/platypush/backend/music/mopidy.py b/platypush/backend/music/mopidy/__init__.py similarity index 98% rename from platypush/backend/music/mopidy.py rename to platypush/backend/music/mopidy/__init__.py index f31905b5e..0448038af 100644 --- a/platypush/backend/music/mopidy.py +++ b/platypush/backend/music/mopidy/__init__.py @@ -2,6 +2,8 @@ import json import re import threading +import websocket + from platypush.backend import Backend from platypush.message.event.music import MusicPlayEvent, MusicPauseEvent, \ MusicStopEvent, NewPlayingTrackEvent, PlaylistChangeEvent, VolumeChangeEvent, \ @@ -32,7 +34,7 @@ class MusicMopidyBackend(Backend): * :class:`platypush.message.event.music.SeekChangeEvent` if a track seek event occurs Requires: - * **websocket-client** (``pip install websocket-client``) + * Mopidy installed and the HTTP service enabled """ @@ -88,7 +90,6 @@ class MusicMopidyBackend(Backend): return conv_track def _communicate(self, msg): - import websocket if isinstance(msg, str): msg = json.loads(msg) @@ -242,8 +243,6 @@ class MusicMopidyBackend(Backend): return hndl def _connect(self): - import websocket - if not self._ws: self._ws = websocket.WebSocketApp(self.url, on_open=self._on_open(), diff --git a/platypush/backend/music/mopidy/manifest.yaml b/platypush/backend/music/mopidy/manifest.yaml new file mode 100644 index 000000000..c34a18da9 --- /dev/null +++ b/platypush/backend/music/mopidy/manifest.yaml @@ -0,0 +1,17 @@ +manifest: + events: + platypush.message.event.music.MusicPauseEvent: if the playback state changed to + pause + platypush.message.event.music.MusicPlayEvent: if the playback state changed to + play + platypush.message.event.music.MusicStopEvent: if the playback state changed to + stop + platypush.message.event.music.MuteChangeEvent: if the mute status has changed + platypush.message.event.music.NewPlayingTrackEvent: if a new track is being played + platypush.message.event.music.PlaylistChangeEvent: if the main playlist has changed + platypush.message.event.music.SeekChangeEvent: if a track seek event occurs + platypush.message.event.music.VolumeChangeEvent: if the main volume has changed + install: + pip: [] + package: platypush.backend.music.mopidy + type: backend diff --git a/platypush/backend/music/mpd/manifest.yaml b/platypush/backend/music/mpd/manifest.yaml new file mode 100644 index 000000000..4120bc3a9 --- /dev/null +++ b/platypush/backend/music/mpd/manifest.yaml @@ -0,0 +1,16 @@ +manifest: + events: + platypush.message.event.music.MusicPauseEvent: if the playback state changed to + pause + platypush.message.event.music.MusicPlayEvent: if the playback state changed to + play + platypush.message.event.music.MusicStopEvent: if the playback state changed to + stop + platypush.message.event.music.NewPlayingTrackEvent: if a new track is being played + platypush.message.event.music.PlaylistChangeEvent: if the main playlist has changed + platypush.message.event.music.VolumeChangeEvent: if the main volume has changed + install: + pip: + - python-mpd2 + package: platypush.backend.music.mpd + type: backend diff --git a/platypush/backend/music/snapcast.py b/platypush/backend/music/snapcast/__init__.py similarity index 100% rename from platypush/backend/music/snapcast.py rename to platypush/backend/music/snapcast/__init__.py diff --git a/platypush/backend/music/snapcast/manifest.yaml b/platypush/backend/music/snapcast/manifest.yaml new file mode 100644 index 000000000..509f12568 --- /dev/null +++ b/platypush/backend/music/snapcast/manifest.yaml @@ -0,0 +1,15 @@ +manifest: + events: + platypush.message.event.music.snapcast.ClientConnectedEvent: '' + platypush.message.event.music.snapcast.ClientDisconnectedEvent: '' + platypush.message.event.music.snapcast.ClientLatencyChangeEvent: '' + platypush.message.event.music.snapcast.ClientNameChangeEvent: '' + platypush.message.event.music.snapcast.ClientVolumeChangeEvent: '' + platypush.message.event.music.snapcast.GroupMuteChangeEvent: '' + platypush.message.event.music.snapcast.GroupStreamChangeEvent: '' + platypush.message.event.music.snapcast.ServerUpdateEvent: '' + platypush.message.event.music.snapcast.StreamUpdateEvent: '' + install: + pip: [] + package: platypush.backend.music.snapcast + type: backend diff --git a/platypush/backend/music/spotify/manifest.yaml b/platypush/backend/music/spotify/manifest.yaml new file mode 100644 index 000000000..8fd3f3944 --- /dev/null +++ b/platypush/backend/music/spotify/manifest.yaml @@ -0,0 +1,21 @@ +manifest: + events: + platypush.message.event.music.MusicPauseEvent: if the playback state changed to + pause + platypush.message.event.music.MusicPlayEvent: if the playback state changed to + play + platypush.message.event.music.MusicStopEvent: if the playback state changed to + stop + platypush.message.event.music.NewPlayingTrackEvent: if a new track is being played + platypush.message.event.music.VolumeChangeEvent: if the volume changes + install: + apt: + - sudo + - cargo + pacman: + - sudo + - cargo + exec: + - sudo cargo install librespot + package: platypush.backend.music.spotify + type: backend diff --git a/platypush/backend/nextcloud.py b/platypush/backend/nextcloud/__init__.py similarity index 100% rename from platypush/backend/nextcloud.py rename to platypush/backend/nextcloud/__init__.py diff --git a/platypush/backend/nextcloud/manifest.yaml b/platypush/backend/nextcloud/manifest.yaml new file mode 100644 index 000000000..432a7a5b0 --- /dev/null +++ b/platypush/backend/nextcloud/manifest.yaml @@ -0,0 +1,10 @@ +manifest: + events: + platypush.message.event.nextcloud.NextCloudActivityEvent: 'when new activity occurs + on the instance.The field ``activity_type`` identifies the activity type (e.g. + ``file_created``, ``file_deleted``,``file_changed``). Example in the case of + the creation of new files:' + install: + pip: [] + package: platypush.backend.nextcloud + type: backend diff --git a/platypush/backend/nfc.py b/platypush/backend/nfc/__init__.py similarity index 100% rename from platypush/backend/nfc.py rename to platypush/backend/nfc/__init__.py diff --git a/platypush/backend/nfc/manifest.yaml b/platypush/backend/nfc/manifest.yaml new file mode 100644 index 000000000..90f8ef5b0 --- /dev/null +++ b/platypush/backend/nfc/manifest.yaml @@ -0,0 +1,13 @@ +manifest: + events: + platypush.message.event.nfc.NFCDeviceConnectedEvent: when an NFC reader/writer + is connected + platypush.message.event.nfc.NFCDeviceDisconnectedEvent: when an NFC reader/writer + is disconnected + platypush.message.event.nfc.NFCTagDetectedEvent: when an NFC tag is detected + platypush.message.event.nfc.NFCTagRemovedEvent: when an NFC tag is removed + install: + pip: + - ndef + package: platypush.backend.nfc + type: backend diff --git a/platypush/backend/nodered/__init__.py b/platypush/backend/nodered/__init__.py index 9c225965f..b8b4bedf2 100644 --- a/platypush/backend/nodered/__init__.py +++ b/platypush/backend/nodered/__init__.py @@ -17,6 +17,7 @@ class NoderedBackend(Backend): Requires: * **pynodered** (``pip install pynodered``) + """ def __init__(self, port: int = 5051, *args, **kwargs): diff --git a/platypush/backend/nodered/manifest.yaml b/platypush/backend/nodered/manifest.yaml new file mode 100644 index 000000000..d2d413e87 --- /dev/null +++ b/platypush/backend/nodered/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - pynodered + package: platypush.backend.nodered + type: backend diff --git a/platypush/backend/ping.py b/platypush/backend/ping/__init__.py similarity index 100% rename from platypush/backend/ping.py rename to platypush/backend/ping/__init__.py diff --git a/platypush/backend/ping/manifest.yaml b/platypush/backend/ping/manifest.yaml new file mode 100644 index 000000000..6c59f9224 --- /dev/null +++ b/platypush/backend/ping/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.ping.HostDownEvent: if a host stops responding ping requests + platypush.message.event.ping.HostUpEvent: if a host starts responding ping requests + install: + pip: [] + package: platypush.backend.ping + type: backend diff --git a/platypush/backend/pushbullet/__init__.py b/platypush/backend/pushbullet/__init__.py index f1d24941e..7d0b21b87 100644 --- a/platypush/backend/pushbullet/__init__.py +++ b/platypush/backend/pushbullet/__init__.py @@ -21,8 +21,8 @@ class PushbulletBackend(Backend): Requires: - * **requests** (``pip install requests``) - * **pushbullet.py** (``pip install git+https://github.com/rbrcsk/pushbullet.py``) + * **pushbullet.py** (``pip install git+https://github.com/pushbullet.py/pushbullet.py``) + """ def __init__(self, token: str, device: str = 'Platypush', proxy_host: Optional[str] = None, @@ -52,7 +52,7 @@ class PushbulletBackend(Backend): try: self.device = self.pb.get_device(self.device_name) except Exception as e: - self.logger.info('Device {} does not exist: {}. Creating it'.format(self.device_name, str(e))) + self.logger.info(f'Device {self.device_name} does not exist: {e}. Creating it') self.device = self.pb.new_device(self.device_name) self.pb_device_id = self.get_device_id() @@ -91,17 +91,15 @@ class PushbulletBackend(Backend): if 'body' not in push: return - self.logger.debug('Received push: {}'.format(push)) + self.logger.debug(f'Received push: {push}') body = push['body'] try: body = json.loads(body) self.on_message(body) except Exception as e: - self.logger.debug(('Unexpected message received on the ' + - 'Pushbullet backend: {}. Message: {}') - .format(str(e), body)) - + self.logger.debug('Unexpected message received on the ' + + f'Pushbullet backend: {e}. Message: {body}') except Exception as e: self.logger.exception(e) return @@ -116,9 +114,7 @@ class PushbulletBackend(Backend): device = self.pb.new_device(self.device_name, model='Platypush virtual device', manufacturer='platypush', icon='system') - self.logger.info('Created Pushbullet device {}'.format( - self.device_name)) - + self.logger.info(f'Created Pushbullet device {self.device_name}') return device.device_iden def close(self): @@ -133,27 +129,33 @@ class PushbulletBackend(Backend): self.logger.info('Pushbullet backend terminated') def on_close(self, err=None): - self.listener = None - raise RuntimeError(err or 'Connection closed') + def callback(*_): + self.listener = None + raise RuntimeError(err or 'Connection closed') + + return callback def on_open(self): - self.logger.info('Pushbullet service connected') + def callback(*_): + self.logger.info('Pushbullet service connected') + + return callback def run_listener(self): from .listener import Listener - self.logger.info('Initializing Pushbullet backend - device_id: {}'.format(self.device_name)) - self.listener = Listener(account=self.pb, on_push=self.on_push(), - on_open=self.on_open, - on_close=self.on_close, - on_error=self.on_close, + self.logger.info(f'Initializing Pushbullet backend - device_id: {self.device_name}') + self.listener = Listener(account=self.pb, + on_push=self.on_push(), + on_open=self.on_open(), + on_close=self.on_close(), + on_error=self.on_close(), http_proxy_host=self.proxy_host, http_proxy_port=self.proxy_port) self.listener.run_forever() def run(self): - # noinspection PyPackageRequirements super().run() initialized = False @@ -163,7 +165,7 @@ class PushbulletBackend(Backend): initialized = True except Exception as e: self.logger.exception(e) - self.logger.error('Pushbullet initialization error: {}'.format(str(e))) + self.logger.error(f'Pushbullet initialization error: {e}') time.sleep(10) while not self.should_stop(): @@ -175,5 +177,4 @@ class PushbulletBackend(Backend): self.logger.info('Retrying connection') - # vim:sw=4:ts=4:et: diff --git a/platypush/backend/pushbullet/manifest.yaml b/platypush/backend/pushbullet/manifest.yaml new file mode 100644 index 000000000..27f5a0f25 --- /dev/null +++ b/platypush/backend/pushbullet/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.pushbullet.PushbulletEvent: if a new push is received + install: + pip: + - git+https://github.com/rbrcsk/pushbullet.py + package: platypush.backend.pushbullet + type: backend diff --git a/platypush/backend/redis.py b/platypush/backend/redis/__init__.py similarity index 97% rename from platypush/backend/redis.py rename to platypush/backend/redis/__init__.py index 45d2a6225..d0b1e7c55 100644 --- a/platypush/backend/redis.py +++ b/platypush/backend/redis/__init__.py @@ -14,11 +14,6 @@ class RedisBackend(Backend): ``platypush_bus_mq``) and posts them to the application bus. Very useful when you have plugin whose code is executed in another process and can't post events or requests to the application bus. - - Requires: - - * **redis** (``pip install redis``) - """ def __init__(self, queue='platypush_bus_mq', redis_args=None, *args, **kwargs): diff --git a/platypush/backend/redis/manifest.yaml b/platypush/backend/redis/manifest.yaml new file mode 100644 index 000000000..dbf975b35 --- /dev/null +++ b/platypush/backend/redis/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.backend.redis + type: backend diff --git a/platypush/backend/scard/__init__.py b/platypush/backend/scard/__init__.py index e1bec4fa6..532539cf3 100644 --- a/platypush/backend/scard/__init__.py +++ b/platypush/backend/scard/__init__.py @@ -1,5 +1,3 @@ -import json - from platypush.backend import Backend from platypush.message.event.scard import SmartCardDetectedEvent, SmartCardRemovedEvent @@ -41,10 +39,15 @@ class ScardBackend(Backend): "supported types: string, list".format( atr, type(atr))) - self.cardtype = ATRCardType( *[toBytes(atr) for atr in self.ATRs] ) + self.cardtype = ATRCardType(*[self._to_bytes(atr) for atr in self.ATRs]) else: self.cardtype = AnyCardType() + @staticmethod + def _to_bytes(data) -> bytes: + if isinstance(data, str): + data = data.encode() + return data def run(self): from smartcard.CardRequest import CardRequest @@ -54,7 +57,7 @@ class ScardBackend(Backend): super().run() self.logger.info('Initialized smart card reader backend - ATR filter: {}'. - format(self.ATRs)) + format(self.ATRs)) prev_atr = None reader = None @@ -70,7 +73,7 @@ class ScardBackend(Backend): if atr != prev_atr: self.logger.info('Smart card detected on reader {}, ATR: {}'. - format(reader, atr)) + format(reader, atr)) self.bus.post(SmartCardDetectedEvent(atr=atr, reader=reader)) prev_atr = atr @@ -82,6 +85,4 @@ class ScardBackend(Backend): prev_atr = None - # vim:sw=4:ts=4:et: - diff --git a/platypush/backend/scard/manifest.yaml b/platypush/backend/scard/manifest.yaml new file mode 100644 index 000000000..3181627f7 --- /dev/null +++ b/platypush/backend/scard/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: + platypush.message.event.scard.SmartCardDetectedEvent: when a smart card is detected + platypush.message.event.scard.SmartCardRemovedEvent: when a smart card is removed + install: + pip: + - pyscard + package: platypush.backend.scard + type: backend diff --git a/platypush/backend/sensor/__init__.py b/platypush/backend/sensor/__init__.py index a7d1a08b7..0cf5beb2f 100644 --- a/platypush/backend/sensor/__init__.py +++ b/platypush/backend/sensor/__init__.py @@ -17,6 +17,7 @@ class SensorBackend(Backend): gone above a configured threshold * :class:`platypush.message.event.sensor.SensorDataBelowThresholdEvent` if the measurements of a sensor have gone below a configured threshold + """ default_tolerance = 1e-7 diff --git a/platypush/backend/sensor/accelerometer.py b/platypush/backend/sensor/accelerometer.py deleted file mode 100644 index 55125d5c2..000000000 --- a/platypush/backend/sensor/accelerometer.py +++ /dev/null @@ -1,18 +0,0 @@ -from platypush.backend.sensor import SensorBackend - - -class SensorAccelerometerBackend(SensorBackend): - """ - Backend to poll position information from an accelerometer sensor. - - Requires: - - * ``Adafruit_Python_GPIO`` (``pip install Adafruit_Python_GPIO``) - * The :mod:`platypush.plugins.gpio.sensor.accelerometer` plugin configured - """ - - def __init__(self, **kwargs): - super().__init__(plugin='gpio.sensor.accelerometer', **kwargs) - - -# vim:sw=4:ts=4:et: diff --git a/platypush/backend/sensor/accelerometer/__init__.py b/platypush/backend/sensor/accelerometer/__init__.py new file mode 100644 index 000000000..5bae1a730 --- /dev/null +++ b/platypush/backend/sensor/accelerometer/__init__.py @@ -0,0 +1,27 @@ +from platypush.backend.sensor import SensorBackend + + +class SensorAccelerometerBackend(SensorBackend): + """ + Backend to poll position information from an accelerometer sensor. + + Requires: + + * ``Adafruit-GPIO`` (``pip install Adafruit-GPIO``) + * The :mod:`platypush.plugins.gpio.sensor.accelerometer` plugin configured + + Triggers: + + * :class:`platypush.message.event.sensor.SensorDataChangeEvent` if the measurements of a sensor have changed + * :class:`platypush.message.event.sensor.SensorDataAboveThresholdEvent` if the measurements of a sensor have + gone above a configured threshold + * :class:`platypush.message.event.sensor.SensorDataBelowThresholdEvent` if the measurements of a sensor have + gone below a configured threshold + + """ + + def __init__(self, **kwargs): + super().__init__(plugin='gpio.sensor.accelerometer', **kwargs) + + +# vim:sw=4:ts=4:et: diff --git a/platypush/backend/sensor/accelerometer/manifest.yaml b/platypush/backend/sensor/accelerometer/manifest.yaml new file mode 100644 index 000000000..ea1aace28 --- /dev/null +++ b/platypush/backend/sensor/accelerometer/manifest.yaml @@ -0,0 +1,13 @@ +manifest: + events: + platypush.message.event.sensor.SensorDataAboveThresholdEvent: if the measurements + of a sensor havegone above a configured threshold + platypush.message.event.sensor.SensorDataBelowThresholdEvent: if the measurements + of a sensor havegone below a configured threshold + platypush.message.event.sensor.SensorDataChangeEvent: if the measurements of a + sensor have changed + install: + pip: + - Adafruit-GPIO + package: platypush.backend.sensor.accelerometer + type: backend diff --git a/platypush/backend/sensor/arduino.py b/platypush/backend/sensor/arduino.py deleted file mode 100644 index a89d12e43..000000000 --- a/platypush/backend/sensor/arduino.py +++ /dev/null @@ -1,18 +0,0 @@ -from platypush.backend.sensor import SensorBackend - - -class SensorArduinoBackend(SensorBackend): - """ - This backend listens for new events from an Arduino with a Firmata-compatible firmware. - - Requires: - - * The :class:`platypush.plugins.arduino.ArduinoPlugin` plugin configured. - - """ - - def __init__(self, **kwargs): - super().__init__(plugin='arduino', **kwargs) - - -# vim:sw=4:ts=4:et: diff --git a/platypush/backend/sensor/arduino/__init__.py b/platypush/backend/sensor/arduino/__init__.py new file mode 100644 index 000000000..ff37ebb61 --- /dev/null +++ b/platypush/backend/sensor/arduino/__init__.py @@ -0,0 +1,26 @@ +from platypush.backend.sensor import SensorBackend + + +class SensorArduinoBackend(SensorBackend): + """ + This backend listens for new events from an Arduino with a Firmata-compatible firmware. + + Requires: + + * The :class:`platypush.plugins.arduino.ArduinoPlugin` plugin configured. + + Triggers: + + * :class:`platypush.message.event.sensor.SensorDataChangeEvent` if the measurements of a sensor have changed + * :class:`platypush.message.event.sensor.SensorDataAboveThresholdEvent` if the measurements of a sensor have + gone above a configured threshold + * :class:`platypush.message.event.sensor.SensorDataBelowThresholdEvent` if the measurements of a sensor have + gone below a configured threshold + + """ + + def __init__(self, **kwargs): + super().__init__(plugin='arduino', **kwargs) + + +# vim:sw=4:ts=4:et: diff --git a/platypush/backend/sensor/arduino/manifest.yaml b/platypush/backend/sensor/arduino/manifest.yaml new file mode 100644 index 000000000..539966d75 --- /dev/null +++ b/platypush/backend/sensor/arduino/manifest.yaml @@ -0,0 +1,12 @@ +manifest: + events: + platypush.message.event.sensor.SensorDataAboveThresholdEvent: if the measurements + of a sensor havegone above a configured threshold + platypush.message.event.sensor.SensorDataBelowThresholdEvent: if the measurements + of a sensor havegone below a configured threshold + platypush.message.event.sensor.SensorDataChangeEvent: if the measurements of a + sensor have changed + install: + pip: [] + package: platypush.backend.sensor.arduino + type: backend diff --git a/platypush/backend/sensor/battery.py b/platypush/backend/sensor/battery/__init__.py similarity index 65% rename from platypush/backend/sensor/battery.py rename to platypush/backend/sensor/battery/__init__.py index 28226b908..11e4ff0b2 100644 --- a/platypush/backend/sensor/battery.py +++ b/platypush/backend/sensor/battery/__init__.py @@ -13,6 +13,15 @@ class SensorBatteryBackend(SensorBackend): Requires: - **psutil** (``pip install psutil``) for CPU load and stats. + + Triggers: + + * :class:`platypush.message.event.sensor.SensorDataChangeEvent` if the measurements of a sensor have changed + * :class:`platypush.message.event.sensor.SensorDataAboveThresholdEvent` if the measurements of a sensor have + gone above a configured threshold + * :class:`platypush.message.event.sensor.SensorDataBelowThresholdEvent` if the measurements of a sensor have + gone below a configured threshold + """ def __init__(self, **kwargs): diff --git a/platypush/backend/sensor/battery/manifest.yaml b/platypush/backend/sensor/battery/manifest.yaml new file mode 100644 index 000000000..d3f055334 --- /dev/null +++ b/platypush/backend/sensor/battery/manifest.yaml @@ -0,0 +1,13 @@ +manifest: + events: + platypush.message.event.sensor.SensorDataAboveThresholdEvent: if the measurements + of a sensor havegone above a configured threshold + platypush.message.event.sensor.SensorDataBelowThresholdEvent: if the measurements + of a sensor havegone below a configured threshold + platypush.message.event.sensor.SensorDataChangeEvent: if the measurements of a + sensor have changed + install: + pip: + - psutil + package: platypush.backend.sensor.battery + type: backend diff --git a/platypush/backend/sensor/bme280.py b/platypush/backend/sensor/bme280/__init__.py similarity index 65% rename from platypush/backend/sensor/bme280.py rename to platypush/backend/sensor/bme280/__init__.py index aa171f626..3690424ff 100644 --- a/platypush/backend/sensor/bme280.py +++ b/platypush/backend/sensor/bme280/__init__.py @@ -9,6 +9,15 @@ class SensorBme280Backend(SensorBackend): Requires: * ``pimoroni-bme280`` (``pip install pimoroni-bme280``) + + Triggers: + + * :class:`platypush.message.event.sensor.SensorDataChangeEvent` if the measurements of a sensor have changed + * :class:`platypush.message.event.sensor.SensorDataAboveThresholdEvent` if the measurements of a sensor have + gone above a configured threshold + * :class:`platypush.message.event.sensor.SensorDataBelowThresholdEvent` if the measurements of a sensor have + gone below a configured threshold + """ def __init__(self, temperature=True, pressure=True, humidity=True, **kwargs): diff --git a/platypush/backend/sensor/bme280/manifest.yaml b/platypush/backend/sensor/bme280/manifest.yaml new file mode 100644 index 000000000..6b2981ee4 --- /dev/null +++ b/platypush/backend/sensor/bme280/manifest.yaml @@ -0,0 +1,13 @@ +manifest: + events: + platypush.message.event.sensor.SensorDataAboveThresholdEvent: if the measurements + of a sensor havegone above a configured threshold + platypush.message.event.sensor.SensorDataBelowThresholdEvent: if the measurements + of a sensor havegone below a configured threshold + platypush.message.event.sensor.SensorDataChangeEvent: if the measurements of a + sensor have changed + install: + pip: + - pimoroni-bme280 + package: platypush.backend.sensor.bme280 + type: backend diff --git a/platypush/backend/sensor/dht.py b/platypush/backend/sensor/dht/__init__.py similarity index 64% rename from platypush/backend/sensor/dht.py rename to platypush/backend/sensor/dht/__init__.py index 552100521..3cc93a9d6 100644 --- a/platypush/backend/sensor/dht.py +++ b/platypush/backend/sensor/dht/__init__.py @@ -10,6 +10,14 @@ class SensorDhtBackend(SensorBackend): * ``Adafruit_Python_DHT`` (``pip install git+https://github.com/adafruit/Adafruit_Python_DHT.git``) * The ``gpio.sensor.dht`` plugin configured and enabled. + Triggers: + + * :class:`platypush.message.event.sensor.SensorDataChangeEvent` if the measurements of a sensor have changed + * :class:`platypush.message.event.sensor.SensorDataAboveThresholdEvent` if the measurements of a sensor have + gone above a configured threshold + * :class:`platypush.message.event.sensor.SensorDataBelowThresholdEvent` if the measurements of a sensor have + gone below a configured threshold + """ def __init__(self, temperature: bool = True, humidity: bool = True, **kwargs): diff --git a/platypush/backend/sensor/dht/manifest.yaml b/platypush/backend/sensor/dht/manifest.yaml new file mode 100644 index 000000000..f20d92f2a --- /dev/null +++ b/platypush/backend/sensor/dht/manifest.yaml @@ -0,0 +1,13 @@ +manifest: + events: + platypush.message.event.sensor.SensorDataAboveThresholdEvent: if the measurements + of a sensor havegone above a configured threshold + platypush.message.event.sensor.SensorDataBelowThresholdEvent: if the measurements + of a sensor havegone below a configured threshold + platypush.message.event.sensor.SensorDataChangeEvent: if the measurements of a + sensor have changed + install: + pip: + - Adafruit_Python_DHT + package: platypush.backend.sensor.dht + type: backend diff --git a/platypush/backend/sensor/distance/__init__.py b/platypush/backend/sensor/distance/__init__.py index 88cfb1a9b..3c717183f 100644 --- a/platypush/backend/sensor/distance/__init__.py +++ b/platypush/backend/sensor/distance/__init__.py @@ -10,6 +10,15 @@ class SensorDistanceBackend(SensorBackend): * ``RPi.GPIO`` (``pip install RPi.GPIO``) * The :mod:`platypush.plugins.gpio.sensor.distance` plugin configured + + Triggers: + + * :class:`platypush.message.event.sensor.SensorDataChangeEvent` if the measurements of a sensor have changed + * :class:`platypush.message.event.sensor.SensorDataAboveThresholdEvent` if the measurements of a sensor have + gone above a configured threshold + * :class:`platypush.message.event.sensor.SensorDataBelowThresholdEvent` if the measurements of a sensor have + gone below a configured threshold + """ def get_measurement(self): diff --git a/platypush/backend/sensor/distance/manifest.yaml b/platypush/backend/sensor/distance/manifest.yaml new file mode 100644 index 000000000..8a8cce48f --- /dev/null +++ b/platypush/backend/sensor/distance/manifest.yaml @@ -0,0 +1,13 @@ +manifest: + events: + platypush.message.event.sensor.SensorDataAboveThresholdEvent: if the measurements + of a sensor havegone above a configured threshold + platypush.message.event.sensor.SensorDataBelowThresholdEvent: if the measurements + of a sensor havegone below a configured threshold + platypush.message.event.sensor.SensorDataChangeEvent: if the measurements of a + sensor have changed + install: + pip: + - RPi.GPIO + package: platypush.backend.sensor.distance + type: backend diff --git a/platypush/backend/sensor/distance/vl53l1x.py b/platypush/backend/sensor/distance/vl53l1x/__init__.py similarity index 66% rename from platypush/backend/sensor/distance/vl53l1x.py rename to platypush/backend/sensor/distance/vl53l1x/__init__.py index cd4f78757..45408f2a5 100644 --- a/platypush/backend/sensor/distance/vl53l1x.py +++ b/platypush/backend/sensor/distance/vl53l1x/__init__.py @@ -10,6 +10,15 @@ class SensorDistanceVl53L1XBackend(SensorBackend): * ``smbus2`` (``pip install smbus2``) * ``vl53l1x`` (``pip install vl53l1x``) + + Triggers: + + * :class:`platypush.message.event.sensor.SensorDataChangeEvent` if the measurements of a sensor have changed + * :class:`platypush.message.event.sensor.SensorDataAboveThresholdEvent` if the measurements of a sensor have + gone above a configured threshold + * :class:`platypush.message.event.sensor.SensorDataBelowThresholdEvent` if the measurements of a sensor have + gone below a configured threshold + """ def __init__(self, short=True, medium=False, long=False, **kwargs): diff --git a/platypush/backend/sensor/distance/vl53l1x/manifest.yaml b/platypush/backend/sensor/distance/vl53l1x/manifest.yaml new file mode 100644 index 000000000..8150eec96 --- /dev/null +++ b/platypush/backend/sensor/distance/vl53l1x/manifest.yaml @@ -0,0 +1,14 @@ +manifest: + events: + platypush.message.event.sensor.SensorDataAboveThresholdEvent: if the measurements + of a sensor havegone above a configured threshold + platypush.message.event.sensor.SensorDataBelowThresholdEvent: if the measurements + of a sensor havegone below a configured threshold + platypush.message.event.sensor.SensorDataChangeEvent: if the measurements of a + sensor have changed + install: + pip: + - smbus2 + - vl53l1x + package: platypush.backend.sensor.distance.vl53l1x + type: backend diff --git a/platypush/backend/sensor/envirophat.py b/platypush/backend/sensor/envirophat/__init__.py similarity index 76% rename from platypush/backend/sensor/envirophat.py rename to platypush/backend/sensor/envirophat/__init__.py index 764c91fb0..fc98db7d6 100644 --- a/platypush/backend/sensor/envirophat.py +++ b/platypush/backend/sensor/envirophat/__init__.py @@ -9,6 +9,15 @@ class SensorEnvirophatBackend(SensorBackend): Requires: * ``envirophat`` (``pip install envirophat``) + + Triggers: + + * :class:`platypush.message.event.sensor.SensorDataChangeEvent` if the measurements of a sensor have changed + * :class:`platypush.message.event.sensor.SensorDataAboveThresholdEvent` if the measurements of a sensor have + gone above a configured threshold + * :class:`platypush.message.event.sensor.SensorDataBelowThresholdEvent` if the measurements of a sensor have + gone below a configured threshold + """ def __init__(self, temperature=True, pressure=True, altitude=True, luminosity=True, diff --git a/platypush/backend/sensor/envirophat/manifest.yaml b/platypush/backend/sensor/envirophat/manifest.yaml new file mode 100644 index 000000000..22a4ec22c --- /dev/null +++ b/platypush/backend/sensor/envirophat/manifest.yaml @@ -0,0 +1,13 @@ +manifest: + events: + platypush.message.event.sensor.SensorDataAboveThresholdEvent: if the measurements + of a sensor havegone above a configured threshold + platypush.message.event.sensor.SensorDataBelowThresholdEvent: if the measurements + of a sensor havegone below a configured threshold + platypush.message.event.sensor.SensorDataChangeEvent: if the measurements of a + sensor have changed + install: + pip: + - envirophat + package: platypush.backend.sensor.envirophat + type: backend diff --git a/platypush/backend/sensor/ir/zeroborg/manifest.yaml b/platypush/backend/sensor/ir/zeroborg/manifest.yaml new file mode 100644 index 000000000..0fc02bdd3 --- /dev/null +++ b/platypush/backend/sensor/ir/zeroborg/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.sensor.ir.IrKeyDownEvent: when a key is pressed + platypush.message.event.sensor.ir.IrKeyUpEvent: when a key is released + install: + pip: [] + package: platypush.backend.sensor.ir.zeroborg + type: backend diff --git a/platypush/backend/sensor/leap.py b/platypush/backend/sensor/leap/__init__.py similarity index 100% rename from platypush/backend/sensor/leap.py rename to platypush/backend/sensor/leap/__init__.py diff --git a/platypush/backend/sensor/leap/manifest.yaml b/platypush/backend/sensor/leap/manifest.yaml new file mode 100644 index 000000000..1dfa51981 --- /dev/null +++ b/platypush/backend/sensor/leap/manifest.yaml @@ -0,0 +1,15 @@ +manifest: + events: + platypush.message.event.sensor.leap.LeapConnectEvent: when a Leap Motion device + is connected + platypush.message.event.sensor.leap.LeapDisconnectEvent: when a Leap Motion device + disconnects + platypush.message.event.sensor.leap.LeapFrameEvent: when a new frame is received + platypush.message.event.sensor.leap.LeapFrameStartEvent: when a new sequence of + frame starts + platypush.message.event.sensor.leap.LeapFrameStopEvent: when a sequence of frame + stops + install: + pip: [] + package: platypush.backend.sensor.leap + type: backend diff --git a/platypush/backend/sensor/ltr559.py b/platypush/backend/sensor/ltr559/__init__.py similarity index 60% rename from platypush/backend/sensor/ltr559.py rename to platypush/backend/sensor/ltr559/__init__.py index 0952bb94e..c5ae8b355 100644 --- a/platypush/backend/sensor/ltr559.py +++ b/platypush/backend/sensor/ltr559/__init__.py @@ -9,6 +9,15 @@ class SensorLtr559Backend(SensorBackend): Requires: * ``ltr559`` (``pip install ltr559``) + + Triggers: + + * :class:`platypush.message.event.sensor.SensorDataChangeEvent` if the measurements of a sensor have changed + * :class:`platypush.message.event.sensor.SensorDataAboveThresholdEvent` if the measurements of a sensor have + gone above a configured threshold + * :class:`platypush.message.event.sensor.SensorDataBelowThresholdEvent` if the measurements of a sensor have + gone below a configured threshold + """ def __init__(self, light=True, proximity=True, **kwargs): diff --git a/platypush/backend/sensor/ltr559/manifest.yaml b/platypush/backend/sensor/ltr559/manifest.yaml new file mode 100644 index 000000000..0cd07a519 --- /dev/null +++ b/platypush/backend/sensor/ltr559/manifest.yaml @@ -0,0 +1,13 @@ +manifest: + events: + platypush.message.event.sensor.SensorDataAboveThresholdEvent: if the measurements + of a sensor havegone above a configured threshold + platypush.message.event.sensor.SensorDataBelowThresholdEvent: if the measurements + of a sensor havegone below a configured threshold + platypush.message.event.sensor.SensorDataChangeEvent: if the measurements of a + sensor have changed + install: + pip: + - ltr559 + package: platypush.backend.sensor.ltr559 + type: backend diff --git a/platypush/backend/sensor/mcp3008.py b/platypush/backend/sensor/mcp3008/__init__.py similarity index 54% rename from platypush/backend/sensor/mcp3008.py rename to platypush/backend/sensor/mcp3008/__init__.py index 2a0327e34..5791926e4 100644 --- a/platypush/backend/sensor/mcp3008.py +++ b/platypush/backend/sensor/mcp3008/__init__.py @@ -10,6 +10,15 @@ class SensorMcp3008Backend(SensorBackend): * ``adafruit-mcp3008`` (``pip install adafruit-mcp3008``) * The :mod:`platypush.plugins.gpio.sensor.mcp3008` plugin configured + + Triggers: + + * :class:`platypush.message.event.sensor.SensorDataChangeEvent` if the measurements of a sensor have changed + * :class:`platypush.message.event.sensor.SensorDataAboveThresholdEvent` if the measurements of a sensor have + gone above a configured threshold + * :class:`platypush.message.event.sensor.SensorDataBelowThresholdEvent` if the measurements of a sensor have + gone below a configured threshold + """ def __init__(self, **kwargs): diff --git a/platypush/backend/sensor/mcp3008/manifest.yaml b/platypush/backend/sensor/mcp3008/manifest.yaml new file mode 100644 index 000000000..095fb2989 --- /dev/null +++ b/platypush/backend/sensor/mcp3008/manifest.yaml @@ -0,0 +1,13 @@ +manifest: + events: + platypush.message.event.sensor.SensorDataAboveThresholdEvent: if the measurements + of a sensor havegone above a configured threshold + platypush.message.event.sensor.SensorDataBelowThresholdEvent: if the measurements + of a sensor havegone below a configured threshold + platypush.message.event.sensor.SensorDataChangeEvent: if the measurements of a + sensor have changed + install: + pip: + - adafruit-mcp3008 + package: platypush.backend.sensor.mcp3008 + type: backend diff --git a/platypush/backend/sensor/motion/pmw3901/__init__.py b/platypush/backend/sensor/motion/pmw3901/__init__.py new file mode 100644 index 000000000..fc8aa0c06 --- /dev/null +++ b/platypush/backend/sensor/motion/pmw3901/__init__.py @@ -0,0 +1,33 @@ +from platypush.backend.sensor import SensorBackend + + +class SensorMotionPmw3901Backend(SensorBackend): + """ + Backend to poll an `PMW3901 `_ + optical flow and motion sensor + + Requires: + + * ``pmw3901`` (``pip install pmw3901``) + + Triggers: + + * :class:`platypush.message.event.sensor.SensorDataChangeEvent` if the measurements of a sensor have changed + * :class:`platypush.message.event.sensor.SensorDataAboveThresholdEvent` if the measurements of a sensor have + gone above a configured threshold + * :class:`platypush.message.event.sensor.SensorDataBelowThresholdEvent` if the measurements of a sensor have + gone below a configured threshold + + """ + + _default_poll_seconds = 0.01 + + def __init__(self, **kwargs): + if 'poll_seconds' not in kwargs: + # noinspection PyTypeChecker + kwargs['poll_seconds'] = self._default_poll_seconds + + super().__init__(plugin='gpio.sensor.motion.pmw3901', **kwargs) + + +# vim:sw=4:ts=4:et: diff --git a/platypush/backend/sensor/motion/pmw3901/manifest.yaml b/platypush/backend/sensor/motion/pmw3901/manifest.yaml new file mode 100644 index 000000000..ad45445ed --- /dev/null +++ b/platypush/backend/sensor/motion/pmw3901/manifest.yaml @@ -0,0 +1,13 @@ +manifest: + events: + platypush.message.event.sensor.SensorDataAboveThresholdEvent: if the measurements + of a sensor havegone above a configured threshold + platypush.message.event.sensor.SensorDataBelowThresholdEvent: if the measurements + of a sensor havegone below a configured threshold + platypush.message.event.sensor.SensorDataChangeEvent: if the measurements of a + sensor have changed + install: + pip: + - pmw3901 + package: platypush.backend.sensor.motion.pmw3901 + type: backend diff --git a/platypush/backend/sensor/motion/pwm3901.py b/platypush/backend/sensor/motion/pwm3901.py deleted file mode 100644 index 6bb7c3290..000000000 --- a/platypush/backend/sensor/motion/pwm3901.py +++ /dev/null @@ -1,24 +0,0 @@ -from platypush.backend.sensor import SensorBackend - - -class SensorMotionPwm3901Backend(SensorBackend): - """ - Backend to poll an `PWM3901 `_ - optical flow and motion sensor - - Requires: - - * ``pwm3901`` (``pip install pwm3901``) - """ - - _default_poll_seconds = 0.01 - - def __init__(self, **kwargs): - if 'poll_seconds' not in kwargs: - # noinspection PyTypeChecker - kwargs['poll_seconds'] = self._default_poll_seconds - - super().__init__(plugin='gpio.sensor.motion.pwm3901', **kwargs) - - -# vim:sw=4:ts=4:et: diff --git a/platypush/backend/sensor/serial.py b/platypush/backend/sensor/serial.py deleted file mode 100644 index 4d8fd4808..000000000 --- a/platypush/backend/sensor/serial.py +++ /dev/null @@ -1,18 +0,0 @@ -from platypush.backend.sensor import SensorBackend - - -class SensorSerialBackend(SensorBackend): - """ - This backend listens for new events from sensors connected through a serial - interface (like Arduino) acting as a wrapper for the ``serial`` plugin. - - Requires: - - * The :mod:`platypush.plugins.serial` plugin configured - """ - - def __init__(self, **kwargs): - super().__init__(plugin='serial', **kwargs) - - -# vim:sw=4:ts=4:et: diff --git a/platypush/backend/sensor/serial/__init__.py b/platypush/backend/sensor/serial/__init__.py new file mode 100644 index 000000000..f6d1b3b5c --- /dev/null +++ b/platypush/backend/sensor/serial/__init__.py @@ -0,0 +1,27 @@ +from platypush.backend.sensor import SensorBackend + + +class SensorSerialBackend(SensorBackend): + """ + This backend listens for new events from sensors connected through a serial + interface (like Arduino) acting as a wrapper for the ``serial`` plugin. + + Requires: + + * The :mod:`platypush.plugins.serial` plugin configured + + Triggers: + + * :class:`platypush.message.event.sensor.SensorDataChangeEvent` if the measurements of a sensor have changed + * :class:`platypush.message.event.sensor.SensorDataAboveThresholdEvent` if the measurements of a sensor have + gone above a configured threshold + * :class:`platypush.message.event.sensor.SensorDataBelowThresholdEvent` if the measurements of a sensor have + gone below a configured threshold + + """ + + def __init__(self, **kwargs): + super().__init__(plugin='serial', **kwargs) + + +# vim:sw=4:ts=4:et: diff --git a/platypush/backend/sensor/serial/manifest.yaml b/platypush/backend/sensor/serial/manifest.yaml new file mode 100644 index 000000000..f0d7abf49 --- /dev/null +++ b/platypush/backend/sensor/serial/manifest.yaml @@ -0,0 +1,12 @@ +manifest: + events: + platypush.message.event.sensor.SensorDataAboveThresholdEvent: if the measurements + of a sensor havegone above a configured threshold + platypush.message.event.sensor.SensorDataBelowThresholdEvent: if the measurements + of a sensor havegone below a configured threshold + platypush.message.event.sensor.SensorDataChangeEvent: if the measurements of a + sensor have changed + install: + pip: [] + package: platypush.backend.sensor.serial + type: backend diff --git a/platypush/backend/stt/deepspeech.py b/platypush/backend/stt/deepspeech/__init__.py similarity index 100% rename from platypush/backend/stt/deepspeech.py rename to platypush/backend/stt/deepspeech/__init__.py diff --git a/platypush/backend/stt/deepspeech/manifest.yaml b/platypush/backend/stt/deepspeech/manifest.yaml new file mode 100644 index 000000000..2ac470b6a --- /dev/null +++ b/platypush/backend/stt/deepspeech/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.backend.stt.deepspeech + type: backend diff --git a/platypush/backend/stt/picovoice/hotword.py b/platypush/backend/stt/picovoice/hotword/__init__.py similarity index 100% rename from platypush/backend/stt/picovoice/hotword.py rename to platypush/backend/stt/picovoice/hotword/__init__.py diff --git a/platypush/backend/stt/picovoice/hotword/manifest.yaml b/platypush/backend/stt/picovoice/hotword/manifest.yaml new file mode 100644 index 000000000..0527afcaa --- /dev/null +++ b/platypush/backend/stt/picovoice/hotword/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.backend.stt.picovoice.hotword + type: backend diff --git a/platypush/backend/stt/picovoice/speech.py b/platypush/backend/stt/picovoice/speech/__init__.py similarity index 100% rename from platypush/backend/stt/picovoice/speech.py rename to platypush/backend/stt/picovoice/speech/__init__.py diff --git a/platypush/backend/stt/picovoice/speech/manifest.yaml b/platypush/backend/stt/picovoice/speech/manifest.yaml new file mode 100644 index 000000000..fc68a467e --- /dev/null +++ b/platypush/backend/stt/picovoice/speech/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.backend.stt.picovoice.speech + type: backend diff --git a/platypush/backend/tcp.py b/platypush/backend/tcp/__init__.py similarity index 100% rename from platypush/backend/tcp.py rename to platypush/backend/tcp/__init__.py diff --git a/platypush/backend/tcp/manifest.yaml b/platypush/backend/tcp/manifest.yaml new file mode 100644 index 000000000..af881fb2e --- /dev/null +++ b/platypush/backend/tcp/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.backend.tcp + type: backend diff --git a/platypush/backend/todoist.py b/platypush/backend/todoist/__init__.py similarity index 98% rename from platypush/backend/todoist.py rename to platypush/backend/todoist/__init__.py index ef8ec74b0..1f1f4f12a 100644 --- a/platypush/backend/todoist.py +++ b/platypush/backend/todoist/__init__.py @@ -16,7 +16,6 @@ class TodoistBackend(Backend): Requires: * **todoist-python** (``pip install todoist-python``) - * **websocket-client** (``pip install websocket-client``) Triggers: diff --git a/platypush/backend/todoist/manifest.yaml b/platypush/backend/todoist/manifest.yaml new file mode 100644 index 000000000..6f556d825 --- /dev/null +++ b/platypush/backend/todoist/manifest.yaml @@ -0,0 +1,16 @@ +manifest: + events: + platypush.message.event.todoist.CheckedItemEvent: when an item is checked. + platypush.message.event.todoist.ItemContentChangeEvent: when the content of an + item is changed. + platypush.message.event.todoist.ModifiedItemEvent: when an item is changed and + the changedoesn't fall into the categories above. + platypush.message.event.todoist.NewItemEvent: when a new item is created. + platypush.message.event.todoist.RemovedItemEvent: when an item is removed. + platypush.message.event.todoist.TodoistSyncRequiredEvent: when an update has occurred + that doesn'tfall into the categories above and a sync is required to get up-to-date. + install: + pip: + - todoist-python + package: platypush.backend.todoist + type: backend diff --git a/platypush/backend/travisci.py b/platypush/backend/travisci/__init__.py similarity index 100% rename from platypush/backend/travisci.py rename to platypush/backend/travisci/__init__.py diff --git a/platypush/backend/travisci/manifest.yaml b/platypush/backend/travisci/manifest.yaml new file mode 100644 index 000000000..eb7fe194c --- /dev/null +++ b/platypush/backend/travisci/manifest.yaml @@ -0,0 +1,10 @@ +manifest: + events: + platypush.message.event.travisci.TravisciBuildFailedEvent: when the build of a + project owned bythe user fails. + platypush.message.event.travisci.TravisciBuildPassedEvent: when the build of a + project owned bythe user passes. + install: + pip: [] + package: platypush.backend.travisci + type: backend diff --git a/platypush/backend/trello.py b/platypush/backend/trello/__init__.py similarity index 98% rename from platypush/backend/trello.py rename to platypush/backend/trello/__init__.py index 2f3b88f27..4f3fe2f73 100644 --- a/platypush/backend/trello.py +++ b/platypush/backend/trello/__init__.py @@ -28,7 +28,6 @@ class TrelloBackend(Backend): Requires: - * **websocket-client** (``pip install websocket-client``) * The :class:`platypush.plugins.trello.TrelloPlugin` configured. Triggers: @@ -171,7 +170,6 @@ class TrelloBackend(Backend): return hndl def _on_open(self): - # noinspection PyUnusedLocal def hndl(*args): ws = args[0] if args else None self._connected.set() diff --git a/platypush/backend/trello/manifest.yaml b/platypush/backend/trello/manifest.yaml new file mode 100644 index 000000000..53553a903 --- /dev/null +++ b/platypush/backend/trello/manifest.yaml @@ -0,0 +1,10 @@ +manifest: + events: + platypush.message.event.ArchivedCardEvent: when a card is archived/closed. + platypush.message.event.MoveCardEvent: when a card is moved. + platypush.message.event.UnarchivedCardEvent: when a card is un-archived/opened. + platypush.message.event.trello.NewCardEvent: when a card is created. + install: + pip: [] + package: platypush.backend.trello + type: backend diff --git a/platypush/backend/weather/__init__.py b/platypush/backend/weather/__init__.py index e2f5f8635..81dbb992b 100644 --- a/platypush/backend/weather/__init__.py +++ b/platypush/backend/weather/__init__.py @@ -1,4 +1,3 @@ -import abc import time from platypush.backend import Backend @@ -6,7 +5,7 @@ from platypush.context import get_plugin from platypush.message.event.weather import NewWeatherConditionEvent -class WeatherBackend(Backend, abc.ABC): +class WeatherBackend(Backend): """ Abstract class for weather update backends. """ diff --git a/platypush/backend/weather/buienradar.py b/platypush/backend/weather/buienradar/__init__.py similarity index 100% rename from platypush/backend/weather/buienradar.py rename to platypush/backend/weather/buienradar/__init__.py diff --git a/platypush/backend/weather/buienradar/manifest.yaml b/platypush/backend/weather/buienradar/manifest.yaml new file mode 100644 index 000000000..12df01184 --- /dev/null +++ b/platypush/backend/weather/buienradar/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.weather.NewWeatherConditionEvent: when there is a weather + condition update + install: + pip: [] + package: platypush.backend.weather.buienradar + type: backend diff --git a/platypush/backend/weather/darksky.py b/platypush/backend/weather/darksky/__init__.py similarity index 100% rename from platypush/backend/weather/darksky.py rename to platypush/backend/weather/darksky/__init__.py diff --git a/platypush/backend/weather/darksky/manifest.yaml b/platypush/backend/weather/darksky/manifest.yaml new file mode 100644 index 000000000..0063b81b8 --- /dev/null +++ b/platypush/backend/weather/darksky/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.weather.NewWeatherConditionEvent: when there is a weather + condition update + install: + pip: [] + package: platypush.backend.weather.darksky + type: backend diff --git a/platypush/backend/weather/openweathermap.py b/platypush/backend/weather/openweathermap/__init__.py similarity index 100% rename from platypush/backend/weather/openweathermap.py rename to platypush/backend/weather/openweathermap/__init__.py diff --git a/platypush/backend/weather/openweathermap/manifest.yaml b/platypush/backend/weather/openweathermap/manifest.yaml new file mode 100644 index 000000000..70b8cc871 --- /dev/null +++ b/platypush/backend/weather/openweathermap/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.weather.NewWeatherConditionEvent: when there is a weather + condition update + install: + pip: [] + package: platypush.backend.weather.openweathermap + type: backend diff --git a/platypush/backend/websocket.py b/platypush/backend/websocket/__init__.py similarity index 89% rename from platypush/backend/websocket.py rename to platypush/backend/websocket/__init__.py index 38c60aac3..fc5e2fac3 100644 --- a/platypush/backend/websocket.py +++ b/platypush/backend/websocket/__init__.py @@ -1,6 +1,3 @@ -import asyncio -import websockets - from platypush.backend import Backend from platypush.context import get_plugin, get_or_create_event_loop from platypush.message import Message @@ -12,10 +9,6 @@ from platypush.utils import get_ssl_server_context class WebsocketBackend(Backend): """ Backend to communicate messages over a websocket medium. - - Requires: - - * **websockets** (``pip install websockets``) """ # Websocket client message recv timeout in seconds @@ -43,10 +36,12 @@ class WebsocketBackend(Backend): :param ssl_cafile: Path to the certificate authority file if required by the SSL configuration (default: None) :type ssl_cafile: str - :param ssl_capath: Path to the certificate authority directory if required by the SSL configuration (default: None) + :param ssl_capath: Path to the certificate authority directory if required by the SSL configuration + (default: None) :type ssl_capath: str - :param client_timeout: Timeout without any messages being received before closing a client connection. A zero timeout keeps the websocket open until an error occurs (default: 0, no timeout) + :param client_timeout: Timeout without any messages being received before closing a client connection. + A zero timeout keeps the websocket open until an error occurs (default: 0, no timeout) :type ping_timeout: int """ @@ -78,6 +73,11 @@ class WebsocketBackend(Backend): def notify_web_clients(self, event): """ Notify all the connected web clients (over websocket) of a new event """ + try: + from websockets.exceptions import ConnectionClosed + except ImportError: + from websockets import ConnectionClosed + async def send_event(websocket): try: await websocket.send(str(event)) @@ -90,11 +90,19 @@ class WebsocketBackend(Backend): for ws in active_websockets: try: loop.run_until_complete(send_event(ws)) - except websockets.exceptions.ConnectionClosed: + except ConnectionClosed: self.logger.info('Client connection lost') self.active_websockets.remove(ws) def run(self): + import asyncio + import websockets + + try: + from websockets.exceptions import ConnectionClosed + except ImportError: + from websockets import ConnectionClosed + super().run() self.register_service(port=self.port, name='ws') @@ -125,7 +133,7 @@ class WebsocketBackend(Backend): await websocket.send(str(response)) - except websockets.exceptions.ConnectionClosed as e: + except ConnectionClosed as e: self.active_websockets.remove(websocket) self.logger.debug('Websocket client {} closed connection'. format(websocket.remote_address[0])) diff --git a/platypush/backend/websocket/manifest.yaml b/platypush/backend/websocket/manifest.yaml new file mode 100644 index 000000000..dc60f459d --- /dev/null +++ b/platypush/backend/websocket/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.backend.websocket + type: backend diff --git a/platypush/backend/wiimote.py b/platypush/backend/wiimote/__init__.py similarity index 81% rename from platypush/backend/wiimote.py rename to platypush/backend/wiimote/__init__.py index 89e596632..cb339c7bc 100644 --- a/platypush/backend/wiimote.py +++ b/platypush/backend/wiimote/__init__.py @@ -30,14 +30,14 @@ class WiimoteBackend(Backend): _last_btn_event_time = 0 _bdaddr = None - def __init__(self, bdaddr=_bdaddr, inactivity_timeout=_inactivity_timeout, *args, **kwargs): """ :param bdaddr: If set, connect to this specific Wiimote physical address (example: 00:11:22:33:44:55) :type bdaddr: str - :param inactivity_timeout: Number of seconds elapsed from the last Wiimote action before disconnecting the device (default: 300 seconds) + :param inactivity_timeout: Number of seconds elapsed from the last Wiimote action before disconnecting the + device (default: 300 seconds) :type inactivity_timeout: float """ @@ -45,7 +45,6 @@ class WiimoteBackend(Backend): self._bdaddr = bdaddr self._inactivity_timeout = inactivity_timeout - def get_wiimote(self): import cwiid @@ -72,35 +71,34 @@ class WiimoteBackend(Backend): # Get buttons all_btns = [attr for attr in dir(cwiid) if attr.startswith('BTN_')] - parsed_state['buttons'] = { btn: True for btn in all_btns - if state.get('buttons', 0) & getattr(cwiid, btn) != 0 } + parsed_state['buttons'] = {btn: True for btn in all_btns + if state.get('buttons', 0) & getattr(cwiid, btn) != 0} # Get LEDs all_leds = [attr for attr in dir(cwiid) if re.match('LED\d_ON', attr)] - parsed_state['led'] = { led[:4]: True for led in all_leds - if state.get('leds', 0) & getattr(cwiid, led) != 0 } + parsed_state['led'] = {led[:4]: True for led in all_leds + if state.get('leds', 0) & getattr(cwiid, led) != 0} # Get errors all_errs = [attr for attr in dir(cwiid) if attr.startswith('ERROR_')] - parsed_state['error'] = { err: True for err in all_errs - if state.get('errs', 0) & getattr(cwiid, err) != 0 } + parsed_state['error'] = {err: True for err in all_errs + if state.get('errs', 0) & getattr(cwiid, err) != 0} - parsed_state['battery'] = round(state.get('battery', 0)/cwiid.BATTERY_MAX, 3) + parsed_state['battery'] = round(state.get('battery', 0) / cwiid.BATTERY_MAX, 3) parsed_state['rumble'] = bool(state.get('rumble', 0)) if 'acc' in state: - parsed_state['acc'] = tuple(int(acc/5)*5 for acc in state['acc']) + parsed_state['acc'] = tuple(int(acc / 5) * 5 for acc in state['acc']) if 'motionplus' in state: parsed_state['motionplus'] = { - 'angle_rate': tuple(int(angle/100) for angle + 'angle_rate': tuple(int(angle / 100) for angle in state['motionplus']['angle_rate']), 'low_speed': state['motionplus']['low_speed'], } return parsed_state - def close(self): if not self._wiimote: return @@ -113,7 +111,6 @@ class WiimoteBackend(Backend): self._wiimote = None self.bus.post(WiimoteDisconnectionEvent()) - def run(self): super().run() @@ -124,8 +121,8 @@ class WiimoteBackend(Backend): while not self.should_stop(): try: state = self.get_state() - changed_state = { k: state[k] for k in state.keys() - if state[k] != last_state.get(k) } + changed_state = {k: state[k] for k in state.keys() + if state[k] != last_state.get(k)} if changed_state: self.bus.post(WiimoteEvent(**changed_state)) @@ -133,7 +130,7 @@ class WiimoteBackend(Backend): if 'buttons' in changed_state: self._last_btn_event_time = time.time() elif last_state and time.time() - \ - self._last_btn_event_time >= self._inactivity_timeout: + self._last_btn_event_time >= self._inactivity_timeout: self.logger.info('Wiimote disconnected upon timeout') self.close() @@ -150,4 +147,3 @@ class WiimoteBackend(Backend): self._connection_attempts += 1 # vim:sw=4:ts=4:et: - diff --git a/platypush/backend/wiimote/manifest.yaml b/platypush/backend/wiimote/manifest.yaml new file mode 100644 index 000000000..d904aae03 --- /dev/null +++ b/platypush/backend/wiimote/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.Wiimote.WiimoteEvent: when the state of the Wiimote (battery, + buttons, acceleration etc.) changes + install: + pip: [] + package: platypush.backend.wiimote + type: backend diff --git a/platypush/backend/zigbee/mqtt.py b/platypush/backend/zigbee/mqtt/__init__.py similarity index 100% rename from platypush/backend/zigbee/mqtt.py rename to platypush/backend/zigbee/mqtt/__init__.py diff --git a/platypush/backend/zigbee/mqtt/manifest.yaml b/platypush/backend/zigbee/mqtt/manifest.yaml new file mode 100644 index 000000000..f1d8ca0fb --- /dev/null +++ b/platypush/backend/zigbee/mqtt/manifest.yaml @@ -0,0 +1,45 @@ +manifest: + events: + platypush.message.event.zigbee.mqtt.ZigbeeMqttDeviceBannedEvent: when a device + is bannedfrom the network. + platypush.message.event.zigbee.mqtt.ZigbeeMqttDeviceBindEvent: when a device bind + eventoccurs. + platypush.message.event.zigbee.mqtt.ZigbeeMqttDeviceConnectedEvent: when a device + connectsto the network. + platypush.message.event.zigbee.mqtt.ZigbeeMqttDevicePairingEvent: when a device + is pairing. + platypush.message.event.zigbee.mqtt.ZigbeeMqttDevicePropertySetEvent: when the + properties of aconnected device change. + platypush.message.event.zigbee.mqtt.ZigbeeMqttDeviceRemovedEvent: when a device + is removedfrom the network. + platypush.message.event.zigbee.mqtt.ZigbeeMqttDeviceRemovedFailedEvent: when a + request toremove a device from the network fails. + platypush.message.event.zigbee.mqtt.ZigbeeMqttDeviceRenamedEvent: when a device + isrenamed on the network. + platypush.message.event.zigbee.mqtt.ZigbeeMqttDeviceUnbindEvent: when a device + unbind eventoccurs. + platypush.message.event.zigbee.mqtt.ZigbeeMqttDeviceWhitelistedEvent: when a device + iswhitelisted on the network. + platypush.message.event.zigbee.mqtt.ZigbeeMqttErrorEvent: when an internal error + occurson the zigbee2mqtt service. + platypush.message.event.zigbee.mqtt.ZigbeeMqttGroupAddedEvent: when a group is + added. + platypush.message.event.zigbee.mqtt.ZigbeeMqttGroupAddedFailedEvent: when a request + toadd a new group fails. + platypush.message.event.zigbee.mqtt.ZigbeeMqttGroupRemoveAllEvent: when all the + devicesare removed from a group. + platypush.message.event.zigbee.mqtt.ZigbeeMqttGroupRemoveAllFailedEvent: when + a request toremove all the devices from a group fails. + platypush.message.event.zigbee.mqtt.ZigbeeMqttGroupRemovedEvent: when a group + is removed. + platypush.message.event.zigbee.mqtt.ZigbeeMqttGroupRemovedFailedEvent: when a + request toremove a group fails. + platypush.message.event.zigbee.mqtt.ZigbeeMqttOfflineEvent: when the service goes + offline. + platypush.message.event.zigbee.mqtt.ZigbeeMqttOnlineEvent: when the service comes + online. + install: + pip: + - paho-mqtt + package: platypush.backend.zigbee.mqtt + type: backend diff --git a/platypush/backend/zwave/manifest.yaml b/platypush/backend/zwave/manifest.yaml new file mode 100644 index 000000000..4ccd9276c --- /dev/null +++ b/platypush/backend/zwave/manifest.yaml @@ -0,0 +1,48 @@ +manifest: + events: + platypush.message.event.zwave.ZwaveButtonCreatedEvent: when a button is added + to the network. + platypush.message.event.zwave.ZwaveButtonOffEvent: when a button is released. + platypush.message.event.zwave.ZwaveButtonOnEvent: when a button is pressed. + platypush.message.event.zwave.ZwaveButtonRemovedEvent: when a button is removed + from the network. + platypush.message.event.zwave.ZwaveCommandEvent: when a command is received on + the network. + platypush.message.event.zwave.ZwaveCommandWaitingEvent: when a command is waiting + for a messageto complete. + platypush.message.event.zwave.ZwaveNetworkErrorEvent: when an error occurs on + the network. + platypush.message.event.zwave.ZwaveNetworkReadyEvent: when the network is up and + running. + platypush.message.event.zwave.ZwaveNetworkResetEvent: when the network is reset. + platypush.message.event.zwave.ZwaveNetworkStoppedEvent: when the network goes + down. + platypush.message.event.zwave.ZwaveNodeAddedEvent: when a node is added to the + network. + platypush.message.event.zwave.ZwaveNodeEvent: when a node attribute changes. + platypush.message.event.zwave.ZwaveNodeGroupEvent: when a node is associated/de-associated + to agroup. + platypush.message.event.zwave.ZwaveNodePollingDisabledEvent: when the polling + is successfully turnedoff a node. + platypush.message.event.zwave.ZwaveNodePollingEnabledEvent: when the polling is + successfully turnedon a node. + platypush.message.event.zwave.ZwaveNodeQueryCompletedEvent: when all the nodes + on the networkhave been queried. + platypush.message.event.zwave.ZwaveNodeReadyEvent: when a node is ready. + platypush.message.event.zwave.ZwaveNodeRemovedEvent: when a node is removed from + the network. + platypush.message.event.zwave.ZwaveNodeRenamedEvent: when a node is renamed. + platypush.message.event.zwave.ZwaveNodeSceneEvent: when a scene is set on a node. + platypush.message.event.zwave.ZwaveValueAddedEvent: when a value is added to a + node on the network. + platypush.message.event.zwave.ZwaveValueChangedEvent: when the value of a node + on the networkchanges. + platypush.message.event.zwave.ZwaveValueRefreshedEvent: when the value of a node + on the networkis refreshed. + platypush.message.event.zwave.ZwaveValueRemovedEvent: when the value of a node + on the networkis removed. + install: + pip: + - python-openzwave + package: platypush.backend.zwave + type: backend diff --git a/platypush/backend/zwave/mqtt.py b/platypush/backend/zwave/mqtt/__init__.py similarity index 100% rename from platypush/backend/zwave/mqtt.py rename to platypush/backend/zwave/mqtt/__init__.py diff --git a/platypush/backend/zwave/mqtt/manifest.yaml b/platypush/backend/zwave/mqtt/manifest.yaml new file mode 100644 index 000000000..37c82ecf8 --- /dev/null +++ b/platypush/backend/zwave/mqtt/manifest.yaml @@ -0,0 +1,20 @@ +manifest: + events: + platypush.message.event.zwave.ZwaveNodeAddedEvent: when a node is added to the + network. + platypush.message.event.zwave.ZwaveNodeAsleepEvent: when a node goes into sleep + mode. + platypush.message.event.zwave.ZwaveNodeAwakeEvent: when a node goes back into + awake mode. + platypush.message.event.zwave.ZwaveNodeEvent: when a node attribute changes. + platypush.message.event.zwave.ZwaveNodeReadyEvent: when a node is ready. + platypush.message.event.zwave.ZwaveNodeRemovedEvent: when a node is removed from + the network. + platypush.message.event.zwave.ZwaveNodeRenamedEvent: when a node is renamed. + platypush.message.event.zwave.ZwaveValueChangedEvent: when the value of a node + on the networkchanges. + install: + pip: + - paho-mqtt + package: platypush.backend.zwave.mqtt + type: backend diff --git a/platypush/bus/__init__.py b/platypush/bus/__init__.py index 109304bcb..0dd57eb03 100644 --- a/platypush/bus/__init__.py +++ b/platypush/bus/__init__.py @@ -92,7 +92,7 @@ class Bus(object): :param event_type: Event type to subscribe (event inheritance also works). :param handler: Event handler - a function that takes an Event object as parameter. - :return: A function that can be called to remove the handler (no paramters required). + :return: A function that can be called to remove the handler (no parameters required). """ if event_type not in self.event_handlers: self.event_handlers[event_type] = set() diff --git a/platypush/common/__init__.py b/platypush/common/__init__.py index b4ca9f4b9..04a43b1aa 100644 --- a/platypush/common/__init__.py +++ b/platypush/common/__init__.py @@ -1,4 +1,8 @@ +import inspect import logging +import os + +from platypush.utils.manifest import Manifest logger = logging.getLogger('platypush') @@ -15,3 +19,16 @@ def exec_wrapper(f, *args, **kwargs): except Exception as e: logger.exception(e) return Response(errors=[str(e)]) + + +class ExtensionWithManifest: + def __init__(self, *_, **__): + self._manifest = self.get_manifest() + + def get_manifest(self) -> Manifest: + manifest_file = os.path.join(os.path.dirname(inspect.getfile(self.__class__)), 'manifest.yaml') + assert os.path.isfile(manifest_file), ( + 'The extension {} has no associated manifest.yaml'.format(self.__class__.__name__) + ) + + return Manifest.from_file(manifest_file) diff --git a/platypush/config/__init__.py b/platypush/config/__init__.py index 78080a913..99e61e7b4 100644 --- a/platypush/config/__init__.py +++ b/platypush/config/__init__.py @@ -141,22 +141,15 @@ class Config(object): self.constants = {} self.cronjobs = {} self.dashboards = {} + self._plugin_manifests = {} + self._backend_manifests = {} + self._init_manifests() self._init_constants() self._load_scripts() self._init_components() self._init_dashboards(self._config['dashboards_dir']) - @staticmethod - def _is_special_token(token): - return token == 'main.db' or \ - token == 'token' or \ - token == 'token_hash' or \ - token == 'logging' or \ - token == 'workdir' or \ - token == 'device_id' or \ - token == 'environment' - def _read_config_file(self, cfgfile): cfgfile_dir = os.path.dirname(os.path.abspath( os.path.expanduser(cfgfile))) @@ -232,7 +225,7 @@ class Config(object): def _init_components(self): for key in self._config.keys(): - if key.startswith('backend.'): + if key.startswith('backend.') and '.'.join(key.split('.')[1:]) in self._backend_manifests: backend_name = '.'.join(key.split('.')[1:]) self.backends[backend_name] = self._config[key] elif key.startswith('event.hook.'): @@ -261,9 +254,24 @@ class Config(object): 'actions': self._config[key], 'args': args, } - elif not self._is_special_token(key): + elif key in self._plugin_manifests: self.plugins[key] = self._config[key] + def _init_manifests(self, base_dir: Optional[str] = None): + if not base_dir: + base_dir = os.path.abspath(os.path.join(__file__, '..', '..')) + plugins_dir = os.path.join(base_dir, 'plugins') + backends_dir = os.path.join(base_dir, 'backend') + self._init_manifests(plugins_dir) + self._init_manifests(backends_dir) + else: + manifests_map = self._plugin_manifests if base_dir.endswith('plugins') else self._backend_manifests + for mf in pathlib.Path(base_dir).rglob('manifest.yaml'): + with open(mf, 'r') as f: + manifest = yaml.safe_load(f)['manifest'] + comp_name = '.'.join(manifest['package'].split('.')[2:]) + manifests_map[comp_name] = manifest + def _init_constants(self): if 'constants' in self._config: self.constants = self._config['constants'] diff --git a/platypush/event/hook.py b/platypush/event/hook.py index fba3f04b0..1d428e36d 100644 --- a/platypush/event/hook.py +++ b/platypush/event/hook.py @@ -81,7 +81,7 @@ class EventAction(Request): def __init__(self, target=None, action=None, **args): if target is None: target = Config.get('device_id') - args_copy = copy.deepcopy(args) + args_copy = dict(copy.deepcopy(args)) super().__init__(target=target, action=action, **args_copy) @classmethod diff --git a/platypush/message/event/adafruit.py b/platypush/message/event/adafruit.py index f4895c243..fea8e2a03 100644 --- a/platypush/message/event/adafruit.py +++ b/platypush/message/event/adafruit.py @@ -7,7 +7,7 @@ class ConnectedEvent(Event): """ def __init__(self, *args, **kwargs): - super().__init__(*args, feed=feed, data=data, **kwargs) + super().__init__(*args, **kwargs) class DisconnectedEvent(Event): @@ -16,7 +16,7 @@ class DisconnectedEvent(Event): """ def __init__(self, *args, **kwargs): - super().__init__(*args, feed=feed, data=data, **kwargs) + super().__init__(*args, **kwargs) class FeedUpdateEvent(Event): diff --git a/platypush/message/event/button/flic/__init__.py b/platypush/message/event/button/flic/__init__.py index 3c6a29538..48245a0f8 100644 --- a/platypush/message/event/button/flic/__init__.py +++ b/platypush/message/event/button/flic/__init__.py @@ -12,17 +12,17 @@ class FlicButtonEvent(Event): :param btn_addr: Physical address of the button that originated the event :type btn_addr: str - :param sequence: Detected sequence, as a list of Flic button event types (either "ShortPressEvent" or "LongPressEvent") + :param sequence: Detected sequence, as a list of Flic button event types (either "ShortPressEvent" or + "LongPressEvent") :type sequence: list[str] """ super().__init__(btn_addr=btn_addr, sequence=sequence, *args, **kwargs) - def matches_condition(self, condition): """ - :param condition: Condition to be checked against, as a sequence of button presses ("ShortPressEvent" and "LongPressEvent") - :type condition: list + :param condition: Condition to be checked against, as a sequence of button presses ("ShortPressEvent" and + "LongPressEvent") """ result = EventMatchResult(is_match=False) @@ -47,6 +47,4 @@ class FlicButtonEvent(Event): result.is_match = len(cond_sequence) == 0 return result - # vim:sw=4:ts=4:et: - diff --git a/platypush/message/event/chat/slack.py b/platypush/message/event/chat/slack.py index 52536e0ce..b795897d6 100644 --- a/platypush/message/event/chat/slack.py +++ b/platypush/message/event/chat/slack.py @@ -1,4 +1,4 @@ -from abc import ABC +from abc import ABCMeta from datetime import datetime from typing import Union, Optional, Iterable @@ -7,7 +7,7 @@ from dateutil.tz import gettz from platypush.message.event import Event -class SlackEvent(Event, ABC): +class SlackEvent(Event, ABCMeta): """ Base class for Slack events. """ @@ -26,7 +26,7 @@ class SlackEvent(Event, ABC): return datetime.fromtimestamp(timestamp, tz=gettz()) -class SlackMessageEvent(SlackEvent, ABC): +class SlackMessageEvent(SlackEvent, ABCMeta): """ Base class for message-related events. """ diff --git a/platypush/message/event/joystick.py b/platypush/message/event/joystick.py index 472049b3c..57bf10f82 100644 --- a/platypush/message/event/joystick.py +++ b/platypush/message/event/joystick.py @@ -1,4 +1,4 @@ -from abc import ABC +from abc import ABCMeta from typing import Optional, Iterable, Union from platypush.message.event import Event @@ -22,7 +22,7 @@ class JoystickEvent(Event): super().__init__(*args, code=code, state=state, **kwargs) -class _JoystickEvent(Event, ABC): +class _JoystickEvent(Event, ABCMeta): """ Base joystick event class. """ diff --git a/platypush/message/event/video/__init__.py b/platypush/message/event/video/__init__.py index 6a0140d4e..e3eb72bec 100644 --- a/platypush/message/event/video/__init__.py +++ b/platypush/message/event/video/__init__.py @@ -1,4 +1,3 @@ -from platypush.message.event import Event from platypush.message.event.media import MediaEvent diff --git a/platypush/platydock/__init__.py b/platypush/platydock/__init__.py index 8eb0da786..a25976035 100755 --- a/platypush/platydock/__init__.py +++ b/platypush/platydock/__init__.py @@ -11,14 +11,17 @@ stop and list) Platypush instances as Docker images. import argparse import enum import os +import pathlib import re +import shutil import subprocess import sys import textwrap import traceback as tb +import yaml from platypush.config import Config -from platypush.context import register_backends, get_plugin, get_backend +from platypush.utils import manifest workdir = os.path.join(os.path.expanduser('~'), '.local', 'share', 'platypush', 'platydock') @@ -39,23 +42,23 @@ def _parse_deps(cls): deps = [] for line in cls.__doc__.split('\n'): - m = re.search('\(``pip install (.+)``\)', line) + m = re.search(r'\(``pip install (.+)``\)', line) if m: deps.append(m.group(1)) return deps -def generate_dockerfile(deps, ports, cfgfile, devdir, python_version): +def generate_dockerfile(deps, ports, cfgfile, device_dir, python_version): device_id = Config.get('device_id') if not device_id: raise RuntimeError(('You need to specify a device_id in {} - Docker ' + 'containers cannot rely on hostname').format(cfgfile)) - os.makedirs(devdir, exist_ok=True) + os.makedirs(device_dir, exist_ok=True) content = textwrap.dedent( ''' - FROM python:{python_version}-slim-buster + FROM python:{python_version}-slim-bullseye RUN mkdir -p /app RUN mkdir -p /etc/platypush @@ -63,66 +66,100 @@ def generate_dockerfile(deps, ports, cfgfile, devdir, python_version): '''.format(python_version=python_version)).lstrip() srcdir = os.path.dirname(cfgfile) - cfgfile_copy = os.path.join(devdir, 'config.yaml') - subprocess.call(['cp', cfgfile, cfgfile_copy]) + cfgfile_copy = os.path.join(device_dir, 'config.yaml') + shutil.copy(cfgfile, cfgfile_copy, follow_symlinks=True) content += 'COPY config.yaml /etc/platypush/\n' + backend_config = Config.get_backends() + # Redis configuration for Docker + if 'redis' not in backend_config: + backend_config['redis'] = { + 'redis_args': { + 'host': 'redis', + 'port': 6379, + } + } + + with open(cfgfile_copy, 'a') as f: + f.write('\n# Automatically added by platydock, do not remove\n' + yaml.dump({ + 'backend.redis': backend_config['redis'], + }) + '\n') + + # Main database configuration + has_main_db = False + with open(cfgfile_copy, 'r') as f: + for line in f.readlines(): + if re.match(r'^(main.)?db.*', line): + has_main_db = True + break + + if not has_main_db: + with open(cfgfile_copy, 'a') as f: + f.write('\n# Automatically added by platydock, do not remove\n' + yaml.dump({ + 'main.db': { + 'engine': 'sqlite:////platypush.db', + } + }) + '\n') + + # Copy included files # noinspection PyProtectedMember for include in Config._included_files: incdir = os.path.relpath(os.path.dirname(include), srcdir) - destdir = os.path.join(devdir, incdir) - - try: - os.makedirs(destdir) - except FileExistsError: - pass - - subprocess.call(['cp', include, destdir]) + destdir = os.path.join(device_dir, incdir) + pathlib.Path(destdir).mkdir(parents=True, exist_ok=True) + shutil.copy(include, destdir, follow_symlinks=True) content += 'RUN mkdir -p /etc/platypush/' + incdir + '\n' content += 'COPY ' + os.path.relpath(include, srcdir) + \ ' /etc/platypush/' + incdir + '\n' - content += textwrap.dedent( - ''' - RUN dpkg --configure -a \\ - && apt-get -f install \\ - && apt-get --fix-missing install \\ - && apt-get clean \\ - && apt-get update \\ - && apt-get -y upgrade \\ - && apt-get -y dist-upgrade \\ - && apt-get install --no-install-recommends -y apt-utils\\ - && apt-get install --no-install-recommends -y build-essential \\ - && apt-get install --no-install-recommends -y git \\ - && apt-get install --no-install-recommends -y libffi-dev \\ - && apt-get install --no-install-recommends -y libjpeg-dev \\ - && apt-get install --no-install-recommends -y zlib1g-dev \\ - ''') + # Copy script files + scripts_dir = os.path.join(os.path.dirname(cfgfile), 'scripts') + if os.path.isdir(scripts_dir): + local_scripts_dir = os.path.join(device_dir, 'scripts') + remote_scripts_dir = '/etc/platypush/scripts' + shutil.copytree(scripts_dir, local_scripts_dir, symlinks=True, dirs_exist_ok=True) + content += f'RUN mkdir -p {remote_scripts_dir}\n' + content += f'COPY scripts/ {remote_scripts_dir}\n' - for i, dep in enumerate(deps): - content += '\t&& pip install --no-cache-dir {}'.format(dep) - if i < len(deps)-1: - content += ' \\'.format(dep) - content += '\n' + packages = deps.pop('packages', None) + pip = deps.pop('pip', None) + exec_cmds = deps.pop('exec', None) + pkg_cmd = f'\n\t&& apt-get install --no-install-recommends -y {" ".join(packages)} \\' if packages else '' + pip_cmd = f'\n\t&& pip install {" ".join(pip)} \\' if pip else '' + content += f''' +RUN dpkg --configure -a \\ + && apt-get -f install \\ + && apt-get --fix-missing install \\ + && apt-get clean \\ + && apt-get update \\ + && apt-get -y upgrade \\ + && apt-get -y dist-upgrade \\ + && apt-get install --no-install-recommends -y apt-utils \\ + && apt-get install --no-install-recommends -y build-essential \\ + && apt-get install --no-install-recommends -y git \\ + && apt-get install --no-install-recommends -y sudo \\ + && apt-get install --no-install-recommends -y libffi-dev \\ + && apt-get install --no-install-recommends -y libjpeg-dev \\{pkg_cmd}{pip_cmd}''' - content += textwrap.dedent( - ''' + for exec_cmd in exec_cmds: + content += f'\n\t&& {exec_cmd} \\' + content += ''' + && apt-get install --no-install-recommends -y zlib1g-dev - RUN git clone --recursive https://git.platypush.tech/platypush/platypush.git /app \\ - && cd /app \\ - && pip install -r requirements.txt +RUN git clone --recursive https://git.platypush.tech/platypush/platypush.git /app \\ + && cd /app \\ + && pip install -r requirements.txt - RUN apt-get remove -y git \\ - && apt-get remove -y build-essential \\ - && apt-get remove -y libffi-dev \\ - && apt-get remove -y libjpeg-dev \\ - && apt-get remove -y zlib1g-dev \\ - && apt-get remove -y apt-utils \\ - && apt-get clean \\ - && apt-get autoremove -y \\ - && rm -rf /var/lib/apt/lists/* - - ''') +RUN apt-get remove -y git \\ + && apt-get remove -y build-essential \\ + && apt-get remove -y libffi-dev \\ + && apt-get remove -y libjpeg-dev \\ + && apt-get remove -y zlib1g-dev \\ + && apt-get remove -y apt-utils \\ + && apt-get clean \\ + && apt-get autoremove -y \\ + && rm -rf /var/lib/apt/lists/* +''' for port in ports: content += 'EXPOSE {}\n'.format(port) @@ -134,7 +171,7 @@ def generate_dockerfile(deps, ports, cfgfile, devdir, python_version): CMD ["python", "-m", "platypush"] ''') - dockerfile = os.path.join(devdir, 'Dockerfile') + dockerfile = os.path.join(device_dir, 'Dockerfile') print('Generating Dockerfile {}'.format(dockerfile)) with open(dockerfile, 'w') as f: @@ -145,51 +182,48 @@ def build(args): global workdir ports = set() - deps = set() - - parser = argparse.ArgumentParser(prog='platydock build', - description='Build a Platypush image ' + - 'from a config.yaml') + parser = argparse.ArgumentParser( + prog='platydock build', + description='Build a Platypush image from a config.yaml' + ) parser.add_argument('-c', '--config', type=str, required=True, help='Path to the platypush configuration file') - parser.add_argument('-p', '--python-version', type=str, default='3.8', + parser.add_argument('-p', '--python-version', type=str, default='3.9', help='Python version to be used') opts, args = parser.parse_known_args(args) cfgfile = os.path.abspath(os.path.expanduser(opts.config)) + manifest._available_package_manager = 'apt' # Force apt for Debian-based Docker images + install_cmds = manifest.get_dependencies_from_conf(cfgfile) python_version = opts.python_version - Config.init(cfgfile) - register_backends() backend_config = Config.get_backends() + # Container exposed ports if backend_config.get('http'): - http_backend = get_backend('http') - ports.add(http_backend.port) - if http_backend.websocket_port: - ports.add(http_backend.websocket_port) + from platypush.backend.http import HttpBackend + # noinspection PyProtectedMember + ports.add(backend_config['http'].get('port', HttpBackend._DEFAULT_HTTP_PORT)) + # noinspection PyProtectedMember + ports.add(backend_config['http'].get('websocket_port', HttpBackend._DEFAULT_WEBSOCKET_PORT)) if backend_config.get('tcp'): - ports.add(get_backend('tcp').port) + ports.add(backend_config['tcp']['port']) if backend_config.get('websocket'): - ports.add(get_backend('websocket').port) + from platypush.backend.websocket import WebsocketBackend + # noinspection PyProtectedMember + ports.add(backend_config['websocket'].get('port', WebsocketBackend._default_websocket_port)) - for name in Config.get_backends().keys(): - deps.update(_parse_deps(get_backend(name))) + dev_dir = os.path.join(workdir, Config.get('device_id')) + generate_dockerfile( + deps=dict(install_cmds), ports=ports, cfgfile=cfgfile, device_dir=dev_dir, python_version=python_version + ) - for name in Config.get_plugins().keys(): - try: - deps.update(_parse_deps(get_plugin(name))) - except Exception as ex: - print('Dependencies parsing error for {}: {}'.format(name, str(ex))) - - devdir = os.path.join(workdir, Config.get('device_id')) - generate_dockerfile(deps=deps, ports=ports, cfgfile=cfgfile, devdir=devdir, python_version=python_version) - - subprocess.call(['docker', 'build', '-t', 'platypush-{}'.format( - Config.get('device_id')), devdir]) + subprocess.call( + ['docker', 'build', '-t', 'platypush-{}'.format(Config.get('device_id')), dev_dir] + ) def start(args): @@ -225,14 +259,13 @@ def start(args): If set, then attach to the container after starting it up (default: false). ''')) - opts, args = parser.parse_known_args(args) ports = {} dockerfile = os.path.join(workdir, opts.image, 'Dockerfile') with open(dockerfile) as f: for line in f: - m = re.match('expose (\d+)', line.strip().lower()) + m = re.match(r'expose (\d+)', line.strip().lower()) if m: ports[m.group(1)] = m.group(1) @@ -288,7 +321,7 @@ def rm(args): opts, args = parser.parse_known_args(args) subprocess.call(['docker', 'rmi', 'platypush-{}'.format(opts.image)]) - subprocess.call(['rm', '-r', os.path.join(workdir, opts.image)]) + shutil.rmtree(os.path.join(workdir, opts.image), ignore_errors=True) def ls(args): @@ -305,7 +338,7 @@ def ls(args): images = [] for line in output: - if re.match('^platypush-(.+?)\s.*', line): + if re.match(r'^platypush-(.+?)\s.*', line): if not opts.filter or (opts.filter and opts.filter in line): images.append(line) diff --git a/platypush/plugins/__init__.py b/platypush/plugins/__init__.py index fd0042aa7..ae7a85efd 100644 --- a/platypush/plugins/__init__.py +++ b/platypush/plugins/__init__.py @@ -2,11 +2,11 @@ import logging import threading import time -from abc import ABC from functools import wraps from typing import Optional from platypush.bus import Bus +from platypush.common import ExtensionWithManifest from platypush.event import EventGenerator from platypush.message.response import Response from platypush.utils import get_decorators, get_plugin_name_by_class, set_thread_name @@ -39,7 +39,7 @@ def action(f): return _execute_action -class Plugin(EventGenerator): +class Plugin(EventGenerator, ExtensionWithManifest): """ Base plugin class """ def __init__(self, **kwargs): @@ -58,7 +58,7 @@ class Plugin(EventGenerator): return getattr(self, method)(*args, **kwargs) -class RunnablePlugin(ABC, Plugin): +class RunnablePlugin(Plugin): """ Class for runnable plugins - i.e. plugins that have a start/stop method and can be started. """ diff --git a/platypush/plugins/adafruit/io.py b/platypush/plugins/adafruit/io/__init__.py similarity index 97% rename from platypush/plugins/adafruit/io.py rename to platypush/plugins/adafruit/io/__init__.py index f8c2684de..2f7e100e5 100644 --- a/platypush/plugins/adafruit/io.py +++ b/platypush/plugins/adafruit/io/__init__.py @@ -85,7 +85,13 @@ class AdafruitIoPlugin(Plugin): def _get_redis(): from redis import Redis - redis_args = get_backend('redis').redis_args + redis_args = { + 'host': 'localhost', + } + + redis_backend = get_backend('redis') + if redis_backend: + redis_args = get_backend('redis').redis_args redis_args['socket_timeout'] = 1 return Redis(**redis_args) diff --git a/platypush/plugins/adafruit/io/manifest.yaml b/platypush/plugins/adafruit/io/manifest.yaml new file mode 100644 index 000000000..b346fa3c4 --- /dev/null +++ b/platypush/plugins/adafruit/io/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - adafruit-io + package: platypush.plugins.adafruit.io + type: plugin diff --git a/platypush/plugins/alarm.py b/platypush/plugins/alarm/__init__.py similarity index 100% rename from platypush/plugins/alarm.py rename to platypush/plugins/alarm/__init__.py diff --git a/platypush/plugins/alarm/manifest.yaml b/platypush/plugins/alarm/manifest.yaml new file mode 100644 index 000000000..68f2434f6 --- /dev/null +++ b/platypush/plugins/alarm/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.alarm + type: plugin diff --git a/platypush/plugins/arduino.py b/platypush/plugins/arduino/__init__.py similarity index 100% rename from platypush/plugins/arduino.py rename to platypush/plugins/arduino/__init__.py diff --git a/platypush/plugins/arduino/manifest.yaml b/platypush/plugins/arduino/manifest.yaml new file mode 100644 index 000000000..dd644b38b --- /dev/null +++ b/platypush/plugins/arduino/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - pyfirmata2 + package: platypush.plugins.arduino + type: plugin diff --git a/platypush/plugins/assistant/echo/manifest.yaml b/platypush/plugins/assistant/echo/manifest.yaml new file mode 100644 index 000000000..b19df7be1 --- /dev/null +++ b/platypush/plugins/assistant/echo/manifest.yaml @@ -0,0 +1,13 @@ +manifest: + events: + platypush.message.event.assistant.ConversationEndEvent: when a new conversation + ends + platypush.message.event.assistant.ConversationStartEvent: when a new conversation + starts + platypush.message.event.assistant.SpeechRecognizedEvent: when a new voice command + is recognized + install: + pip: + - avs + package: platypush.plugins.assistant.echo + type: plugin diff --git a/platypush/plugins/assistant/google/manifest.yaml b/platypush/plugins/assistant/google/manifest.yaml new file mode 100644 index 000000000..0ec3fa8d1 --- /dev/null +++ b/platypush/plugins/assistant/google/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.assistant.google + type: plugin diff --git a/platypush/plugins/assistant/google/pushtotalk.py b/platypush/plugins/assistant/google/pushtotalk/__init__.py similarity index 100% rename from platypush/plugins/assistant/google/pushtotalk.py rename to platypush/plugins/assistant/google/pushtotalk/__init__.py diff --git a/platypush/plugins/assistant/google/pushtotalk/manifest.yaml b/platypush/plugins/assistant/google/pushtotalk/manifest.yaml new file mode 100644 index 000000000..2f3745079 --- /dev/null +++ b/platypush/plugins/assistant/google/pushtotalk/manifest.yaml @@ -0,0 +1,14 @@ +manifest: + events: + platypush.message.event.assistant.ConversationEndEvent: when a new conversation + ends + platypush.message.event.assistant.ConversationStartEvent: when a new conversation + starts + platypush.message.event.assistant.SpeechRecognizedEvent: when a new voice command + is recognized + install: + pip: + - tenacity + - google-assistant-sdk + package: platypush.plugins.assistant.google.pushtotalk + type: plugin diff --git a/platypush/plugins/autoremote.py b/platypush/plugins/autoremote/__init__.py similarity index 97% rename from platypush/plugins/autoremote.py rename to platypush/plugins/autoremote/__init__.py index f73c6d54b..a1d26d454 100644 --- a/platypush/plugins/autoremote.py +++ b/platypush/plugins/autoremote/__init__.py @@ -10,10 +10,6 @@ class AutoremotePlugin(Plugin): Android device that runs AutoRemote (https://joaoapps.com/autoremote/). You can also build custom actions to run on your Android device upon AutoRemote events using Tasker (https://tasker.joaoapps.com/). - - Requires: - - * **requests** (``pip install requests``) """ _AUTOREMOTE_BASE_URL = 'https://autoremotejoaomgcd.appspot.com' @@ -56,7 +52,7 @@ class AutoremotePlugin(Plugin): @action def send_message(self, msg, key=None, password=None, devices=None, target=None, - sender=None, ttl=None, group=None, *args, **kwargs): + sender=None, ttl=None, group=None, *_, **__): """ Sends a message to AutoRemote. @@ -85,9 +81,6 @@ class AutoremotePlugin(Plugin): :param group: Message group name (default: None) :type group: str """ - - target_devices = [] - if devices: target_devices = [self.devices[name] for name in self.devices.keys() if name in devices] @@ -130,14 +123,11 @@ class AutoremotePlugin(Plugin): dismiss_on_touch=False, priority=0, number=None, content_info=None, subtext=None, max_progress=None, progress=None, indeterminate_progress=False, - action_on_dismiss=None, cancel=False, *args, **kwargs): + action_on_dismiss=None, cancel=False, *_, **__): """ Sends a notification to AutoRemote. Click on your AutoRemote URL -> Send Notification for a detailed explanation of the attributes. """ - - target_devices = [] - if devices: target_devices = [self.devices[name] for name in self.devices.keys() if name in devices] diff --git a/platypush/plugins/autoremote/manifest.yaml b/platypush/plugins/autoremote/manifest.yaml new file mode 100644 index 000000000..91584916a --- /dev/null +++ b/platypush/plugins/autoremote/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.autoremote + type: plugin diff --git a/platypush/plugins/bluetooth/__init__.py b/platypush/plugins/bluetooth/__init__.py index 0c72921ed..f221243b0 100644 --- a/platypush/plugins/bluetooth/__init__.py +++ b/platypush/plugins/bluetooth/__init__.py @@ -27,6 +27,7 @@ class BluetoothPlugin(SensorPlugin): class _DeviceDiscoverer(bluetooth.DeviceDiscoverer): def __init__(self, name, *args, **kwargs): + # noinspection PyArgumentList super().__init__(*args, **kwargs) self.name = name self.device = {} @@ -35,6 +36,7 @@ class BluetoothPlugin(SensorPlugin): def pre_inquiry(self): self.done = False + # noinspection PyUnusedLocal def device_discovered(self, dev_addr, dev_class, rssi, dev_name): dev_name = dev_name.decode() if dev_name == self.name: diff --git a/platypush/plugins/bluetooth/ble.py b/platypush/plugins/bluetooth/ble/__init__.py similarity index 100% rename from platypush/plugins/bluetooth/ble.py rename to platypush/plugins/bluetooth/ble/__init__.py diff --git a/platypush/plugins/bluetooth/ble/manifest.yaml b/platypush/plugins/bluetooth/ble/manifest.yaml new file mode 100644 index 000000000..4f6c29bdd --- /dev/null +++ b/platypush/plugins/bluetooth/ble/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - pybluez + - gattlib + package: platypush.plugins.bluetooth.ble + type: plugin diff --git a/platypush/plugins/bluetooth/manifest.yaml b/platypush/plugins/bluetooth/manifest.yaml new file mode 100644 index 000000000..75ab682b7 --- /dev/null +++ b/platypush/plugins/bluetooth/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - pybluez + - pyobex + package: platypush.plugins.bluetooth + type: plugin diff --git a/platypush/plugins/calendar/__init__.py b/platypush/plugins/calendar/__init__.py index 377848b25..191e19671 100644 --- a/platypush/plugins/calendar/__init__.py +++ b/platypush/plugins/calendar/__init__.py @@ -22,9 +22,6 @@ class CalendarPlugin(Plugin, CalendarInterface): """ The CalendarPlugin allows you to keep track of multiple calendars (Google or iCal URLs) and get joined events from all of them. - - Requires: - * **dateutil** (``pip install python-dateutil``) """ def __init__(self, calendars=None, *args, **kwargs): diff --git a/platypush/plugins/calendar/ical.py b/platypush/plugins/calendar/ical/__init__.py similarity index 85% rename from platypush/plugins/calendar/ical.py rename to platypush/plugins/calendar/ical/__init__.py index 792d1cc35..4f8f02945 100644 --- a/platypush/plugins/calendar/ical.py +++ b/platypush/plugins/calendar/ical/__init__.py @@ -17,7 +17,7 @@ class CalendarIcalPlugin(Plugin, CalendarInterface): Requires: * **icalendar** (``pip install icalendar``) - * **python-dateutil** (``pip install python-dateutil``) + """ def __init__(self, url, *args, **kwargs): @@ -28,8 +28,8 @@ class CalendarIcalPlugin(Plugin, CalendarInterface): super().__init__(*args, **kwargs) self.url = url - - def _translate_event(self, event): + @staticmethod + def _translate_event(event): return { 'id': str(event.get('uid')) if event.get('uid') else None, 'kind': 'calendar#event', @@ -57,7 +57,6 @@ class CalendarIcalPlugin(Plugin, CalendarInterface): }, } - @action def get_upcoming_events(self, max_results=10, only_participating=True): """ @@ -71,7 +70,7 @@ class CalendarIcalPlugin(Plugin, CalendarInterface): events = [] response = requests.get(self.url) assert response.ok, \ - "HTTP error while getting events from {}: {}".format(self.url, response.text) + "HTTP error while getting events from {}: {}".format(self.url, response.text) calendar = Calendar.from_ical(response.text) for event in calendar.walk(): @@ -82,16 +81,14 @@ class CalendarIcalPlugin(Plugin, CalendarInterface): if event['status'] and event['responseStatus'] \ and dateutil.parser.parse(event['end']['dateTime']) >= \ - datetime.datetime.now(pytz.timezone('UTC')) \ + datetime.datetime.now(pytz.timezone('UTC')) \ and ( - (only_participating - and event['status'] == 'confirmed' - and event['responseStatus'] in ['accepted', 'tentative']) - or not only_participating): + (only_participating + and event['status'] == 'confirmed' + and event['responseStatus'] in ['accepted', 'tentative']) + or not only_participating): events.append(event) return events - # vim:sw=4:ts=4:et: - diff --git a/platypush/plugins/calendar/ical/manifest.yaml b/platypush/plugins/calendar/ical/manifest.yaml new file mode 100644 index 000000000..e451d7889 --- /dev/null +++ b/platypush/plugins/calendar/ical/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - icalendar + package: platypush.plugins.calendar.ical + type: plugin diff --git a/platypush/plugins/calendar/manifest.yaml b/platypush/plugins/calendar/manifest.yaml new file mode 100644 index 000000000..5291334b3 --- /dev/null +++ b/platypush/plugins/calendar/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.calendar + type: plugin diff --git a/platypush/plugins/camera/__init__.py b/platypush/plugins/camera/__init__.py index d85b51e77..2182add2d 100644 --- a/platypush/plugins/camera/__init__.py +++ b/platypush/plugins/camera/__init__.py @@ -490,6 +490,7 @@ class CameraPlugin(Plugin, ABC): return image_file + # noinspection PyUnusedLocal @action def take_picture(self, image_file: str, preview: bool = False, **camera) -> str: """ diff --git a/platypush/plugins/camera/android/ipcam.py b/platypush/plugins/camera/android/ipcam/__init__.py similarity index 100% rename from platypush/plugins/camera/android/ipcam.py rename to platypush/plugins/camera/android/ipcam/__init__.py diff --git a/platypush/plugins/camera/android/ipcam/manifest.yaml b/platypush/plugins/camera/android/ipcam/manifest.yaml new file mode 100644 index 000000000..eeae48c2a --- /dev/null +++ b/platypush/plugins/camera/android/ipcam/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.camera.android.ipcam + type: plugin diff --git a/platypush/plugins/camera/cv.py b/platypush/plugins/camera/cv/__init__.py similarity index 100% rename from platypush/plugins/camera/cv.py rename to platypush/plugins/camera/cv/__init__.py diff --git a/platypush/plugins/camera/cv/manifest.yaml b/platypush/plugins/camera/cv/manifest.yaml new file mode 100644 index 000000000..5c2befa2f --- /dev/null +++ b/platypush/plugins/camera/cv/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - opencv-python + - Pillow + package: platypush.plugins.camera.cv + type: plugin diff --git a/platypush/plugins/camera/ffmpeg/manifest.yaml b/platypush/plugins/camera/ffmpeg/manifest.yaml new file mode 100644 index 000000000..62d3dc670 --- /dev/null +++ b/platypush/plugins/camera/ffmpeg/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: {} + install: + apt: + - ffmpeg + pacman: + - ffmpeg + package: platypush.plugins.camera.ffmpeg + type: plugin diff --git a/platypush/plugins/camera/gstreamer/__init__.py b/platypush/plugins/camera/gstreamer/__init__.py index 50df0d8e1..2654b9fa3 100644 --- a/platypush/plugins/camera/gstreamer/__init__.py +++ b/platypush/plugins/camera/gstreamer/__init__.py @@ -14,7 +14,15 @@ class CameraGstreamerPlugin(CameraPlugin): Requires: - * **gst-python** (``pip install gst-python``) + * **gst-python** + + On Debian and derived systems: + + * ``[sudo] apt-get install python3-gi python3-gst-1.0 + + On Arch and derived systems: + + * ``[sudo] pacman -S gst-python """ diff --git a/platypush/plugins/camera/gstreamer/manifest.yaml b/platypush/plugins/camera/gstreamer/manifest.yaml new file mode 100644 index 000000000..64128f7cd --- /dev/null +++ b/platypush/plugins/camera/gstreamer/manifest.yaml @@ -0,0 +1,12 @@ +manifest: + events: {} + install: + apt: + - python3-gi + - python3-gst-1.0 + pacman: + - gst-python + - python-gobject + + package: platypush.plugins.camera.gstreamer + type: plugin diff --git a/platypush/plugins/camera/ir/mlx90640/manifest.yaml b/platypush/plugins/camera/ir/mlx90640/manifest.yaml new file mode 100644 index 000000000..d2326e0a3 --- /dev/null +++ b/platypush/plugins/camera/ir/mlx90640/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: {} + install: + apt: + - libi2c-dev + pacman: + - i2c-tools + package: platypush.plugins.camera.ir.mlx90640 + type: plugin diff --git a/platypush/plugins/camera/pi/manifest.yaml b/platypush/plugins/camera/pi/manifest.yaml new file mode 100644 index 000000000..d8e06a82b --- /dev/null +++ b/platypush/plugins/camera/pi/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: {} + install: + pip: + - picamera + - numpy + - Pillow + package: platypush.plugins.camera.pi + type: plugin diff --git a/platypush/plugins/chat/telegram.py b/platypush/plugins/chat/telegram/__init__.py similarity index 100% rename from platypush/plugins/chat/telegram.py rename to platypush/plugins/chat/telegram/__init__.py diff --git a/platypush/plugins/chat/telegram/manifest.yaml b/platypush/plugins/chat/telegram/manifest.yaml new file mode 100644 index 000000000..8f33fecf6 --- /dev/null +++ b/platypush/plugins/chat/telegram/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - python-telegram-bot + package: platypush.plugins.chat.telegram + type: plugin diff --git a/platypush/plugins/clipboard.py b/platypush/plugins/clipboard/__init__.py similarity index 100% rename from platypush/plugins/clipboard.py rename to platypush/plugins/clipboard/__init__.py diff --git a/platypush/plugins/clipboard/manifest.yaml b/platypush/plugins/clipboard/manifest.yaml new file mode 100644 index 000000000..38c268669 --- /dev/null +++ b/platypush/plugins/clipboard/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - pyperclip + package: platypush.plugins.clipboard + type: plugin diff --git a/platypush/plugins/config.py b/platypush/plugins/config/__init__.py similarity index 88% rename from platypush/plugins/config.py rename to platypush/plugins/config/__init__.py index f8cf7558c..77c4452ad 100644 --- a/platypush/plugins/config.py +++ b/platypush/plugins/config/__init__.py @@ -6,6 +6,10 @@ from platypush.plugins import Plugin, action class ConfigPlugin(Plugin): + """ + This plugin can be used to programmatically access the application configuration. + """ + @action def get(self) -> dict: return Config.get() diff --git a/platypush/plugins/config/manifest.yaml b/platypush/plugins/config/manifest.yaml new file mode 100644 index 000000000..77a56e7a4 --- /dev/null +++ b/platypush/plugins/config/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.config + type: plugin diff --git a/platypush/plugins/covid19.py b/platypush/plugins/covid19/__init__.py similarity index 100% rename from platypush/plugins/covid19.py rename to platypush/plugins/covid19/__init__.py diff --git a/platypush/plugins/covid19/manifest.yaml b/platypush/plugins/covid19/manifest.yaml new file mode 100644 index 000000000..2cdf8127f --- /dev/null +++ b/platypush/plugins/covid19/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.covid19 + type: plugin diff --git a/platypush/plugins/csv.py b/platypush/plugins/csv/__init__.py similarity index 98% rename from platypush/plugins/csv.py rename to platypush/plugins/csv/__init__.py index f19eb12f4..1cd15b334 100644 --- a/platypush/plugins/csv.py +++ b/platypush/plugins/csv/__init__.py @@ -1,7 +1,10 @@ import csv import os from typing import Optional, List, Any, Union, Dict -from typing.io import TextIO +try: + from typing.io import TextIO +except ImportError: + from typing import TextIO from platypush.plugins import Plugin, action diff --git a/platypush/plugins/csv/manifest.yaml b/platypush/plugins/csv/manifest.yaml new file mode 100644 index 000000000..f977e22a8 --- /dev/null +++ b/platypush/plugins/csv/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.csv + type: plugin diff --git a/platypush/plugins/db/__init__.py b/platypush/plugins/db/__init__.py index 0ea221a06..fb56e1f56 100644 --- a/platypush/plugins/db/__init__.py +++ b/platypush/plugins/db/__init__.py @@ -15,9 +15,6 @@ class DbPlugin(Plugin): Database plugin. It allows you to programmatically select, insert, update and delete records on a database backend through requests, procedures and event hooks. - - Requires: - * **sqlalchemy** (``pip install sqlalchemy``) """ engine = None @@ -28,8 +25,8 @@ class DbPlugin(Plugin): """ :param engine: Default SQLAlchemy connection engine string (e.g. ``sqlite:///:memory:`` or ``mysql://user:pass@localhost/test``) that will be used. You can override the default engine in the db actions. :type engine: str - :param args: Extra arguments that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html) - :param kwargs: Extra kwargs that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html) + :param args: Extra arguments that will be passed to ``sqlalchemy.create_engine`` (see https://docs.sqlalchemy.org/en/latest/core/engines.html) + :param kwargs: Extra kwargs that will be passed to ``sqlalchemy.create_engine`` (seehttps:///docs.sqlalchemy.org/en/latest/core/engines.html) """ super().__init__() @@ -46,6 +43,7 @@ class DbPlugin(Plugin): return self.engine + # noinspection PyUnusedLocal @staticmethod def _build_condition(table, column, value): if isinstance(value, str): @@ -71,8 +69,8 @@ class DbPlugin(Plugin): :type statement: str :param engine: Engine to be used (default: default class engine) :type engine: str - :param args: Extra arguments that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html) - :param kwargs: Extra kwargs that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html) + :param args: Extra arguments that will be passed to ``sqlalchemy.create_engine`` (see https://docs.sqlalchemy.org/en/latest/core/engines.html) + :param kwargs: Extra kwargs that will be passed to ``sqlalchemy.create_engine`` (seehttps:///docs.sqlalchemy.org/en/latest/core/engines.html) """ engine = self._get_engine(engine, *args, **kwargs) @@ -124,9 +122,9 @@ class DbPlugin(Plugin): :param engine: Engine to be used (default: default class engine) :type engine: str :param args: Extra arguments that will be passed to ``sqlalchemy.create_engine`` - (see http://docs.sqlalchemy.org/en/latest/core/engines.html) + (see https://docs.sqlalchemy.org/en/latest/core/engines.html) :param kwargs: Extra kwargs that will be passed to ``sqlalchemy.create_engine`` - (see http://docs.sqlalchemy.org/en/latest/core/engines.html) + (seehttps:///docs.sqlalchemy.org/en/latest/core/engines.html) :returns: List of hashes representing the result rows. Examples: @@ -206,8 +204,8 @@ class DbPlugin(Plugin): :type key_columns: list :param on_duplicate_update: If set, update the records in case of duplicate rows (default: False). If set, you'll need to specify ``key_columns`` as well. :type on_duplicate_update: bool - :param args: Extra arguments that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html) - :param kwargs: Extra kwargs that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html) + :param args: Extra arguments that will be passed to ``sqlalchemy.create_engine`` (see https://docs.sqlalchemy.org/en/latest/core/engines.html) + :param kwargs: Extra kwargs that will be passed to ``sqlalchemy.create_engine`` (seehttps:///docs.sqlalchemy.org/en/latest/core/engines.html) Example: @@ -267,8 +265,8 @@ class DbPlugin(Plugin): :type key_columns: list :param engine: Engine to be used (default: default class engine) :type engine: str - :param args: Extra arguments that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html) - :param kwargs: Extra kwargs that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html) + :param args: Extra arguments that will be passed to ``sqlalchemy.create_engine`` (see https://docs.sqlalchemy.org/en/latest/core/engines.html) + :param kwargs: Extra kwargs that will be passed to ``sqlalchemy.create_engine`` (seehttps:///docs.sqlalchemy.org/en/latest/core/engines.html) Example: @@ -323,8 +321,8 @@ class DbPlugin(Plugin): :type records: list :param engine: Engine to be used (default: default class engine) :type engine: str - :param args: Extra arguments that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html) - :param kwargs: Extra kwargs that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html) + :param args: Extra arguments that will be passed to ``sqlalchemy.create_engine`` (see https://docs.sqlalchemy.org/en/latest/core/engines.html) + :param kwargs: Extra kwargs that will be passed to ``sqlalchemy.create_engine`` (seehttps:///docs.sqlalchemy.org/en/latest/core/engines.html) Example: diff --git a/platypush/plugins/db/manifest.yaml b/platypush/plugins/db/manifest.yaml new file mode 100644 index 000000000..4ff19b161 --- /dev/null +++ b/platypush/plugins/db/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.db + type: plugin diff --git a/platypush/plugins/dbus.py b/platypush/plugins/dbus/__init__.py similarity index 100% rename from platypush/plugins/dbus.py rename to platypush/plugins/dbus/__init__.py diff --git a/platypush/plugins/dbus/manifest.yaml b/platypush/plugins/dbus/manifest.yaml new file mode 100644 index 000000000..dfd484f51 --- /dev/null +++ b/platypush/plugins/dbus/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - dbus-python + package: platypush.plugins.dbus + type: plugin diff --git a/platypush/plugins/dropbox.py b/platypush/plugins/dropbox/__init__.py similarity index 100% rename from platypush/plugins/dropbox.py rename to platypush/plugins/dropbox/__init__.py diff --git a/platypush/plugins/dropbox/manifest.yaml b/platypush/plugins/dropbox/manifest.yaml new file mode 100644 index 000000000..2e6d807e2 --- /dev/null +++ b/platypush/plugins/dropbox/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - dropbox + package: platypush.plugins.dropbox + type: plugin diff --git a/platypush/plugins/esp/__init__.py b/platypush/plugins/esp/__init__.py index ad57be9dd..ba328eb0c 100644 --- a/platypush/plugins/esp/__init__.py +++ b/platypush/plugins/esp/__init__.py @@ -2,9 +2,10 @@ import base64 import io import os import threading - from typing import Dict, Optional, List, Any, Union +import websocket + from platypush import Response from platypush.message.response.esp import EspWifiScanResult, EspWifiConfigResult from platypush.plugins import Plugin, action @@ -60,11 +61,6 @@ class EspPlugin(Plugin): - Follow the instructions, set a password and reset your device. A websocket service should be available by default on the port 8266 of your ESP8266/ESP32 and it can accept commands sent by platypush. - - Requires: - - * **websocket-client** (``pip install websocket-client``) - """ def __init__(self, devices: List[Union[Device, dict]] = None, **kwargs): @@ -114,14 +110,15 @@ class EspPlugin(Plugin): conn.close() def on_open(self, conn: Connection): - def callback(ws): + def callback(*_): conn.on_connect() - self.logger.info('Connection to {} opened'.format(ws.url)) + self.logger.info('Connection to {} opened'.format(conn.ws.url)) return callback def on_message(self, conn: Connection): - def handler(ws, msg): + def handler(*args): + msg = args[1] if len(args) > 1 else args[0] if not isinstance(msg, str): # Bytes sequences will be handled by on_data return @@ -147,7 +144,7 @@ class EspPlugin(Plugin): return - self.logger.debug('Message received on {}: {}'.format(ws.url, msg)) + self.logger.debug('Message received on {}: {}'.format(conn.ws.url, msg)) def callback(ws, msg): try: @@ -174,9 +171,7 @@ class EspPlugin(Plugin): return # noinspection PyUnusedLocal - def callback(ws, data, data_type, continue_flag): - import websocket - + def callback(ws, data, data_type, *_): try: if data_type == websocket.ABNF.OPCODE_BINARY: handler(ws, data) @@ -187,9 +182,9 @@ class EspPlugin(Plugin): return callback def on_close(self, conn: Connection): - def callback(ws): + def callback(*_): try: - ws.close() + conn.ws.close() except Exception as e: self.logger.warning('Could not close connection: {}'.format(str(e))) @@ -199,9 +194,10 @@ class EspPlugin(Plugin): return callback def on_error(self, conn: Connection): - def callback(ws, err): + def callback(*args): + err = args[1] if len(args) > 1 else args[0] conn.on_close() - self.logger.warning('Error on the connection to {}: {}'.format(ws.url, err)) + self.logger.warning('Websocket connection error: {}'.format(err)) return callback @@ -242,8 +238,6 @@ class EspPlugin(Plugin): :param password: ESP WebREPL password. :param timeout: Connection timeout (default: 10 seconds). """ - import websocket - device = self._get_device(device=device, host=host, port=port, password=password) host = device['host'] port = device['port'] diff --git a/platypush/plugins/esp/manifest.yaml b/platypush/plugins/esp/manifest.yaml new file mode 100644 index 000000000..37f39fe8a --- /dev/null +++ b/platypush/plugins/esp/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.esp + type: plugin diff --git a/platypush/plugins/ffmpeg.py b/platypush/plugins/ffmpeg/__init__.py similarity index 100% rename from platypush/plugins/ffmpeg.py rename to platypush/plugins/ffmpeg/__init__.py diff --git a/platypush/plugins/ffmpeg/manifest.yaml b/platypush/plugins/ffmpeg/manifest.yaml new file mode 100644 index 000000000..5f2454fdf --- /dev/null +++ b/platypush/plugins/ffmpeg/manifest.yaml @@ -0,0 +1,11 @@ +manifest: + events: {} + install: + pip: + - ffmpeg-python + apt: + - ffmpeg + pacman: + - ffmpeg + package: platypush.plugins.ffmpeg + type: plugin diff --git a/platypush/plugins/file.py b/platypush/plugins/file/__init__.py similarity index 100% rename from platypush/plugins/file.py rename to platypush/plugins/file/__init__.py diff --git a/platypush/plugins/file/manifest.yaml b/platypush/plugins/file/manifest.yaml new file mode 100644 index 000000000..cda28b793 --- /dev/null +++ b/platypush/plugins/file/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.file + type: plugin diff --git a/platypush/plugins/foursquare.py b/platypush/plugins/foursquare/__init__.py similarity index 100% rename from platypush/plugins/foursquare.py rename to platypush/plugins/foursquare/__init__.py diff --git a/platypush/plugins/foursquare/manifest.yaml b/platypush/plugins/foursquare/manifest.yaml new file mode 100644 index 000000000..35acebd00 --- /dev/null +++ b/platypush/plugins/foursquare/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.foursquare + type: plugin diff --git a/platypush/plugins/google/calendar.py b/platypush/plugins/google/calendar/__init__.py similarity index 85% rename from platypush/plugins/google/calendar.py rename to platypush/plugins/google/calendar/__init__.py index 5a633538c..b5caea8b4 100644 --- a/platypush/plugins/google/calendar.py +++ b/platypush/plugins/google/calendar/__init__.py @@ -11,7 +11,13 @@ from platypush.plugins.calendar import CalendarInterface class GoogleCalendarPlugin(GooglePlugin, CalendarInterface): """ - Google calendar plugin + Google calendar plugin. + + Requires: + + * **google-api-python-client** (``pip install google-api-python-client``) + * **oauth2client** (``pip install oauth2client``) + """ scopes = ['https://www.googleapis.com/auth/calendar.readonly'] diff --git a/platypush/plugins/google/calendar/manifest.yaml b/platypush/plugins/google/calendar/manifest.yaml new file mode 100644 index 000000000..f73f0f58c --- /dev/null +++ b/platypush/plugins/google/calendar/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - google-api-python-client + - oauth2client + package: platypush.plugins.google.calendar + type: plugin diff --git a/platypush/plugins/google/drive.py b/platypush/plugins/google/drive/__init__.py similarity index 98% rename from platypush/plugins/google/drive.py rename to platypush/plugins/google/drive/__init__.py index 76736a5d2..959e4830e 100644 --- a/platypush/plugins/google/drive.py +++ b/platypush/plugins/google/drive/__init__.py @@ -10,6 +10,12 @@ from platypush.message.response.google.drive import GoogleDriveFile class GoogleDrivePlugin(GooglePlugin): """ Google Drive plugin. + + Requires: + + * **google-api-python-client** (``pip install google-api-python-client``) + * **oauth2client** (``pip install oauth2client``) + """ scopes = ['https://www.googleapis.com/auth/drive', diff --git a/platypush/plugins/google/drive/manifest.yaml b/platypush/plugins/google/drive/manifest.yaml new file mode 100644 index 000000000..13fc150fd --- /dev/null +++ b/platypush/plugins/google/drive/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - google-api-python-client + - oauth2client + package: platypush.plugins.google.drive + type: plugin diff --git a/platypush/plugins/google/fit.py b/platypush/plugins/google/fit/__init__.py similarity index 90% rename from platypush/plugins/google/fit.py rename to platypush/plugins/google/fit/__init__.py index df0165b83..ec66ffcc8 100644 --- a/platypush/plugins/google/fit.py +++ b/platypush/plugins/google/fit/__init__.py @@ -4,7 +4,13 @@ from platypush.plugins.google import GooglePlugin class GoogleFitPlugin(GooglePlugin): """ - Google Fit plugin + Google Fit plugin. + + Requires: + + * **google-api-python-client** (``pip install google-api-python-client``) + * **oauth2client** (``pip install oauth2client``) + """ scopes = ['https://www.googleapis.com/auth/fitness.activity.read', @@ -44,6 +50,8 @@ class GoogleFitPlugin(GooglePlugin): :param data_source_id: Data source ID, see `get_data_sources` :type data_source_id: str + :param user_id: Target user ID (default: configured user). + :param limit: Maximum number of items to return. """ service = self.get_service(service='fitness', version='v1') diff --git a/platypush/plugins/google/fit/manifest.yaml b/platypush/plugins/google/fit/manifest.yaml new file mode 100644 index 000000000..abd723fff --- /dev/null +++ b/platypush/plugins/google/fit/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - google-api-python-client + - oauth2client + package: platypush.plugins.google.fit + type: plugin diff --git a/platypush/plugins/google/mail.py b/platypush/plugins/google/mail/__init__.py similarity index 95% rename from platypush/plugins/google/mail.py rename to platypush/plugins/google/mail/__init__.py index d713138e3..750839a3e 100644 --- a/platypush/plugins/google/mail.py +++ b/platypush/plugins/google/mail/__init__.py @@ -21,6 +21,12 @@ from platypush.plugins.google import GooglePlugin class GoogleMailPlugin(GooglePlugin): """ GMail plugin. It allows you to programmatically compose and (TODO) get emails + + Requires: + + * **google-api-python-client** (``pip install google-api-python-client``) + * **oauth2client** (``pip install oauth2client``) + """ scopes = ['https://www.googleapis.com/auth/gmail.modify'] diff --git a/platypush/plugins/google/mail/manifest.yaml b/platypush/plugins/google/mail/manifest.yaml new file mode 100644 index 000000000..fe0472905 --- /dev/null +++ b/platypush/plugins/google/mail/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - google-api-python-client + - oauth2client + package: platypush.plugins.google.mail + type: plugin diff --git a/platypush/plugins/google/maps.py b/platypush/plugins/google/maps/__init__.py similarity index 95% rename from platypush/plugins/google/maps.py rename to platypush/plugins/google/maps/__init__.py index b2e8750dd..4eec5de8c 100644 --- a/platypush/plugins/google/maps.py +++ b/platypush/plugins/google/maps/__init__.py @@ -11,6 +11,12 @@ from platypush.plugins.google import GooglePlugin class GoogleMapsPlugin(GooglePlugin): """ Plugins that provides utilities to interact with Google Maps API services. + + Requires: + + * **google-api-python-client** (``pip install google-api-python-client``) + * **oauth2client** (``pip install oauth2client``) + """ scopes = [] diff --git a/platypush/plugins/google/maps/manifest.yaml b/platypush/plugins/google/maps/manifest.yaml new file mode 100644 index 000000000..227a36ec3 --- /dev/null +++ b/platypush/plugins/google/maps/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - google-api-python-client + - oauth2client + package: platypush.plugins.google.maps + type: plugin diff --git a/platypush/plugins/google/pubsub.py b/platypush/plugins/google/pubsub/__init__.py similarity index 96% rename from platypush/plugins/google/pubsub.py rename to platypush/plugins/google/pubsub/__init__.py index cfe3746b6..1f7521131 100644 --- a/platypush/plugins/google/pubsub.py +++ b/platypush/plugins/google/pubsub/__init__.py @@ -21,8 +21,11 @@ class GooglePubsubPlugin(Plugin): Requires: + * **google-api-python-client** (``pip install google-api-python-client``) + * **oauth2client** (``pip install oauth2client``) * **google-cloud-pubsub** (``pip install google-cloud-pubsub``) + """ publisher_audience = 'https://pubsub.googleapis.com/google.pubsub.v1.Publisher' diff --git a/platypush/plugins/google/pubsub/manifest.yaml b/platypush/plugins/google/pubsub/manifest.yaml new file mode 100644 index 000000000..569b3c9c0 --- /dev/null +++ b/platypush/plugins/google/pubsub/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: {} + install: + pip: + - google-api-python-client + - oauth2client + - google-cloud-pubsub + package: platypush.plugins.google.pubsub + type: plugin diff --git a/platypush/plugins/google/translate.py b/platypush/plugins/google/translate/__init__.py similarity index 97% rename from platypush/plugins/google/translate.py rename to platypush/plugins/google/translate/__init__.py index 339a080b5..28d173a2a 100644 --- a/platypush/plugins/google/translate.py +++ b/platypush/plugins/google/translate/__init__.py @@ -26,6 +26,8 @@ class GoogleTranslatePlugin(Plugin): Requires: + * **google-api-python-client** (``pip install google-api-python-client``) + * **oauth2client** (``pip install oauth2client``) * **google-cloud-translate** (``pip install google-cloud-translate``) """ diff --git a/platypush/plugins/google/translate/manifest.yaml b/platypush/plugins/google/translate/manifest.yaml new file mode 100644 index 000000000..561878caf --- /dev/null +++ b/platypush/plugins/google/translate/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: {} + install: + pip: + - google-api-python-client + - oauth2client + - google-cloud-translate + package: platypush.plugins.google.translate + type: plugin diff --git a/platypush/plugins/google/youtube.py b/platypush/plugins/google/youtube/__init__.py similarity index 93% rename from platypush/plugins/google/youtube.py rename to platypush/plugins/google/youtube/__init__.py index 2500dc6b2..03cb8cdbd 100644 --- a/platypush/plugins/google/youtube.py +++ b/platypush/plugins/google/youtube/__init__.py @@ -8,7 +8,13 @@ from platypush.plugins.google import GooglePlugin class GoogleYoutubePlugin(GooglePlugin): """ - YouTube plugin + YouTube plugin. + + Requires: + + * **google-api-python-client** (``pip install google-api-python-client``) + * **oauth2client** (``pip install oauth2client``) + """ scopes = ['https://www.googleapis.com/auth/youtube.readonly'] diff --git a/platypush/plugins/google/youtube/manifest.yaml b/platypush/plugins/google/youtube/manifest.yaml new file mode 100644 index 000000000..a08ca8f56 --- /dev/null +++ b/platypush/plugins/google/youtube/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - google-api-python-client + - oauth2client + package: platypush.plugins.google.youtube + type: plugin diff --git a/platypush/plugins/gpio/__init__.py b/platypush/plugins/gpio/__init__.py index cd20baebd..e4bddbc58 100644 --- a/platypush/plugins/gpio/__init__.py +++ b/platypush/plugins/gpio/__init__.py @@ -13,7 +13,8 @@ class GpioPlugin(Plugin): Plugin to handle raw read/write operation on the Raspberry Pi GPIO pins. Requires: - * **RPi.GPIO** (`pip install RPi.GPIO`) + + * **RPi.GPIO** (``pip install RPi.GPIO``) """ def __init__(self, pins: Optional[Dict[str, int]] = None, mode: str = 'board', **kwargs): diff --git a/platypush/plugins/gpio/manifest.yaml b/platypush/plugins/gpio/manifest.yaml new file mode 100644 index 000000000..49d157e55 --- /dev/null +++ b/platypush/plugins/gpio/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - RPi.GPIO + package: platypush.plugins.gpio + type: plugin diff --git a/platypush/plugins/gpio/sensor/__init__.py b/platypush/plugins/gpio/sensor/__init__.py index 3bf82ee0a..0d0c81a21 100644 --- a/platypush/plugins/gpio/sensor/__init__.py +++ b/platypush/plugins/gpio/sensor/__init__.py @@ -3,7 +3,7 @@ from abc import ABC from platypush.plugins.sensor import SensorPlugin -class GpioSensorPlugin(ABC, SensorPlugin): +class GpioSensorPlugin(SensorPlugin, ABC): pass diff --git a/platypush/plugins/gpio/sensor/accelerometer/__init__.py b/platypush/plugins/gpio/sensor/accelerometer/__init__.py index cb4b4bd24..acfb5e81f 100644 --- a/platypush/plugins/gpio/sensor/accelerometer/__init__.py +++ b/platypush/plugins/gpio/sensor/accelerometer/__init__.py @@ -10,10 +10,10 @@ class GpioSensorAccelerometerPlugin(GpioSensorPlugin): Requires: - * ``Adafruit_Python_GPIO`` (``pip install Adafruit_Python_GPIO``) + * ``Adafruit-GPIO`` (``pip install Adafruit-GPIO``) """ - def __init__(self, g=4, precision=None, *args, **kwargs): + def __init__(self, g=4, precision=None, **kwargs): """ Only LIS3DH in I2C mode is currently supported: https://learn.adafruit.com/assets/59080. @@ -25,7 +25,7 @@ class GpioSensorAccelerometerPlugin(GpioSensorPlugin): :type precision: int """ - super().__init__(*args, **kwargs) + super().__init__(**kwargs) from platypush.plugins.gpio.sensor.accelerometer.lib.LIS3DH import LIS3DH if g == 2: diff --git a/platypush/plugins/gpio/sensor/accelerometer/lib/LIS3DH.py b/platypush/plugins/gpio/sensor/accelerometer/lib/LIS3DH.py index 420caca0f..e850e93ad 100644 --- a/platypush/plugins/gpio/sensor/accelerometer/lib/LIS3DH.py +++ b/platypush/plugins/gpio/sensor/accelerometer/lib/LIS3DH.py @@ -12,7 +12,7 @@ Version 1.2 - 21/01/18 (holzfigure) Using new Adafruit library Adafruit_GPIO; Replacing variable name "range" (which is a keyword) with "g-range"; -Requires the Adafruit_Python_GPIO library +Requires the Adafruit-GPIO library https://github.com/adafruit/Adafruit_Python_GPIO Inspiration and assistance from: diff --git a/platypush/plugins/gpio/sensor/accelerometer/manifest.yaml b/platypush/plugins/gpio/sensor/accelerometer/manifest.yaml new file mode 100644 index 000000000..0e88bcd98 --- /dev/null +++ b/platypush/plugins/gpio/sensor/accelerometer/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - Adafruit-GPIO + package: platypush.plugins.gpio.sensor.accelerometer + type: plugin diff --git a/platypush/plugins/gpio/sensor/bme280.py b/platypush/plugins/gpio/sensor/bme280/__init__.py similarity index 100% rename from platypush/plugins/gpio/sensor/bme280.py rename to platypush/plugins/gpio/sensor/bme280/__init__.py diff --git a/platypush/plugins/gpio/sensor/bme280/manifest.yaml b/platypush/plugins/gpio/sensor/bme280/manifest.yaml new file mode 100644 index 000000000..ad8a2fb6f --- /dev/null +++ b/platypush/plugins/gpio/sensor/bme280/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - pimoroni-bme280 + package: platypush.plugins.gpio.sensor.bme280 + type: plugin diff --git a/platypush/plugins/gpio/sensor/dht.py b/platypush/plugins/gpio/sensor/dht/__init__.py similarity index 98% rename from platypush/plugins/gpio/sensor/dht.py rename to platypush/plugins/gpio/sensor/dht/__init__.py index ca1634267..7f59541b3 100644 --- a/platypush/plugins/gpio/sensor/dht.py +++ b/platypush/plugins/gpio/sensor/dht/__init__.py @@ -39,8 +39,7 @@ class GpioSensorDhtPlugin(GpioSensorPlugin): @action def read(self, sensor_type: Optional[str] = None, pin: Optional[int] = None, - retries: Optional[int] = None, retry_seconds: Optional[int] = None, - **kwargs) -> Dict[str, float]: + retries: Optional[int] = None, retry_seconds: Optional[int] = None, **__) -> Dict[str, float]: """ Read data from the sensor. diff --git a/platypush/plugins/gpio/sensor/dht/manifest.yaml b/platypush/plugins/gpio/sensor/dht/manifest.yaml new file mode 100644 index 000000000..cecb1984a --- /dev/null +++ b/platypush/plugins/gpio/sensor/dht/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - Adafruit_Python_DHT + package: platypush.plugins.gpio.sensor.dht + type: plugin diff --git a/platypush/plugins/gpio/sensor/distance/manifest.yaml b/platypush/plugins/gpio/sensor/distance/manifest.yaml new file mode 100644 index 000000000..3b7399876 --- /dev/null +++ b/platypush/plugins/gpio/sensor/distance/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: + platypush.message.event.distance.DistanceSensorEvent: when a new distance measurement + is available + install: + pip: + - RPi.GPIO + package: platypush.plugins.gpio.sensor.distance + type: plugin diff --git a/platypush/plugins/gpio/sensor/distance/vl53l1x.py b/platypush/plugins/gpio/sensor/distance/vl53l1x/__init__.py similarity index 100% rename from platypush/plugins/gpio/sensor/distance/vl53l1x.py rename to platypush/plugins/gpio/sensor/distance/vl53l1x/__init__.py diff --git a/platypush/plugins/gpio/sensor/distance/vl53l1x/manifest.yaml b/platypush/plugins/gpio/sensor/distance/vl53l1x/manifest.yaml new file mode 100644 index 000000000..ed530f874 --- /dev/null +++ b/platypush/plugins/gpio/sensor/distance/vl53l1x/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: [] + install: + pip: + - smbus2 + - vl53l1x + package: platypush.plugins.gpio.sensor.distance.vl53l1x + type: plugin diff --git a/platypush/plugins/gpio/sensor/envirophat.py b/platypush/plugins/gpio/sensor/envirophat/__init__.py similarity index 100% rename from platypush/plugins/gpio/sensor/envirophat.py rename to platypush/plugins/gpio/sensor/envirophat/__init__.py diff --git a/platypush/plugins/gpio/sensor/envirophat/manifest.yaml b/platypush/plugins/gpio/sensor/envirophat/manifest.yaml new file mode 100644 index 000000000..6793f4fcd --- /dev/null +++ b/platypush/plugins/gpio/sensor/envirophat/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - envirophat + package: platypush.plugins.gpio.sensor.envirophat + type: plugin diff --git a/platypush/plugins/gpio/sensor/ltr559.py b/platypush/plugins/gpio/sensor/ltr559/__init__.py similarity index 100% rename from platypush/plugins/gpio/sensor/ltr559.py rename to platypush/plugins/gpio/sensor/ltr559/__init__.py diff --git a/platypush/plugins/gpio/sensor/ltr559/manifest.yaml b/platypush/plugins/gpio/sensor/ltr559/manifest.yaml new file mode 100644 index 000000000..28740526b --- /dev/null +++ b/platypush/plugins/gpio/sensor/ltr559/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - ltr559 + package: platypush.plugins.gpio.sensor.ltr559 + type: plugin diff --git a/platypush/plugins/gpio/sensor/mcp3008/manifest.yaml b/platypush/plugins/gpio/sensor/mcp3008/manifest.yaml new file mode 100644 index 000000000..e709c2727 --- /dev/null +++ b/platypush/plugins/gpio/sensor/mcp3008/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - adafruit-mcp3008 + package: platypush.plugins.gpio.sensor.mcp3008 + type: plugin diff --git a/platypush/plugins/gpio/sensor/motion/pwm3901.py b/platypush/plugins/gpio/sensor/motion/pmw3901/__init__.py similarity index 95% rename from platypush/plugins/gpio/sensor/motion/pwm3901.py rename to platypush/plugins/gpio/sensor/motion/pmw3901/__init__.py index dbee7b868..79987b7cd 100644 --- a/platypush/plugins/gpio/sensor/motion/pwm3901.py +++ b/platypush/plugins/gpio/sensor/motion/pmw3901/__init__.py @@ -18,14 +18,14 @@ class SPISlot(enum.Enum): BACK = 'back' -class GpioSensorMotionPwm3901Plugin(GpioSensorPlugin): +class GpioSensorMotionPmw3901Plugin(GpioSensorPlugin): """ - Plugin to interact with an `PWM3901 `_ + Plugin to interact with an `PMW3901 `_ optical flow and motion sensor Requires: - * ``pwm3901`` (``pip install pwm3901``) + * ``pmw3901`` (``pip install pmw3901``) """ def __init__(self, rotation=Rotation.ROTATE_0.value, spi_slot=SPISlot.FRONT.value, spi_port=0, **kwargs): diff --git a/platypush/plugins/gpio/sensor/motion/pmw3901/manifest.yaml b/platypush/plugins/gpio/sensor/motion/pmw3901/manifest.yaml new file mode 100644 index 000000000..5597ddddc --- /dev/null +++ b/platypush/plugins/gpio/sensor/motion/pmw3901/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - pmw3901 + package: platypush.plugins.gpio.sensor.motion.pmw3901 + type: plugin diff --git a/platypush/plugins/gpio/zeroborg/lib/__init__.py b/platypush/plugins/gpio/zeroborg/lib/__init__.py index 740ca314f..4b5567f0b 100644 --- a/platypush/plugins/gpio/zeroborg/lib/__init__.py +++ b/platypush/plugins/gpio/zeroborg/lib/__init__.py @@ -354,7 +354,7 @@ the current busNumber. 'drivers are running?') self.bus = None else: - self.Print('ZeroBorg loaded on bus %d' % (self.busNumber)) + self.Print('ZeroBorg loaded on bus %d' % self.busNumber) def SetMotor1(self, power): """ diff --git a/platypush/plugins/gpio/zeroborg/manifest.yaml b/platypush/plugins/gpio/zeroborg/manifest.yaml new file mode 100644 index 000000000..0feb94546 --- /dev/null +++ b/platypush/plugins/gpio/zeroborg/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.zeroborg.ZeroborgDriveEvent: when motors direction changes + platypush.message.event.zeroborg.ZeroborgStopEvent: upon motors stop + install: + pip: [] + package: platypush.plugins.gpio.zeroborg + type: plugin diff --git a/platypush/plugins/graphite.py b/platypush/plugins/graphite/__init__.py similarity index 97% rename from platypush/plugins/graphite.py rename to platypush/plugins/graphite/__init__.py index 943989ee4..7d06892ea 100644 --- a/platypush/plugins/graphite.py +++ b/platypush/plugins/graphite/__init__.py @@ -36,6 +36,7 @@ class GraphitePlugin(Plugin): :param value: Value to be sent. :param host: Graphite host (default: default configured ``host``). :param port: Graphite port (default: default configured ``port``). + :param timeout: Timeout in seconds. :param tags: Map of tags for the metric. :param prefix: Metric prefix name (default: empty string). :param protocol: Communication protocol - possible values: 'tcp', 'udp' (default: 'tcp'). diff --git a/platypush/plugins/graphite/manifest.yaml b/platypush/plugins/graphite/manifest.yaml new file mode 100644 index 000000000..e1bfd956b --- /dev/null +++ b/platypush/plugins/graphite/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.graphite + type: plugin diff --git a/platypush/plugins/homeseer.py b/platypush/plugins/homeseer.py deleted file mode 100644 index 8d6e3d7d9..000000000 --- a/platypush/plugins/homeseer.py +++ /dev/null @@ -1,101 +0,0 @@ - -from platypush.plugins import Plugin, action - - -class HomeseerPlugin(Plugin): - """ - This plugin allows you interact with an existing HomeSeer setup, - query and control connected devices. - - Requires: - - * **pyhomeseer** (``pip install git+https://github.com/legrego/PyHomeSeer``) - """ - - def __init__(self, host, username=None, password=None, *args, **kwargs): - """ - :param host: IP or hostname of your HomeSeer hub - :type host: str - - :param username: HomeSeer username - :type username: str - - :param password: HomeSeer password - :type password: str - """ - - super().__init__(*args, **kwargs) - - self.host = host - self.username = username - self.password = password - self._client = None - - def _get_client(self): - from pyhomeseer.homeseer_client import HomeSeerClient - - if not self._client: - self._client = HomeSeerClient(host=self.host, - username=self.username, - password=self.password) - - return self._client - - - @action - def query_devices(self, ref=None, location=None): - """ - Get a list of devices connected to HomeSeer with their status - - :param ref: Device reference. If not set, all the devices will be queried - :type ref: int - - :param location: Device location. If not set, all the devices will be queried - :type location: str - """ - - client = self._get_client() - - if ref is not None: - devices = client.get_devices(ref=ref) - elif location is not None: - devices = client.get_devices(location=location) - else: - devices = client.get_devices() - - return [ - { - attr: getattr(dev, attr) - for attr in ['ref','name','location','value','status'] - } - for dev in devices - ] - - - @action - def control(self, ref, value=None, label=None): - """ - Control a HomeSeer connected device. - - :param ref: Device reference - :type ref: int - - :param value: If set, then control the device with this specific int value - :type value: int - - :param label: If set, then control the device with this specific label - (e.g. 'On' or 'Off') - :type label: str - """ - - if value is None and label is None: - raise RuntimeError('Please specify either value or label') - - client = self._get_client() - - if value is not None: - return client.control(ref=ref, value=value) - return client.control(ref=ref, label=label) - - -# vim:sw=4:ts=4:et: diff --git a/platypush/plugins/http/request/__init__.py b/platypush/plugins/http/request/__init__.py index 89d911d59..3384259e9 100644 --- a/platypush/plugins/http/request/__init__.py +++ b/platypush/plugins/http/request/__init__.py @@ -12,10 +12,6 @@ class HttpRequestPlugin(Plugin): """ Plugin for executing custom HTTP requests. - Requires: - - * **requests** (``pip install requests``) - Some example usages:: # Execute a GET request on a JSON endpoint @@ -84,7 +80,7 @@ class HttpRequestPlugin(Plugin): :param kwargs: Additional arguments that will be transparently provided to the ``requests`` object, including but not limited to query params, data, JSON, headers etc. - (see http://docs.python-requests.org/en/master/user/quickstart/#make-a-request) + (see https://docs.python-requests.org/en/master/user/quickstart/#make-a-request) :type kwargs: dict """ @@ -100,7 +96,7 @@ class HttpRequestPlugin(Plugin): :param kwargs: Additional arguments that will be transparently provided to the ``requests`` object, including but not limited to query params, data, JSON, headers etc. - (see http://docs.python-requests.org/en/master/user/quickstart/#make-a-request) + (see https://docs.python-requests.org/en/master/user/quickstart/#make-a-request) :type kwargs: dict """ @@ -116,7 +112,7 @@ class HttpRequestPlugin(Plugin): :param kwargs: Additional arguments that will be transparently provided to the ``requests`` object, including but not limited to query params, data, JSON, headers etc. - (see http://docs.python-requests.org/en/master/user/quickstart/#make-a-request) + (see https://docs.python-requests.org/en/master/user/quickstart/#make-a-request) :type kwargs: dict """ @@ -132,7 +128,7 @@ class HttpRequestPlugin(Plugin): :param kwargs: Additional arguments that will be transparently provided to the ``requests`` object, including but not limited to query params, data, JSON, headers etc. - (see http://docs.python-requests.org/en/master/user/quickstart/#make-a-request) + (see https://docs.python-requests.org/en/master/user/quickstart/#make-a-request) :type kwargs: dict """ @@ -148,7 +144,7 @@ class HttpRequestPlugin(Plugin): :param kwargs: Additional arguments that will be transparently provided to the ``requests`` object, including but not limited to query params, data, JSON, headers etc. - (see http://docs.python-requests.org/en/master/user/quickstart/#make-a-request) + (see https://docs.python-requests.org/en/master/user/quickstart/#make-a-request) :type kwargs: dict """ @@ -164,7 +160,7 @@ class HttpRequestPlugin(Plugin): :param kwargs: Additional arguments that will be transparently provided to the ``requests`` object, including but not limited to query params, data, JSON, headers etc. - (see http://docs.python-requests.org/en/master/user/quickstart/#make-a-request) + (see https://docs.python-requests.org/en/master/user/quickstart/#make-a-request) :type kwargs: dict """ diff --git a/platypush/plugins/http/request/manifest.yaml b/platypush/plugins/http/request/manifest.yaml new file mode 100644 index 000000000..b37744cc5 --- /dev/null +++ b/platypush/plugins/http/request/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.http.request + type: plugin diff --git a/platypush/plugins/http/request/rss.py b/platypush/plugins/http/request/rss/__init__.py similarity index 100% rename from platypush/plugins/http/request/rss.py rename to platypush/plugins/http/request/rss/__init__.py diff --git a/platypush/plugins/http/request/rss/manifest.yaml b/platypush/plugins/http/request/rss/manifest.yaml new file mode 100644 index 000000000..e16ae74eb --- /dev/null +++ b/platypush/plugins/http/request/rss/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - feedparser + package: platypush.plugins.http.request.rss + type: plugin diff --git a/platypush/plugins/http/webpage/__init__.py b/platypush/plugins/http/webpage/__init__.py index 2626202f6..59d201187 100644 --- a/platypush/plugins/http/webpage/__init__.py +++ b/platypush/plugins/http/webpage/__init__.py @@ -16,10 +16,10 @@ class HttpWebpagePlugin(Plugin): Requires: - * **requests** (``pip install requests``) * **weasyprint** (``pip install weasyprint``), optional, for HTML->PDF conversion * **node** and **npm** installed on your system (to use the mercury-parser interface) * The mercury-parser library installed (``npm install @postlight/mercury-parser``) + """ _mercury_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'mercury-parser.js') @@ -114,7 +114,10 @@ class HttpWebpagePlugin(Plugin): if outfile.lower().endswith('.pdf'): import weasyprint - from weasyprint.fonts import FontConfiguration + try: + from weasyprint.fonts import FontConfiguration + except ImportError: + from weasyprint.document import FontConfiguration font_config = FontConfiguration() css = [weasyprint.CSS('https://fonts.googleapis.com/css?family=Merriweather'), diff --git a/platypush/plugins/http/webpage/manifest.yaml b/platypush/plugins/http/webpage/manifest.yaml new file mode 100644 index 000000000..9badd0af6 --- /dev/null +++ b/platypush/plugins/http/webpage/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - weasyprint + package: platypush.plugins.http.webpage + type: plugin diff --git a/platypush/plugins/ifttt.py b/platypush/plugins/ifttt/__init__.py similarity index 96% rename from platypush/plugins/ifttt.py rename to platypush/plugins/ifttt/__init__.py index 571ddb9bf..313b26f70 100644 --- a/platypush/plugins/ifttt.py +++ b/platypush/plugins/ifttt/__init__.py @@ -12,10 +12,6 @@ class IftttPlugin(Plugin): any action not natively supported by Platypush but available on your IFTTT configuration. - Requires: - - * **requests** (``pip install requests``) - An example:: # Trigger an IFTTT event named "at_home" diff --git a/platypush/plugins/ifttt/manifest.yaml b/platypush/plugins/ifttt/manifest.yaml new file mode 100644 index 000000000..49fd3a977 --- /dev/null +++ b/platypush/plugins/ifttt/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.ifttt + type: plugin diff --git a/platypush/plugins/inputs.py b/platypush/plugins/inputs/__init__.py similarity index 100% rename from platypush/plugins/inputs.py rename to platypush/plugins/inputs/__init__.py diff --git a/platypush/plugins/inputs/manifest.yaml b/platypush/plugins/inputs/manifest.yaml new file mode 100644 index 000000000..332f693ff --- /dev/null +++ b/platypush/plugins/inputs/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - pyuserinput + package: platypush.plugins.inputs + type: plugin diff --git a/platypush/plugins/inspect.py b/platypush/plugins/inspect/__init__.py similarity index 100% rename from platypush/plugins/inspect.py rename to platypush/plugins/inspect/__init__.py diff --git a/platypush/plugins/inspect/manifest.yaml b/platypush/plugins/inspect/manifest.yaml new file mode 100644 index 000000000..42352b97e --- /dev/null +++ b/platypush/plugins/inspect/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - docutils + package: platypush.plugins.inspect + type: plugin diff --git a/platypush/plugins/kafka.py b/platypush/plugins/kafka/__init__.py similarity index 100% rename from platypush/plugins/kafka.py rename to platypush/plugins/kafka/__init__.py diff --git a/platypush/plugins/kafka/manifest.yaml b/platypush/plugins/kafka/manifest.yaml new file mode 100644 index 000000000..31134fcb0 --- /dev/null +++ b/platypush/plugins/kafka/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: + platypush.message.event.kafka.KafkaMessageEvent: when a new message is received + on the consumer topic. + install: + pip: + - kafka + package: platypush.plugins.kafka + type: plugin diff --git a/platypush/plugins/lastfm/__init__.py b/platypush/plugins/lastfm/__init__.py index 1305cc274..a43230247 100644 --- a/platypush/plugins/lastfm/__init__.py +++ b/platypush/plugins/lastfm/__init__.py @@ -2,6 +2,7 @@ import time from platypush.plugins import Plugin, action + class LastfmPlugin(Plugin): """ Plugin to interact with your Last.FM (https://last.fm) account, update your @@ -36,14 +37,13 @@ class LastfmPlugin(Plugin): self.password = password self.lastfm = pylast.LastFMNetwork( - api_key = self.api_key, - api_secret = self.api_secret, - username = self.username, - password_hash = pylast.md5(self.password)) - + api_key=self.api_key, + api_secret=self.api_secret, + username=self.username, + password_hash=pylast.md5(self.password)) @action - def scrobble(self, artist, title, album=None, **kwargs): + def scrobble(self, artist, title, album=None): """ Scrobble a track to Last.FM @@ -56,15 +56,14 @@ class LastfmPlugin(Plugin): """ self.lastfm.scrobble( - artist = artist, - title = title, - album = album, - timestamp = int(time.time()), + artist=artist, + title=title, + album=album, + timestamp=int(time.time()), ) - @action - def update_now_playing(self, artist, title, album=None, **kwargs): + def update_now_playing(self, artist, title, album=None): """ Update the currently playing track @@ -77,11 +76,9 @@ class LastfmPlugin(Plugin): """ self.lastfm.update_now_playing( - artist = artist, - title = title, - album = album, + artist=artist, + title=title, + album=album, ) - # vim:sw=4:ts=4:et: - diff --git a/platypush/plugins/lastfm/manifest.yaml b/platypush/plugins/lastfm/manifest.yaml new file mode 100644 index 000000000..ef01bc833 --- /dev/null +++ b/platypush/plugins/lastfm/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - pylast + package: platypush.plugins.lastfm + type: plugin diff --git a/platypush/plugins/lcd/gpio.py b/platypush/plugins/lcd/gpio/__init__.py similarity index 100% rename from platypush/plugins/lcd/gpio.py rename to platypush/plugins/lcd/gpio/__init__.py diff --git a/platypush/plugins/lcd/gpio/manifest.yaml b/platypush/plugins/lcd/gpio/manifest.yaml new file mode 100644 index 000000000..30deaa44d --- /dev/null +++ b/platypush/plugins/lcd/gpio/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - RPLCD + - RPi.GPIO + package: platypush.plugins.lcd.gpio + type: plugin diff --git a/platypush/plugins/lcd/i2c.py b/platypush/plugins/lcd/i2c/__init__.py similarity index 98% rename from platypush/plugins/lcd/i2c.py rename to platypush/plugins/lcd/i2c/__init__.py index eb9d38220..92fa03e69 100644 --- a/platypush/plugins/lcd/i2c.py +++ b/platypush/plugins/lcd/i2c/__init__.py @@ -73,4 +73,8 @@ class LcdI2cPlugin(LcdPlugin): auto_linebreaks=self.auto_linebreaks) +class LcdI2CPlugin(LcdI2cPlugin): + pass + + # vim:sw=4:ts=4:et: diff --git a/platypush/plugins/lcd/i2c/manifest.yaml b/platypush/plugins/lcd/i2c/manifest.yaml new file mode 100644 index 000000000..e8d0e86b4 --- /dev/null +++ b/platypush/plugins/lcd/i2c/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - RPLCD + - RPi.GPIO + package: platypush.plugins.lcd.i2c + type: plugin diff --git a/platypush/plugins/light/__init__.py b/platypush/plugins/light/__init__.py index 369d77cdd..3943924d7 100644 --- a/platypush/plugins/light/__init__.py +++ b/platypush/plugins/light/__init__.py @@ -1,4 +1,4 @@ -from abc import ABC +from abc import ABC, abstractmethod from platypush.plugins import action from platypush.plugins.switch import SwitchPlugin @@ -10,16 +10,19 @@ class LightPlugin(SwitchPlugin, ABC): """ @action + @abstractmethod def on(self): """ Turn the light on """ raise NotImplementedError() @action + @abstractmethod def off(self): """ Turn the light off """ raise NotImplementedError() @action + @abstractmethod def toggle(self): """ Toggle the light status (on/off) """ raise NotImplementedError() diff --git a/platypush/plugins/light/hue/manifest.yaml b/platypush/plugins/light/hue/manifest.yaml new file mode 100644 index 000000000..cd18d5195 --- /dev/null +++ b/platypush/plugins/light/hue/manifest.yaml @@ -0,0 +1,11 @@ +manifest: + events: + platypush.message.event.light.LightAnimationStartedEvent: when an animation is + started. + platypush.message.event.light.LightAnimationStoppedEvent: when an animation is + stopped. + install: + pip: + - phue + package: platypush.plugins.light.hue + type: plugin diff --git a/platypush/plugins/linode.py b/platypush/plugins/linode/__init__.py similarity index 100% rename from platypush/plugins/linode.py rename to platypush/plugins/linode/__init__.py diff --git a/platypush/plugins/linode/manifest.yaml b/platypush/plugins/linode/manifest.yaml new file mode 100644 index 000000000..2b2aa3461 --- /dev/null +++ b/platypush/plugins/linode/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - linode_api4 + package: platypush.plugins.linode + type: plugin diff --git a/platypush/plugins/logger.py b/platypush/plugins/logger/__init__.py similarity index 100% rename from platypush/plugins/logger.py rename to platypush/plugins/logger/__init__.py diff --git a/platypush/plugins/logger/manifest.yaml b/platypush/plugins/logger/manifest.yaml new file mode 100644 index 000000000..87acf2a3a --- /dev/null +++ b/platypush/plugins/logger/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.logger + type: plugin diff --git a/platypush/plugins/luma/oled.py b/platypush/plugins/luma/oled/__init__.py similarity index 99% rename from platypush/plugins/luma/oled.py rename to platypush/plugins/luma/oled/__init__.py index cec30e5db..842e5afa3 100644 --- a/platypush/plugins/luma/oled.py +++ b/platypush/plugins/luma/oled/__init__.py @@ -70,14 +70,14 @@ class LumaOledPlugin(Plugin): :param font: Path to a default TTF font used to display the text. :param font_size: Font size - it only applies if ``font`` is set. """ - import luma.core.interface.serial + import luma.core.interface.serial as serial import luma.oled.device from luma.core.render import canvas super().__init__(**kwargs) iface_name = interface - interface = getattr(luma.core.interface.serial, DeviceInterface(interface).value) + interface = getattr(serial, DeviceInterface(interface).value) if iface_name == DeviceInterface.SPI.value: self.serial = interface(port=port, device=slot, cs_high=cs_high, gpio_DC=gpio_DC, diff --git a/platypush/plugins/luma/oled/manifest.yaml b/platypush/plugins/luma/oled/manifest.yaml new file mode 100644 index 000000000..662a3ae87 --- /dev/null +++ b/platypush/plugins/luma/oled/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - luma.oled + package: platypush.plugins.luma.oled + type: plugin diff --git a/platypush/plugins/mail/__init__.py b/platypush/plugins/mail/__init__.py index 68681dcd3..599da2f2a 100644 --- a/platypush/plugins/mail/__init__.py +++ b/platypush/plugins/mail/__init__.py @@ -2,7 +2,6 @@ import inspect import os import subprocess -from abc import ABC from dataclasses import dataclass from datetime import datetime from email.message import Message @@ -62,7 +61,7 @@ class Mail(JSONAble): } -class MailPlugin(Plugin, ABC): +class MailPlugin(Plugin): """ Base class for mail plugins. """ @@ -112,7 +111,7 @@ class MailPlugin(Plugin, ABC): return info -class MailInPlugin(MailPlugin, ABC): +class MailInPlugin(MailPlugin): """ Base class for mail in plugins. """ @@ -141,7 +140,7 @@ class MailInPlugin(MailPlugin, ABC): raise NotImplementedError() -class MailOutPlugin(MailPlugin, ABC): +class MailOutPlugin(MailPlugin): """ Base class for mail out plugins. """ diff --git a/platypush/plugins/mail/imap.py b/platypush/plugins/mail/imap/__init__.py similarity index 100% rename from platypush/plugins/mail/imap.py rename to platypush/plugins/mail/imap/__init__.py diff --git a/platypush/plugins/mail/imap/manifest.yaml b/platypush/plugins/mail/imap/manifest.yaml new file mode 100644 index 000000000..87adccd6f --- /dev/null +++ b/platypush/plugins/mail/imap/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - imapclient + package: platypush.plugins.mail.imap + type: plugin diff --git a/platypush/plugins/mail/smtp.py b/platypush/plugins/mail/smtp/__init__.py similarity index 100% rename from platypush/plugins/mail/smtp.py rename to platypush/plugins/mail/smtp/__init__.py diff --git a/platypush/plugins/mail/smtp/manifest.yaml b/platypush/plugins/mail/smtp/manifest.yaml new file mode 100644 index 000000000..baf0400bc --- /dev/null +++ b/platypush/plugins/mail/smtp/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.mail.smtp + type: plugin diff --git a/platypush/plugins/media/__init__.py b/platypush/plugins/media/__init__.py index 0ff03713d..b7ec992ae 100644 --- a/platypush/plugins/media/__init__.py +++ b/platypush/plugins/media/__init__.py @@ -4,6 +4,7 @@ import os import queue import re import requests +from abc import ABC, abstractmethod from typing import Optional, List, Dict, Union import subprocess @@ -22,17 +23,17 @@ class PlayerState(enum.Enum): IDLE = 'idle' -class MediaPlugin(Plugin): +class MediaPlugin(Plugin, ABC): """ Generic plugin to interact with a media player. Requires: * A media player installed (supported so far: mplayer, vlc, mpv, omxplayer, chromecast) - * **python-libtorrent** (``pip install python-libtorrent``), optional, for torrent support over native library + * **python-libtorrent-bin** (``pip install python-libtorrent-bin``), optional, for torrent support over native + library * *rtorrent* installed - optional, for torrent support over rtorrent * **youtube-dl** installed on your system (see your distro instructions), optional for YouTube support - * **requests** (``pip install requests``), optional, for local files over HTTP streaming supporting * **ffmpeg**,optional, to get media files metadata To start the local media stream service over HTTP you will also need the @@ -218,34 +219,42 @@ class MediaPlugin(Plugin): self.logger.warning(f'Could not stop torrent plugin: {str(e)}') @action + @abstractmethod def play(self, resource, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def pause(self, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def stop(self, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def quit(self, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def voldown(self, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def volup(self, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def back(self, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def forward(self, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @@ -259,42 +268,52 @@ class MediaPlugin(Plugin): return self.play(video) @action + @abstractmethod def toggle_subtitles(self, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def set_subtitles(self, filename, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def remove_subtitles(self, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def is_playing(self, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def load(self, resource, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def mute(self, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def seek(self, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def set_position(self, *args, **kwargs): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def set_volume(self, volume): raise self._NOT_IMPLEMENTED_ERR @action + @abstractmethod def status(self): raise self._NOT_IMPLEMENTED_ERR diff --git a/platypush/plugins/media/chromecast.py b/platypush/plugins/media/chromecast/__init__.py similarity index 99% rename from platypush/plugins/media/chromecast.py rename to platypush/plugins/media/chromecast/__init__.py index 5b2903512..55268cf1f 100644 --- a/platypush/plugins/media/chromecast.py +++ b/platypush/plugins/media/chromecast/__init__.py @@ -592,5 +592,11 @@ class MediaChromecastPlugin(MediaPlugin): cast.wait() return self.status(chromecast=chromecast) + def set_subtitles(self, filename, *args, **kwargs): + raise NotImplementedError + + def remove_subtitles(self, *args, **kwargs): + raise NotImplementedError + # vim:sw=4:ts=4:et: diff --git a/platypush/plugins/media/chromecast/manifest.yaml b/platypush/plugins/media/chromecast/manifest.yaml new file mode 100644 index 000000000..5e02465f4 --- /dev/null +++ b/platypush/plugins/media/chromecast/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - pychromecast + package: platypush.plugins.media.chromecast + type: plugin diff --git a/platypush/plugins/media/gstreamer/__init__.py b/platypush/plugins/media/gstreamer/__init__.py index aee692b4e..fcf79fbe8 100644 --- a/platypush/plugins/media/gstreamer/__init__.py +++ b/platypush/plugins/media/gstreamer/__init__.py @@ -14,7 +14,15 @@ class MediaGstreamerPlugin(MediaPlugin): Requires: - * **gst-python** (``pip install gst-python``) + * **gst-python** + + On Debian and derived systems: + + * ``[sudo] apt-get install python3-gi python3-gst-1.0 + + On Arch and derived systems: + + * ``[sudo] pacman -S gst-python """ @@ -217,5 +225,14 @@ class MediaGstreamerPlugin(MediaPlugin): return PlayerState.PLAY return PlayerState.IDLE + def toggle_subtitles(self, *args, **kwargs): + raise NotImplementedError + + def set_subtitles(self, filename, *args, **kwargs): + raise NotImplementedError + + def remove_subtitles(self, *args, **kwargs): + raise NotImplementedError + # vim:sw=4:ts=4:et: diff --git a/platypush/plugins/media/gstreamer/manifest.yaml b/platypush/plugins/media/gstreamer/manifest.yaml new file mode 100644 index 000000000..bdc0c567b --- /dev/null +++ b/platypush/plugins/media/gstreamer/manifest.yaml @@ -0,0 +1,12 @@ +manifest: + events: {} + install: + apt: + - python3-gi + - python3-gst-1.0 + pacman: + - gst-python + - python-gobject + + package: platypush.plugins.media.gstreamer + type: plugin diff --git a/platypush/plugins/media/kodi.py b/platypush/plugins/media/kodi/__init__.py similarity index 96% rename from platypush/plugins/media/kodi.py rename to platypush/plugins/media/kodi/__init__.py index 2d22d30db..c5cedc0cc 100644 --- a/platypush/plugins/media/kodi.py +++ b/platypush/plugins/media/kodi/__init__.py @@ -9,7 +9,6 @@ from platypush.message.event.media import MediaPlayEvent, MediaPauseEvent, Media MediaSeekEvent, MediaVolumeChangedEvent -# noinspection PyUnusedLocal class MediaKodiPlugin(MediaPlugin): """ Plugin to interact with a Kodi media player instance @@ -17,9 +16,9 @@ class MediaKodiPlugin(MediaPlugin): Requires: * **kodi-json** (``pip install kodi-json``) - * **websocket-client** (``pip install websocket-client``), optional, for player events support """ + # noinspection HttpUrlsUsage def __init__(self, host, http_port=8080, websocket_port=9090, username=None, password=None, **kwargs): """ :param host: Kodi host name or IP @@ -504,6 +503,7 @@ class MediaKodiPlugin(MediaPlugin): :param position: Seek time in seconds :type position: float + :param player_id: ID of the target player (default: configured/current player). """ if player_id is None: @@ -522,6 +522,7 @@ class MediaKodiPlugin(MediaPlugin): :param position: Seek time in seconds :type position: float + :param player_id: ID of the target player (default: configured/current player). """ return self.seek(position=position, player_id=player_id, *args, **kwargs) @@ -532,6 +533,7 @@ class MediaKodiPlugin(MediaPlugin): :param offset: Backward seek duration (default: 30 seconds) :type offset: float + :param player_id: ID of the target player (default: configured/current player). """ if player_id is None: @@ -552,6 +554,7 @@ class MediaKodiPlugin(MediaPlugin): :param offset: Forward seek duration (default: 30 seconds) :type offset: float + :param player_id: ID of the target player (default: configured/current player). """ if player_id is None: @@ -647,5 +650,20 @@ class MediaKodiPlugin(MediaPlugin): ret['state'] = PlayerState.PAUSE.value if player_info.get('speed', 0) == 0 else PlayerState.PLAY.value return ret + def toggle_subtitles(self, *args, **kwargs): + raise NotImplementedError + + def set_subtitles(self, filename, *args, **kwargs): + raise NotImplementedError + + def remove_subtitles(self, *args, **kwargs): + raise NotImplementedError + + def is_playing(self, *args, **kwargs): + raise NotImplementedError + + def load(self, resource, *args, **kwargs): + raise NotImplementedError + # vim:sw=4:ts=4:et: diff --git a/platypush/plugins/media/kodi/manifest.yaml b/platypush/plugins/media/kodi/manifest.yaml new file mode 100644 index 000000000..123e964f4 --- /dev/null +++ b/platypush/plugins/media/kodi/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - kodi-json + package: platypush.plugins.media.kodi + type: plugin diff --git a/platypush/plugins/media/mplayer.py b/platypush/plugins/media/mplayer/__init__.py similarity index 97% rename from platypush/plugins/media/mplayer.py rename to platypush/plugins/media/mplayer/__init__.py index d5e8571c3..f4219dca3 100644 --- a/platypush/plugins/media/mplayer.py +++ b/platypush/plugins/media/mplayer/__init__.py @@ -208,7 +208,7 @@ class MediaMplayerPlugin(MediaPlugin): def execute(self, cmd, args=None): """ Execute a raw MPlayer command. See - http://www.mplayerhq.hu/DOCS/tech/slave.txt for a reference or call + https://www.mplayerhq.hu/DOCS/tech/slave.txt for a reference or call :meth:`platypush.plugins.media.mplayer.list_actions` to get a list """ @@ -329,7 +329,7 @@ class MediaMplayerPlugin(MediaPlugin): return self.status() @action - def add_subtitles(self, filename, **args): + def add_subtitles(self, filename, **__): """ Sets media subtitles from filename """ self._exec('sub_visibility', 1) self._exec('sub_load', filename) @@ -451,7 +451,7 @@ class MediaMplayerPlugin(MediaPlugin): def get_property(self, property, args=None): """ Get a player property (e.g. pause, fullscreen etc.). See - http://www.mplayerhq.hu/DOCS/tech/slave.txt for a full list of the + https://www.mplayerhq.hu/DOCS/tech/slave.txt for a full list of the available properties """ @@ -473,7 +473,7 @@ class MediaMplayerPlugin(MediaPlugin): def set_property(self, property, value, args=None): """ Set a player property (e.g. pause, fullscreen etc.). See - http://www.mplayerhq.hu/DOCS/tech/slave.txt for a full list of the + https://www.mplayerhq.hu/DOCS/tech/slave.txt for a full list of the available properties """ @@ -497,7 +497,7 @@ class MediaMplayerPlugin(MediaPlugin): def step_property(self, property, value, args=None): """ Step a player property (e.g. volume, time_pos etc.). See - http://www.mplayerhq.hu/DOCS/tech/slave.txt for a full list of the + https://www.mplayerhq.hu/DOCS/tech/slave.txt for a full list of the available steppable properties """ @@ -517,4 +517,8 @@ class MediaMplayerPlugin(MediaPlugin): return response + def set_subtitles(self, filename, *args, **kwargs): + raise NotImplementedError + + # vim:sw=4:ts=4:et: diff --git a/platypush/plugins/media/mplayer/manifest.yaml b/platypush/plugins/media/mplayer/manifest.yaml new file mode 100644 index 000000000..41af7f624 --- /dev/null +++ b/platypush/plugins/media/mplayer/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: {} + install: + apt: + - mplayer + pacman: + - mplayer + package: platypush.plugins.media.mplayer + type: plugin diff --git a/platypush/plugins/media/mpv.py b/platypush/plugins/media/mpv/__init__.py similarity index 100% rename from platypush/plugins/media/mpv.py rename to platypush/plugins/media/mpv/__init__.py diff --git a/platypush/plugins/media/mpv/manifest.yaml b/platypush/plugins/media/mpv/manifest.yaml new file mode 100644 index 000000000..ce2ca462b --- /dev/null +++ b/platypush/plugins/media/mpv/manifest.yaml @@ -0,0 +1,11 @@ +manifest: + events: {} + install: + pip: + - python-mpv + apt: + - mpv + pacman: + - mpv + package: platypush.plugins.media.mpv + type: plugin diff --git a/platypush/plugins/media/omxplayer.py b/platypush/plugins/media/omxplayer/__init__.py similarity index 96% rename from platypush/plugins/media/omxplayer.py rename to platypush/plugins/media/omxplayer/__init__.py index 93af739fc..967dabc59 100644 --- a/platypush/plugins/media/omxplayer.py +++ b/platypush/plugins/media/omxplayer/__init__.py @@ -29,7 +29,7 @@ class MediaOmxplayerPlugin(MediaPlugin): :param args: Arguments that will be passed to the OMXPlayer constructor (e.g. subtitles, volume, start position, window size etc.) see https://github.com/popcornmix/omxplayer#synopsis and - http://python-omxplayer-wrapper.readthedocs.io/en/latest/omxplayer/#omxplayer.player.OMXPlayer + https://python-omxplayer-wrapper.readthedocs.io/en/latest/omxplayer/#omxplayer.player.OMXPlayer :type args: list """ @@ -376,7 +376,7 @@ class MediaOmxplayerPlugin(MediaPlugin): return _f def on_stop(self): - def _f(player, *_, **__): + def _f(*_, **__): self._post_event(MediaStopEvent) for callback in self._handlers[PlayerEvent.STOP.value]: callback() @@ -398,5 +398,14 @@ class MediaOmxplayerPlugin(MediaPlugin): self._player.positionEvent += self.on_seek() self._player.seekEvent += self.on_seek() + def toggle_subtitles(self, *args, **kwargs): + raise NotImplementedError + + def set_subtitles(self, filename, *args, **kwargs): + raise NotImplementedError + + def remove_subtitles(self, *args, **kwargs): + raise NotImplementedError + # vim:sw=4:ts=4:et: diff --git a/platypush/plugins/media/omxplayer/manifest.yaml b/platypush/plugins/media/omxplayer/manifest.yaml new file mode 100644 index 000000000..e77f8ac9d --- /dev/null +++ b/platypush/plugins/media/omxplayer/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: {} + install: + pip: + - omxplayer-wrapper + apt: + - omxplayer + package: platypush.plugins.media.omxplayer + type: plugin diff --git a/platypush/plugins/media/plex.py b/platypush/plugins/media/plex/__init__.py similarity index 99% rename from platypush/plugins/media/plex.py rename to platypush/plugins/media/plex/__init__.py index caf2abd84..4986348fc 100644 --- a/platypush/plugins/media/plex.py +++ b/platypush/plugins/media/plex/__init__.py @@ -119,7 +119,7 @@ class MediaPlexPlugin(Plugin): @staticmethod def get_chromecast(chromecast): - from .lib.plexcast import PlexController + from ..lib.plexcast import PlexController hndl = PlexController() hndl.namespace = 'urn:x-cast:com.google.cast.sse' diff --git a/platypush/plugins/media/plex/manifest.yaml b/platypush/plugins/media/plex/manifest.yaml new file mode 100644 index 000000000..7729a8d73 --- /dev/null +++ b/platypush/plugins/media/plex/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - plexapi + package: platypush.plugins.media.plex + type: plugin diff --git a/platypush/plugins/media/search/local.py b/platypush/plugins/media/search/local.py index 5d2e54029..3298dfe17 100644 --- a/platypush/plugins/media/search/local.py +++ b/platypush/plugins/media/search/local.py @@ -22,10 +22,6 @@ class LocalMediaSearcher(MediaSearcher): will index the media files for a faster search, it will detect which directories have been changed since the last scan and re-index their content if needed. - - Requires: - - * **sqlalchemy** (``pip install sqlalchemy``) """ _filename_separators = r'[.,_\-@()\[\]\{\}\s\'\"]+' diff --git a/platypush/plugins/media/subtitles.py b/platypush/plugins/media/subtitles/__init__.py similarity index 99% rename from platypush/plugins/media/subtitles.py rename to platypush/plugins/media/subtitles/__init__.py index f55e9bef9..b65277d14 100644 --- a/platypush/plugins/media/subtitles.py +++ b/platypush/plugins/media/subtitles/__init__.py @@ -16,7 +16,7 @@ class MediaSubtitlesPlugin(Plugin): * **python-opensubtitles** (``pip install -e 'git+https://github.com/agonzalezro/python-opensubtitles#egg=python-opensubtitles'``) * **webvtt** (``pip install webvtt-py``), optional, to convert srt subtitles into vtt format ready for web streaming - * **requests** (``pip install requests``) + """ def __init__(self, username, password, language=None, **kwargs): diff --git a/platypush/plugins/media/subtitles/manifest.yaml b/platypush/plugins/media/subtitles/manifest.yaml new file mode 100644 index 000000000..81bda0931 --- /dev/null +++ b/platypush/plugins/media/subtitles/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - python-opensubtitles + - webvtt-py + package: platypush.plugins.media.subtitles + type: plugin diff --git a/platypush/plugins/media/vlc.py b/platypush/plugins/media/vlc/__init__.py similarity index 100% rename from platypush/plugins/media/vlc.py rename to platypush/plugins/media/vlc/__init__.py diff --git a/platypush/plugins/media/vlc/manifest.yaml b/platypush/plugins/media/vlc/manifest.yaml new file mode 100644 index 000000000..13af03381 --- /dev/null +++ b/platypush/plugins/media/vlc/manifest.yaml @@ -0,0 +1,11 @@ +manifest: + events: {} + install: + pip: + - python-vlc + apt: + - vlc + pacman: + - vlc + package: platypush.plugins.media.vlc + type: plugin diff --git a/platypush/plugins/media/webtorrent.py b/platypush/plugins/media/webtorrent/__init__.py similarity index 94% rename from platypush/plugins/media/webtorrent.py rename to platypush/plugins/media/webtorrent/__init__.py index 747943167..3e654a22d 100644 --- a/platypush/plugins/media/webtorrent.py +++ b/platypush/plugins/media/webtorrent/__init__.py @@ -34,7 +34,6 @@ class MediaWebtorrentPlugin(MediaPlugin): * **webtorrent-cli** installed on your system (``npm install -g webtorrent-cli``) * A media plugin configured for streaming (e.g. media.mplayer, media.vlc, media.mpv or media.omxplayer) """ - _supported_media_plugins = {'media.mplayer', 'media.omxplayer', 'media.mpv', 'media.vlc', 'media.webtorrent'} @@ -421,5 +420,44 @@ class MediaWebtorrentPlugin(MediaPlugin): return {'state': self._media_plugin.status().get('state', PlayerState.STOP.value)} + def pause(self, *args, **kwargs): + raise NotImplementedError + + def voldown(self, *args, **kwargs): + raise NotImplementedError + + def volup(self, *args, **kwargs): + raise NotImplementedError + + def back(self, *args, **kwargs): + raise NotImplementedError + + def forward(self, *args, **kwargs): + raise NotImplementedError + + def toggle_subtitles(self, *args, **kwargs): + raise NotImplementedError + + def set_subtitles(self, filename, *args, **kwargs): + raise NotImplementedError + + def remove_subtitles(self, *args, **kwargs): + raise NotImplementedError + + def is_playing(self, *args, **kwargs): + raise NotImplementedError + + def mute(self, *args, **kwargs): + raise NotImplementedError + + def seek(self, *args, **kwargs): + raise NotImplementedError + + def set_position(self, *args, **kwargs): + raise NotImplementedError + + def set_volume(self, volume): + raise NotImplementedError + # vim:sw=4:ts=4:et: diff --git a/platypush/plugins/media/webtorrent/manifest.yaml b/platypush/plugins/media/webtorrent/manifest.yaml new file mode 100644 index 000000000..bc5d7160a --- /dev/null +++ b/platypush/plugins/media/webtorrent/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.media.webtorrent + type: plugin diff --git a/platypush/plugins/midi.py b/platypush/plugins/midi/__init__.py similarity index 82% rename from platypush/plugins/midi.py rename to platypush/plugins/midi/__init__.py index a954050c3..226a1c878 100644 --- a/platypush/plugins/midi.py +++ b/platypush/plugins/midi/__init__.py @@ -15,15 +15,13 @@ class MidiPlugin(Plugin): _played_notes = set() - def __init__(self, device_name='Platypush virtual MIDI output', - *args, **kwargs): + def __init__(self, device_name='Platypush virtual MIDI output', **kwargs): """ :param device_name: MIDI virtual device name (default: *Platypush virtual MIDI output*) :type device_name: str """ - import rtmidi - super().__init__(*args, **kwargs) + super().__init__(**kwargs) self.device_name = device_name self.midiout = rtmidi.MidiOut() @@ -33,15 +31,14 @@ class MidiPlugin(Plugin): self.midiout.open_port(0) self.logger.info('Initialized MIDI plugin on port 0') else: - self.open_virtual_port(self.device_name) - self.logger.info('Initialized MIDI plugin on virtual device {}'. - format(self.device_name)) - + self.midiout.open_virtual_port(self.device_name) + self.logger.info('Initialized MIDI plugin on virtual device {}'.format(self.device_name)) @action - def send_message(self, values, *args, **kwargs): + def send_message(self, values): """ - :param values: Values is expected to be a list containing the MIDI command code and the command parameters - see reference at https://ccrma.stanford.edu/~craig/articles/linuxmidi/misc/essenmidi.html + :param values: Values is expected to be a list containing the MIDI command code and the command parameters - + see reference at https://ccrma.stanford.edu/~craig/articles/linuxmidi/misc/essenmidi.html :type values: list[int] Available MIDI commands: @@ -64,13 +61,9 @@ class MidiPlugin(Plugin): * ``0xFC`` Stop (Sys Realtime) * ``0xFE`` Active Sensing (Sys Realtime) * ``0xFF`` System Reset (Sys Realtime) - - :param args: Extra args that will be passed to ``rtmidi.send_message`` - :param kwargs: Extra kwargs that will be passed to ``rtmidi.send_message`` """ - self.midiout.send_message(values, *args, **kwargs) - + self.midiout.send_message(values) @action def play_note(self, note, velocity, duration=0): @@ -95,7 +88,6 @@ class MidiPlugin(Plugin): self.send_message([0x80, note, 0]) # Note off self._played_notes.remove(note) - @action def release_note(self, note): """ @@ -108,7 +100,6 @@ class MidiPlugin(Plugin): self.send_message([0x80, note, 0]) # Note off self._played_notes.remove(note) - @action def release_all_notes(self): """ @@ -119,7 +110,6 @@ class MidiPlugin(Plugin): for note in played_notes: self.release_note(note) - @action def query_ports(self): """ @@ -131,10 +121,8 @@ class MidiPlugin(Plugin): out_ports = rtmidi.MidiOut().get_ports() return { - 'in': { i: port for i, port in enumerate(in_ports) }, - 'out': { i: port for i, port in enumerate(out_ports) }, + 'in': {i: port for i, port in enumerate(in_ports)}, + 'out': {i: port for i, port in enumerate(out_ports)}, } - # vim:sw=4:ts=4:et: - diff --git a/platypush/plugins/midi/manifest.yaml b/platypush/plugins/midi/manifest.yaml new file mode 100644 index 000000000..3a91aba97 --- /dev/null +++ b/platypush/plugins/midi/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - python-rtmidi + package: platypush.plugins.midi + type: plugin diff --git a/platypush/plugins/ml/cv.py b/platypush/plugins/ml/cv/__init__.py similarity index 100% rename from platypush/plugins/ml/cv.py rename to platypush/plugins/ml/cv/__init__.py diff --git a/platypush/plugins/ml/cv/manifest.yaml b/platypush/plugins/ml/cv/manifest.yaml new file mode 100644 index 000000000..474141682 --- /dev/null +++ b/platypush/plugins/ml/cv/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - numpy + - opencv-python + package: platypush.plugins.ml.cv + type: plugin diff --git a/platypush/plugins/mobile/join/__init__.py b/platypush/plugins/mobile/join/__init__.py index 5ca5ce95d..fb65e6ff0 100644 --- a/platypush/plugins/mobile/join/__init__.py +++ b/platypush/plugins/mobile/join/__init__.py @@ -359,7 +359,7 @@ class MobileJoinPlugin(Plugin): Default is 2. :param vibration_pattern: If the notification is received on an Android device, the vibration pattern in this field will change the way the device vibrates with it. You can easily create a pattern by going to the - `AutoRemote notification page `_ + `AutoRemote notification page `_ and generate the pattern in the Vibration Pattern field :type vibration_pattern: str (comma-separated float values) or list[float] :param dismiss_on_touch: If set the notification will be dismissed when touched (default: False) diff --git a/platypush/plugins/mobile/join/manifest.yaml b/platypush/plugins/mobile/join/manifest.yaml new file mode 100644 index 000000000..dd5aa8dff --- /dev/null +++ b/platypush/plugins/mobile/join/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.mobile.join + type: plugin diff --git a/platypush/plugins/mqtt.py b/platypush/plugins/mqtt/__init__.py similarity index 99% rename from platypush/plugins/mqtt.py rename to platypush/plugins/mqtt/__init__.py index 2fe9eb377..d757211cc 100644 --- a/platypush/plugins/mqtt.py +++ b/platypush/plugins/mqtt/__init__.py @@ -13,7 +13,7 @@ from platypush.plugins import Plugin, action class MqttPlugin(Plugin): """ This plugin allows you to send custom message to a message queue compatible - with the MQTT protocol, see http://mqtt.org/ + with the MQTT protocol, see https://mqtt.org/ Requires: diff --git a/platypush/plugins/mqtt/manifest.yaml b/platypush/plugins/mqtt/manifest.yaml new file mode 100644 index 000000000..267ac1d44 --- /dev/null +++ b/platypush/plugins/mqtt/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - paho-mqtt + package: platypush.plugins.mqtt + type: plugin diff --git a/platypush/plugins/music/mpd/manifest.yaml b/platypush/plugins/music/mpd/manifest.yaml new file mode 100644 index 000000000..42824c0ec --- /dev/null +++ b/platypush/plugins/music/mpd/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - python-mpd2 + package: platypush.plugins.music.mpd + type: plugin diff --git a/platypush/plugins/music/snapcast.py b/platypush/plugins/music/snapcast/__init__.py similarity index 99% rename from platypush/plugins/music/snapcast.py rename to platypush/plugins/music/snapcast/__init__.py index ccdde50d7..b1cd3bfcb 100644 --- a/platypush/plugins/music/snapcast.py +++ b/platypush/plugins/music/snapcast/__init__.py @@ -19,8 +19,7 @@ class MusicSnapcastPlugin(Plugin): _DEFAULT_SNAPCAST_PORT = 1705 _SOCKET_EOL = '\r\n'.encode() - def __init__(self, host='localhost', port=_DEFAULT_SNAPCAST_PORT, - *args, **kwargs): + def __init__(self, host='localhost', port=_DEFAULT_SNAPCAST_PORT, **kwargs): """ :param host: Default Snapcast server host (default: localhost) :type host: str diff --git a/platypush/plugins/music/snapcast/manifest.yaml b/platypush/plugins/music/snapcast/manifest.yaml new file mode 100644 index 000000000..7ca2536f6 --- /dev/null +++ b/platypush/plugins/music/snapcast/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.music.snapcast + type: plugin diff --git a/platypush/plugins/music/spotify.py b/platypush/plugins/music/spotify/__init__.py similarity index 100% rename from platypush/plugins/music/spotify.py rename to platypush/plugins/music/spotify/__init__.py diff --git a/platypush/plugins/music/spotify/manifest.yaml b/platypush/plugins/music/spotify/manifest.yaml new file mode 100644 index 000000000..c68d1c422 --- /dev/null +++ b/platypush/plugins/music/spotify/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.music.spotify + type: plugin diff --git a/platypush/plugins/nextcloud.py b/platypush/plugins/nextcloud/__init__.py similarity index 99% rename from platypush/plugins/nextcloud.py rename to platypush/plugins/nextcloud/__init__.py index 4cf57ee42..a2306cb3b 100644 --- a/platypush/plugins/nextcloud.py +++ b/platypush/plugins/nextcloud/__init__.py @@ -46,7 +46,7 @@ class NextcloudPlugin(Plugin): Requires: - * **nextcloud-API** (``pip install git+https://github.com/EnterpriseyIntranet/nextcloud-API.git``) + * **nextcloud-api-wrapper** (``pip install nextcloud-api-wrapper``) """ diff --git a/platypush/plugins/nextcloud/manifest.yaml b/platypush/plugins/nextcloud/manifest.yaml new file mode 100644 index 000000000..47a10c6be --- /dev/null +++ b/platypush/plugins/nextcloud/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - nextcloud-api-wrapper + package: platypush.plugins.nextcloud + type: plugin diff --git a/platypush/plugins/nmap.py b/platypush/plugins/nmap/__init__.py similarity index 100% rename from platypush/plugins/nmap.py rename to platypush/plugins/nmap/__init__.py diff --git a/platypush/plugins/nmap/manifest.yaml b/platypush/plugins/nmap/manifest.yaml new file mode 100644 index 000000000..cc2a02841 --- /dev/null +++ b/platypush/plugins/nmap/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.nmap + type: plugin diff --git a/platypush/plugins/otp.py b/platypush/plugins/otp/__init__.py similarity index 100% rename from platypush/plugins/otp.py rename to platypush/plugins/otp/__init__.py diff --git a/platypush/plugins/otp/manifest.yaml b/platypush/plugins/otp/manifest.yaml new file mode 100644 index 000000000..a4e2b5123 --- /dev/null +++ b/platypush/plugins/otp/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - pyotp + package: platypush.plugins.otp + type: plugin diff --git a/platypush/plugins/pihole.py b/platypush/plugins/pihole/__init__.py similarity index 100% rename from platypush/plugins/pihole.py rename to platypush/plugins/pihole/__init__.py diff --git a/platypush/plugins/pihole/manifest.yaml b/platypush/plugins/pihole/manifest.yaml new file mode 100644 index 000000000..23b683a4f --- /dev/null +++ b/platypush/plugins/pihole/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.pihole + type: plugin diff --git a/platypush/plugins/ping.py b/platypush/plugins/ping/__init__.py similarity index 100% rename from platypush/plugins/ping.py rename to platypush/plugins/ping/__init__.py diff --git a/platypush/plugins/ping/manifest.yaml b/platypush/plugins/ping/manifest.yaml new file mode 100644 index 000000000..8d7984be3 --- /dev/null +++ b/platypush/plugins/ping/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.ping + type: plugin diff --git a/platypush/plugins/printer/cups.py b/platypush/plugins/printer/cups/__init__.py similarity index 100% rename from platypush/plugins/printer/cups.py rename to platypush/plugins/printer/cups/__init__.py diff --git a/platypush/plugins/printer/cups/manifest.yaml b/platypush/plugins/printer/cups/manifest.yaml new file mode 100644 index 000000000..1d832d6cb --- /dev/null +++ b/platypush/plugins/printer/cups/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - pycups + package: platypush.plugins.printer.cups + type: plugin diff --git a/platypush/plugins/pushbullet.py b/platypush/plugins/pushbullet/__init__.py similarity index 98% rename from platypush/plugins/pushbullet.py rename to platypush/plugins/pushbullet/__init__.py index 837e2bb29..9c9fa1225 100644 --- a/platypush/plugins/pushbullet.py +++ b/platypush/plugins/pushbullet/__init__.py @@ -1,5 +1,6 @@ import json import os +from typing import Optional import requests @@ -15,11 +16,10 @@ class PushbulletPlugin(Plugin): Requires: - * **requests** (``pip install requests``) * The :class:`platypush.backend.pushbullet.Pushbullet` backend enabled """ - def __init__(self, token: str = None, **kwargs): + def __init__(self, token: Optional[str] = None, **kwargs): """ :param token: Pushbullet API token. If not set the plugin will try to retrieve it from the Pushbullet backend configuration, if available diff --git a/platypush/plugins/pushbullet/manifest.yaml b/platypush/plugins/pushbullet/manifest.yaml new file mode 100644 index 000000000..4e334226f --- /dev/null +++ b/platypush/plugins/pushbullet/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.pushbullet + type: plugin diff --git a/platypush/plugins/pwm/pca9685.py b/platypush/plugins/pwm/pca9685/__init__.py similarity index 98% rename from platypush/plugins/pwm/pca9685.py rename to platypush/plugins/pwm/pca9685/__init__.py index 1d27efee0..6da28116d 100644 --- a/platypush/plugins/pwm/pca9685.py +++ b/platypush/plugins/pwm/pca9685/__init__.py @@ -28,6 +28,11 @@ class PwmPca9685Plugin(Plugin): # pip3 install --upgrade adafruit-circuitpython-pca9685 This plugin works with a PCA9685 circuit connected to the Platypush host over I2C interface. + + Requires: + + - **adafruit-circuitpython-pca9685** (``pip install adafruit-circuitpython-pca9685``) + """ def __init__(self, frequency: float, min_duty_cycle: int = 0, max_duty_cycle: int = 0xffff, channels: Iterable[int] = tuple(range(16)), **kwargs): diff --git a/platypush/plugins/pwm/pca9685/manifest.yaml b/platypush/plugins/pwm/pca9685/manifest.yaml new file mode 100644 index 000000000..5abb1a021 --- /dev/null +++ b/platypush/plugins/pwm/pca9685/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - adafruit-circuitpython-pca9685 + package: platypush.plugins.pwm.pca9685 + type: plugin diff --git a/platypush/plugins/qrcode.py b/platypush/plugins/qrcode/__init__.py similarity index 93% rename from platypush/plugins/qrcode.py rename to platypush/plugins/qrcode/__init__.py index 1a51b1f59..e97fb3657 100644 --- a/platypush/plugins/qrcode.py +++ b/platypush/plugins/qrcode/__init__.py @@ -49,7 +49,7 @@ class QrcodePlugin(Plugin): # noinspection PyShadowingBuiltins @action def generate(self, content: str, output_file: Optional[str] = None, show: bool = False, - format: str = 'png', camera_plugin: Optional[str] = None) -> QrcodeGeneratedResponse: + format: str = 'png') -> QrcodeGeneratedResponse: """ Generate a QR code. If you configured the :class:`platypush.backend.http.HttpBackend` then you can also generate @@ -62,8 +62,6 @@ class QrcodePlugin(Plugin): :param show: If True, and if the device where the application runs has an active display, then the generated QR code will be shown on display. :param format: Output image format (default: ``png``). - :param camera_plugin: If set then this plugin (e.g. ``camera`` or ``camera.pi``) will be used to capture - live images from the camera and search for bar codes or QR-codes. :return: :class:`platypush.message.response.qrcode.QrcodeGeneratedResponse`. """ import qrcode @@ -102,12 +100,13 @@ class QrcodePlugin(Plugin): results = pyzbar.decode(img) return QrcodeDecodedResponse(results) - def _convert_frame(self, frame): + @staticmethod + def _convert_frame(frame): import numpy as np from PIL import Image assert isinstance(frame, np.ndarray), \ - 'Image conversion only works with numpy arrays for now (got {})'.format(type(frame)) + 'Image conversion only works with numpy arrays for now (got {})'.format(type(frame)) mode = 'RGB' if len(frame.shape) > 2 and frame.shape[2] == 4: mode = 'RGBA' @@ -173,5 +172,4 @@ class QrcodePlugin(Plugin): def stop_scanning(self): self._capturing.clear() - # vim:sw=4:ts=4:et: diff --git a/platypush/plugins/qrcode/manifest.yaml b/platypush/plugins/qrcode/manifest.yaml new file mode 100644 index 000000000..b64b1b80b --- /dev/null +++ b/platypush/plugins/qrcode/manifest.yaml @@ -0,0 +1,10 @@ +manifest: + events: {} + install: + pip: + - numpy + - qrcode + - pyzbar + - Pillow + package: platypush.plugins.qrcode + type: plugin diff --git a/platypush/plugins/redis.py b/platypush/plugins/redis/__init__.py similarity index 97% rename from platypush/plugins/redis.py rename to platypush/plugins/redis/__init__.py index 0c45bae82..56aa26a9a 100644 --- a/platypush/plugins/redis.py +++ b/platypush/plugins/redis/__init__.py @@ -7,10 +7,6 @@ from platypush.plugins import Plugin, action class RedisPlugin(Plugin): """ Plugin to send messages on Redis queues. - - Requires: - - * **redis** (``pip install redis``) """ def __init__(self, *args, **kwargs): diff --git a/platypush/plugins/redis/manifest.yaml b/platypush/plugins/redis/manifest.yaml new file mode 100644 index 000000000..c41c2cb82 --- /dev/null +++ b/platypush/plugins/redis/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.redis + type: plugin diff --git a/platypush/plugins/rtorrent.py b/platypush/plugins/rtorrent/__init__.py similarity index 100% rename from platypush/plugins/rtorrent.py rename to platypush/plugins/rtorrent/__init__.py diff --git a/platypush/plugins/rtorrent/manifest.yaml b/platypush/plugins/rtorrent/manifest.yaml new file mode 100644 index 000000000..8c6da50ce --- /dev/null +++ b/platypush/plugins/rtorrent/manifest.yaml @@ -0,0 +1,23 @@ +manifest: + events: + platypush.message.event.torrent.TorrentDownloadCompletedEvent: when a transfer + is completed. + platypush.message.event.torrent.TorrentDownloadProgressEvent: when a transfer + is progressing. + platypush.message.event.torrent.TorrentDownloadStartEvent: when a torrent transfer + starts. + platypush.message.event.torrent.TorrentDownloadedMetadataEvent: when the metadata + of a torrenttransfer has been downloaded. + platypush.message.event.torrent.TorrentPausedEvent: when a transfer is paused. + platypush.message.event.torrent.TorrentQueuedEvent: when a new torrent transfer + is queued. + platypush.message.event.torrent.TorrentRemovedEvent: when a torrent transfer is + removed. + platypush.message.event.torrent.TorrentResumedEvent: when a transfer is resumed. + install: + apt: + - rtorrent + pacman: + - rtorrent + package: platypush.plugins.rtorrent + type: plugin diff --git a/platypush/plugins/sensor/__init__.py b/platypush/plugins/sensor/__init__.py index eccc8ef42..a60a8a9eb 100644 --- a/platypush/plugins/sensor/__init__.py +++ b/platypush/plugins/sensor/__init__.py @@ -1,7 +1,9 @@ +from abc import ABC, abstractmethod + from platypush.plugins import Plugin, action -class SensorPlugin(Plugin): +class SensorPlugin(Plugin, ABC): """ Sensor abstract plugin. Any plugin that interacts with sensors should implement this class (and the get_measurement() method) @@ -10,6 +12,7 @@ class SensorPlugin(Plugin): def __init__(self, **kwargs): super().__init__(**kwargs) + @abstractmethod @action def get_measurement(self, *args, **kwargs): """ @@ -43,7 +46,6 @@ class SensorPlugin(Plugin): """ Alias for ``get_measurement`` """ - return self.get_measurement(*args, **kwargs).output @action diff --git a/platypush/plugins/serial/manifest.yaml b/platypush/plugins/serial/manifest.yaml new file mode 100644 index 000000000..e5978d23a --- /dev/null +++ b/platypush/plugins/serial/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.serial + type: plugin diff --git a/platypush/plugins/shell/manifest.yaml b/platypush/plugins/shell/manifest.yaml new file mode 100644 index 000000000..39ea9f5aa --- /dev/null +++ b/platypush/plugins/shell/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.shell + type: plugin diff --git a/platypush/plugins/slack.py b/platypush/plugins/slack/__init__.py similarity index 95% rename from platypush/plugins/slack.py rename to platypush/plugins/slack/__init__.py index 5e4cfdbeb..9e85f6691 100644 --- a/platypush/plugins/slack.py +++ b/platypush/plugins/slack/__init__.py @@ -3,7 +3,6 @@ from typing import Optional, Iterable import multiprocessing import requests -import websocket from websocket import WebSocketApp from platypush.context import get_bus @@ -62,7 +61,7 @@ class SlackPlugin(ChatPlugin, RunnablePlugin): self._bot_token = bot_token self._user_token = user_token self._ws_url: Optional[str] = None - self._ws_app: Optional[websocket.WebSocketApp] = None + self._ws_app: Optional[WebSocketApp] = None self._ws_listener: Optional[multiprocessing.Process] = None self._connected_event = multiprocessing.Event() self._disconnected_event = multiprocessing.Event() @@ -155,11 +154,11 @@ class SlackPlugin(ChatPlugin, RunnablePlugin): rs = rs.json() assert rs.get('ok') self._ws_url = rs.get('url') - self._ws_app = websocket.WebSocketApp(self._ws_url, - on_open=self._on_open(), - on_message=self._on_msg(), - on_error=self._on_error(), - on_close=self._on_close()) + self._ws_app = WebSocketApp(self._ws_url, + on_open=self._on_open(), + on_message=self._on_msg(), + on_error=self._on_error(), + on_close=self._on_close()) def server(): self._ws_app.run_forever() diff --git a/platypush/plugins/slack/manifest.yaml b/platypush/plugins/slack/manifest.yaml new file mode 100644 index 000000000..e9690c677 --- /dev/null +++ b/platypush/plugins/slack/manifest.yaml @@ -0,0 +1,14 @@ +manifest: + events: + platypush.message.event.chat.slack.SlackAppMentionReceivedEvent: when a message + that mentionsthe app is received on a monitored channel. + platypush.message.event.chat.slack.SlackMessageDeletedEvent: when a message is + deleted from amonitored channel. + platypush.message.event.chat.slack.SlackMessageEditedEvent: when a message is + edited on amonitored channel. + platypush.message.event.chat.slack.SlackMessageReceivedEvent: when a message is + received on amonitored channel. + install: + pip: [] + package: platypush.plugins.slack + type: plugin diff --git a/platypush/plugins/smartthings.py b/platypush/plugins/smartthings/__init__.py similarity index 100% rename from platypush/plugins/smartthings.py rename to platypush/plugins/smartthings/__init__.py diff --git a/platypush/plugins/smartthings/manifest.yaml b/platypush/plugins/smartthings/manifest.yaml new file mode 100644 index 000000000..25e01e7f5 --- /dev/null +++ b/platypush/plugins/smartthings/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - pysmartthings + package: platypush.plugins.smartthings + type: plugin diff --git a/platypush/plugins/sound/__init__.py b/platypush/plugins/sound/__init__.py index f63beca8c..9f7e4e306 100644 --- a/platypush/plugins/sound/__init__.py +++ b/platypush/plugins/sound/__init__.py @@ -389,7 +389,7 @@ class SoundPlugin(Plugin): raise e completed_callback_event.wait() - except queue.Full as e: + except queue.Full: if stream_index is None or \ self._get_playback_state(stream_index) != PlaybackState.STOPPED: self.logger.warning('Playback timeout: audio callback failed?') @@ -721,7 +721,7 @@ class SoundPlugin(Plugin): time.sleep(0.1) - except queue.Empty as e: + except queue.Empty: self.logger.warning('Recording timeout: audio callback failed?') finally: self.stop_playback([stream_index]) @@ -774,7 +774,7 @@ class SoundPlugin(Plugin): completed_callback_event), True) - return (stream_index, False) + return stream_index, False def _allocate_stream_index(self, stream_name=None, completed_callback_event=None): @@ -885,7 +885,6 @@ class SoundPlugin(Plugin): format(i)) continue - stream = self.active_streams[i] if self.playback_state[i] == PlaybackState.PAUSED: self.playback_state[i] = PlaybackState.PLAYING elif self.playback_state[i] == PlaybackState.PLAYING: diff --git a/platypush/plugins/sound/core.py b/platypush/plugins/sound/core.py index f225126b5..cfc51342b 100644 --- a/platypush/plugins/sound/core.py +++ b/platypush/plugins/sound/core.py @@ -3,15 +3,16 @@ """ import enum +import logging import json import math class WaveShape(enum.Enum): - SIN='sin' - SQUARE='square' - SAWTOOTH='sawtooth' - TRIANG='triang' + SIN = 'sin' + SQUARE = 'square' + SAWTOOTH = 'sawtooth' + TRIANG = 'triang' class Sound(object): @@ -99,7 +100,7 @@ class Sound(object): """ return (2.0 ** ((midi_note - cls.STANDARD_A_MIDI_NOTE) / 12.0)) \ - * A_frequency + * A_frequency @classmethod def freq_to_note(cls, frequency, A_frequency=STANDARD_A_FREQUENCY): @@ -107,7 +108,7 @@ class Sound(object): Converts a frequency in Hz to its closest MIDI note :param frequency: Frequency in Hz - :type midi_note: float + :type frequency: float :param A_frequency: Reference A4 frequency (default: 440 Hz) :type A_frequency: float @@ -115,7 +116,7 @@ class Sound(object): # TODO return also the offset in % between the provided frequency # and the standard MIDI note frequency - return int(12.0 * math.log(frequency/A_frequency, 2) + return int(12.0 * math.log(frequency / A_frequency, 2) + cls.STANDARD_A_MIDI_NOTE) def get_wave(self, t_start=0., t_end=0., samplerate=_DEFAULT_SAMPLERATE): @@ -136,19 +137,19 @@ class Sound(object): """ import numpy as np - x = np.linspace(t_start, t_end, int((t_end-t_start)*samplerate)) + x = np.linspace(t_start, t_end, int((t_end - t_start) * samplerate)) x = x.reshape(len(x), 1) if self.shape == WaveShape.SIN or self.shape == WaveShape.SQUARE: - wave = np.sin((2*np.pi*self.frequency*x) + np.pi*self.phase) + wave = np.sin((2 * np.pi * self.frequency * x) + np.pi * self.phase) if self.shape == WaveShape.SQUARE: wave[wave < 0] = -1 wave[wave >= 0] = 1 elif self.shape == WaveShape.SAWTOOTH or self.shape == WaveShape.TRIANG: - wave = 2 * (self.frequency*x - - np.floor(0.5 + self.frequency*x)) + wave = 2 * (self.frequency * x - + np.floor(0.5 + self.frequency * x)) if self.shape == WaveShape.TRIANG: wave = 2 * np.abs(wave) - 1 else: @@ -156,7 +157,6 @@ class Sound(object): return self.gain * wave - def fft(self, t_start=0., t_end=0., samplerate=_DEFAULT_SAMPLERATE, freq_range=None, freq_buckets=None): """ @@ -186,7 +186,7 @@ class Sound(object): import numpy as np if not freq_range: - freq_range = (0, int(samplerate/2)) + freq_range = (0, int(samplerate / 2)) wave = self.get_wave(t_start=t_start, t_end=t_end, samplerate=samplerate) fft = np.fft.fft(wave.reshape(len(wave))) @@ -199,13 +199,11 @@ class Sound(object): def __iter__(self): for attr in ['midi_note', 'frequency', 'gain', 'duration']: - yield (attr, getattr(self, attr)) - + yield attr, getattr(self, attr) def __str__(self): return json.dumps(dict(self)) - @classmethod def build(cls, *args, **kwargs): """ @@ -236,24 +234,21 @@ class Mix(object): def __init__(self, *sounds): self._sounds = [] + self.logger = logging.getLogger(__name__) for sound in sounds: self.add(sound) - def __iter__(self): for sound in self._sounds: yield dict(sound) - def __str__(self): return json.dumps(list(self)) - def add(self, sound): self._sounds.append(Sound.build(sound)) - def remove(self, sound_index): if sound_index >= len(self._sounds): self.logger.error('No such sound index: {} in mix {}'.format( @@ -262,7 +257,7 @@ class Mix(object): self._sounds.pop(sound_index) - + # noinspection PyProtectedMember def get_wave(self, t_start=0., t_end=0., normalize_range=(-1.0, 1.0), on_clip='scale', samplerate=Sound._DEFAULT_SAMPLERATE): """ @@ -303,8 +298,8 @@ class Mix(object): wave += sound_wave if normalize_range and len(wave): - scale_factor = (normalize_range[1]-normalize_range[0]) / \ - (wave.max()-wave.min()) + scale_factor = (normalize_range[1] - normalize_range[0]) / \ + (wave.max() - wave.min()) if scale_factor < 1.0: # Wave clipping if on_clip == 'scale': @@ -318,7 +313,7 @@ class Mix(object): return wave - + # noinspection PyProtectedMember def fft(self, t_start=0., t_end=0., samplerate=Sound._DEFAULT_SAMPLERATE, freq_range=None, freq_buckets=None): """ @@ -348,7 +343,7 @@ class Mix(object): import numpy as np if not freq_range: - freq_range = (0, int(samplerate/2)) + freq_range = (0, int(samplerate / 2)) wave = self.get_wave(t_start=t_start, t_end=t_end, samplerate=samplerate) fft = np.fft.fft(wave.reshape(len(wave))) @@ -359,7 +354,6 @@ class Mix(object): return fft - def duration(self): """ :returns: The duration of the mix in seconds as duration of its longest @@ -376,5 +370,4 @@ class Mix(object): return duration - # vim:sw=4:ts=4:et: diff --git a/platypush/plugins/sound/manifest.yaml b/platypush/plugins/sound/manifest.yaml new file mode 100644 index 000000000..c833f0ac7 --- /dev/null +++ b/platypush/plugins/sound/manifest.yaml @@ -0,0 +1,15 @@ +manifest: + events: + platypush.message.event.sound.SoundPlaybackPausedEvent: on playback pause + platypush.message.event.sound.SoundPlaybackStartedEvent: on playback start + platypush.message.event.sound.SoundPlaybackStoppedEvent: on playback stop + platypush.message.event.sound.SoundRecordingPausedEvent: on recording pause + platypush.message.event.sound.SoundRecordingStartedEvent: on recording start + platypush.message.event.sound.SoundRecordingStoppedEvent: on recording stop + install: + pip: + - sounddevice + - soundfile + - numpy + package: platypush.plugins.sound + type: plugin diff --git a/platypush/plugins/ssh/__init__.py b/platypush/plugins/ssh/__init__.py index caa096d8d..8aef1dab4 100644 --- a/platypush/plugins/ssh/__init__.py +++ b/platypush/plugins/ssh/__init__.py @@ -9,9 +9,14 @@ from binascii import hexlify from stat import S_ISDIR, S_ISREG, S_ISLNK, S_ISCHR, S_ISFIFO, S_ISSOCK, S_ISBLK, S_ISDOOR from typing import Optional, Dict, Tuple, List, Union, Any -from paramiko import DSSKey, RSAKey, SSHClient, WarningPolicy, GSS_AUTH_AVAILABLE, SFTPClient +from paramiko import DSSKey, RSAKey, SSHClient, WarningPolicy, SFTPClient from paramiko.py3compat import u +try: + from paramiko import GSS_AUTH_AVAILABLE +except ImportError: + from paramiko.ssh_gss import GSS_AUTH_AVAILABLE + from platypush import Response from platypush.message.response.ssh import SSHKeygenResponse from platypush.plugins import Plugin, action @@ -21,7 +26,7 @@ from platypush.plugins.ssh.tunnel.reverse import reverse_tunnel, close_tunnel class SshPlugin(Plugin): """ - SSh plugin. + SSH plugin. Requires: diff --git a/platypush/plugins/ssh/manifest.yaml b/platypush/plugins/ssh/manifest.yaml new file mode 100644 index 000000000..62b91a408 --- /dev/null +++ b/platypush/plugins/ssh/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - paramiko + package: platypush.plugins.ssh + type: plugin diff --git a/platypush/plugins/stt/deepspeech.py b/platypush/plugins/stt/deepspeech/__init__.py similarity index 100% rename from platypush/plugins/stt/deepspeech.py rename to platypush/plugins/stt/deepspeech/__init__.py diff --git a/platypush/plugins/stt/deepspeech/manifest.yaml b/platypush/plugins/stt/deepspeech/manifest.yaml new file mode 100644 index 000000000..8a07f7790 --- /dev/null +++ b/platypush/plugins/stt/deepspeech/manifest.yaml @@ -0,0 +1,9 @@ +manifest: + events: {} + install: + pip: + - deepspeech + - numpy + - sounddevice + package: platypush.plugins.stt.deepspeech + type: plugin diff --git a/platypush/plugins/stt/picovoice/hotword.py b/platypush/plugins/stt/picovoice/hotword/__init__.py similarity index 100% rename from platypush/plugins/stt/picovoice/hotword.py rename to platypush/plugins/stt/picovoice/hotword/__init__.py diff --git a/platypush/plugins/stt/picovoice/hotword/manifest.yaml b/platypush/plugins/stt/picovoice/hotword/manifest.yaml new file mode 100644 index 000000000..f8e9d210a --- /dev/null +++ b/platypush/plugins/stt/picovoice/hotword/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - pvporcupine + package: platypush.plugins.stt.picovoice.hotword + type: plugin diff --git a/platypush/plugins/stt/picovoice/speech.py b/platypush/plugins/stt/picovoice/speech/__init__.py similarity index 100% rename from platypush/plugins/stt/picovoice/speech.py rename to platypush/plugins/stt/picovoice/speech/__init__.py diff --git a/platypush/plugins/stt/picovoice/speech/manifest.yaml b/platypush/plugins/stt/picovoice/speech/manifest.yaml new file mode 100644 index 000000000..0e7a01a8a --- /dev/null +++ b/platypush/plugins/stt/picovoice/speech/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - cheetah + package: platypush.plugins.stt.picovoice.speech + type: plugin diff --git a/platypush/plugins/sun.py b/platypush/plugins/sun/__init__.py similarity index 100% rename from platypush/plugins/sun.py rename to platypush/plugins/sun/__init__.py diff --git a/platypush/plugins/sun/manifest.yaml b/platypush/plugins/sun/manifest.yaml new file mode 100644 index 000000000..b02a7cfee --- /dev/null +++ b/platypush/plugins/sun/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: + platypush.message.event.sun.SunriseEvent: on sunrise. + platypush.message.event.sun.SunsetEvent: on sunset. + install: + pip: [] + package: platypush.plugins.sun + type: plugin diff --git a/platypush/plugins/switch/__init__.py b/platypush/plugins/switch/__init__.py index aaef9440b..e73513d90 100644 --- a/platypush/plugins/switch/__init__.py +++ b/platypush/plugins/switch/__init__.py @@ -1,9 +1,10 @@ +from abc import ABC, abstractmethod from typing import List, Union from platypush.plugins import Plugin, action -class SwitchPlugin(Plugin): +class SwitchPlugin(Plugin, ABC): """ Abstract class for interacting with switch devices """ @@ -12,16 +13,19 @@ class SwitchPlugin(Plugin): super().__init__(**kwargs) @action + @abstractmethod def on(self, device, *args, **kwargs): """ Turn the device on """ raise NotImplementedError() @action + @abstractmethod def off(self, device, *args, **kwargs): """ Turn the device off """ raise NotImplementedError() @action + @abstractmethod def toggle(self, device, *args, **kwargs): """ Toggle the device status (on/off) """ raise NotImplementedError() @@ -52,6 +56,7 @@ class SwitchPlugin(Plugin): return self.switch_status(device) @property + @abstractmethod def switches(self) -> List[dict]: """ :return: .. schema:: switch.SwitchStatusSchema(many=True) diff --git a/platypush/plugins/switch/tplink.py b/platypush/plugins/switch/tplink/__init__.py similarity index 100% rename from platypush/plugins/switch/tplink.py rename to platypush/plugins/switch/tplink/__init__.py diff --git a/platypush/plugins/switch/tplink/manifest.yaml b/platypush/plugins/switch/tplink/manifest.yaml new file mode 100644 index 000000000..71335f391 --- /dev/null +++ b/platypush/plugins/switch/tplink/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - pyHS100 + package: platypush.plugins.switch.tplink + type: plugin diff --git a/platypush/plugins/switch/wemo/__init__.py b/platypush/plugins/switch/wemo/__init__.py index 6df63d430..312c1c31f 100644 --- a/platypush/plugins/switch/wemo/__init__.py +++ b/platypush/plugins/switch/wemo/__init__.py @@ -12,10 +12,6 @@ class SwitchWemoPlugin(SwitchPlugin): """ Plugin to control a Belkin WeMo smart switches (https://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/) - - Requires: - - * **requests** (``pip install requests``) """ _default_port = 49153 diff --git a/platypush/plugins/switch/wemo/manifest.yaml b/platypush/plugins/switch/wemo/manifest.yaml new file mode 100644 index 000000000..139028747 --- /dev/null +++ b/platypush/plugins/switch/wemo/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.switch.wemo + type: plugin diff --git a/platypush/plugins/switchbot/bluetooth.py b/platypush/plugins/switchbot/bluetooth/__init__.py similarity index 100% rename from platypush/plugins/switchbot/bluetooth.py rename to platypush/plugins/switchbot/bluetooth/__init__.py diff --git a/platypush/plugins/switchbot/bluetooth/manifest.yaml b/platypush/plugins/switchbot/bluetooth/manifest.yaml new file mode 100644 index 000000000..1e362e136 --- /dev/null +++ b/platypush/plugins/switchbot/bluetooth/manifest.yaml @@ -0,0 +1,13 @@ +manifest: + events: {} + install: + pip: + - pybluez + - gattlib + apt: + - libboost-python-dev + - libboost-thread-dev + pacman: + - boost-libs + package: platypush.plugins.switchbot.bluetooth + type: plugin diff --git a/platypush/plugins/switchbot/manifest.yaml b/platypush/plugins/switchbot/manifest.yaml new file mode 100644 index 000000000..368fb344b --- /dev/null +++ b/platypush/plugins/switchbot/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.switchbot + type: plugin diff --git a/platypush/plugins/system/manifest.yaml b/platypush/plugins/system/manifest.yaml new file mode 100644 index 000000000..bf404b996 --- /dev/null +++ b/platypush/plugins/system/manifest.yaml @@ -0,0 +1,8 @@ +manifest: + events: {} + install: + pip: + - py-cpuinfo + - psutil + package: platypush.plugins.system + type: plugin diff --git a/platypush/plugins/tcp.py b/platypush/plugins/tcp/__init__.py similarity index 100% rename from platypush/plugins/tcp.py rename to platypush/plugins/tcp/__init__.py diff --git a/platypush/plugins/tcp/manifest.yaml b/platypush/plugins/tcp/manifest.yaml new file mode 100644 index 000000000..60771e978 --- /dev/null +++ b/platypush/plugins/tcp/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.tcp + type: plugin diff --git a/platypush/plugins/tensorflow/manifest.yaml b/platypush/plugins/tensorflow/manifest.yaml new file mode 100644 index 000000000..f42dbc48d --- /dev/null +++ b/platypush/plugins/tensorflow/manifest.yaml @@ -0,0 +1,22 @@ +manifest: + events: + platypush.message.event.tensorflow.TensorflowBatchEndedEvent: when a the processing + of a Tensorflow model training/evaluation batch ends. + platypush.message.event.tensorflow.TensorflowBatchStartedEvent: when a Tensorflow + model training/evaluation batch starts being processed. + platypush.message.event.tensorflow.TensorflowEpochEndedEvent: when a Tensorflow + model training/evaluation epoch ends. + platypush.message.event.tensorflow.TensorflowEpochStartedEvent: when a Tensorflow + model training/evaluation epoch begins. + platypush.message.event.tensorflow.TensorflowTrainEndedEvent: when the training + phase of a Tensorflow model ends. + platypush.message.event.tensorflow.TensorflowTrainStartedEvent: when a Tensorflow + model starts being trained. + install: + pip: + - numpy + - pandas + - tensorflow + - keras + package: platypush.plugins.tensorflow + type: plugin diff --git a/platypush/plugins/todoist.py b/platypush/plugins/todoist/__init__.py similarity index 100% rename from platypush/plugins/todoist.py rename to platypush/plugins/todoist/__init__.py diff --git a/platypush/plugins/todoist/manifest.yaml b/platypush/plugins/todoist/manifest.yaml new file mode 100644 index 000000000..689eaa2a3 --- /dev/null +++ b/platypush/plugins/todoist/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - todoist-python + package: platypush.plugins.todoist + type: plugin diff --git a/platypush/plugins/torrent.py b/platypush/plugins/torrent/__init__.py similarity index 99% rename from platypush/plugins/torrent.py rename to platypush/plugins/torrent/__init__.py index 5ec289daf..db9e5aa53 100644 --- a/platypush/plugins/torrent.py +++ b/platypush/plugins/torrent/__init__.py @@ -21,8 +21,8 @@ class TorrentPlugin(Plugin): Requires: - * **python-libtorrent** (``pip install git+https://github.com/arvidn/libtorrent``) - * **requests** (``pip install requests``) [optional] for torrent info URL download + * **python-libtorrent-bin** (``pip install python-libtorrent-bin``) + """ # Wait time in seconds between two torrent transfer checks diff --git a/platypush/plugins/torrent/manifest.yaml b/platypush/plugins/torrent/manifest.yaml new file mode 100644 index 000000000..86adf245a --- /dev/null +++ b/platypush/plugins/torrent/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - python-libtorrent-bin + package: platypush.plugins.torrent + type: plugin diff --git a/platypush/plugins/travisci.py b/platypush/plugins/travisci/__init__.py similarity index 100% rename from platypush/plugins/travisci.py rename to platypush/plugins/travisci/__init__.py diff --git a/platypush/plugins/travisci/manifest.yaml b/platypush/plugins/travisci/manifest.yaml new file mode 100644 index 000000000..1da625201 --- /dev/null +++ b/platypush/plugins/travisci/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.travisci + type: plugin diff --git a/platypush/plugins/trello.py b/platypush/plugins/trello/__init__.py similarity index 100% rename from platypush/plugins/trello.py rename to platypush/plugins/trello/__init__.py diff --git a/platypush/plugins/trello/manifest.yaml b/platypush/plugins/trello/manifest.yaml new file mode 100644 index 000000000..c9536915d --- /dev/null +++ b/platypush/plugins/trello/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - py-trello + package: platypush.plugins.trello + type: plugin diff --git a/platypush/plugins/tts/__init__.py b/platypush/plugins/tts/__init__.py index 398c23161..f09fc4ae1 100644 --- a/platypush/plugins/tts/__init__.py +++ b/platypush/plugins/tts/__init__.py @@ -65,7 +65,7 @@ class TtsPlugin(Plugin): """ language = language or self.language player_args = player_args or self.player_args - url = 'http://translate.google.com/translate_tts?{}'.format( + url = 'https://translate.google.com/translate_tts?{}'.format( urllib.parse.urlencode({ 'ie': 'UTF-8', 'client': 'tw-ob', diff --git a/platypush/plugins/tts/google.py b/platypush/plugins/tts/google/__init__.py similarity index 96% rename from platypush/plugins/tts/google.py rename to platypush/plugins/tts/google/__init__.py index 60a90303d..c3965c560 100644 --- a/platypush/plugins/tts/google.py +++ b/platypush/plugins/tts/google/__init__.py @@ -14,8 +14,7 @@ class TtsGooglePlugin(TtsPlugin): Requires: - * **google-cloud-texttospeech** - ``pip install google-cloud-texttospeech`` - * **mplayer** - see your distribution docs on how to install the mplayer package + * **google-cloud-texttospeech** (``pip install google-cloud-texttospeech``) """ diff --git a/platypush/plugins/tts/google/manifest.yaml b/platypush/plugins/tts/google/manifest.yaml new file mode 100644 index 000000000..029a4f379 --- /dev/null +++ b/platypush/plugins/tts/google/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - google-cloud-texttospeech + package: platypush.plugins.tts.google + type: plugin diff --git a/platypush/plugins/tts/manifest.yaml b/platypush/plugins/tts/manifest.yaml new file mode 100644 index 000000000..9748a54e1 --- /dev/null +++ b/platypush/plugins/tts/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.tts + type: plugin diff --git a/platypush/plugins/tv/samsung/ws.py b/platypush/plugins/tv/samsung/ws/__init__.py similarity index 100% rename from platypush/plugins/tv/samsung/ws.py rename to platypush/plugins/tv/samsung/ws/__init__.py diff --git a/platypush/plugins/tv/samsung/ws/manifest.yaml b/platypush/plugins/tv/samsung/ws/manifest.yaml new file mode 100644 index 000000000..8e28c0947 --- /dev/null +++ b/platypush/plugins/tv/samsung/ws/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - samsungtvws + package: platypush.plugins.tv.samsung.ws + type: plugin diff --git a/platypush/plugins/twilio.py b/platypush/plugins/twilio/__init__.py similarity index 100% rename from platypush/plugins/twilio.py rename to platypush/plugins/twilio/__init__.py diff --git a/platypush/plugins/twilio/manifest.yaml b/platypush/plugins/twilio/manifest.yaml new file mode 100644 index 000000000..fa160f539 --- /dev/null +++ b/platypush/plugins/twilio/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - twilio + package: platypush.plugins.twilio + type: plugin diff --git a/platypush/plugins/udp.py b/platypush/plugins/udp/__init__.py similarity index 100% rename from platypush/plugins/udp.py rename to platypush/plugins/udp/__init__.py diff --git a/platypush/plugins/udp/manifest.yaml b/platypush/plugins/udp/manifest.yaml new file mode 100644 index 000000000..8f61c0d81 --- /dev/null +++ b/platypush/plugins/udp/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.udp + type: plugin diff --git a/platypush/plugins/user.py b/platypush/plugins/user/__init__.py similarity index 100% rename from platypush/plugins/user.py rename to platypush/plugins/user/__init__.py diff --git a/platypush/plugins/user/manifest.yaml b/platypush/plugins/user/manifest.yaml new file mode 100644 index 000000000..6cddf0c06 --- /dev/null +++ b/platypush/plugins/user/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.user + type: plugin diff --git a/platypush/plugins/utils.py b/platypush/plugins/utils/__init__.py similarity index 100% rename from platypush/plugins/utils.py rename to platypush/plugins/utils/__init__.py diff --git a/platypush/plugins/utils/manifest.yaml b/platypush/plugins/utils/manifest.yaml new file mode 100644 index 000000000..b78a4b2d2 --- /dev/null +++ b/platypush/plugins/utils/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.utils + type: plugin diff --git a/platypush/plugins/variable.py b/platypush/plugins/variable/__init__.py similarity index 97% rename from platypush/plugins/variable.py rename to platypush/plugins/variable/__init__.py index 7810507d2..0346ba888 100644 --- a/platypush/plugins/variable.py +++ b/platypush/plugins/variable/__init__.py @@ -9,11 +9,6 @@ class VariablePlugin(Plugin): accessed across your tasks. It requires the :mod:`platypush.plugins.db` and :mod:`platypush.plugins.redis` plugins to be enabled, as the variables will be stored either persisted on a local database or on the local Redis instance. - - Requires: - - * **sqlalchemy** (``pip install sqlalchemy``) - * **redis** (``pip install redis``) """ _variable_table_name = 'variable' diff --git a/platypush/plugins/variable/manifest.yaml b/platypush/plugins/variable/manifest.yaml new file mode 100644 index 000000000..5b2acc550 --- /dev/null +++ b/platypush/plugins/variable/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.variable + type: plugin diff --git a/platypush/plugins/weather/__init__.py b/platypush/plugins/weather/__init__.py index 13544ae7e..95a0ce596 100644 --- a/platypush/plugins/weather/__init__.py +++ b/platypush/plugins/weather/__init__.py @@ -1,4 +1,4 @@ -from abc import ABC +from abc import ABC, abstractmethod from platypush.plugins import Plugin, action @@ -9,5 +9,6 @@ class WeatherPlugin(Plugin, ABC): """ @action + @abstractmethod def get_current_weather(self, *args, **kwargs): raise NotImplementedError diff --git a/platypush/plugins/weather/buienradar.py b/platypush/plugins/weather/buienradar/__init__.py similarity index 100% rename from platypush/plugins/weather/buienradar.py rename to platypush/plugins/weather/buienradar/__init__.py diff --git a/platypush/plugins/weather/buienradar/manifest.yaml b/platypush/plugins/weather/buienradar/manifest.yaml new file mode 100644 index 000000000..ab494de4f --- /dev/null +++ b/platypush/plugins/weather/buienradar/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - buienradar + package: platypush.plugins.weather.buienradar + type: plugin diff --git a/platypush/plugins/weather/darksky.py b/platypush/plugins/weather/darksky/__init__.py similarity index 100% rename from platypush/plugins/weather/darksky.py rename to platypush/plugins/weather/darksky/__init__.py diff --git a/platypush/plugins/weather/darksky/manifest.yaml b/platypush/plugins/weather/darksky/manifest.yaml new file mode 100644 index 000000000..5d592f0ed --- /dev/null +++ b/platypush/plugins/weather/darksky/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.weather.darksky + type: plugin diff --git a/platypush/plugins/weather/openweathermap.py b/platypush/plugins/weather/openweathermap/__init__.py similarity index 98% rename from platypush/plugins/weather/openweathermap.py rename to platypush/plugins/weather/openweathermap/__init__.py index 457c53315..5046ad2ca 100644 --- a/platypush/plugins/weather/openweathermap.py +++ b/platypush/plugins/weather/openweathermap/__init__.py @@ -22,7 +22,7 @@ class WeatherOpenweathermapPlugin(HttpRequestPlugin, WeatherPlugin): :param location: If set, then this location will be used by default for weather lookup. If multiple locations share the same name you can disambiguate by specifying the country code as well - e.g. ``London,GB``. :param city_id: If set, then this city ID will be used by default for weather lookup. The full list of city IDs - is available `here `_. + is available `here `_. :param lat: If lat/long are set, then the weather by default will be retrieved for the specified geo location. :param long: If lat/long are set, then the weather by default will be retrieved for the specified geo location. :param zip_code: If set, then this ZIP code (should be in the form ``zip,country_code``) will be used by default diff --git a/platypush/plugins/weather/openweathermap/manifest.yaml b/platypush/plugins/weather/openweathermap/manifest.yaml new file mode 100644 index 000000000..9de6ca3f6 --- /dev/null +++ b/platypush/plugins/weather/openweathermap/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.weather.openweathermap + type: plugin diff --git a/platypush/plugins/websocket.py b/platypush/plugins/websocket/__init__.py similarity index 91% rename from platypush/plugins/websocket.py rename to platypush/plugins/websocket/__init__.py index 2a29a3369..0941e376c 100644 --- a/platypush/plugins/websocket.py +++ b/platypush/plugins/websocket/__init__.py @@ -1,6 +1,11 @@ import json import websockets +try: + from websockets.exceptions import ConnectionClosed +except ImportError: + from websockets import ConnectionClosed + from platypush.context import get_or_create_event_loop from platypush.message import Message from platypush.plugins import Plugin, action @@ -9,11 +14,7 @@ from platypush.utils import get_ssl_client_context class WebsocketPlugin(Plugin): """ - Plugin to send messages over a websocket connection - - Requires: - - * **websockets** (``pip install websockets``) + Plugin to send messages over a websocket connection. """ def __init__(self, **kwargs): @@ -54,7 +55,7 @@ class WebsocketPlugin(Plugin): async with websockets.connect(url, **websocket_args) as websocket: try: await websocket.send(str(msg)) - except websockets.exceptions.ConnectionClosed as err: + except ConnectionClosed as err: self.logger.warning('Error on websocket {}: {}'. format(url, err)) diff --git a/platypush/plugins/websocket/manifest.yaml b/platypush/plugins/websocket/manifest.yaml new file mode 100644 index 000000000..8c95c60ed --- /dev/null +++ b/platypush/plugins/websocket/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.websocket + type: plugin diff --git a/platypush/plugins/wiimote.py b/platypush/plugins/wiimote/__init__.py similarity index 100% rename from platypush/plugins/wiimote.py rename to platypush/plugins/wiimote/__init__.py diff --git a/platypush/plugins/wiimote/manifest.yaml b/platypush/plugins/wiimote/manifest.yaml new file mode 100644 index 000000000..80d570e87 --- /dev/null +++ b/platypush/plugins/wiimote/manifest.yaml @@ -0,0 +1,6 @@ +manifest: + events: {} + install: + pip: [] + package: platypush.plugins.wiimote + type: plugin diff --git a/platypush/plugins/zeroconf.py b/platypush/plugins/zeroconf/__init__.py similarity index 100% rename from platypush/plugins/zeroconf.py rename to platypush/plugins/zeroconf/__init__.py diff --git a/platypush/plugins/zeroconf/manifest.yaml b/platypush/plugins/zeroconf/manifest.yaml new file mode 100644 index 000000000..695516fcb --- /dev/null +++ b/platypush/plugins/zeroconf/manifest.yaml @@ -0,0 +1,13 @@ +manifest: + events: + platypush.message.event.zeroconf.ZeroconfServiceAddedEvent: when a new service + is discovered. + platypush.message.event.zeroconf.ZeroconfServiceRemovedEvent: when a service is + removed. + platypush.message.event.zeroconf.ZeroconfServiceUpdatedEvent: when a service is + updated. + install: + pip: + - zeroconf + package: platypush.plugins.zeroconf + type: plugin diff --git a/platypush/plugins/zigbee/mqtt.py b/platypush/plugins/zigbee/mqtt/__init__.py similarity index 100% rename from platypush/plugins/zigbee/mqtt.py rename to platypush/plugins/zigbee/mqtt/__init__.py diff --git a/platypush/plugins/zigbee/mqtt/manifest.yaml b/platypush/plugins/zigbee/mqtt/manifest.yaml new file mode 100644 index 000000000..3c57ec8d1 --- /dev/null +++ b/platypush/plugins/zigbee/mqtt/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - paho-mqtt + package: platypush.plugins.zigbee.mqtt + type: plugin diff --git a/platypush/plugins/zwave/_base.py b/platypush/plugins/zwave/_base.py index 0099b9e88..76a984793 100644 --- a/platypush/plugins/zwave/_base.py +++ b/platypush/plugins/zwave/_base.py @@ -1,23 +1,26 @@ -from abc import ABC +from abc import ABC, abstractmethod from typing import Any, Dict, Optional, List, Union from platypush.plugins import action from platypush.plugins.switch import SwitchPlugin -class ZwaveBasePlugin(ABC, SwitchPlugin): +class ZwaveBasePlugin(SwitchPlugin, ABC): """ Base class for Z-Wave plugins. """ + @abstractmethod @action def start_network(self): raise NotImplementedError + @abstractmethod @action def stop_network(self): raise NotImplementedError + @abstractmethod @action def status(self) -> Dict[str, Any]: """ @@ -25,6 +28,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def add_node(self, *args, **kwargs): """ @@ -32,6 +36,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def remove_node(self): """ @@ -39,6 +44,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def remove_failed_node(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs): """ @@ -49,6 +55,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def replace_failed_node(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs): """ @@ -59,6 +66,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def replication_send(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs): """ @@ -69,6 +77,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def request_network_update(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs): """ @@ -79,6 +88,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def request_node_neighbour_update(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs): """ @@ -89,6 +99,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_nodes(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) -> Dict[str, Any]: """ @@ -99,6 +110,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_node_stats(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) \ -> Dict[str, Any]: @@ -110,6 +122,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def set_node_name(self, new_name: str, node_id: Optional[int] = None, node_name: Optional[str] = None): """ @@ -121,6 +134,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def set_node_product_name(self, product_name: str, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs): @@ -133,6 +147,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def set_node_manufacturer_name(self, manufacturer_name: str, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs): @@ -145,6 +160,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def set_node_location(self, location: str, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs): @@ -157,6 +173,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def cancel_command(self): """ @@ -164,6 +181,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def kill_command(self): """ @@ -171,6 +189,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def set_controller_name(self, name: str, **kwargs): """ @@ -180,6 +199,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_capabilities(self, **kwargs) -> List[str]: """ @@ -187,6 +207,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def receive_configuration(self, **kwargs): """ @@ -194,6 +215,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def transfer_primary_role(self, **kwargs): """ @@ -202,6 +224,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def heal(self, refresh_routes: bool = False, **kwargs): """ @@ -211,6 +234,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def switch_all(self, state: bool, **kwargs): """ @@ -220,6 +244,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def test(self, count: int = 1, **kwargs): """ @@ -229,6 +254,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_value(self, value_id: Optional[int] = None, id_on_network: Optional[str] = None, value_label: Optional[str] = None, node_id: Optional[int] = None, node_name: Optional[str] = None, @@ -244,6 +270,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def set_value(self, data, value_id: Optional[int] = None, id_on_network: Optional[str] = None, value_label: Optional[str] = None, node_id: Optional[int] = None, node_name: Optional[str] = None, @@ -260,6 +287,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def set_value_label(self, new_label: str, value_id: Optional[int] = None, id_on_network: Optional[str] = None, value_label: Optional[str] = None, node_id: Optional[int] = None, @@ -276,6 +304,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def node_add_value(self, value_id: Optional[int] = None, id_on_network: Optional[str] = None, value_label: Optional[str] = None, node_id: Optional[int] = None, @@ -291,6 +320,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def node_remove_value(self, value_id: Optional[int] = None, id_on_network: Optional[str] = None, value_label: Optional[str] = None, node_id: Optional[int] = None, @@ -306,6 +336,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def node_heal(self, node_id: Optional[int] = None, node_name: Optional[str] = None, refresh_routes: bool = False, **kwargs): @@ -318,6 +349,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def node_update_neighbours(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs): """ @@ -328,6 +360,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def node_network_update(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs): """ @@ -338,6 +371,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def node_refresh_info(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs): """ @@ -348,6 +382,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_dimmers(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) -> Dict[int, Any]: """ @@ -358,6 +393,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_node_config(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) \ -> Dict[int, Any]: @@ -369,6 +405,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_battery_levels(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) \ -> Dict[int, Any]: @@ -380,6 +417,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_power_levels(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) \ -> Dict[int, Any]: @@ -391,6 +429,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_bulbs(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) -> Dict[int, Any]: """ @@ -401,6 +440,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_switches(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) -> Dict[int, Any]: """ @@ -411,6 +451,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_sensors(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) -> Dict[int, Any]: """ @@ -421,6 +462,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_doorlocks(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) -> Dict[int, Any]: """ @@ -431,6 +473,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_usercodes(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) -> Dict[int, Any]: """ @@ -441,6 +484,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_thermostats(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) \ -> Dict[int, Any]: @@ -452,6 +496,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_protections(self, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs) \ -> Dict[int, Any]: @@ -463,6 +508,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_groups(self, **kwargs) -> Dict[int, Any]: """ @@ -470,6 +516,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_scenes(self, **kwargs) -> Dict[str, Any]: """ @@ -477,6 +524,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def create_scene(self, label: str, **kwargs): """ @@ -486,6 +534,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def remove_scene(self, scene_id: Optional[int] = None, scene_label: Optional[str] = None, **kwargs): """ @@ -496,6 +545,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def activate_scene(self, scene_id: Optional[int] = None, scene_label: Optional[str] = None, **kwargs): """ @@ -506,6 +556,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def set_scene_label(self, new_label: str, scene_id: Optional[int] = None, scene_label: Optional[str] = None, **kwargs): @@ -518,6 +569,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def scene_add_value(self, data: Optional[Any] = None, value_id: Optional[int] = None, id_on_network: Optional[str] = None, @@ -538,6 +590,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def scene_remove_value(self, value_id: Optional[int] = None, id_on_network: Optional[str] = None, value_label: Optional[str] = None, scene_id: Optional[int] = None, @@ -556,6 +609,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_scene_values(self, scene_id: Optional[int] = None, scene_label: Optional[str] = None, **kwargs) -> dict: """ @@ -567,6 +621,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def get_scene_values(self, scene_id: Optional[int] = None, scene_label: Optional[str] = None, **kwargs) -> dict: """ @@ -577,6 +632,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def create_button(self, button_id: Union[int, str], node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs): @@ -589,6 +645,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def delete_button(self, button_id: Union[int, str], node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs): @@ -601,6 +658,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def add_node_to_group(self, group_index: Optional[int] = None, group_label: Optional[str] = None, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs): @@ -614,6 +672,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def remove_node_from_group(self, group_index: Optional[int] = None, group_label: Optional[str] = None, node_id: Optional[int] = None, node_name: Optional[str] = None, **kwargs): @@ -627,6 +686,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def create_new_primary(self, **kwargs): """ @@ -634,6 +694,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def hard_reset(self, **kwargs): """ @@ -642,6 +703,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def soft_reset(self, **kwargs): """ @@ -650,6 +712,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def write_config(self, **kwargs): """ @@ -657,6 +720,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def on(self, device: str, *args, **kwargs): """ @@ -666,6 +730,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def off(self, device: str, *args, **kwargs): """ @@ -675,6 +740,7 @@ class ZwaveBasePlugin(ABC, SwitchPlugin): """ raise NotImplementedError + @abstractmethod @action def toggle(self, device: str, *args, **kwargs): """ diff --git a/platypush/plugins/zwave/manifest.yaml b/platypush/plugins/zwave/manifest.yaml new file mode 100644 index 000000000..101c95c40 --- /dev/null +++ b/platypush/plugins/zwave/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - python-openzwave + package: platypush.plugins.zwave + type: plugin diff --git a/platypush/plugins/zwave/mqtt.py b/platypush/plugins/zwave/mqtt/__init__.py similarity index 100% rename from platypush/plugins/zwave/mqtt.py rename to platypush/plugins/zwave/mqtt/__init__.py diff --git a/platypush/plugins/zwave/mqtt/manifest.yaml b/platypush/plugins/zwave/mqtt/manifest.yaml new file mode 100644 index 000000000..9cce3fd0c --- /dev/null +++ b/platypush/plugins/zwave/mqtt/manifest.yaml @@ -0,0 +1,7 @@ +manifest: + events: {} + install: + pip: + - paho-mqtt + package: platypush.plugins.zwave.mqtt + type: plugin diff --git a/platypush/user/__init__.py b/platypush/user/__init__.py index c519799bf..981a4e464 100644 --- a/platypush/user/__init__.py +++ b/platypush/user/__init__.py @@ -7,6 +7,11 @@ from typing import Optional, Dict import bcrypt import jwt +try: + from jwt.exceptions import PyJWTError +except ImportError: + from jwt import PyJWTError + from sqlalchemy import Column, Integer, String, DateTime, ForeignKey from sqlalchemy.orm import sessionmaker, scoped_session from sqlalchemy.ext.declarative import declarative_base @@ -150,11 +155,19 @@ class UserManager: @staticmethod def _encrypt_password(pwd): - return bcrypt.hashpw(pwd.encode(), bcrypt.gensalt(12)) + if isinstance(pwd, str): + pwd = pwd.encode() + return bcrypt.hashpw(pwd, bcrypt.gensalt(12)).decode() + + @classmethod + def _check_password(cls, pwd, hashed_pwd): + return bcrypt.checkpw(cls._to_bytes(pwd), cls._to_bytes(hashed_pwd)) @staticmethod - def _check_password(pwd, hashed_pwd): - return bcrypt.checkpw(pwd.encode(), hashed_pwd) + def _to_bytes(data) -> bytes: + if isinstance(data, str): + data = data.encode() + return data @staticmethod def generate_session_token(): @@ -218,7 +231,7 @@ class UserManager: try: payload = jwt.decode(token.encode(), pub_key, algorithms=['RS256']) - except jwt.exceptions.PyJWTError as e: + except PyJWTError as e: raise InvalidJWTTokenException(str(e)) expires_at = payload.get('expires_at') diff --git a/platypush/utils/__init__.py b/platypush/utils/__init__.py index 2c337677b..1ffc76832 100644 --- a/platypush/utils/__init__.py +++ b/platypush/utils/__init__.py @@ -138,22 +138,27 @@ def clear_timeout(): def get_hash(s): - """ Get the SHA256 hash hexdigest of a string input """ + """ Get the SHA256 hash hex digest of a string input """ return hashlib.sha256(s.encode('utf-8')).hexdigest() def get_decorators(cls, climb_class_hierarchy=False): """ Get the decorators of a class as a {"decorator_name": [list of methods]} dictionary - :param climb_class_hierarchy: If set to True (default: False), it will search return the decorators in the parent classes as well + + :param cls: Class type + :param climb_class_hierarchy: If set to True (default: False), it will search return the decorators in the parent + classes as well :type climb_class_hierarchy: bool """ decorators = {} + # noinspection PyPep8Naming def visit_FunctionDef(node): for n in node.decorator_list: if isinstance(n, ast.Call): + # noinspection PyUnresolvedReferences name = n.func.attr if isinstance(n.func, ast.Attribute) else n.func.id else: name = n.attr if isinstance(n, ast.Attribute) else n.id @@ -228,6 +233,7 @@ def get_ssl_client_context(ssl_cert=None, ssl_key=None, ssl_cafile=None, ssl_cert=ssl_cert, ssl_key=ssl_key, ssl_cafile=ssl_cafile, ssl_capath=ssl_capath) + def set_thread_name(name): global logger @@ -263,7 +269,7 @@ def find_files_by_ext(directory, *exts): result = [] for root, dirs, files in os.walk(directory): - for i in range(min_len, max_len+1): + for i in range(min_len, max_len + 1): result += [f for f in files if f[-i:] in exts] return result @@ -296,6 +302,7 @@ def get_mime_type(resource): if resource.startswith('file://'): resource = resource[len('file://'):] + # noinspection HttpUrlsUsage if resource.startswith('http://') or resource.startswith('https://'): with urllib.request.urlopen(resource) as response: return response.info().get_content_type() @@ -444,5 +451,4 @@ def get_redis() -> Redis: from platypush.config import Config return Redis(**(Config.get('backend.redis') or {}).get('redis_args', {})) - # vim:sw=4:ts=4:et: diff --git a/platypush/utils/manifest.py b/platypush/utils/manifest.py new file mode 100644 index 000000000..b26573e7e --- /dev/null +++ b/platypush/utils/manifest.py @@ -0,0 +1,200 @@ +import enum +import inspect +import json +import logging +import os +import pathlib +import shutil +import yaml + +from abc import ABC, abstractmethod +from typing import Optional, Iterable, Mapping, Callable, Type + +supported_package_managers = { + 'pacman': 'pacman -S', + 'apt': 'apt-get install', +} + +_available_package_manager = None + + +class ManifestType(enum.Enum): + PLUGIN = 'plugin' + BACKEND = 'backend' + + +class Manifest(ABC): + """ + Base class for plugin/backend manifests. + """ + def __init__(self, package: str, description: Optional[str] = None, + install: Optional[Iterable[str]] = None, events: Optional[Mapping] = None, **_): + self.description = description + self.install = install or {} + self.events = events or {} + self.logger = logging.getLogger(__name__) + self.package = package + self.component_name = '.'.join(package.split('.')[2:]) + self.component = None + + @classmethod + @property + @abstractmethod + def component_getter(self) -> Callable[[str], object]: + raise NotImplementedError + + @classmethod + def from_file(cls, filename: str) -> "Manifest": + with open(str(filename), 'r') as f: + manifest = yaml.safe_load(f).get('manifest', {}) + + assert 'type' in manifest, f'Manifest file {filename} has no type field' + comp_type = ManifestType(manifest.pop('type')) + manifest_class = _manifest_class_by_type[comp_type] + return manifest_class(**manifest) + + @classmethod + def from_class(cls, clazz) -> "Manifest": + return cls.from_file(os.path.dirname(inspect.getfile(clazz))) + + @classmethod + def from_component(cls, comp) -> "Manifest": + return cls.from_class(comp.__class__) + + def get_component(self): + try: + self.component = self.component_getter(self.component_name) + except Exception as e: + self.logger.warning(f'Could not load {self.component_name}: {e}') + + return self.component + + def __repr__(self): + return json.dumps({ + 'description': self.description, + 'install': self.install, + 'events': self.events, + 'type': _manifest_type_by_class[self.__class__].value, + 'package': self.package, + 'component_name': self.component_name, + }) + + +class PluginManifest(Manifest): + @classmethod + @property + def component_getter(self): + from platypush.context import get_plugin + return get_plugin + + +class BackendManifest(Manifest): + @classmethod + @property + def component_getter(self): + from platypush.context import get_backend + return get_backend + + +_manifest_class_by_type: Mapping[ManifestType, Type[Manifest]] = { + ManifestType.PLUGIN: PluginManifest, + ManifestType.BACKEND: BackendManifest, +} + +_manifest_type_by_class: Mapping[Type[Manifest], ManifestType] = { + cls: t for t, cls in _manifest_class_by_type.items() +} + + +def scan_manifests(base_class: Type) -> Iterable[str]: + for mf in pathlib.Path(os.path.dirname(inspect.getfile(base_class))).rglob('manifest.yaml'): + yield str(mf) + + +def get_manifests(base_class: Type) -> Iterable[Manifest]: + return [ + Manifest.from_file(mf) + for mf in scan_manifests(base_class) + ] + + +def get_components(base_class: Type) -> Iterable: + manifests = get_manifests(base_class) + components = {mf.get_component() for mf in manifests} + return {comp for comp in components if comp is not None} + + +def get_manifests_from_conf(conf_file: Optional[str] = None) -> Mapping[str, Manifest]: + import platypush + from platypush.config import Config + + conf_args = [] + if conf_file: + conf_args.append(conf_file) + + Config.init(*conf_args) + app_dir = os.path.dirname(inspect.getfile(platypush)) + manifest_files = set() + + for name in Config.get_backends().keys(): + manifest_files.add(os.path.join(app_dir, 'backend', *name.split('.'), 'manifest.yaml')) + + for name in Config.get_plugins().keys(): + manifest_files.add(os.path.join(app_dir, 'plugins', *name.split('.'), 'manifest.yaml')) + + return { + manifest_file: Manifest.from_file(manifest_file) + for manifest_file in manifest_files + } + + +def get_dependencies_from_conf(conf_file: Optional[str] = None) -> Mapping[str, Iterable[str]]: + manifests = get_manifests_from_conf(conf_file) + deps = { + 'pip': set(), + 'packages': set(), + 'exec': set(), + } + + for manifest in manifests.values(): + deps['pip'].update(manifest.install.get('pip', set())) + deps['exec'].update(manifest.install.get('exec', set())) + has_requires_packages = len([ + section for section in manifest.install.keys() + if section in supported_package_managers + ]) > 0 + + if has_requires_packages: + pkg_manager = get_available_package_manager() + deps['packages'].update(manifest.install.get(pkg_manager, set())) + + return deps + + +def get_install_commands_from_conf(conf_file: Optional[str] = None) -> Mapping[str, str]: + deps = get_dependencies_from_conf(conf_file) + return { + 'pip': f'pip install {" ".join(deps["pip"])}', + 'exec': deps["exec"], + 'packages': f'{supported_package_managers[_available_package_manager]} {" ".join(deps["packages"])}' + if deps['packages'] else None, + } + + +def get_available_package_manager() -> str: + global _available_package_manager + if _available_package_manager: + return _available_package_manager + + available_package_managers = [ + pkg_manager for pkg_manager in supported_package_managers.keys() + if shutil.which(pkg_manager) + ] + + assert available_package_managers, ( + 'Your OS does not provide any of the supported package managers. ' + f'Supported package managers: {supported_package_managers.keys()}' + ) + + _available_package_manager = available_package_managers[0] + return _available_package_manager diff --git a/requirements.txt b/requirements.txt index c69964660..2fc1c8fbf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,323 +1,22 @@ ### -# Platypush Python requirements -# -# Uncomment the lines associated to the optional dependencies that -# you may want to install to use some particular plugins or backends +# Platypush common requirements ### -# YAML configuration support pyyaml - -# Responses and schemas marshmallow - -# Support for setting thread/process name -# python-prctl - -# Apache Kafka backend support -# kafka-python - -# Pushbullet backend support -# git+https://github.com/rbrcsk/pushbullet.py - -# HTTP backend support +python-prctl flask websockets redis python-dateutil tz -#uwsgi - -# HTTP poll backend support frozendict requests - -# Database plugin support sqlalchemy - -# Support for multi-users and password authentication bcrypt cryptography pyjwt - -# Support for Zeroconf/Bonjour zeroconf - -# RSS feeds support -# feedparser - -# PDF generation support -# weasyprint - -# Philips Hue plugin support -# phue - -# MPD/Mopidy music server support -# python-mpd2 - -# Google Assistant support -# google-assistant-sdk[samples] -# google-assistant-library - -# Google APIs general layer support -# google-api-python-client -# oauth2client - -# Google text-to-speech API support -# google-cloud-texttospeech - -# Last.FM scrobbler plugin support -# pylast - -# Flic buttons support -# It doesn't come with a pip package nor a setup.py, -# follow the instructions on github to get the flicd daemon -# running, set up the buttons you want to use, and then -# enable backend.button.flic in your configuration. -# git+https://github.com/50ButtonsEach/fliclib-linux-hci - -# text2speech plugin: mplayer system package - -# Video support on RaspberryPi -# omxplayer-wrapper - -# Custom hotword detection: Snowboy -# snowboy - -# Support for the RaspberryPi camera module -# picamera -# Pillow - -# Support for torrents download -# python-libtorrent - -# Support for smart cards detection -# pyscard - -# Support for MCP3008 analog-to-digital converter plugin -# adafruit-mcp3008 - -# Support for real-time MIDI events -# rtmidi - -# Support for inotify plugin -# inotify - -# Support for MQTT paho-mqtt - -# iCal calendars support -# icalendar - -# Serial port support -# pyserial - -# Bluetooth devices support -# pybluez -# gattlib -# git+https://github.com/BlackLight/PyOBEX - -# Support for TP-Link HS100 and similar smart switches/plugins -# pyHS100 - -# Support for joystick backend -# inputs - -# Support for Kodi -# kodi-json - -# Support for Plex -# plexapi - -# Support for Chromecast -# pychromecast - -# Support for sound devices, playback and recording -# sounddevice -# soundfile -# numpy - -# Support for media subtitles -# git+https://github.com/agonzalezro/python-opensubtitles -# webvtt-py - -# Multiple plugins and backends require the websocket client websocket-client - -# mpv player plugin -# python-mpv - -# Support for NFC tags -# nfcpy >= 1.0 -# ndeflib - -# Support for enviropHAT -# envirophat - -# Support for GPS integration -# gps - -# Support for BME280 environment sensor -# pimoroni-bme280 - -# Support for LTR559 light/proximity sensor -# ltr559 - -# Support for VL53L1X laser ranger/distance sensor -# smbus2 -# vl53l1x - -# Support for PWM3901 2-Dimensional Optical Flow Sensor -# pwm3901 - -# Support for MLX90640 thermal camera -# Pillow - -# Support for machine learning CV plugin -# cv2 -# numpy - -# Support for cronjobs croniter - -# Support for Dropbox -# dropbox - -# Support for Alexa/Echo voice integrations -# git+https://github.com:BlackLight/avs.git - -# Support for clipboard manipulation -# pyperclip - -# Support for RST->HTML docstring conversion -# docutils - -# Support for Node-RED integration -# nodered - -# Support for Todoist integration -# todoist-python - -# Support for Trello integration -# py-trello - -# Support for Google Pub/Sub -# google-cloud-pubsub - -# Support for keyboard/mouse plugin -# pyuserinput - -# Support for Buienradar weather forecast -# buienradar - -# Support for Telegram integration -# python-telegram-bot - -# Support for Arduino integration -# pyserial -# pyfirmata2 - -# Support for CUPS printers management -# pycups - -# Support for Graphite integration -# graphyte - -# Support for CPU and memory monitoring and info -# py-cpuinfo -# psutil - -# Support for nmap integration -# python-nmap - -# Support for zigbee2mqtt -# paho-mqtt - -# Support for Z-Wave -# python-openzwave - -# Support for Mozilla DeepSpeech speech-to-text engine -# deepspeech -# numpy -# sounddevice - -# Support for PicoVoice hotword engine -# pvporcupine - -# Support for PicoVoice speech-to-text engine -# pvcheetah - -# Support for OTP (One-Time Password) generation -# pyotp - -# Support for Linode integration -# linode_api4 - -# Support for QR codes -# numpy -# qrcode -# Pillow -# pyzbar - -# Support for Tensorflow -# numpy -# pandas -# tensorflow>=2.0 -# keras - -# Support for Samsung TizenOS-based smart TVs -# samsungtvws - -# Support for SSH integration -# paramiko - -# Support for clipboard integration -# pyperclip - -# Support for Google Translate -# google-cloud-translate - -# Support for luma.oled -# git+https://github.com/rm-hull/luma.oled - -# Support for DBus integration -# python-dbus - -# Support for Twilio -# twilio - -# Support for Github -# pytz - -# Support for DHT11/DHT22/AM2302 temperature/humidity sensors -# git+https://github.com/adafruit/Adafruit_Python_DHT - -# Support for LCD display integration -# RPi.GPIO -# RPLCD - -# Support for IMAP mail integration -# imapclient - -# Support for NextCloud integration -# git+https://github.com/EnterpriseyIntranet/nextcloud-API.git - -# Support for GStreamer integration -# gst-python - -# Generic support for cameras -# Pillow - -# VLC integration -# python-vlc - -# SmartThings integration -# pysmartthings -# aiohttp - -# Support for file.monitor backend -#watchdog - -# Support for Adafruit PCA9685 PWM controller -#adafruit-python-shell -#adafruit-circuitpython-pca9685 diff --git a/setup.py b/setup.py index d93a4e669..87dd86230 100755 --- a/setup.py +++ b/setup.py @@ -34,7 +34,7 @@ setup( description="Platypush service", license="MIT", python_requires='>= 3.6', - keywords="home-automation iot mqtt websockets redis dashboard notificaions", + keywords="home-automation automation iot mqtt websockets redis dashboard notifications", url="https://platypush.tech", packages=find_packages(), include_package_data=True, @@ -67,6 +67,7 @@ setup( 'cryptography', 'pyjwt', 'marshmallow', + 'frozendict', ], extras_require={ @@ -75,11 +76,11 @@ setup( # Support for Kafka backend and plugin 'kafka': ['kafka-python'], # Support for Pushbullet backend and plugin - 'pushbullet': ['pushbullet.py @ https://github.com/BlackLight/pushbullet.py/tarball/master'], + 'pushbullet': ['pushbullet.py @ https://github.com/rbrcsk/pushbullet.py/tarball/master'], # Support for HTTP backend - 'http': ['flask', 'frozendict', 'bcrypt'], + 'http': ['flask', 'bcrypt', 'python-magic'], # Support for uWSGI HTTP backend - 'uwsgi': ['flask', 'frozendict', 'uwsgi', 'bcrypt'], + 'uwsgi': ['flask', 'uwsgi', 'bcrypt', 'python-magic'], # Support for MQTT backends 'mqtt': ['paho-mqtt'], # Support for RSS feeds parser @@ -97,7 +98,7 @@ setup( # Support for YouTube 'youtube': ['youtube-dl'], # Support for torrents download - 'torrent': ['python-libtorrent'], + 'torrent': ['python-libtorrent-bin'], # Generic support for cameras 'camera': ['numpy', 'Pillow'], # Support for RaspberryPi camera @@ -167,12 +168,12 @@ setup( 'pyobex @ https://github.com/BlackLight/PyOBEX/tarball/master'], # Support for TP-Link devices 'tplink': ['pyHS100'], - # Support for PWM3901 2-Dimensional Optical Flow Sensor - 'pwm3901': ['pwm3901'], + # Support for PMW3901 2-Dimensional Optical Flow Sensor + 'pmw3901': ['pmw3901'], # Support for MLX90640 thermal camera 'mlx90640': ['Pillow'], # Support for machine learning models and cameras over OpenCV - 'cv': ['cv2', 'numpy', 'Pillow'], + 'cv': ['opencv-python', 'numpy', 'Pillow'], # Support for the generation of HTML documentation from docstring 'htmldoc': ['docutils'], # Support for Node-RED integration @@ -240,9 +241,7 @@ setup( # Support for IMAP mail integration 'imap': ['imapclient'], # Support for NextCloud integration - 'nextcloud': ['nextcloud-API @ git+https://github.com/EnterpriseyIntranet/nextcloud-API.git'], - # Support for GStreamer integration - 'gstreamer': ['gst-python'], + 'nextcloud': ['nextcloud-api-wrapper'], # Support for VLC integration 'vlc': ['python-vlc'], # Support for SmartThings integration