appdaemon 4.5.0__tar.gz → 4.5.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- appdaemon-4.5.2/PKG-INFO +80 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/adapi.py +8 -4
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/adbase.py +5 -3
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/app_management.py +15 -6
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/default/variables.yaml +1 -1
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/glassic/variables.yaml +1 -1
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/obsidian/variables.yaml +1 -1
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/simplyred/variables.yaml +1 -1
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/dependency.py +22 -7
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/dependency_manager.py +9 -3
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/entity.py +2 -3
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/exceptions.py +7 -4
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/http.py +16 -12
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/internal/app_management.py +1 -1
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/plugins/hass/hassapi.py +2 -2
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/plugins/hass/hassplugin.py +2 -2
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/plugins/mqtt/mqttapi.py +7 -13
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/scheduler.py +74 -215
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/threads.py +30 -59
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/utils.py +19 -20
- appdaemon-4.5.2/appdaemon/version.py +2 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basefan/basefan.js +1 -1
- appdaemon-4.5.2/appdaemon.egg-info/PKG-INFO +80 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon.egg-info/requires.txt +1 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/ObjectTracker/general_app_functions.py +4 -8
- {appdaemon-4.5.0 → appdaemon-4.5.2}/pyproject.toml +11 -4
- appdaemon-4.5.0/PKG-INFO +0 -275
- appdaemon-4.5.0/appdaemon/version.py +0 -2
- appdaemon-4.5.0/appdaemon.egg-info/PKG-INFO +0 -275
- {appdaemon-4.5.0 → appdaemon-4.5.2}/LICENSE.md +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/MANIFEST.in +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/README.md +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/README.rst +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/__init__.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/__main__.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/admin.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/admin_loop.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/appdaemon.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/aui/appdaemon.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/aui/css/app.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/aui/css/chunk-vendors.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/aui/favicon.ico +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/aui/index.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/aui/js/app.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/aui/js/app.js.map +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/aui/js/chunk-vendors.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/aui/js/chunk-vendors.js.map +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/all.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/climacons-font.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/default/dashboard.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/fontawesome.min.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/fonts.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/glassic/dashboard.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/glassic/img/carbon1.jpg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/glassic/img/carbon2.jpg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/glassic/img/carbon3.jpg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/glassic/img/carbon4.jpg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/glassic/img/glassic_bg.jpg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/images/ui-icons_444444_256x240.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/images/ui-icons_555555_256x240.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/images/ui-icons_777620_256x240.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/images/ui-icons_777777_256x240.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/images/ui-icons_cc0000_256x240.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/images/ui-icons_ffffff_256x240.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/jquery-ui.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/jquery.gridster.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/main.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/materialdesignicons.min.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/non_dashboard.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/obsidian/dashboard.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/obsidian/img/obsidian_bg.jpg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/obsidian/img/obsidian_w_bg.jpg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/obsidian/img/obsidianbg.jpg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/obsidian/img/widgetbg.jpg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/rickshaw.min.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/simplyred/dashboard.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/simplyred/img/goldgradient.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/simplyred/img/goldtexture.jpg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/simplyred/js/timer.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/v4-shims.min.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/zen/dashboard.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/zen/img/zen_bg.jpg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/zen/img/zen_bg2.jpg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/zen/img/zen_weatherbg.jpg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/css/zen/variables.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/fonts/TickingTimebombBB.ttf +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/fonts/climacons-webfont.eot +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/fonts/climacons-webfont.svg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/fonts/climacons-webfont.ttf +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/fonts/climacons-webfont.woff +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/fonts/digital-7-mono.eot +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/fonts/digital-7-mono.ttf +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/fonts/materialdesignicons-webfont.eot +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/fonts/materialdesignicons-webfont.ttf +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/fonts/materialdesignicons-webfont.woff +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/fonts/materialdesignicons-webfont.woff2 +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/fonts/repetition.ttf +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/images/Blank.gif +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/images/android-chrome-192x192.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/images/android-chrome-512x512.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/images/apple-touch-icon.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/images/browserconfig.xml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/images/favicon-16x16.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/images/favicon-32x32.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/images/favicon.ico +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/images/manifest.json +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/images/mstile-144x144.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/images/mstile-150x150.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/images/mstile-310x150.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/images/mstile-310x310.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/images/mstile-70x70.png +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/admin.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/d3.layout.min.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/d3.min.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/dashboard.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/gauge.min.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/jquery-3.1.1.min.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/jquery-ui.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/jquery.gridster.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/justgage.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/knockout-3.4.1.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/list.min.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/plotly.min.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/raphael-2.1.4.min.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/reconnecting-websocket.min.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/rickshaw.min.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/socket.io.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/sockjs.min.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/javascript/stream.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/templates/admin.jinja2 +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/templates/body_include.jinja2 +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/templates/dashboard.jinja2 +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/templates/dashinit.jinja2 +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/templates/error.jinja2 +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/templates/head_include.jinja2 +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/templates/list.jinja2 +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/templates/logon.jinja2 +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/webfonts/fa-brands-400.eot +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/webfonts/fa-brands-400.svg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/webfonts/fa-brands-400.ttf +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/webfonts/fa-brands-400.woff +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/webfonts/fa-brands-400.woff2 +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/webfonts/fa-regular-400.eot +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/webfonts/fa-regular-400.svg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/webfonts/fa-regular-400.ttf +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/webfonts/fa-regular-400.woff +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/webfonts/fa-regular-400.woff2 +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/webfonts/fa-solid-900.eot +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/webfonts/fa-solid-900.svg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/webfonts/fa-solid-900.ttf +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/webfonts/fa-solid-900.woff +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/assets/webfonts/fa-solid-900.woff2 +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/callbacks.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/dashboard.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/events.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/futures.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/logging.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/__init__.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/config/__init__.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/config/api.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/config/app.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/config/appdaemon.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/config/common.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/config/dashboard.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/config/http.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/config/log.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/config/misc.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/config/plugin.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/config/sequence.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/config/yaml.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/internal/__init__.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/internal/file_check.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/internal/plugin.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/internal/state.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/internal/threading.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/notification/__init__.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/notification/android.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/notification/base.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/models/notification/iOS.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/plugin_management.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/plugins/__init__.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/plugins/dummy/dummyapi.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/plugins/dummy/dummyplugin.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/plugins/hass/__init__.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/plugins/hass/exceptions.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/plugins/hass/models.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/plugins/hass/notifications.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/plugins/hass/utils.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/plugins/mqtt/__init__.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/plugins/mqtt/mqttplugin.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/pyversions.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/sequences.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/services.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/state.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/stream/__init__.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/stream/adstream.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/stream/socketio_handler.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/stream/sockjs_handler.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/stream/ws_handler.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/thread_async.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/utility_loop.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/AdminLog.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/AdminSummary.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/AdminTable.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/alarm.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basealarm/basealarm.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basealarm/basealarm.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basealarm/basealarm.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basecamera/basecamera.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basecamera/basecamera.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basecamera/basecamera.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseclimate/baseclimate.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseclimate/baseclimate.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseclimate/baseclimate.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseclock/baseclock.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseclock/baseclock.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseclock/baseclock.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basedatetime/basedatetime.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basedatetime/basedatetime.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basedatetime/basedatetime.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basedisplay/basedisplay.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basedisplay/basedisplay.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basedisplay/basedisplay.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseentitypicture/baseentitypicture.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseentitypicture/baseentitypicture.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseentitypicture/baseentitypicture.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseerror/baseerror.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseerror/baseerror.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseerror/baseerror.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basefan/basefan.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basefan/basefan.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basegauge/basegauge.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basegauge/basegauge.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basegauge/basegauge.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseheater/baseheater.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseheater/baseheater.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseheater/baseheater.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseicon/baseicon.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseicon/baseicon.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseicon/baseicon.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseiframe/baseiframe.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseiframe/baseiframe.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseiframe/baseiframe.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseinputnumber/baseinputnumber.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseinputnumber/baseinputnumber.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseinputnumber/baseinputnumber.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basejavascript/basejavascript.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basejavascript/basejavascript.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basejavascript/basejavascript.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baselight/baselight.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baselight/baselight.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baselight/baselight.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basemedia/basemedia.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basemedia/basemedia.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basemedia/basemedia.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseradial/baseradial.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseradial/baseradial.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseradial/baseradial.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baserss/baserss.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baserss/baserss.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baserss/baserss.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseselect/baseselect.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseselect/baseselect.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseselect/baseselect.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseslider/baseslider.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseslider/baseslider.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseslider/baseslider.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseswitch/baseswitch.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseswitch/baseswitch.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseswitch/baseswitch.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basetemperature/basetemperature.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basetemperature/basetemperature.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basetemperature/basetemperature.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basetext/basetext.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basetext/basetext.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/basetext/basetext.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseweather/baseweather.css +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseweather/baseweather.html +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/baseweather/baseweather.js +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/binary_sensor.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/camera.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/climate.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/clock.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/cover.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/device_tracker.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/entitypicture.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/fan.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/gauge.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/group.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/heater.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/icon.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/iframe.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/input_boolean.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/input_datetime.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/input_number.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/input_select.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/input_slider.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/input_text.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/javascript.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/label.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/light.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/lock.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/london_underground.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/media_player.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/mode.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/navigate.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/person.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/pirateweather.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/radial.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/reload.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/rss.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/scene.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/script.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/sensor.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/sequence.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/switch.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/temperature.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/text_sensor.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/weather.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon/widgets/weather_summary.yaml +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon.egg-info/SOURCES.txt +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon.egg-info/dependency_links.txt +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon.egg-info/entry_points.txt +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/appdaemon.egg-info/top_level.txt +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/apps/hello.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/ObjectTracker/objectcontrole.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/alexa.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/battery.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/bysykkel.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/commute.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/dark_day.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/door_notification.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/eventCache.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/eventMonitor.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/globals.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/grandfather.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/hwcheck.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/ical.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/minimote.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/modes.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/momentary_switch.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/motion_lights.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/motion_notification.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/occusim.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/outside_lights.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/presence.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/ruter.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/secure.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/sensor_notification.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/sensor_notify.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/sequence.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/smart_heat.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/sound.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/switch_reset.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/conf/example_apps/yr.py +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/setup.cfg +0 -0
- {appdaemon-4.5.0 → appdaemon-4.5.2}/tests/test_main.py +0 -0
appdaemon-4.5.2/PKG-INFO
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: appdaemon
|
|
3
|
+
Version: 4.5.2
|
|
4
|
+
Summary: Apps for the Home Assistant home automation package.
|
|
5
|
+
Author-email: Andrew I Cockburn <appdaemon@acockburn.com>
|
|
6
|
+
Project-URL: documentation, https://appdaemon.readthedocs.io
|
|
7
|
+
Project-URL: repository, https://github.com/AppDaemon
|
|
8
|
+
Project-URL: changelog, https://github.com/AppDaemon/appdaemon/blob/master/docs/HISTORY.rst
|
|
9
|
+
Keywords: appdaemon,home,automation
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Natural Language :: English
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Home Automation
|
|
17
|
+
Requires-Python: <3.13,>=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE.md
|
|
20
|
+
Requires-Dist: importlib-metadata; python_version < "3.8"
|
|
21
|
+
Requires-Dist: aiohttp<3.12.0,>=3.9.0
|
|
22
|
+
Requires-Dist: aiohttp_jinja2<1.7.0,>=1.5.1
|
|
23
|
+
Requires-Dist: astral~=3.2
|
|
24
|
+
Requires-Dist: bcrypt<4.3.0,>=4.0.1
|
|
25
|
+
Requires-Dist: deepdiff==8.2.0
|
|
26
|
+
Requires-Dist: feedparser~=6.0.10
|
|
27
|
+
Requires-Dist: iso8601<2.2,>=1.1
|
|
28
|
+
Requires-Dist: paho-mqtt<2.2.0,>=1.6.1
|
|
29
|
+
Requires-Dist: pid~=3.0.4
|
|
30
|
+
Requires-Dist: python-dateutil<2.10.0,>=2.8.2
|
|
31
|
+
Requires-Dist: python-socketio<5.12,>=5.5
|
|
32
|
+
Requires-Dist: pytz<2025.2.0,>=2022.7.1
|
|
33
|
+
Requires-Dist: pyyaml~=6.0.1
|
|
34
|
+
Requires-Dist: requests<2.33.0,>=2.28.2
|
|
35
|
+
Requires-Dist: sockjs<0.14,>=0.11
|
|
36
|
+
Requires-Dist: uvloop==0.21.0; sys_platform != "win32"
|
|
37
|
+
Requires-Dist: tomli==2.2.1
|
|
38
|
+
Requires-Dist: tomli_w<1.3,>=1.0
|
|
39
|
+
Requires-Dist: pydantic~=2.10.6
|
|
40
|
+
Provides-Extra: dev
|
|
41
|
+
Requires-Dist: pip-tools<7.5.0,>=6.12.3; extra == "dev"
|
|
42
|
+
Requires-Dist: build<1.3,>=0.10; extra == "dev"
|
|
43
|
+
Requires-Dist: flake8~=7.1.1; extra == "dev"
|
|
44
|
+
Requires-Dist: black<25.2,>=23.1; extra == "dev"
|
|
45
|
+
Requires-Dist: pre-commit<3.9.0,>=3.1.1; python_version > "3.7" and extra == "dev"
|
|
46
|
+
Requires-Dist: pytest<8.4.0,>=7.2.1; extra == "dev"
|
|
47
|
+
Requires-Dist: ruff<0.7.0,>=0.0.261; extra == "dev"
|
|
48
|
+
Requires-Dist: codespell>=2.4.1; extra == "dev"
|
|
49
|
+
Provides-Extra: doc
|
|
50
|
+
Requires-Dist: sphinx-autobuild<2024.10.0,>=2021.3.14; extra == "doc"
|
|
51
|
+
Requires-Dist: sphinx-rtd-theme==3.0.2; extra == "doc"
|
|
52
|
+
Requires-Dist: pygments<2.20,>=2.14; extra == "doc"
|
|
53
|
+
Requires-Dist: myst-parser==4.0.0; extra == "doc"
|
|
54
|
+
Dynamic: license-file
|
|
55
|
+
|
|
56
|
+
# Description
|
|
57
|
+
|
|
58
|
+
AppDaemon is a loosely coupled, multi-threaded, sandboxed python
|
|
59
|
+
execution environment for writing automation apps for various types of Home Automation Software including [Home
|
|
60
|
+
Assistant](https://home-assistant.io/) and MQTT. It has a pluggable architecture allowing it to be integrated with
|
|
61
|
+
practically any event driven application.
|
|
62
|
+
|
|
63
|
+
It also provides a configurable dashboard (HADashboard)
|
|
64
|
+
suitable for wall mounted tablets.
|
|
65
|
+
|
|
66
|
+
## Getting started
|
|
67
|
+
|
|
68
|
+
For full instructions on installation and usage check out the [AppDaemon Project Documentation](http://appdaemon.readthedocs.io).
|
|
69
|
+
|
|
70
|
+
## Release Cycle Frequency
|
|
71
|
+
|
|
72
|
+
AppDaemon has reached a very stable point, works reliably and is fairly feature rich at this point
|
|
73
|
+
in its development. For that reason, releases have been slow in recent months. This does not mean that AppDaemon has been abandoned -
|
|
74
|
+
it is used every day by the core developers and has an active discord server [here](https://discord.gg/sgSr79jW5x) - please join us for tips
|
|
75
|
+
and tricks, AppDaemon discussions and general home automation.
|
|
76
|
+
|
|
77
|
+
## Contributing
|
|
78
|
+
|
|
79
|
+
This is an active open-source project. We are always open to people who want to use the code or contribute to it. Thank you for being involved!
|
|
80
|
+
Have a look at the [official documentation](https://appdaemon.readthedocs.io/en/latest/DEV.html) for more information.
|
|
@@ -255,8 +255,11 @@ class ADAPI:
|
|
|
255
255
|
# Its a user defined log
|
|
256
256
|
logger = self.logger if log is None else self.get_user_log(log)
|
|
257
257
|
|
|
258
|
+
if ascii_encode is None:
|
|
259
|
+
ascii_encode = self.AD.config.ascii_encode
|
|
260
|
+
|
|
258
261
|
kwargs = dict(
|
|
259
|
-
ascii_encode=ascii_encode
|
|
262
|
+
ascii_encode=ascii_encode,
|
|
260
263
|
stack_info=stack_info,
|
|
261
264
|
stacklevel=stacklevel,
|
|
262
265
|
extra=extra,
|
|
@@ -1678,7 +1681,7 @@ class ADAPI:
|
|
|
1678
1681
|
`namespace documentation <APPGUIDE.html#namespaces>`__ for more information.
|
|
1679
1682
|
copy (bool, optional): Whether to return a copy of the internal data. This is ``True`` by default in order
|
|
1680
1683
|
to protect the user from accidentally modifying AppDaemon's internal data structures, which is dangerous
|
|
1681
|
-
and can cause undefined
|
|
1684
|
+
and can cause undefined behavior. Only set this to ``False`` for read-only operations.
|
|
1682
1685
|
|
|
1683
1686
|
Returns:
|
|
1684
1687
|
The state or attribute of the entity ID provided or a dict of that maps entity IDs to their respective
|
|
@@ -1809,7 +1812,7 @@ class ADAPI:
|
|
|
1809
1812
|
accept arbitrary keyword arguments.
|
|
1810
1813
|
|
|
1811
1814
|
Registering services in namespaces that already have plugins is not recommended, as it can lead to some
|
|
1812
|
-
unpredictable behavior.
|
|
1815
|
+
unpredictable behavior. Instead, it's recommended to use a user-defined namespace or one that is not tied to
|
|
1813
1816
|
plugin.
|
|
1814
1817
|
|
|
1815
1818
|
Args:
|
|
@@ -3639,7 +3642,8 @@ class ADAPI:
|
|
|
3639
3642
|
self.AD.futures.add_future(self.name, future)
|
|
3640
3643
|
return future
|
|
3641
3644
|
|
|
3642
|
-
|
|
3645
|
+
@utils.sync_decorator
|
|
3646
|
+
async def create_task(
|
|
3643
3647
|
self,
|
|
3644
3648
|
coro: Coroutine[Any, Any, T],
|
|
3645
3649
|
callback: Callable | None = None,
|
|
@@ -5,8 +5,9 @@ from pathlib import Path
|
|
|
5
5
|
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
7
|
from appdaemon import adapi
|
|
8
|
+
from appdaemon import utils
|
|
8
9
|
from appdaemon.models.config.app import AppConfig
|
|
9
|
-
|
|
10
|
+
|
|
10
11
|
|
|
11
12
|
# Check if the module is being imported using the legacy method
|
|
12
13
|
if __name__ == Path(__file__).name:
|
|
@@ -31,7 +32,7 @@ class Entities: # @todo
|
|
|
31
32
|
pass
|
|
32
33
|
|
|
33
34
|
def __get__(self, instance, owner):
|
|
34
|
-
stateattrs = StateAttrs(instance.get_state())
|
|
35
|
+
stateattrs = utils.StateAttrs(instance.get_state())
|
|
35
36
|
return stateattrs
|
|
36
37
|
|
|
37
38
|
|
|
@@ -165,7 +166,8 @@ class ADBase:
|
|
|
165
166
|
def get_ad_api(self) -> adapi.ADAPI:
|
|
166
167
|
return adapi.ADAPI(self.AD, self.config_model)
|
|
167
168
|
|
|
168
|
-
|
|
169
|
+
@utils.sync_decorator
|
|
170
|
+
async def get_plugin_api(self, plugin_name: str):
|
|
169
171
|
"""Get the plugin API for a specific plugin."""
|
|
170
172
|
if isinstance(cfg := self.app_config.root.get(self.name), AppConfig):
|
|
171
173
|
return self.AD.plugins.get_plugin_api(plugin_name, cfg)
|
|
@@ -569,7 +569,7 @@ class AppManagement:
|
|
|
569
569
|
yield new_cfg
|
|
570
570
|
|
|
571
571
|
def update(d1: dict, d2: dict) -> dict:
|
|
572
|
-
"""Internal
|
|
572
|
+
"""Internal function to log warnings if an app's name gets repeated."""
|
|
573
573
|
if overlap := set(k.lower() for k in d2 if k in d1):
|
|
574
574
|
# There's a special case for the sequences in order to merge them if they're defined in multiple files
|
|
575
575
|
if "sequence" in overlap:
|
|
@@ -615,7 +615,7 @@ class AppManagement:
|
|
|
615
615
|
self._compare_sequences(update_actions, cfg, files_to_read)
|
|
616
616
|
continue
|
|
617
617
|
|
|
618
|
-
if name in self.non_apps:
|
|
618
|
+
if name in self.non_apps or cfg.disable:
|
|
619
619
|
continue
|
|
620
620
|
|
|
621
621
|
# New config found
|
|
@@ -685,8 +685,14 @@ class AppManagement:
|
|
|
685
685
|
if not module_name.startswith("appdaemon"):
|
|
686
686
|
self.logger.debug("Importing '%s'", module_name)
|
|
687
687
|
importlib.import_module(module_name)
|
|
688
|
-
except
|
|
689
|
-
|
|
688
|
+
except Exception as exc:
|
|
689
|
+
match exc:
|
|
690
|
+
case SyntaxError():
|
|
691
|
+
path = Path(exc.filename)
|
|
692
|
+
case NameError():
|
|
693
|
+
path = Path(traceback.extract_tb(exc.__traceback__)[-1].filename)
|
|
694
|
+
case _:
|
|
695
|
+
raise exc
|
|
690
696
|
mtime = self.dependency_manager.python_deps.files.mtimes.get(path)
|
|
691
697
|
self.dependency_manager.python_deps.bad_files.add((path, mtime))
|
|
692
698
|
raise exc
|
|
@@ -846,7 +852,7 @@ class AppManagement:
|
|
|
846
852
|
for path in import_dirs:
|
|
847
853
|
self.add_to_import_path(path)
|
|
848
854
|
|
|
849
|
-
# Add any
|
|
855
|
+
# Add any additional import paths
|
|
850
856
|
for path in map(Path, self.AD.import_paths):
|
|
851
857
|
if not path.exists():
|
|
852
858
|
self.logger.warning(
|
|
@@ -989,13 +995,16 @@ class AppManagement:
|
|
|
989
995
|
update_actions.apps.reload -= failed_to_stop
|
|
990
996
|
|
|
991
997
|
async def _start_apps(self, update_actions: UpdateActions):
|
|
998
|
+
if failed := update_actions.apps.failed:
|
|
999
|
+
self.logger.warning('Failed to start apps: %s', failed)
|
|
1000
|
+
|
|
992
1001
|
start_order = update_actions.apps.start_sort(self.dependency_manager)
|
|
993
1002
|
if start_order:
|
|
994
1003
|
self.logger.info("Starting apps: %s", update_actions.apps.init_set)
|
|
995
1004
|
self.logger.debug("App start order: %s", start_order)
|
|
996
1005
|
|
|
997
1006
|
for app_name in start_order:
|
|
998
|
-
if isinstance((cfg := self.app_config.root[app_name]), AppConfig):
|
|
1007
|
+
if isinstance((cfg := self.app_config.root[app_name]), AppConfig) and not cfg.disable:
|
|
999
1008
|
@ade.wrap_async(self.error, self.AD.app_dir, f"'{app_name}' instantiation")
|
|
1000
1009
|
async def safe_create(self: "AppManagement"):
|
|
1001
1010
|
try:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Core styles. Reference these wherever possible rather than making custom
|
|
2
2
|
# versions of red, green, etc. This will make it easier to quickly change the
|
|
3
|
-
# overall
|
|
3
|
+
# overall palette of the dashboard just by overriding these variables.
|
|
4
4
|
|
|
5
5
|
# This file contains the application "defaults".
|
|
6
6
|
# IF YOU WANT TO CUSTOMIZE styleS FOR YOUR OWN INSTANCE, DO NOT EDIT THIS FILE.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Core styles. Reference these wherever possible rather than making custom
|
|
2
2
|
# versions of red, green, etc. This will make it easier to quickly change the
|
|
3
|
-
# overall
|
|
3
|
+
# overall palette of the dashboard just by overriding these variables.
|
|
4
4
|
|
|
5
5
|
# This file contains the application "defaults".
|
|
6
6
|
# IF YOU WANT TO CUSTOMIZE styleS FOR YOUR OWN INSTANCE, DO NOT EDIT THIS FILE.
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
# gray and getting progressively darker towards night. Be aware that if you remove
|
|
23
23
|
# it, you will end up with a white background so plan accordingly if this is a problem.
|
|
24
24
|
#
|
|
25
|
-
# The meta tag
|
|
25
|
+
# The meta tag just above this refreshes your dash once an hour so you can see the
|
|
26
26
|
# effect of the script without manually reloading the dashboard. The content value
|
|
27
27
|
# is in seconds so if you want it shorter or longer you can adjust that value
|
|
28
28
|
#
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
# gray and getting progressively darker towards night. Be aware that if you remove
|
|
23
23
|
# it, you will end up with a white background so plan accordingly if this is a problem.
|
|
24
24
|
#
|
|
25
|
-
# The meta tag
|
|
25
|
+
# The meta tag just above this refreshes your dash once an hour so you can see the
|
|
26
26
|
# effect of the script without manually reloading the dashboard. The content value
|
|
27
27
|
# is in seconds so if you want it shorter or longer you can adjust that value
|
|
28
28
|
#
|
|
@@ -92,6 +92,7 @@ def get_file_deps(file_path: str | Path) -> set[str]:
|
|
|
92
92
|
mod: ast.Module = ast.parse(file_content, filename=file_path)
|
|
93
93
|
except Exception as e:
|
|
94
94
|
logger.warning(f"Error parsing python module with AST: {e}")
|
|
95
|
+
raise e
|
|
95
96
|
else:
|
|
96
97
|
for node in get_imports(mod):
|
|
97
98
|
match node:
|
|
@@ -107,18 +108,32 @@ def get_file_deps(file_path: str | Path) -> set[str]:
|
|
|
107
108
|
return set(gen_modules())
|
|
108
109
|
|
|
109
110
|
|
|
110
|
-
def get_dependency_graph(
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
def get_dependency_graph(
|
|
112
|
+
files: Iterable[Path],
|
|
113
|
+
exclude: set[Path] | None = None
|
|
114
|
+
) -> tuple[dict[str, set[str]], set[Path]]:
|
|
115
|
+
"""Gets the dependency graph for some Python files.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
A tuple containing:
|
|
119
|
+
- A dictionary where keys are module names and values are sets of module names that the key module depends on.
|
|
120
|
+
- A set of paths that failed to parse or resolve dependencies.
|
|
121
|
+
"""
|
|
122
|
+
graph = {}
|
|
123
|
+
failed = set()
|
|
124
|
+
for f in files:
|
|
125
|
+
if exclude is None or f not in exclude:
|
|
126
|
+
try:
|
|
127
|
+
graph[get_full_module_name(f)] = get_file_deps(f)
|
|
128
|
+
except Exception:
|
|
129
|
+
failed.add(f)
|
|
130
|
+
continue
|
|
116
131
|
|
|
117
132
|
for mod, deps in graph.items():
|
|
118
133
|
if mod in deps:
|
|
119
134
|
deps.remove(mod)
|
|
120
135
|
|
|
121
|
-
return graph
|
|
136
|
+
return graph, failed
|
|
122
137
|
|
|
123
138
|
|
|
124
139
|
def get_all_nodes(deps: dict[str, set[str]]) -> set[str]:
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from abc import ABC
|
|
2
|
+
from copy import deepcopy
|
|
2
3
|
from dataclasses import InitVar, dataclass, field
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
from typing import Iterable
|
|
@@ -16,14 +17,14 @@ class Dependencies(ABC):
|
|
|
16
17
|
ext: str = field(init=False) # this has to be defined by the children classes
|
|
17
18
|
dep_graph: dict[str, set[str]] = field(init=False)
|
|
18
19
|
rev_graph: dict[str, set[str]] = field(init=False)
|
|
19
|
-
bad_files: set[Path] = field(default_factory=set, init=False)
|
|
20
|
+
bad_files: set[tuple[Path, float]] = field(default_factory=set, init=False)
|
|
20
21
|
|
|
21
22
|
def __post_init__(self):
|
|
22
23
|
self.refresh_dep_graph()
|
|
23
24
|
|
|
24
25
|
def update(self, new_files: Iterable[Path]):
|
|
25
26
|
self.files.update(new_files)
|
|
26
|
-
for bf, mtime in self.bad_files:
|
|
27
|
+
for bf, mtime in deepcopy(self.bad_files):
|
|
27
28
|
new_mtime = self.files.mtimes.get(bf)
|
|
28
29
|
if new_mtime != mtime:
|
|
29
30
|
assert new_mtime > mtime, f"File {bf} was modified in the future"
|
|
@@ -65,7 +66,12 @@ class PythonDeps(Dependencies):
|
|
|
65
66
|
if self.bad_files:
|
|
66
67
|
bad_files, _ = zip(*self.bad_files)
|
|
67
68
|
bad_files = set(bad_files)
|
|
68
|
-
|
|
69
|
+
|
|
70
|
+
self.dep_graph, failed = get_dependency_graph(self.files, exclude=bad_files)
|
|
71
|
+
|
|
72
|
+
for file in failed:
|
|
73
|
+
self.bad_files.add((file, self.files.mtimes.get(file, 0)))
|
|
74
|
+
|
|
69
75
|
self.rev_graph = reverse_graph(self.dep_graph)
|
|
70
76
|
|
|
71
77
|
def modules_to_import(self) -> set[str]:
|
|
@@ -151,7 +151,7 @@ class Entity:
|
|
|
151
151
|
default (any, optional): The value to return when the entity or the attribute doesn't exist.
|
|
152
152
|
copy (bool, optional): Whether to return a copy of the internal data. This is ``True`` by default in order
|
|
153
153
|
to protect the user from accidentally modifying AppDaemon's internal data structures, which is dangerous
|
|
154
|
-
and can cause undefined
|
|
154
|
+
and can cause undefined behavior. Only set this to ``False`` for read-only operations.
|
|
155
155
|
|
|
156
156
|
Returns:
|
|
157
157
|
The entire state of the entity at that given time, if if ``get_state()``
|
|
@@ -550,7 +550,6 @@ class Entity:
|
|
|
550
550
|
|
|
551
551
|
@property
|
|
552
552
|
def _simple_state(self) -> dict[str, Any]:
|
|
553
|
-
return self.adapi.get_state()
|
|
554
553
|
return self.AD.state.get_state_simple(self.namespace, self.entity_id)
|
|
555
554
|
|
|
556
555
|
@property
|
|
@@ -603,7 +602,7 @@ class Entity:
|
|
|
603
602
|
def last_changed_delta(self) -> timedelta | None:
|
|
604
603
|
"""A timedelta object representing the time since the entity was last changed"""
|
|
605
604
|
if time_str := self.last_changed:
|
|
606
|
-
compare = self.adapi.
|
|
605
|
+
compare = self.adapi.parse_datetime(time_str, aware=True)
|
|
607
606
|
now = self.AD.sched.get_now_sync()
|
|
608
607
|
return (now - compare)
|
|
609
608
|
|
|
@@ -54,9 +54,10 @@ def user_exception_block(logger: Logger, exception: AppDaemonException, app_dir:
|
|
|
54
54
|
"""Function to generate a user-friendly block of text for an exception. Gets the whole chain of exception causes to decide what to do.
|
|
55
55
|
"""
|
|
56
56
|
width = 75
|
|
57
|
+
spacing = 4
|
|
57
58
|
inset = 5
|
|
58
59
|
if header is not None:
|
|
59
|
-
header = f'{"=" * inset} {header} {"=" * (width - inset - len(header))}'
|
|
60
|
+
header = f'{"=" * inset} {header} {"=" * (width - spacing - inset - len(header))}'
|
|
60
61
|
else:
|
|
61
62
|
header = '=' * width
|
|
62
63
|
logger.error(header)
|
|
@@ -86,10 +87,12 @@ def user_exception_block(logger: Logger, exception: AppDaemonException, app_dir:
|
|
|
86
87
|
logger.error(f'{indent}{filename} line {line} in {func_name}')
|
|
87
88
|
case OSError() if str(exc).endswith('address already in use'):
|
|
88
89
|
logger.error(f'{indent}{exc.__class__.__name__}: {exc}')
|
|
89
|
-
case NameError():
|
|
90
|
+
case NameError() | ImportError():
|
|
90
91
|
logger.error(f'{indent}{exc.__class__.__name__}: {exc}')
|
|
91
92
|
if tb := traceback.extract_tb(exc.__traceback__):
|
|
92
93
|
frame = tb[-1]
|
|
94
|
+
file = Path(frame.filename).relative_to(app_dir.parent)
|
|
95
|
+
logger.error(f'{indent} line {frame.lineno} in {file.name}')
|
|
93
96
|
logger.error(f'{indent} {frame._line.rstrip()}')
|
|
94
97
|
error_len = frame.end_colno - frame.colno
|
|
95
98
|
logger.error(f'{indent} {" " * (frame.colno - 1)}{"^" * error_len}')
|
|
@@ -112,7 +115,7 @@ def user_exception_block(logger: Logger, exception: AppDaemonException, app_dir:
|
|
|
112
115
|
for line in lines:
|
|
113
116
|
logger.error(f'{indent}{line}')
|
|
114
117
|
|
|
115
|
-
logger.error('=' *
|
|
118
|
+
logger.error('=' * width)
|
|
116
119
|
|
|
117
120
|
|
|
118
121
|
def unexpected_block(logger: Logger, exception: Exception):
|
|
@@ -318,7 +321,7 @@ class HTTPHostError(AppDaemonException):
|
|
|
318
321
|
|
|
319
322
|
def __str__(self):
|
|
320
323
|
res = "Invalid host specified in URL for HTTP component\n"
|
|
321
|
-
res += "As of AppDaemon 4.5 the host name
|
|
324
|
+
res += "As of AppDaemon 4.5 the host name specified in the URL must resolve to a known host\n"
|
|
322
325
|
res += "You can restore previous behavior by using `0.0.0.0` as the host portion of the URL\n"
|
|
323
326
|
res += f"For instance: `http://0.0.0.0:{self.port}`\n"
|
|
324
327
|
return res
|
|
@@ -96,9 +96,7 @@ def route_secure(myfunc):
|
|
|
96
96
|
return await myfunc(*args)
|
|
97
97
|
|
|
98
98
|
elif "adcreds" in request.cookies:
|
|
99
|
-
match = await utils.run_in_executor(
|
|
100
|
-
self, bcrypt.checkpw, str.encode(self.password), str.encode(request.cookies["adcreds"])
|
|
101
|
-
)
|
|
99
|
+
match = await utils.run_in_executor(self, bcrypt.checkpw, str.encode(self.password), str.encode(request.cookies["adcreds"]))
|
|
102
100
|
if match:
|
|
103
101
|
return await myfunc(*args)
|
|
104
102
|
|
|
@@ -117,13 +115,14 @@ class HTTP:
|
|
|
117
115
|
AD: "AppDaemon"
|
|
118
116
|
"""Reference to the AppDaemon container object
|
|
119
117
|
"""
|
|
118
|
+
name: str = "_http"
|
|
120
119
|
|
|
121
120
|
stopping: bool
|
|
122
121
|
executor: concurrent.futures.ThreadPoolExecutor
|
|
123
122
|
|
|
124
123
|
def __init__(self, ad: "AppDaemon", dashboard, old_admin, admin, api, http):
|
|
125
124
|
self.AD = ad
|
|
126
|
-
self.logger = self.logging.get_child(
|
|
125
|
+
self.logger = self.logging.get_child(self.name)
|
|
127
126
|
self.access = self.logging.get_access()
|
|
128
127
|
|
|
129
128
|
self.dashboard = dashboard
|
|
@@ -175,12 +174,19 @@ class HTTP:
|
|
|
175
174
|
|
|
176
175
|
try:
|
|
177
176
|
url = urlparse(self.url)
|
|
178
|
-
|
|
179
177
|
self.host = url.hostname
|
|
180
|
-
|
|
178
|
+
self.scheme = url.scheme
|
|
179
|
+
|
|
180
|
+
if url.port is None:
|
|
181
|
+
match url.scheme:
|
|
182
|
+
case "http":
|
|
183
|
+
self.port = 80
|
|
184
|
+
case "https":
|
|
185
|
+
self.port = 443
|
|
186
|
+
case _:
|
|
187
|
+
self.port = None # let the validation catch it
|
|
188
|
+
else:
|
|
181
189
|
self.port = url.port
|
|
182
|
-
except IndexError:
|
|
183
|
-
self.port = 80
|
|
184
190
|
|
|
185
191
|
if self.host == "":
|
|
186
192
|
raise ValueError("Invalid host for 'url'")
|
|
@@ -372,9 +378,7 @@ class HTTP:
|
|
|
372
378
|
|
|
373
379
|
self._process_arg("url", http)
|
|
374
380
|
if not self.url:
|
|
375
|
-
self.logger.warning(
|
|
376
|
-
"'{arg}' is '{value}'. Please configure appdaemon.yaml".format(arg="url", value=self.url)
|
|
377
|
-
)
|
|
381
|
+
self.logger.warning("'{arg}' is '{value}'. Please configure appdaemon.yaml".format(arg="url", value=self.url))
|
|
378
382
|
exit(0)
|
|
379
383
|
|
|
380
384
|
self._process_arg("transport", http)
|
|
@@ -893,7 +897,7 @@ class HTTP:
|
|
|
893
897
|
return self.get_response(request, code, "App Not Found")
|
|
894
898
|
|
|
895
899
|
elif code == 500:
|
|
896
|
-
return self.get_response(request, code, "An Error
|
|
900
|
+
return self.get_response(request, code, "An Error occurred while processing request")
|
|
897
901
|
|
|
898
902
|
response = "OK"
|
|
899
903
|
self.access.info("API Call to %s: status: %s %s", endpoint, code, response)
|
|
@@ -71,7 +71,7 @@ class LoadingActions:
|
|
|
71
71
|
Uses a dependency graph to sort the internal ``init`` and ``reload`` sets together
|
|
72
72
|
"""
|
|
73
73
|
items = copy(self.init_set)
|
|
74
|
-
items |= find_all_dependents(items, dm.app_deps.
|
|
74
|
+
items |= find_all_dependents(items, dm.app_deps.dep_graph)
|
|
75
75
|
priorities = {
|
|
76
76
|
app_name: dm.app_deps.app_config.root[app_name].priority
|
|
77
77
|
for app_name in items
|
|
@@ -384,7 +384,7 @@ class Hass(ADBase, ADAPI):
|
|
|
384
384
|
case Iterable():
|
|
385
385
|
constraints = value if isinstance(value, list) else list(value)
|
|
386
386
|
|
|
387
|
-
assert isinstance(
|
|
387
|
+
assert isinstance(constraints, list) and all(isinstance(v, str) for v in constraints)
|
|
388
388
|
|
|
389
389
|
for constraint in constraints:
|
|
390
390
|
parts = re.split(r',\s*', constraint)
|
|
@@ -475,7 +475,7 @@ class Hass(ADBase, ADAPI):
|
|
|
475
475
|
``timeout``. If ``timeout`` is shorter than this one, it will trigger before this one does.
|
|
476
476
|
suppress_log_messages (bool, optional): Only applicable to the Hass plugin. If this is set to ``True``,
|
|
477
477
|
Appdaemon will suppress logging of warnings for service calls to Home Assistant, specifically timeouts
|
|
478
|
-
and non OK statuses. Use this flag and set it to ``True`` to
|
|
478
|
+
and non OK statuses. Use this flag and set it to ``True`` to suppress these log messages if you are
|
|
479
479
|
performing your own error checking as described `here <APPGUIDE.html#some-notes-on-service-calls>`__
|
|
480
480
|
service_data (dict, optional): Used as an additional dictionary to pass arguments into the ``service_data``
|
|
481
481
|
field of the JSON that goes to Home Assistant. This is useful if you have a dictionary that you want to
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Interface with Home Assistant, send and
|
|
2
|
+
Interface with Home Assistant, send and receive evets, state etc.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
@@ -661,7 +661,7 @@ class HassPlugin(PluginBase):
|
|
|
661
661
|
shorter than this one, it will trigger before this one does.
|
|
662
662
|
suppress_log_messages (bool, optional): If this is set to ``True``, Appdaemon will suppress logging of
|
|
663
663
|
warnings for service calls to Home Assistant, specifically timeouts and non OK statuses. Use this flag
|
|
664
|
-
and set it to ``True`` to
|
|
664
|
+
and set it to ``True`` to suppress these log messages if you are performing your own error checking as
|
|
665
665
|
described `here <APPGUIDE.html#some-notes-on-service-calls>`__
|
|
666
666
|
service_data (dict, optional): Used as an additional dictionary to pass arguments into the ``service_data``
|
|
667
667
|
field of the JSON that goes to Home Assistant. This is useful if you have a dictionary that you want to
|
|
@@ -120,7 +120,7 @@ class Mqtt(adbase.ADBase, adapi.ADAPI):
|
|
|
120
120
|
|
|
121
121
|
binary (bool, optional): If wanting the payload to be returned as binary, this should
|
|
122
122
|
be specified. If not given, AD will return the payload as decoded data. It should
|
|
123
|
-
be noted that it is not possible to have different apps
|
|
123
|
+
be noted that it is not possible to have different apps receive both binary and non-binary
|
|
124
124
|
data on the same topic
|
|
125
125
|
|
|
126
126
|
Returns:
|
|
@@ -229,23 +229,17 @@ class Mqtt(adbase.ADBase, adapi.ADAPI):
|
|
|
229
229
|
result = self.call_service(service, **kwargs)
|
|
230
230
|
return result
|
|
231
231
|
|
|
232
|
-
def _run_service_call(self, task: str, topic:
|
|
232
|
+
def _run_service_call(self, task: str, topic: str | list[str], **kwargs: Optional[Any]) -> None:
|
|
233
233
|
"""Used to process the subscribe/unsubscribe service calls"""
|
|
234
234
|
|
|
235
235
|
# first we validate the topic
|
|
236
236
|
if not isinstance(topic, (str, list)):
|
|
237
237
|
raise ValueError(f"The given topic {topic} is not supported. Please only strs and lists are supported")
|
|
238
238
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
self.call_service(service, **kwargs)
|
|
239
|
+
kwargs["topic"] = topic
|
|
240
|
+
service = f"mqtt/{task}"
|
|
241
|
+
return self.call_service(service, **kwargs)
|
|
243
242
|
|
|
244
|
-
else: # its a list
|
|
245
|
-
for t in topic:
|
|
246
|
-
kwargs["topic"] = t
|
|
247
|
-
service = f"mqtt/{task}"
|
|
248
|
-
self.call_service(service, **kwargs)
|
|
249
243
|
|
|
250
244
|
def mqtt_subscribe(self, topic: Union[str, list], **kwargs: Optional[Any]) -> None:
|
|
251
245
|
"""Subscribes to a MQTT topic.
|
|
@@ -284,7 +278,7 @@ class Mqtt(adbase.ADBase, adapi.ADAPI):
|
|
|
284
278
|
|
|
285
279
|
"""
|
|
286
280
|
|
|
287
|
-
self._run_service_call("subscribe", topic, **kwargs)
|
|
281
|
+
return self._run_service_call("subscribe", topic, **kwargs)
|
|
288
282
|
|
|
289
283
|
def mqtt_unsubscribe(self, topic: Union[str, list], **kwargs: Optional[Any]) -> None:
|
|
290
284
|
"""Unsubscribes from a MQTT topic.
|
|
@@ -323,7 +317,7 @@ class Mqtt(adbase.ADBase, adapi.ADAPI):
|
|
|
323
317
|
|
|
324
318
|
"""
|
|
325
319
|
|
|
326
|
-
self._run_service_call("unsubscribe", topic, **kwargs)
|
|
320
|
+
return self._run_service_call("unsubscribe", topic, **kwargs)
|
|
327
321
|
|
|
328
322
|
@utils.sync_decorator
|
|
329
323
|
async def is_client_connected(self, **kwargs: Optional[Any]) -> bool:
|