boneio 1.4.0.dev4__tar.gz → 1.4.0.dev5__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.
- {boneio-1.4.0.dev4/boneio.egg-info → boneio-1.4.0.dev5}/PKG-INFO +1 -1
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/irrigation/controller.py +101 -4
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/irrigation.py +23 -2
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/manager.py +1 -1
- boneio-1.4.0.dev5/boneio/core/messaging/lox.py +326 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/integration/homeassistant.py +84 -0
- boneio-1.4.0.dev5/boneio/integration/lox_template.py +367 -0
- boneio-1.4.0.dev5/boneio/modbus/devices/hvac/eht-topventil-plus.json +243 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/remote_outputs.yaml +3 -1
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/schema.yaml +22 -1
- boneio-1.4.0.dev5/boneio/version.py +2 -0
- boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/ConfigEditor-BBQ49dou.js → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/ConfigEditor-A8cWujvP.js +1 -1
- boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/aiConfig-BwEuqxu2.js → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/aiConfig-DxFilBWK.js +2 -2
- boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/aiWizardPrompt-CEIyLZ8l.js → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/aiWizardPrompt-CrWwS7zb.js +1 -1
- boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/index-D-R9QzIP.css → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/index-BtCN44rd.css +1 -1
- boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/index-CfQ35RrC.js → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/index-ChujUEJh.js +62 -6
- boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/useTranslation-ChbxfQ44.js → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/useTranslation-CxUU9LHE.js +2 -2
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/index.html +4 -4
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/config.schema.json +21 -3
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/irrigation.schema.json +9 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/modbus_devices.schema.json +3 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/remote_outputs.schema.json +0 -3
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/template.schema.json +9 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/sw.js +1 -1
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/irrigation.py +217 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/config.schema.json +21 -3
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/irrigation.schema.json +9 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/modbus_devices.schema.json +3 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/remote_outputs.schema.json +0 -3
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/template.schema.json +9 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5/boneio.egg-info}/PKG-INFO +1 -1
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio.egg-info/SOURCES.txt +7 -7
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/pyproject.toml +1 -0
- boneio-1.4.0.dev4/boneio/core/messaging/lox.py +0 -221
- boneio-1.4.0.dev4/boneio/core/messaging/loxone.py +0 -181
- boneio-1.4.0.dev4/boneio/integration/lox_template.py +0 -243
- boneio-1.4.0.dev4/boneio/version.py +0 -2
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/LICENSE +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/MANIFEST.in +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/README.md +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.2/input.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.2/output_24_16.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.2/output_32_10.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.2/output_32_5.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.2/output_cover.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.2/output_cover_mix.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.3/input.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.3/output_24_16.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.3/output_32_10.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.3/output_32_5.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.3/output_cover.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.3/output_cover_mix.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.4/input.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.4/output_24_16.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.4/output_32_10.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.4/output_32_5.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.4/output_cover.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.4/output_cover_mix.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.5/input.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.5/output_24_16.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.5/output_32_10.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.5/output_cover.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.5/output_cover_mix.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.6/input.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.6/output_24_16.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.6/output_32_10.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.6/output_cover.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.6/output_cover_mix.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.7/input.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.7/output_24_16.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.7/output_32_10.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.7/output_48_4.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.7/output_cover.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.7/output_cover_mix.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.8/input.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.8/output_24_16.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.8/output_32_10.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.8/output_48_4.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.8/output_cover.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.8/output_cover_mix.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/bonecli.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/cover/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/cover/cover.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/cover/time_based.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/cover/venetian.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/group/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/group/output_group.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/input/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/input/binary_sensor.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/input/detectors.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/input/event.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/input/remote/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/input/remote/base.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/input/remote/esphome.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/irrigation/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/irrigation/water_source.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/output/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/output/basic.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/output/mcp.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/output/pca.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/output/pcf.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/output/remote.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/sensor/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/sensor/virtual_energy.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/template/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/template/alarm_panel.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/template/gate_cover.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/template/thermostat.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/const.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/cloud/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/cloud/data/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/cloud/data/docker-compose-cloud.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/cloud/data/docker-compose.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/cloud/data/init-certs-cloud.sh +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/cloud/registration.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/cloud/secrets.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/config_helper.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/migrations/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/migrations/v1_proxy_port.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/migrations/v2_transition.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/package-lock.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/package.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/schema_converter.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/yaml_util.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/discovery.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/events/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/events/bus.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/action_conditions.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/canopen.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/covers.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/display.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/inputs.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/modbus.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/outputs.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/remote.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/remote_input_registrar.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/sensors.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/templates/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/templates/alarm.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/templates/gate_cover.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/templates/thermostat.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/templates.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/update.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/messaging/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/messaging/basic.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/messaging/basic_mqtt.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/messaging/composite.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/messaging/local.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/messaging/mqtt.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/messaging/queue.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/remote/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/remote/base.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/remote/can.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/remote/esphome.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/remote/mqtt.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/remote/wled.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/sensor/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/sensor/base.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/sensor/system.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/state/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/state/manager.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/system/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/system/host_data.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/system/monitor.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/async_updater.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/conditions.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/filter.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/font_util.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/logger.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/timeperiod.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/util.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/24x16/adc.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/24x16/binary_sensor.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/24x16/config.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/24x16/event.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/24x16/mqtt.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/24x16/output24x16A.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/32x10/adc.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/32x10/binary_sensor.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/32x10/config.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/32x10/event.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/32x10/mqtt.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/32x10/output32x10A.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/48x4/adc.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/48x4/binary_sensor.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/48x4/config.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/48x4/event.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/48x4/mqtt.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/48x4/output48x4A.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/can_master.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/can_slave.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover/adc.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover/binary_sensor.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover/config.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover/cover.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover/event.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover/mqtt.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover/outputCover.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/adc.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/binary_sensor.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/config.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/cover.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/event.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/mqtt.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/outputCoverMix.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/adc.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/all_binary_sensor.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/binary_sensor.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/binary_sensor_v_0_7.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/config_24_16.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/event_all.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/event_v_0_7.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/led32x4A.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/output24x16A.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/output24x16A_v0.3.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/output32x10A.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/output32x5A.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/exceptions.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/analog/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/analog/adc.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/can/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/can/bridge.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/can/client.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/can/interface.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/can/node.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/can/node_id.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/can/test_od.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/display/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/display/early_oled.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/display/fonts/danube__.ttf +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/display/oled.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/expanders/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/expanders/mcp23017.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/expanders/pca9685.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/expanders/pcf8575.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/input/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/input/base.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/input/manager.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/i2c/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/i2c/bus.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/i2c/ina219.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/i2c/ina219_driver.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/i2c/mcp9808.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/i2c/pct2075.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/onewire/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/onewire/bus.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/onewire/dallas.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/onewire/ds2482.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/sensor/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/sensor/temperature/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/sensor/temperature/base.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/sensor/temperature/mcp9808.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/sensor/temperature/pct2075.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/integration/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/integration/interlock.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/actions.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/MANIFEST.sha256 +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/docker/daemon.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/docker/nodered/docker-compose.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/docker/nodered/nginx/default.conf +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/docker/nodered/node-red/settings.js +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/journald/journald.conf +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/mosquitto/boneio.conf +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/sudoers/boneio +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/systemd/boneio-oled-boot.service +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/systemd/boneio.service +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/systemd/set-hostname-once.service +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/usr-local-bin/set-hostname-once.sh +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/usr-sbin/oled_boot_splash.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/usr-sbin/oled_boot_splash.sh +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/usr-sbin/oled_msg.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/usr-sbin/oled_msg.sh +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/bootstrap/boneio-migrate +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/bootstrap/install-helper.sh +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/bootstrap/sudoers-migrate +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/runner.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/versions/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/versions/v1_3_0_baseline.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/versions/v1_3_1_fix_oled_boot.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/versions/v1_3_2_cleanup_can_sudoers.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/versions/v1_4_0_fix_mqtt_sudoers.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/cli.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/client.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/coordinator.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/le-03mw.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/le-03mwct.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/orno-or-we-517.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/sdm120.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/sdm630.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/socomec_e03.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/socomec_e23.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/hvac/fujitsu-ac.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/hvac/ventclear.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/inverters/sofar.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/inverters/thessla.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/other/esp32_relay_x4_modbus.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/other/n4dsc08.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/other/r4dcb08.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/other/wanas415.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/boneio-edge-temp.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/cwt.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/dts1964_3f.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/dyp-a12-ultrasonic.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/gdfs.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/gdfx.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/liquid-sensor.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/pt100.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/sht20.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/sht30.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/base.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/derived/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/derived/numeric.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/derived/select.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/derived/switch.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/derived/text.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/sensor/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/sensor/binary.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/sensor/numeric.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/sensor/text.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/writeable/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/writeable/binary.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/writeable/numeric.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/utils.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/models/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/models/actions.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/models/events.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/models/files.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/models/logs.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/models/mqtt.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/models/state.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/runner.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/actions.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/actions_sensor.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/actions_switch.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/condition.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/filters.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/filters_adc.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/id.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/remote_devices.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/remote_inputs.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/temp_unit.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/update_interval.yaml +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/action_validation.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/app.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/codicon-DCmgc-ay.ttf +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/editor.worker-BVjSvWeP.js +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/json.worker-CqOJL4FD.js +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/monaco-B9WiNxkw.css +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/monaco-CAZoGZNF.js +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/rolldown-runtime-Dw2cE7zH.js +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/vendor-BD5Ml_Uz.js +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/workbox-window.prod.es5-BJd1pjeW.js +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/yaml.worker-nZQZSRZ7.js +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/boneio-192.png +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/boneio-512.png +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/boneio.svg +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/boneio_fav.svg +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/adc.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/areas.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/binary_sensor.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/boneio.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/can.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/cover.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/dallas.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/ds2482.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/event.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/ina219.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/lm75.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/logger.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/lox_udp.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/mcp23017.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/mcp9808.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/modbus.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/mqtt.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/oled.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/output.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/output_group.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/pca9685.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/pcf8575.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/remote_devices.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/remote_inputs.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/sensor.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/virtual_energy_sensor.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/web.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/workbox-4eca85ba.js +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/middleware/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/middleware/auth.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/auth.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/caddy.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/can.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/config.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/covers.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/migrations.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/modbus.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/outputs.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/remote_devices.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/sensors.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/system.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/templates.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/timezone_sudoers.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/tools.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/update.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/adc.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/areas.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/binary_sensor.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/boneio.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/can.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/cover.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/dallas.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/ds2482.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/event.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/ina219.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/lm75.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/logger.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/lox_udp.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/mcp23017.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/mcp9808.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/modbus.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/mqtt.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/oled.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/output.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/output_group.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/pca9685.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/pcf8575.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/remote_devices.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/remote_inputs.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/sensor.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/virtual_energy_sensor.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/web.schema.json +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/services/__init__.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/services/logs.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/web_server.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/websocket_manager.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio.egg-info/dependency_links.txt +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio.egg-info/entry_points.txt +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio.egg-info/requires.txt +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio.egg-info/top_level.txt +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/setup.cfg +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/setup.py +0 -0
- {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/tests/test_py313_compatibility.py +0 -0
|
@@ -75,6 +75,7 @@ class IrrigationController:
|
|
|
75
75
|
repeat: int = 0,
|
|
76
76
|
auto_advance: bool = True,
|
|
77
77
|
reverse: bool = False,
|
|
78
|
+
pause_timeout_s: int = 1800,
|
|
78
79
|
) -> None:
|
|
79
80
|
"""Initialize irrigation controller.
|
|
80
81
|
|
|
@@ -95,6 +96,8 @@ class IrrigationController:
|
|
|
95
96
|
repeat: Number of cycle repeats.
|
|
96
97
|
auto_advance: Automatically advance to next zone.
|
|
97
98
|
reverse: Run zones in reverse order.
|
|
99
|
+
pause_timeout_s: Auto-shutdown after this many seconds in PAUSED state.
|
|
100
|
+
Default 1800 (30 minutes). Set 0 to disable.
|
|
98
101
|
"""
|
|
99
102
|
self.id = id
|
|
100
103
|
self.name = name
|
|
@@ -119,6 +122,8 @@ class IrrigationController:
|
|
|
119
122
|
self._skip_next_run = False
|
|
120
123
|
|
|
121
124
|
self._zone_timer_cancel = None
|
|
125
|
+
self._pause_timer_cancel = None
|
|
126
|
+
self._pause_timeout_s = max(0, pause_timeout_s)
|
|
122
127
|
self._run_start_utc: datetime | None = None
|
|
123
128
|
self._active_zone_idx: int | None = None
|
|
124
129
|
self._active_zone_remaining_s: int | None = None
|
|
@@ -181,6 +186,10 @@ class IrrigationController:
|
|
|
181
186
|
def _schedule_skip_cmd_topic(self, idx: int) -> str:
|
|
182
187
|
return f"{self._topic_prefix}/cmd/{IRRIGATION}/{self.id}/schedule/{idx}/skip/set"
|
|
183
188
|
|
|
189
|
+
def _event_topic(self) -> str:
|
|
190
|
+
"""MQTT topic for HA event entity notifications."""
|
|
191
|
+
return f"{self._topic_prefix}/{IRRIGATION}/{self.id}/event"
|
|
192
|
+
|
|
184
193
|
def _state_key(self, suffix: str) -> str:
|
|
185
194
|
return f"{self.id}/{suffix}"
|
|
186
195
|
|
|
@@ -223,6 +232,24 @@ class IrrigationController:
|
|
|
223
232
|
_LOGGER.debug("Irrigation MQTT publish: topic='%s' payload=%s retain=%s", topic, payload, retain)
|
|
224
233
|
self._message_bus.send_message(topic=topic, payload=payload, retain=retain)
|
|
225
234
|
|
|
235
|
+
def _publish_event(self, event_type: str, **attributes: Any) -> None:
|
|
236
|
+
"""Publish an event to the HA event entity topic.
|
|
237
|
+
|
|
238
|
+
The payload follows the HA MQTT event entity format:
|
|
239
|
+
``{"event_type": "...", ...extra attributes}``.
|
|
240
|
+
|
|
241
|
+
Events are NOT retained — they are instantaneous notifications.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
event_type: One of the registered event types
|
|
245
|
+
(interlock_fault, cycle_complete, standby_blocked).
|
|
246
|
+
**attributes: Additional key-value pairs included in the event payload.
|
|
247
|
+
"""
|
|
248
|
+
import json
|
|
249
|
+
|
|
250
|
+
payload = {"event_type": event_type, **attributes}
|
|
251
|
+
self._publish(self._event_topic(), json.dumps(payload), retain=False)
|
|
252
|
+
|
|
226
253
|
def _ordered_zones(self) -> list[tuple[int, IrrigationZone]]:
|
|
227
254
|
indexed = list(enumerate(self._zones))
|
|
228
255
|
if self._reverse:
|
|
@@ -352,6 +379,7 @@ class IrrigationController:
|
|
|
352
379
|
"".join(traceback.format_stack(limit=5)),
|
|
353
380
|
)
|
|
354
381
|
self.stop_schedules()
|
|
382
|
+
self._cancel_pause_timer()
|
|
355
383
|
await self._stop_current_zone()
|
|
356
384
|
await self._handle_pump_stop_sequence()
|
|
357
385
|
self._state = ControllerState.IDLE
|
|
@@ -370,11 +398,13 @@ class IrrigationController:
|
|
|
370
398
|
self._cancel_zone_timer()
|
|
371
399
|
await self._stop_current_zone()
|
|
372
400
|
self._state = ControllerState.PAUSED
|
|
401
|
+
self._arm_pause_timer()
|
|
373
402
|
await self.publish_all_states()
|
|
374
403
|
|
|
375
404
|
async def resume(self) -> None:
|
|
376
405
|
if self._state != ControllerState.PAUSED or self._active_zone_idx is None:
|
|
377
406
|
return
|
|
407
|
+
self._cancel_pause_timer()
|
|
378
408
|
remaining = self._active_zone_remaining_s or self._current_zone_duration_seconds()
|
|
379
409
|
await self._start_zone(self._active_zone_idx, override_duration=remaining)
|
|
380
410
|
|
|
@@ -400,6 +430,11 @@ class IrrigationController:
|
|
|
400
430
|
)
|
|
401
431
|
if self._standby:
|
|
402
432
|
_LOGGER.info("Irrigation %s is in standby mode, not starting", self.id)
|
|
433
|
+
self._publish_event(
|
|
434
|
+
"standby_blocked",
|
|
435
|
+
controller=self.id,
|
|
436
|
+
message=f"Irrigation '{self.name}' start blocked: standby mode is active",
|
|
437
|
+
)
|
|
403
438
|
return
|
|
404
439
|
|
|
405
440
|
if self._state in (ControllerState.RUNNING, ControllerState.PAUSED):
|
|
@@ -428,6 +463,12 @@ class IrrigationController:
|
|
|
428
463
|
)
|
|
429
464
|
if self._standby:
|
|
430
465
|
_LOGGER.info("Irrigation %s is in standby mode, not starting zone", self.id)
|
|
466
|
+
self._publish_event(
|
|
467
|
+
"standby_blocked",
|
|
468
|
+
controller=self.id,
|
|
469
|
+
zone=zone_id,
|
|
470
|
+
message=f"Irrigation '{self.name}' zone '{zone_id}' blocked: standby mode is active",
|
|
471
|
+
)
|
|
431
472
|
return
|
|
432
473
|
|
|
433
474
|
match_idx = None
|
|
@@ -551,6 +592,11 @@ class IrrigationController:
|
|
|
551
592
|
await self._start_cycle_from_eligible()
|
|
552
593
|
return
|
|
553
594
|
|
|
595
|
+
self._publish_event(
|
|
596
|
+
"cycle_complete",
|
|
597
|
+
controller=self.id,
|
|
598
|
+
message=f"Irrigation '{self.name}' cycle completed",
|
|
599
|
+
)
|
|
554
600
|
await self.shutdown()
|
|
555
601
|
|
|
556
602
|
def _ordered_zone_indices(self) -> list[int]:
|
|
@@ -718,8 +764,10 @@ class IrrigationController:
|
|
|
718
764
|
async def _handle_interlock_fault(self, zone_id: str, source_id: str | None) -> None:
|
|
719
765
|
"""Handle interlock-blocked activation.
|
|
720
766
|
|
|
721
|
-
Shuts down the controller and publishes a fault
|
|
722
|
-
|
|
767
|
+
Shuts down the controller and publishes both a retained fault status
|
|
768
|
+
message and a non-retained HA event notification via the event entity.
|
|
769
|
+
Home Assistant automations can listen to the event entity to trigger
|
|
770
|
+
mobile push notifications, Telegram messages, etc.
|
|
723
771
|
|
|
724
772
|
Args:
|
|
725
773
|
zone_id: ID of the zone that was being started.
|
|
@@ -734,13 +782,15 @@ class IrrigationController:
|
|
|
734
782
|
source_info,
|
|
735
783
|
)
|
|
736
784
|
|
|
737
|
-
|
|
785
|
+
fault_message = f"Irrigation '{self.name}' stopped: output blocked by interlock (zone: {zone_id})"
|
|
786
|
+
|
|
787
|
+
# Publish retained fault status on MQTT (legacy topic)
|
|
738
788
|
fault_payload = {
|
|
739
789
|
"fault": "interlock_blocked",
|
|
740
790
|
"controller": self.id,
|
|
741
791
|
"zone": zone_id,
|
|
742
792
|
"source": source_id or "",
|
|
743
|
-
"message":
|
|
793
|
+
"message": fault_message,
|
|
744
794
|
}
|
|
745
795
|
self._publish(
|
|
746
796
|
f"{self._topic_prefix}/{IRRIGATION}/{self.id}/fault",
|
|
@@ -748,6 +798,15 @@ class IrrigationController:
|
|
|
748
798
|
retain=False,
|
|
749
799
|
)
|
|
750
800
|
|
|
801
|
+
# Publish HA event entity notification (non-retained, instantaneous)
|
|
802
|
+
self._publish_event(
|
|
803
|
+
"interlock_fault",
|
|
804
|
+
controller=self.id,
|
|
805
|
+
zone=zone_id,
|
|
806
|
+
source=source_id or "",
|
|
807
|
+
message=fault_message,
|
|
808
|
+
)
|
|
809
|
+
|
|
751
810
|
await self.shutdown()
|
|
752
811
|
await self.publish_all_states()
|
|
753
812
|
|
|
@@ -799,6 +858,44 @@ class IrrigationController:
|
|
|
799
858
|
async def _zone_timer_callback(self, _timestamp: datetime) -> None:
|
|
800
859
|
await self._advance_to_next_zone(force=False)
|
|
801
860
|
|
|
861
|
+
def _cancel_pause_timer(self) -> None:
|
|
862
|
+
"""Cancel the pause timeout timer if active."""
|
|
863
|
+
if self._pause_timer_cancel is not None:
|
|
864
|
+
self._pause_timer_cancel()
|
|
865
|
+
self._pause_timer_cancel = None
|
|
866
|
+
|
|
867
|
+
def _arm_pause_timer(self) -> None:
|
|
868
|
+
"""Arm an auto-shutdown timer for the PAUSED state.
|
|
869
|
+
|
|
870
|
+
If pause_timeout_s is 0, no timer is set (pause lasts indefinitely).
|
|
871
|
+
Otherwise, the controller will auto-shutdown after the configured timeout.
|
|
872
|
+
"""
|
|
873
|
+
self._cancel_pause_timer()
|
|
874
|
+
if self._pause_timeout_s <= 0:
|
|
875
|
+
return
|
|
876
|
+
point = utcnow() + timedelta(seconds=self._pause_timeout_s)
|
|
877
|
+
self._pause_timer_cancel = async_track_point_in_time(
|
|
878
|
+
loop=self._event_bus._loop,
|
|
879
|
+
job=self._pause_timeout_callback,
|
|
880
|
+
point_in_time=point,
|
|
881
|
+
)
|
|
882
|
+
_LOGGER.info(
|
|
883
|
+
"Irrigation %s: pause timeout armed for %d seconds",
|
|
884
|
+
self.id,
|
|
885
|
+
self._pause_timeout_s,
|
|
886
|
+
)
|
|
887
|
+
|
|
888
|
+
async def _pause_timeout_callback(self, _timestamp: datetime) -> None:
|
|
889
|
+
"""Handle pause timeout — auto-shutdown the controller."""
|
|
890
|
+
if self._state != ControllerState.PAUSED:
|
|
891
|
+
return
|
|
892
|
+
_LOGGER.warning(
|
|
893
|
+
"Irrigation %s: pause timeout expired after %d seconds, shutting down",
|
|
894
|
+
self.id,
|
|
895
|
+
self._pause_timeout_s,
|
|
896
|
+
)
|
|
897
|
+
await self.shutdown()
|
|
898
|
+
|
|
802
899
|
async def handle_main_command(self, payload: str) -> None:
|
|
803
900
|
cmd = payload.strip()
|
|
804
901
|
upper = cmd.upper()
|
|
@@ -11,11 +11,13 @@ from boneio.const import NEXT_VALVE, ON, PAUSE, RESUME
|
|
|
11
11
|
from boneio.core.utils.timeperiod import parse_time_to_seconds
|
|
12
12
|
from boneio.integration.homeassistant import (
|
|
13
13
|
ha_irrigation_button_message,
|
|
14
|
+
ha_irrigation_event_message,
|
|
14
15
|
ha_irrigation_main_switch_message,
|
|
15
16
|
ha_irrigation_number_message,
|
|
16
17
|
ha_irrigation_select_message,
|
|
17
18
|
ha_irrigation_switch_message,
|
|
18
19
|
ha_irrigation_timestamp_sensor_message,
|
|
20
|
+
ha_irrigation_valve_message,
|
|
19
21
|
)
|
|
20
22
|
|
|
21
23
|
if TYPE_CHECKING:
|
|
@@ -90,6 +92,7 @@ class IrrigationManager:
|
|
|
90
92
|
repeat=int(cfg.get("repeat", 0)),
|
|
91
93
|
auto_advance=bool(cfg.get("auto_advance", True)),
|
|
92
94
|
reverse=bool(cfg.get("reverse", False)),
|
|
95
|
+
pause_timeout_s=int(parse_time_to_seconds(cfg.get("pause_timeout"), 1800)),
|
|
93
96
|
)
|
|
94
97
|
|
|
95
98
|
def _build_zone(self, zone_cfg: dict[str, Any]) -> IrrigationZone | None:
|
|
@@ -280,9 +283,10 @@ class IrrigationManager:
|
|
|
280
283
|
(f"{ctrl.id}_next_valve", "button"),
|
|
281
284
|
(f"{ctrl.id}_pause", "button"),
|
|
282
285
|
(f"{ctrl.id}_resume", "button"),
|
|
286
|
+
(f"{ctrl.id}_event", "event"),
|
|
283
287
|
]
|
|
284
288
|
for zone in ctrl.zones:
|
|
285
|
-
discovery_ids.append((f"{ctrl.id}_zone_{zone.id}", "
|
|
289
|
+
discovery_ids.append((f"{ctrl.id}_zone_{zone.id}", "valve"))
|
|
286
290
|
discovery_ids.append((f"{ctrl.id}_zone_{zone.id}_enabled", "switch"))
|
|
287
291
|
discovery_ids.append((f"{ctrl.id}_zone_{zone.id}_duration", "number"))
|
|
288
292
|
for idx in range(len(ctrl._schedule)):
|
|
@@ -506,10 +510,16 @@ class IrrigationManager:
|
|
|
506
510
|
)
|
|
507
511
|
|
|
508
512
|
for zone in ctrl.zones:
|
|
513
|
+
# Remove stale switch discovery (migration from switch → valve)
|
|
509
514
|
self._manager.publish_ha_discovery(
|
|
510
515
|
id=f"{ctrl.id}_zone_{zone.id}",
|
|
511
516
|
ha_type="switch",
|
|
512
|
-
payload=
|
|
517
|
+
payload="",
|
|
518
|
+
)
|
|
519
|
+
self._manager.publish_ha_discovery(
|
|
520
|
+
id=f"{ctrl.id}_zone_{zone.id}",
|
|
521
|
+
ha_type="valve",
|
|
522
|
+
payload=ha_irrigation_valve_message(
|
|
513
523
|
ctrl.id,
|
|
514
524
|
ctrl.name,
|
|
515
525
|
suffix=f"zone/{zone.id}",
|
|
@@ -584,3 +594,14 @@ class IrrigationManager:
|
|
|
584
594
|
config_helper=cfg,
|
|
585
595
|
),
|
|
586
596
|
)
|
|
597
|
+
|
|
598
|
+
# Event entity — fires on interlock faults, cycle completions, etc.
|
|
599
|
+
self._manager.publish_ha_discovery(
|
|
600
|
+
id=f"{ctrl.id}_event",
|
|
601
|
+
ha_type="event",
|
|
602
|
+
payload=ha_irrigation_event_message(
|
|
603
|
+
ctrl.id,
|
|
604
|
+
ctrl.name,
|
|
605
|
+
config_helper=cfg,
|
|
606
|
+
),
|
|
607
|
+
)
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
"""Lox UDP Client for BoneIO.
|
|
2
|
+
|
|
3
|
+
Implements the Loxone UDP protocol for bidirectional communication
|
|
4
|
+
between BoneIO and a Loxone Miniserver:
|
|
5
|
+
|
|
6
|
+
- Receiving commands from Miniserver (e.g. "OUT_04=ON")
|
|
7
|
+
- Sending state feedback to Miniserver (e.g. "OUT_04=ON", "cover1=50")
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import asyncio
|
|
13
|
+
import logging
|
|
14
|
+
from collections.abc import Awaitable, Callable
|
|
15
|
+
from typing import TYPE_CHECKING, Any
|
|
16
|
+
|
|
17
|
+
from boneio.core.messaging.basic import MessageBus
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from boneio.core.config import ConfigHelper
|
|
21
|
+
from boneio.core.manager import Manager
|
|
22
|
+
from boneio.integration.homeassistant import HomeAssistantDiscoveryMessage
|
|
23
|
+
|
|
24
|
+
_LOGGER = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
# Entity types whose state changes should be forwarded to Loxone
|
|
27
|
+
_LOX_ENTITY_TYPES = frozenset(
|
|
28
|
+
("output", "cover", "sensor", "event", "binary_sensor", "input")
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class LoxUDPProtocol(asyncio.DatagramProtocol):
|
|
33
|
+
"""Protocol for handling Lox UDP communication."""
|
|
34
|
+
|
|
35
|
+
def __init__(self, callback: Callable[[str, str], Awaitable[None]]):
|
|
36
|
+
self._callback = callback
|
|
37
|
+
self._loop = asyncio.get_running_loop()
|
|
38
|
+
|
|
39
|
+
def connection_made(self, transport: asyncio.DatagramTransport) -> None:
|
|
40
|
+
"""Handle connection established."""
|
|
41
|
+
self.transport = transport
|
|
42
|
+
|
|
43
|
+
def datagram_received(self, data: bytes, addr: tuple[str, int]) -> None:
|
|
44
|
+
"""Handle incoming datagram.
|
|
45
|
+
|
|
46
|
+
Expected message format: "device_id=value" or just "device_id".
|
|
47
|
+
"""
|
|
48
|
+
try:
|
|
49
|
+
message = data.decode("utf-8").strip()
|
|
50
|
+
_LOGGER.debug("Received Lox UDP message: %s from %s", message, addr)
|
|
51
|
+
|
|
52
|
+
# Message format expected: "device=value" or just "device"
|
|
53
|
+
if "=" in message:
|
|
54
|
+
device, payload = message.split("=", 1)
|
|
55
|
+
else:
|
|
56
|
+
device = message
|
|
57
|
+
payload = "pressed"
|
|
58
|
+
|
|
59
|
+
self._loop.create_task(self._callback(device, payload))
|
|
60
|
+
except Exception as e:
|
|
61
|
+
_LOGGER.error("Error processing Lox UDP datagram: %s", e)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class LoxUDPClient(MessageBus):
|
|
65
|
+
"""Represent a Lox UDP client.
|
|
66
|
+
|
|
67
|
+
This message bus translates between BoneIO's internal MQTT-style
|
|
68
|
+
topic/payload model and the simple "key=value" UDP protocol
|
|
69
|
+
expected by Loxone Miniserver.
|
|
70
|
+
|
|
71
|
+
Outgoing (BoneIO → Miniserver):
|
|
72
|
+
topic "boneio/{serial}/output/relay1" + payload {"state": "ON"}
|
|
73
|
+
→ UDP datagram "relay1=ON" sent to Miniserver
|
|
74
|
+
|
|
75
|
+
Incoming (Miniserver → BoneIO):
|
|
76
|
+
UDP datagram "relay1=ON"
|
|
77
|
+
→ routed to Manager as "boneio/{serial}/cmd/output/relay1/set" = "ON"
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
config_helper: ConfigHelper,
|
|
83
|
+
host: str,
|
|
84
|
+
send_port: int,
|
|
85
|
+
listen_port: int,
|
|
86
|
+
) -> None:
|
|
87
|
+
"""Set up client.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
config_helper: BoneIO configuration helper.
|
|
91
|
+
host: Loxone Miniserver IP address.
|
|
92
|
+
send_port: Port on Miniserver to send state feedback to.
|
|
93
|
+
listen_port: Port BoneIO listens on for commands from Miniserver.
|
|
94
|
+
"""
|
|
95
|
+
self._manager: Manager | None = None
|
|
96
|
+
self._config_helper = config_helper
|
|
97
|
+
self.host = host
|
|
98
|
+
self.send_port = send_port
|
|
99
|
+
self.listen_port = listen_port
|
|
100
|
+
self._transport: asyncio.DatagramTransport | None = None
|
|
101
|
+
self._listeners: dict[str, Callable[[str, str], Awaitable[None]]] = {}
|
|
102
|
+
self._state = False
|
|
103
|
+
|
|
104
|
+
def send_message(
|
|
105
|
+
self,
|
|
106
|
+
topic: str,
|
|
107
|
+
payload: str | int | bytes | dict[str, Any] | HomeAssistantDiscoveryMessage | None,
|
|
108
|
+
retain: bool = False,
|
|
109
|
+
qos: int = 0,
|
|
110
|
+
) -> None:
|
|
111
|
+
"""Send a state update to Loxone Miniserver via UDP.
|
|
112
|
+
|
|
113
|
+
Converts BoneIO's MQTT-style topic/payload into a simple UDP
|
|
114
|
+
datagram in the format "device_id=state_value".
|
|
115
|
+
|
|
116
|
+
Topic format: boneio/{serial}/{entity_type}/{device_id}
|
|
117
|
+
or: boneio/{serial}/{entity_type}/{device_id}/state
|
|
118
|
+
or: boneio/{serial}/{entity_type}/{device_id}/pos
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
topic: MQTT-style topic string.
|
|
122
|
+
payload: State payload (dict, string, bytes, int, or None).
|
|
123
|
+
retain: Ignored for UDP.
|
|
124
|
+
qos: Ignored for UDP.
|
|
125
|
+
"""
|
|
126
|
+
if payload is None:
|
|
127
|
+
return
|
|
128
|
+
|
|
129
|
+
topic_str = str(topic)
|
|
130
|
+
parts = topic_str.split("/")
|
|
131
|
+
|
|
132
|
+
# Need at least: prefix/serial/entity_type/device_id
|
|
133
|
+
if len(parts) < 4:
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
# Skip HA Discovery messages (homeassistant/*/config topics)
|
|
137
|
+
if parts[0] == "homeassistant" or topic_str.endswith("/config"):
|
|
138
|
+
return
|
|
139
|
+
|
|
140
|
+
# Skip command topics — we only send state feedback, not commands
|
|
141
|
+
if "cmd" in parts:
|
|
142
|
+
return
|
|
143
|
+
|
|
144
|
+
# Determine entity_type and device_id based on topic structure
|
|
145
|
+
# Standard: boneio/{serial}/{entity_type}/{device_id}
|
|
146
|
+
# With suffix: boneio/{serial}/{entity_type}/{device_id}/state
|
|
147
|
+
# With suffix: boneio/{serial}/{entity_type}/{device_id}/pos
|
|
148
|
+
entity_type = parts[2] if len(parts) >= 3 else ""
|
|
149
|
+
suffix = parts[-1] if len(parts) >= 5 else ""
|
|
150
|
+
|
|
151
|
+
# For topics with suffix (state/pos), device_id is parts[-2]
|
|
152
|
+
if suffix in ("state", "pos", "set"):
|
|
153
|
+
device_id = parts[-2]
|
|
154
|
+
else:
|
|
155
|
+
device_id = parts[-1]
|
|
156
|
+
|
|
157
|
+
# Skip non-relevant entity types
|
|
158
|
+
if entity_type not in _LOX_ENTITY_TYPES:
|
|
159
|
+
return
|
|
160
|
+
|
|
161
|
+
# Skip "set" suffix — those are incoming commands, not state feedback
|
|
162
|
+
if suffix == "set":
|
|
163
|
+
return
|
|
164
|
+
|
|
165
|
+
# Extract state value from payload
|
|
166
|
+
state_value = self._extract_state_value(payload)
|
|
167
|
+
if not state_value:
|
|
168
|
+
return
|
|
169
|
+
|
|
170
|
+
self._send_udp(device_id, state_value)
|
|
171
|
+
|
|
172
|
+
@staticmethod
|
|
173
|
+
def _extract_state_value(
|
|
174
|
+
payload: str | int | bytes | dict[str, Any] | HomeAssistantDiscoveryMessage,
|
|
175
|
+
) -> str:
|
|
176
|
+
"""Extract a simple state string from various payload formats.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
payload: The message payload in any supported format.
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
State value as string, or empty string if extraction fails.
|
|
183
|
+
"""
|
|
184
|
+
if isinstance(payload, dict):
|
|
185
|
+
# Try standard keys: {"state": "ON"}, {"value": "50"}
|
|
186
|
+
state_value = payload.get("state", payload.get("value", ""))
|
|
187
|
+
if state_value:
|
|
188
|
+
return str(state_value)
|
|
189
|
+
# Fallback: use first value from dict
|
|
190
|
+
if payload:
|
|
191
|
+
return str(next(iter(payload.values()), ""))
|
|
192
|
+
return ""
|
|
193
|
+
if isinstance(payload, bytes):
|
|
194
|
+
return payload.decode("utf-8")
|
|
195
|
+
return str(payload)
|
|
196
|
+
|
|
197
|
+
def _send_udp(self, device_id: str, state_value: str) -> None:
|
|
198
|
+
"""Send a UDP datagram to Loxone Miniserver.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
device_id: Entity identifier (e.g. "relay1", "cover1").
|
|
202
|
+
state_value: State value string (e.g. "ON", "50").
|
|
203
|
+
"""
|
|
204
|
+
try:
|
|
205
|
+
udp_msg = f"{device_id}={state_value}".encode()
|
|
206
|
+
if self._transport:
|
|
207
|
+
self._transport.sendto(udp_msg, (self.host, self.send_port))
|
|
208
|
+
_LOGGER.debug(
|
|
209
|
+
"Sent Lox UDP message: %s to %s:%s",
|
|
210
|
+
udp_msg.decode("utf-8"),
|
|
211
|
+
self.host,
|
|
212
|
+
self.send_port,
|
|
213
|
+
)
|
|
214
|
+
else:
|
|
215
|
+
_LOGGER.debug(
|
|
216
|
+
"Lox UDP transport not ready, dropping: %s",
|
|
217
|
+
udp_msg.decode("utf-8"),
|
|
218
|
+
)
|
|
219
|
+
except Exception as e:
|
|
220
|
+
_LOGGER.error("Error sending Lox UDP message: %s", e)
|
|
221
|
+
|
|
222
|
+
@property
|
|
223
|
+
def state(self) -> bool:
|
|
224
|
+
"""State of Lox Client."""
|
|
225
|
+
return self._state
|
|
226
|
+
|
|
227
|
+
async def start_client(self) -> None:
|
|
228
|
+
"""Start UDP server and client."""
|
|
229
|
+
try:
|
|
230
|
+
loop = asyncio.get_running_loop()
|
|
231
|
+
transport, protocol = await loop.create_datagram_endpoint(
|
|
232
|
+
lambda: LoxUDPProtocol(self._handle_incoming),
|
|
233
|
+
local_addr=("0.0.0.0", self.listen_port),
|
|
234
|
+
)
|
|
235
|
+
self._transport = transport
|
|
236
|
+
self._state = True
|
|
237
|
+
_LOGGER.info(
|
|
238
|
+
"Lox UDP client started. Listening on port %s, sending to %s:%s",
|
|
239
|
+
self.listen_port,
|
|
240
|
+
self.host,
|
|
241
|
+
self.send_port,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# Announce online status so Lox Miniserver knows we are alive
|
|
245
|
+
self._transport.sendto(b"boneio=online", (self.host, self.send_port))
|
|
246
|
+
|
|
247
|
+
while True:
|
|
248
|
+
await asyncio.sleep(3600)
|
|
249
|
+
|
|
250
|
+
except asyncio.CancelledError:
|
|
251
|
+
_LOGGER.info("Lox UDP client shutting down...")
|
|
252
|
+
except Exception as e:
|
|
253
|
+
_LOGGER.error("Failed to start Lox UDP client: %s", e)
|
|
254
|
+
self._state = False
|
|
255
|
+
finally:
|
|
256
|
+
if self._transport:
|
|
257
|
+
self._transport.close()
|
|
258
|
+
|
|
259
|
+
def set_manager(self, manager: Manager) -> None:
|
|
260
|
+
"""Set manager reference for routing incoming commands."""
|
|
261
|
+
self._manager = manager
|
|
262
|
+
|
|
263
|
+
async def announce_offline(self) -> None:
|
|
264
|
+
"""Announce offline status to Miniserver."""
|
|
265
|
+
if self._transport:
|
|
266
|
+
self._transport.sendto(b"boneio=offline", (self.host, self.send_port))
|
|
267
|
+
|
|
268
|
+
async def subscribe_and_listen(
|
|
269
|
+
self, topic: str, callback: Callable[[str, str], Awaitable[None]]
|
|
270
|
+
) -> None:
|
|
271
|
+
"""Register a listener for a topic pattern."""
|
|
272
|
+
self._listeners[topic] = callback
|
|
273
|
+
|
|
274
|
+
async def unsubscribe_and_stop_listen(self, topic: str) -> None:
|
|
275
|
+
"""Unregister a listener."""
|
|
276
|
+
if topic in self._listeners:
|
|
277
|
+
del self._listeners[topic]
|
|
278
|
+
|
|
279
|
+
async def _handle_incoming(self, device: str, payload: str) -> None:
|
|
280
|
+
"""Handle incoming Lox messages and route them to Manager.
|
|
281
|
+
|
|
282
|
+
Resolves the device name to an entity type (output/cover) and
|
|
283
|
+
forwards the command to the Manager's receive_message method.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
device: Device identifier from UDP message (e.g. "relay1").
|
|
287
|
+
payload: Command value from UDP message (e.g. "ON").
|
|
288
|
+
"""
|
|
289
|
+
_LOGGER.debug("Lox handle incoming: %s = %s", device, payload)
|
|
290
|
+
|
|
291
|
+
if not self._manager:
|
|
292
|
+
return
|
|
293
|
+
|
|
294
|
+
try:
|
|
295
|
+
cmd_prefix = self._config_helper.cmd_topic_prefix
|
|
296
|
+
msg_type = None
|
|
297
|
+
|
|
298
|
+
output = self._manager.outputs.get_output(
|
|
299
|
+
device
|
|
300
|
+
) or self._manager.outputs.get_output_group(device)
|
|
301
|
+
if output:
|
|
302
|
+
msg_type = "output"
|
|
303
|
+
else:
|
|
304
|
+
cover = self._manager.covers.get_cover(device)
|
|
305
|
+
if cover:
|
|
306
|
+
msg_type = "cover"
|
|
307
|
+
|
|
308
|
+
if not msg_type:
|
|
309
|
+
_LOGGER.warning(
|
|
310
|
+
"Lox UDP device %s not found in outputs/covers", device
|
|
311
|
+
)
|
|
312
|
+
return
|
|
313
|
+
|
|
314
|
+
full_topic = f"{cmd_prefix}{msg_type}/{device}/set"
|
|
315
|
+
|
|
316
|
+
# Check explicit listeners
|
|
317
|
+
for listen_topic, callback in self._listeners.items():
|
|
318
|
+
if listen_topic == full_topic or (
|
|
319
|
+
listen_topic.endswith("/#")
|
|
320
|
+
and full_topic.startswith(listen_topic[:-2])
|
|
321
|
+
):
|
|
322
|
+
await callback(full_topic, payload)
|
|
323
|
+
|
|
324
|
+
await self._manager.receive_message(full_topic, payload)
|
|
325
|
+
except Exception as e:
|
|
326
|
+
_LOGGER.error("Error passing Lox message to manager: %s", e)
|