boneio 1.5.0.dev2__tar.gz → 1.5.0.dev4__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.5.0.dev2/boneio.egg-info → boneio-1.5.0.dev4}/PKG-INFO +1 -1
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/cover/cover.py +2 -2
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/input/detectors.py +45 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/irrigation/controller.py +16 -1
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/schema_converter.py +25 -1
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/yaml_util.py +31 -19
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/irrigation.py +3 -3
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/manager.py +34 -1
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/input/manager.py +52 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/client.py +100 -0
- boneio-1.5.0.dev4/boneio/modbus/devices/energy_meters/dts1964_3f.json +247 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/energy_meters/le-03mw.json +369 -365
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/energy_meters/le-03mwct.json +369 -365
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/energy_meters/orno-or-we-517.json +6 -1
- boneio-1.5.0.dev4/boneio/modbus/devices/energy_meters/sdm120.json +130 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/energy_meters/sdm630.json +5 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/energy_meters/socomec_e03.json +74 -11
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/energy_meters/socomec_e23.json +124 -18
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/hvac/eht-topventil-plus.json +37 -8
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/hvac/fujitsu-ac.json +7 -2
- {boneio-1.5.0.dev2/boneio/modbus/devices/inverters → boneio-1.5.0.dev4/boneio/modbus/devices/hvac}/thessla.json +7 -2
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/hvac/ventclear.json +8 -3
- {boneio-1.5.0.dev2/boneio/modbus/devices/other → boneio-1.5.0.dev4/boneio/modbus/devices/hvac}/wanas415.json +5 -2
- boneio-1.5.0.dev4/boneio/modbus/devices/inverters/sofar.json +396 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/other/esp32_relay_x4_modbus.json +7 -2
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/other/n4dsc08.json +7 -2
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/other/r4dcb08.json +70 -9
- boneio-1.5.0.dev4/boneio/modbus/devices/sensors/boneio-edge-temp.json +163 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/sensors/cwt.json +28 -4
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/sensors/dyp-a12-ultrasonic.json +14 -2
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/sensors/gdfs.json +7 -2
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/sensors/gdfx.json +7 -2
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/sensors/liquid-sensor.json +18 -3
- boneio-1.5.0.dev4/boneio/modbus/devices/sensors/pt100.json +33 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/sensors/sht20.json +27 -4
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/sensors/sht30.json +27 -4
- boneio-1.5.0.dev4/boneio/modbus/mock_coordinator.py +283 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/schema.yaml +1 -27
- boneio-1.5.0.dev4/boneio/version.py +2 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/app.py +7 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/dashboard_cards.py +39 -0
- boneio-1.5.0.dev2/boneio/webui/frontend-dist/assets/ConfigEditor-DVdxuuOd.js → boneio-1.5.0.dev4/boneio/webui/frontend-dist/assets/ConfigEditor-DSm0FS9G.js +1 -1
- boneio-1.5.0.dev2/boneio/webui/frontend-dist/assets/aiWizardPrompt-Qk4nus2t.js → boneio-1.5.0.dev4/boneio/webui/frontend-dist/assets/aiWizardPrompt-ChA7lLsf.js +1 -1
- boneio-1.5.0.dev4/boneio/webui/frontend-dist/assets/index-BT7TrtpF.css +2 -0
- boneio-1.5.0.dev2/boneio/webui/frontend-dist/assets/index-Bz9etcWZ.js → boneio-1.5.0.dev4/boneio/webui/frontend-dist/assets/index-wbedWLv9.js +35 -35
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/index.html +2 -2
- {boneio-1.5.0.dev2/boneio/webui → boneio-1.5.0.dev4/boneio/webui/frontend-dist}/schema/config.schema.json +7 -1
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/modbus_devices.schema.json +7 -1
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/sw.js +1 -1
- boneio-1.5.0.dev4/boneio/webui/hvac_svg_templates.py +240 -0
- boneio-1.5.0.dev4/boneio/webui/modbus_card_templates.py +576 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/__init__.py +3 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/dashboard.py +33 -35
- boneio-1.5.0.dev4/boneio/webui/routes/dev_fake_device.py +703 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/modbus.py +120 -1
- {boneio-1.5.0.dev2/boneio/webui/frontend-dist → boneio-1.5.0.dev4/boneio/webui}/schema/config.schema.json +7 -1
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/modbus_devices.schema.json +7 -1
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4/boneio.egg-info}/PKG-INFO +1 -1
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio.egg-info/SOURCES.txt +11 -7
- boneio-1.5.0.dev2/boneio/modbus/devices/energy_meters/sdm120.json +0 -126
- boneio-1.5.0.dev2/boneio/modbus/devices/inverters/sofar.json +0 -267
- boneio-1.5.0.dev2/boneio/modbus/devices/sensors/boneio-edge-temp.json +0 -148
- boneio-1.5.0.dev2/boneio/modbus/devices/sensors/dts1964_3f.json +0 -242
- boneio-1.5.0.dev2/boneio/modbus/devices/sensors/pt100.json +0 -21
- boneio-1.5.0.dev2/boneio/version.py +0 -2
- boneio-1.5.0.dev2/boneio/webui/frontend-dist/assets/index-CJECcrbK.css +0 -2
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/LICENSE +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/MANIFEST.in +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/README.md +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.2/input.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.2/output_24_16.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.2/output_32_10.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.2/output_32_5.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.2/output_cover.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.2/output_cover_mix.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.3/input.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.3/output_24_16.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.3/output_32_10.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.3/output_32_5.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.3/output_cover.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.3/output_cover_mix.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.4/input.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.4/output_24_16.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.4/output_32_10.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.4/output_32_5.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.4/output_cover.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.4/output_cover_mix.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.5/input.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.5/output_24_16.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.5/output_32_10.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.5/output_cover.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.5/output_cover_mix.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.6/input.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.6/output_24_16.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.6/output_32_10.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.6/output_cover.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.6/output_cover_mix.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.7/input.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.7/output_24_16.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.7/output_32_10.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.7/output_48_4.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.7/output_cover.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.7/output_cover_mix.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.8/input.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.8/output_24_16.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.8/output_32_10.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.8/output_48_4.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.8/output_cover.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.8/output_cover_mix.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/bonecli.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/cover/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/cover/time_based.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/cover/venetian.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/group/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/group/output_group.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/input/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/input/binary_sensor.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/input/event.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/input/remote/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/input/remote/base.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/input/remote/esphome.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/irrigation/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/irrigation/water_source.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/output/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/output/basic.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/output/mcp.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/output/pca.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/output/pcf.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/output/remote.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/sensor/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/sensor/virtual_energy.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/template/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/template/alarm_panel.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/template/gate_cover.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/template/thermostat.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/const.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/cloud/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/cloud/data/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/cloud/data/docker-compose-cloud.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/cloud/data/docker-compose.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/cloud/data/init-certs-cloud.sh +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/cloud/registration.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/cloud/secrets.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/config_helper.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/migrations/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/migrations/v1_proxy_port.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/migrations/v2_transition.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/package-lock.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/package.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/discovery.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/events/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/events/bus.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/action_conditions.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/canopen.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/covers.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/display.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/inputs.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/modbus.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/outputs.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/remote.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/remote_input_registrar.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/sensors.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/templates/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/templates/alarm.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/templates/gate_cover.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/templates/thermostat.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/templates.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/update.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/basic.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/basic_mqtt.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/composite.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/local.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/lox.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/mqtt.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/queue.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/remote/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/remote/base.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/remote/can.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/remote/esphome.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/remote/mqtt.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/remote/wled.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/sensor/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/sensor/base.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/sensor/system.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/state/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/state/manager.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/system/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/system/host_data.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/system/monitor.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/async_updater.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/conditions.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/filter.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/font_util.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/logger.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/timeperiod.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/util.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/24x16/adc.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/24x16/binary_sensor.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/24x16/config.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/24x16/event.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/24x16/mqtt.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/24x16/output24x16A.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/32x10/adc.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/32x10/binary_sensor.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/32x10/config.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/32x10/event.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/32x10/mqtt.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/32x10/output32x10A.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/48x4/adc.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/48x4/binary_sensor.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/48x4/config.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/48x4/event.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/48x4/mqtt.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/48x4/output48x4A.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/can_master.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/can_slave.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover/adc.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover/binary_sensor.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover/config.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover/cover.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover/event.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover/mqtt.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover/outputCover.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover_mix/adc.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover_mix/binary_sensor.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover_mix/config.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover_mix/cover.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover_mix/event.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover_mix/mqtt.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover_mix/outputCoverMix.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/adc.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/all_binary_sensor.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/binary_sensor.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/binary_sensor_v_0_7.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/config_24_16.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/event_all.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/event_v_0_7.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/led32x4A.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/output24x16A.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/output24x16A_v0.3.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/output32x10A.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/output32x5A.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/exceptions.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/analog/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/analog/adc.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/can/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/can/bridge.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/can/client.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/can/interface.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/can/node.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/can/node_id.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/can/test_od.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/display/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/display/early_oled.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/display/fonts/danube__.ttf +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/display/oled.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/expanders/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/expanders/mcp23017.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/expanders/pca9685.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/expanders/pcf8575.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/input/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/input/base.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/i2c/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/i2c/bus.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/i2c/ina219.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/i2c/ina219_driver.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/i2c/mcp9808.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/i2c/pct2075.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/onewire/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/onewire/bus.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/onewire/dallas.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/onewire/ds2482.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/sensor/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/sensor/temperature/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/sensor/temperature/base.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/sensor/temperature/mcp9808.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/sensor/temperature/pct2075.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/integration/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/integration/homeassistant.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/integration/interlock.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/integration/lox_template.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/actions.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/MANIFEST.sha256 +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/docker/daemon.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/docker/nodered/caddy/502.html +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/docker/nodered/caddy/init-certs.sh +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/docker/nodered/docker-compose.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/docker/nodered/nginx/default.conf +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/docker/nodered/node-red/settings.js +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/journald/journald.conf +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/mosquitto/boneio.conf +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/sudoers/boneio +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/systemd/boneio-oled-boot.service +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/systemd/boneio-oled-shutdown.service +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/systemd/boneio.service +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/systemd/set-hostname-once.service +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/usr-local-bin/set-hostname-once.sh +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/usr-sbin/oled_boot_splash.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/usr-sbin/oled_boot_splash.sh +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/usr-sbin/oled_msg.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/usr-sbin/oled_msg.sh +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/bootstrap/boneio-migrate +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/bootstrap/install-helper.sh +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/bootstrap/sudoers-migrate +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/runner.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/v1_3_0_baseline.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/v1_3_1_fix_oled_boot.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/v1_3_2_cleanup_can_sudoers.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/v1_4_0_fix_mqtt_sudoers.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/v1_4_3_oled_shutdown.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/v1_4_4_caddy.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/v1_5_0_fix_oled_fifo_permissions.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/cli.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/coordinator.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/base.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/derived/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/derived/numeric.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/derived/select.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/derived/switch.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/derived/text.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/sensor/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/sensor/binary.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/sensor/numeric.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/sensor/text.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/writeable/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/writeable/binary.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/writeable/numeric.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/utils.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/models/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/models/actions.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/models/events.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/models/files.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/models/logs.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/models/mqtt.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/models/state.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/runner.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/actions.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/actions_sensor.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/actions_switch.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/condition.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/filters.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/filters_adc.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/id.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/remote_devices.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/remote_inputs.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/remote_outputs.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/temp_unit.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/update_interval.yaml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/action_validation.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/codicon-ngg6Pgfi.ttf +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/css.worker-CvXBzhp8.js +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/editor.worker-Cn2oRESe.js +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/html.worker-BO6WuOEO.js +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/json.worker-BkJRGcCJ.js +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/monaco-61yH0vfd.js +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/monaco-Br_kD0ds.css +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/rolldown-runtime-QTnfLwEv.js +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/ts.worker-B0J26iPs.js +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/vendor-pmGLHP0_.js +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/workbox-window.prod.es5-Bd17z0YL.js +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/yaml.worker-BKRoXlmz.js +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/boneio-192.png +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/boneio-512.png +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/boneio.svg +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/boneio_fav.svg +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/adc.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/areas.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/binary_sensor.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/boneio.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/can.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/cover.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/dallas.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/ds2482.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/event.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/ina219.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/irrigation.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/lm75.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/logger.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/lox_udp.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/mcp23017.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/mcp9808.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/modbus.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/mqtt.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/oled.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/output.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/output_group.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/pca9685.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/pcf8575.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/remote_devices.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/remote_inputs.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/remote_outputs.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/sensor.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/template.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/virtual_energy_sensor.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/web.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/workbox-4918f2f6.js +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/middleware/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/middleware/auth.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/auth.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/caddy.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/can.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/config.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/covers.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/irrigation.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/migrations.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/outputs.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/remote_devices.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/sensors.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/system.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/templates.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/timezone_sudoers.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/tools.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/update.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/adc.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/areas.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/binary_sensor.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/boneio.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/can.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/cover.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/dallas.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/ds2482.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/event.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/ina219.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/irrigation.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/lm75.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/logger.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/lox_udp.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/mcp23017.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/mcp9808.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/modbus.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/mqtt.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/oled.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/output.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/output_group.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/pca9685.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/pcf8575.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/remote_devices.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/remote_inputs.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/remote_outputs.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/sensor.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/template.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/virtual_energy_sensor.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/web.schema.json +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/services/__init__.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/services/logs.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/web_server.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/websocket_manager.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio.egg-info/dependency_links.txt +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio.egg-info/entry_points.txt +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio.egg-info/requires.txt +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio.egg-info/top_level.txt +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/pyproject.toml +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/setup.cfg +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/setup.py +0 -0
- {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/tests/test_py313_compatibility.py +0 -0
|
@@ -386,8 +386,8 @@ class BaseCover(BaseCoverABC, BasicMqtt):
|
|
|
386
386
|
**json_position,
|
|
387
387
|
)
|
|
388
388
|
self._event_bus.trigger_event(CoverEvent(entity_id=self.id, state=event))
|
|
389
|
-
self._message_bus.send_message(topic=f"{self._send_topic}/state", payload=state)
|
|
390
|
-
self._message_bus.send_message(topic=f"{self._send_topic}/pos", payload=json.dumps(json_position))
|
|
389
|
+
self._message_bus.send_message(topic=f"{self._send_topic}/state", payload=state, retain=True)
|
|
390
|
+
self._message_bus.send_message(topic=f"{self._send_topic}/pos", payload=json.dumps(json_position), retain=True)
|
|
391
391
|
|
|
392
392
|
@property
|
|
393
393
|
def saved_position(self) -> SavedPositionDict:
|
|
@@ -109,6 +109,7 @@ class MultiClickDetector:
|
|
|
109
109
|
self._pin = pin
|
|
110
110
|
self._max_long_press_seconds = max_long_press_seconds
|
|
111
111
|
self._state = ClickState()
|
|
112
|
+
self._boot_press_suppressed = False # Set by GpioManager._seed_initial_states
|
|
112
113
|
|
|
113
114
|
# Pre-compute which click types should be delayed in exclusive mode
|
|
114
115
|
# based on enabled sequences
|
|
@@ -491,6 +492,21 @@ class MultiClickDetector:
|
|
|
491
492
|
)
|
|
492
493
|
return
|
|
493
494
|
|
|
495
|
+
# Boot-press suppression: if GpioManager detected this pin was
|
|
496
|
+
# LOW at startup, the first FALLING_EDGE is a phantom boot event.
|
|
497
|
+
# Record the timestamp (for debounce) but do NOT schedule timers.
|
|
498
|
+
if self._boot_press_suppressed:
|
|
499
|
+
_LOGGER.info(
|
|
500
|
+
"Suppressing phantom boot press on %s (%s) — recording timestamp only",
|
|
501
|
+
self._name,
|
|
502
|
+
self._pin,
|
|
503
|
+
)
|
|
504
|
+
self._state.last_press_ts = timestamp_s
|
|
505
|
+
self._state.last_press_loop_ts = None
|
|
506
|
+
self._state.last_release_ts = None
|
|
507
|
+
self._boot_press_suppressed = False
|
|
508
|
+
return
|
|
509
|
+
|
|
494
510
|
_LOGGER.debug("PRESSED: %s (%s)", self._name, self._pin)
|
|
495
511
|
self._state.last_press_ts = timestamp_s
|
|
496
512
|
self._state.last_press_loop_ts = self._loop.time() # Store loop time for duration calc
|
|
@@ -552,6 +568,35 @@ class MultiClickDetector:
|
|
|
552
568
|
|
|
553
569
|
press_duration_ms = (timestamp_s - self._state.last_press_ts) * 1000 if self._state.last_press_ts else 0
|
|
554
570
|
_LOGGER.debug("RELEASED: %s (%s) after %.1f ms", self._name, self._pin, press_duration_ms)
|
|
571
|
+
|
|
572
|
+
# Guard: stale release from phantom press at boot.
|
|
573
|
+
# If time since press exceeds max_long_press_seconds, the press
|
|
574
|
+
# was a startup artifact (GPIO settling at boot), not a real user
|
|
575
|
+
# action. Reset the detector so the next real press is accepted.
|
|
576
|
+
if self._state.last_press_ts and press_duration_ms > self._max_long_press_seconds * 1000:
|
|
577
|
+
_LOGGER.warning(
|
|
578
|
+
"Stale release on %s (%s): %.1fs since press exceeds max %.0fs. "
|
|
579
|
+
"Likely phantom press from boot. Resetting detector.",
|
|
580
|
+
self._name,
|
|
581
|
+
self._pin,
|
|
582
|
+
press_duration_ms / 1000,
|
|
583
|
+
self._max_long_press_seconds,
|
|
584
|
+
)
|
|
585
|
+
self._state.last_press_ts = None
|
|
586
|
+
self._state.last_press_loop_ts = None
|
|
587
|
+
self._state.last_release_ts = timestamp_s
|
|
588
|
+
self._state.click_count = 0
|
|
589
|
+
if self._state.long_press_timer:
|
|
590
|
+
self._state.long_press_timer.cancel()
|
|
591
|
+
self._state.long_press_timer = None
|
|
592
|
+
self._state.long_press_scheduled_loop_ts = None
|
|
593
|
+
if self._state.long_hold_periodic_timer:
|
|
594
|
+
self._state.long_hold_periodic_timer.cancel()
|
|
595
|
+
self._state.long_hold_periodic_timer = None
|
|
596
|
+
self._state.executed_long_actions = set()
|
|
597
|
+
self._state.last_repeat_times = {}
|
|
598
|
+
return
|
|
599
|
+
|
|
555
600
|
self._state.last_release_ts = timestamp_s
|
|
556
601
|
|
|
557
602
|
_LOGGER.debug(
|
|
@@ -419,6 +419,12 @@ class IrrigationController:
|
|
|
419
419
|
)
|
|
420
420
|
|
|
421
421
|
async def shutdown(self) -> None:
|
|
422
|
+
"""Stop the active irrigation cycle without killing schedule tasks.
|
|
423
|
+
|
|
424
|
+
This method is safe to call from within a schedule task — it does NOT
|
|
425
|
+
cancel schedule loops. Use :meth:`full_stop` to tear down the
|
|
426
|
+
controller completely (including schedule tasks).
|
|
427
|
+
"""
|
|
422
428
|
_LOGGER.debug(
|
|
423
429
|
"Irrigation %s shutdown called (state=%s, active_zone=%s). Caller: %s",
|
|
424
430
|
self.id,
|
|
@@ -426,7 +432,6 @@ class IrrigationController:
|
|
|
426
432
|
self._active_zone_idx,
|
|
427
433
|
"".join(traceback.format_stack(limit=5)),
|
|
428
434
|
)
|
|
429
|
-
self.stop_schedules()
|
|
430
435
|
self._cancel_pause_timer()
|
|
431
436
|
await self._stop_current_zone()
|
|
432
437
|
await self._handle_pump_stop_sequence()
|
|
@@ -437,6 +442,16 @@ class IrrigationController:
|
|
|
437
442
|
self._single_zone_target_idx = None
|
|
438
443
|
await self.publish_all_states()
|
|
439
444
|
|
|
445
|
+
async def full_stop(self) -> None:
|
|
446
|
+
"""Fully stop the controller including schedule tasks.
|
|
447
|
+
|
|
448
|
+
Should only be called by the IrrigationManager when stopping
|
|
449
|
+
or reloading controllers — never from within a schedule task.
|
|
450
|
+
"""
|
|
451
|
+
_LOGGER.info("Irrigation %s full_stop: stopping schedules and active cycle", self.id)
|
|
452
|
+
self.stop_schedules()
|
|
453
|
+
await self.shutdown()
|
|
454
|
+
|
|
440
455
|
async def pause(self) -> None:
|
|
441
456
|
if self._state != ControllerState.RUNNING or self._active_zone_idx is None:
|
|
442
457
|
return
|
|
@@ -271,7 +271,31 @@ def main():
|
|
|
271
271
|
# Load the schema
|
|
272
272
|
with open(schema_file) as f:
|
|
273
273
|
schema = yaml.load(f, Loader=BoneIOLoader)
|
|
274
|
-
|
|
274
|
+
|
|
275
|
+
# Dynamically inject modbus device models into the schema.
|
|
276
|
+
# NOTE: This is a standalone copy of the logic from yaml_util.py.
|
|
277
|
+
# We cannot import yaml_util here because it pulls in the full boneIO
|
|
278
|
+
# dependency graph (cerberus, pymodbus, smbus2 …) which is NOT installed
|
|
279
|
+
# in the CI environment that runs this converter script.
|
|
280
|
+
devices_dir = os.path.normpath(
|
|
281
|
+
os.path.join(script_dir, "..", "..", "modbus", "devices")
|
|
282
|
+
)
|
|
283
|
+
models: list[str] = []
|
|
284
|
+
if os.path.isdir(devices_dir):
|
|
285
|
+
for root, dirs, files in os.walk(devices_dir):
|
|
286
|
+
dirs[:] = [d for d in dirs if d != "__pycache__"]
|
|
287
|
+
for fname in files:
|
|
288
|
+
if fname.endswith(".json"):
|
|
289
|
+
models.append(fname[:-5])
|
|
290
|
+
models.sort()
|
|
291
|
+
|
|
292
|
+
try:
|
|
293
|
+
model_field = schema["modbus_devices"]["schema"]["schema"]["model"]
|
|
294
|
+
model_field["allowed"] = models
|
|
295
|
+
print(f"Injected {len(models)} modbus models into schema")
|
|
296
|
+
except (KeyError, TypeError):
|
|
297
|
+
print("WARNING: Could not inject modbus models into schema")
|
|
298
|
+
|
|
275
299
|
# Convert and save the main schema
|
|
276
300
|
json_schema = convert_cerberus_to_json_schema(schema)
|
|
277
301
|
main_schema_file = os.path.join(output_dir, "config.schema.json")
|
|
@@ -26,12 +26,39 @@ _SCHEMA_CACHE = None
|
|
|
26
26
|
_BOARD_CONFIG_CACHE = {}
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
def _get_modbus_device_models() -> list[str]:
|
|
30
|
+
"""Scan modbus/devices/ directory and return filenames as model keys.
|
|
31
|
+
|
|
32
|
+
Only does os.walk (no JSON parsing) — <1ms even on BeagleBone.
|
|
33
|
+
"""
|
|
34
|
+
devices_dir = os.path.normpath(os.path.join(os.path.dirname(__file__), "../../modbus/devices"))
|
|
35
|
+
models = []
|
|
36
|
+
if os.path.isdir(devices_dir):
|
|
37
|
+
for root, dirs, files in os.walk(devices_dir):
|
|
38
|
+
dirs[:] = [d for d in dirs if d != "__pycache__"]
|
|
39
|
+
for fname in files:
|
|
40
|
+
if fname.endswith(".json"):
|
|
41
|
+
models.append(fname[:-5])
|
|
42
|
+
return sorted(models)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _inject_modbus_models(schema: dict) -> None:
|
|
46
|
+
"""Dynamically set allowed modbus model values from device files."""
|
|
47
|
+
try:
|
|
48
|
+
model_field = schema["modbus_devices"]["schema"]["schema"]["model"]
|
|
49
|
+
model_field["allowed"] = _get_modbus_device_models()
|
|
50
|
+
_LOGGER.debug("Injected %d modbus models into schema", len(model_field["allowed"]))
|
|
51
|
+
except (KeyError, TypeError):
|
|
52
|
+
_LOGGER.warning("Could not inject modbus models into schema")
|
|
53
|
+
|
|
54
|
+
|
|
29
55
|
def _get_schema():
|
|
30
56
|
"""Get schema from cache or load it if not cached."""
|
|
31
57
|
global _SCHEMA_CACHE
|
|
32
58
|
if _SCHEMA_CACHE is None:
|
|
33
59
|
_LOGGER.debug("Loading schema from file (first time)")
|
|
34
60
|
_SCHEMA_CACHE = load_yaml_file(schema_file)
|
|
61
|
+
_inject_modbus_models(_SCHEMA_CACHE)
|
|
35
62
|
return _SCHEMA_CACHE
|
|
36
63
|
|
|
37
64
|
|
|
@@ -653,29 +680,14 @@ class CustomValidator(Validator):
|
|
|
653
680
|
raise ValueError(f"Could not parse power value: {value}")
|
|
654
681
|
num = float(match.group(1))
|
|
655
682
|
unit = match.group(2) or "w"
|
|
656
|
-
if unit in ("w", ""):
|
|
683
|
+
if unit in ("w", "", "wh"):
|
|
657
684
|
multiplier = 1.0
|
|
658
|
-
elif unit
|
|
659
|
-
multiplier = 1000.0
|
|
660
|
-
elif unit == "mw":
|
|
661
|
-
multiplier = 1_000_000.0
|
|
662
|
-
elif unit == "gw":
|
|
663
|
-
multiplier = 1_000_000_000.0
|
|
664
|
-
elif unit == "mw":
|
|
665
|
-
multiplier = 1_000_000.0
|
|
666
|
-
elif unit == "kwh":
|
|
667
|
-
# 1 kWh = 1000 W (for 1h). For config, treat as 1000W average.
|
|
685
|
+
elif unit in ("kw", "kwh"):
|
|
668
686
|
multiplier = 1000.0
|
|
669
|
-
elif unit
|
|
687
|
+
elif unit in ("mw", "mwh"):
|
|
670
688
|
multiplier = 1_000_000.0
|
|
671
|
-
elif unit
|
|
689
|
+
elif unit in ("gw", "gwh"):
|
|
672
690
|
multiplier = 1_000_000_000.0
|
|
673
|
-
elif unit == "mw":
|
|
674
|
-
multiplier = 1_000_000.0
|
|
675
|
-
elif unit == "wh":
|
|
676
|
-
multiplier = 1.0
|
|
677
|
-
elif unit == "mw" or unit == "mw" or unit == "mw" or unit == "mw" or unit == "mw" or unit == "mw":
|
|
678
|
-
multiplier = 1_000_000.0
|
|
679
691
|
else:
|
|
680
692
|
_LOGGER.warning(f"Unknown unit for power value: {unit}")
|
|
681
693
|
raise ValueError(f"Unknown unit for power value: {unit}")
|
|
@@ -226,7 +226,7 @@ class IrrigationManager:
|
|
|
226
226
|
self._subscribed_topics.clear()
|
|
227
227
|
|
|
228
228
|
for ctrl in self._controllers.values():
|
|
229
|
-
await ctrl.
|
|
229
|
+
await ctrl.full_stop()
|
|
230
230
|
|
|
231
231
|
async def reload_irrigation(self) -> None:
|
|
232
232
|
"""Reload irrigation configuration from file.
|
|
@@ -256,7 +256,7 @@ class IrrigationManager:
|
|
|
256
256
|
ctrl = self._controllers[ctrl_id]
|
|
257
257
|
_LOGGER.info("Removing irrigation controller '%s'", ctrl_id)
|
|
258
258
|
ctrl.stop_schedules()
|
|
259
|
-
await ctrl.
|
|
259
|
+
await ctrl.full_stop()
|
|
260
260
|
# Remove HA discovery for this controller
|
|
261
261
|
self._remove_discovery(ctrl)
|
|
262
262
|
del self._controllers[ctrl_id]
|
|
@@ -271,7 +271,7 @@ class IrrigationManager:
|
|
|
271
271
|
if ctrl_id in self._controllers:
|
|
272
272
|
old_ctrl = self._controllers[ctrl_id]
|
|
273
273
|
old_ctrl.stop_schedules()
|
|
274
|
-
await old_ctrl.
|
|
274
|
+
await old_ctrl.full_stop()
|
|
275
275
|
del self._controllers[ctrl_id]
|
|
276
276
|
|
|
277
277
|
# Build new controller
|
|
@@ -1692,7 +1692,9 @@ class Manager:
|
|
|
1692
1692
|
async def reconnect_callback(self) -> None:
|
|
1693
1693
|
"""Function to invoke when connection to MQTT is (re-)established.
|
|
1694
1694
|
|
|
1695
|
-
Sends online status to MQTT
|
|
1695
|
+
Sends online status to MQTT, resends all entity states with retain
|
|
1696
|
+
so that Home Assistant immediately knows device positions after a
|
|
1697
|
+
broker restart, and starts template MQTT subscriptions.
|
|
1696
1698
|
|
|
1697
1699
|
IMPORTANT: This is called on every MQTT reconnect, not just the first
|
|
1698
1700
|
connection. Schedule tasks must NOT be restarted here — they are
|
|
@@ -1708,10 +1710,41 @@ class Manager:
|
|
|
1708
1710
|
# Immediately refresh OLED MQTT status (event-driven, no polling delay)
|
|
1709
1711
|
self.display.notify_mqtt_state_changed()
|
|
1710
1712
|
|
|
1713
|
+
# Resend all entity states with retain so HA has correct state
|
|
1714
|
+
# after a broker restart (retained messages may have been lost).
|
|
1715
|
+
_LOGGER.info("Resending all entity states after MQTT reconnect.")
|
|
1716
|
+
await self._resend_all_states()
|
|
1717
|
+
|
|
1711
1718
|
# Start template entities (subscribe to MQTT command topics)
|
|
1712
1719
|
await self.templates.start()
|
|
1713
1720
|
await self.irrigation.reconnect()
|
|
1714
1721
|
|
|
1722
|
+
async def _resend_all_states(self) -> None:
|
|
1723
|
+
"""Resend current state of all entities via MQTT with retain.
|
|
1724
|
+
|
|
1725
|
+
Called on MQTT reconnect to ensure the broker has up-to-date
|
|
1726
|
+
retained messages after a broker restart. Each entity's
|
|
1727
|
+
``send_state`` / ``async_send_state`` already publishes with
|
|
1728
|
+
``retain=True``, so calling them here refreshes the broker's
|
|
1729
|
+
retained store.
|
|
1730
|
+
"""
|
|
1731
|
+
# Resend output states
|
|
1732
|
+
for output in self.outputs.get_all_outputs().values():
|
|
1733
|
+
try:
|
|
1734
|
+
if output.output_type not in ("cover", "none"):
|
|
1735
|
+
await output.async_send_state()
|
|
1736
|
+
except Exception as e:
|
|
1737
|
+
_LOGGER.debug("Error resending output state %s: %s", output.id, e)
|
|
1738
|
+
|
|
1739
|
+
# Resend cover states (send_state now uses retain=True)
|
|
1740
|
+
self.covers._broadcast_all_states()
|
|
1741
|
+
|
|
1742
|
+
_LOGGER.info(
|
|
1743
|
+
"Resent states: %d outputs, %d covers.",
|
|
1744
|
+
len([o for o in self.outputs.get_all_outputs().values() if o.output_type not in ("cover", "none")]),
|
|
1745
|
+
len(self.covers.get_all_covers()),
|
|
1746
|
+
)
|
|
1747
|
+
|
|
1715
1748
|
async def receive_message(self, topic: str, message: str) -> None:
|
|
1716
1749
|
"""Callback for receiving MQTT messages.
|
|
1717
1750
|
|
|
@@ -302,6 +302,58 @@ class GpioManager:
|
|
|
302
302
|
_LOGGER.error("Error in on-start callback: %s", e)
|
|
303
303
|
self._on_start_callbacks.clear()
|
|
304
304
|
|
|
305
|
+
# Seed detectors with current GPIO state to prevent phantom events
|
|
306
|
+
# at boot. Must run after on-start callbacks so detectors are ready.
|
|
307
|
+
self._seed_initial_states()
|
|
308
|
+
|
|
309
|
+
def _seed_initial_states(self) -> None:
|
|
310
|
+
"""Read current GPIO states and seed detectors to prevent phantom presses.
|
|
311
|
+
|
|
312
|
+
At boot, some GPIO pins may already be LOW (e.g. button circuits pulling
|
|
313
|
+
down through pull-up resistors). gpiod generates a FALLING_EDGE for
|
|
314
|
+
this initial state, which the detector interprets as a real button
|
|
315
|
+
press — scheduling a long press timer that fires 400ms later and
|
|
316
|
+
triggers an action.
|
|
317
|
+
|
|
318
|
+
By setting ``_boot_press_suppressed`` on the detector, the first
|
|
319
|
+
FALLING_EDGE records the kernel timestamp (for debounce) but does
|
|
320
|
+
NOT schedule the long press timer. The subsequent RISING_EDGE
|
|
321
|
+
(when the user actually presses) is caught by the stale-release
|
|
322
|
+
guard and handled correctly.
|
|
323
|
+
"""
|
|
324
|
+
from boneio.components.input.detectors import MultiClickDetector
|
|
325
|
+
|
|
326
|
+
seeded = 0
|
|
327
|
+
for chip, request in self._requests.items():
|
|
328
|
+
for (c, line), detector in self._detectors.items():
|
|
329
|
+
if c != chip:
|
|
330
|
+
continue
|
|
331
|
+
if not isinstance(detector, MultiClickDetector):
|
|
332
|
+
continue
|
|
333
|
+
try:
|
|
334
|
+
values = request.get_values([line])
|
|
335
|
+
pin_is_low = not bool(values[0])
|
|
336
|
+
except Exception as exc:
|
|
337
|
+
_LOGGER.debug(
|
|
338
|
+
"Could not read initial state for chip%d/line%d: %s",
|
|
339
|
+
chip, line, exc,
|
|
340
|
+
)
|
|
341
|
+
continue
|
|
342
|
+
|
|
343
|
+
if pin_is_low:
|
|
344
|
+
alias = self._aliases.get((chip, line), f"chip{chip}/line{line}")
|
|
345
|
+
_LOGGER.info(
|
|
346
|
+
"GPIO %s is LOW at startup — arming boot press suppression",
|
|
347
|
+
alias,
|
|
348
|
+
)
|
|
349
|
+
detector._boot_press_suppressed = True
|
|
350
|
+
seeded += 1
|
|
351
|
+
|
|
352
|
+
if seeded:
|
|
353
|
+
_LOGGER.info(
|
|
354
|
+
"Armed boot press suppression on %d GPIO detector(s)", seeded
|
|
355
|
+
)
|
|
356
|
+
|
|
305
357
|
def _handle_gpiod_events(self, chip: int, request: gpiod.LineRequest) -> None:
|
|
306
358
|
"""Handle GPIO events from libgpiod.
|
|
307
359
|
|
|
@@ -578,3 +578,103 @@ class Modbus:
|
|
|
578
578
|
if self._inter_device_delay > 0:
|
|
579
579
|
await asyncio.sleep(self._inter_device_delay)
|
|
580
580
|
return result
|
|
581
|
+
|
|
582
|
+
def write_registers_blocking(self, unit: int | str, address: int, values: list[int]):
|
|
583
|
+
"""Write multiple registers blocking (synchronous) - FC16.
|
|
584
|
+
|
|
585
|
+
Sends a Modbus FC16 (Write Multiple Registers) request to write
|
|
586
|
+
a list of 16-bit values starting at the given register address.
|
|
587
|
+
|
|
588
|
+
Args:
|
|
589
|
+
unit: Device address (1-247).
|
|
590
|
+
address: Starting register address.
|
|
591
|
+
values: List of 16-bit integer values to write.
|
|
592
|
+
|
|
593
|
+
Returns:
|
|
594
|
+
Pymodbus response object on success, None on failure.
|
|
595
|
+
"""
|
|
596
|
+
start_time = time.perf_counter()
|
|
597
|
+
result = None
|
|
598
|
+
try:
|
|
599
|
+
connected = self._pymodbus_connect()
|
|
600
|
+
if not connected:
|
|
601
|
+
_LOGGER.error("Can't connect to Modbus.")
|
|
602
|
+
return None
|
|
603
|
+
|
|
604
|
+
_LOGGER.debug(
|
|
605
|
+
"Writing %d registers starting at %s with values %s to device %s (FC16).",
|
|
606
|
+
len(values),
|
|
607
|
+
address,
|
|
608
|
+
values,
|
|
609
|
+
unit,
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
assert self._client is not None
|
|
613
|
+
result = self._client.write_registers(
|
|
614
|
+
address=address, values=values, device_id=int(unit)
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
if isinstance(result, ExceptionResponse):
|
|
618
|
+
_LOGGER.error("FC16 write operation failed: %s", result)
|
|
619
|
+
result = None
|
|
620
|
+
|
|
621
|
+
except ValueError as exception_error:
|
|
622
|
+
_LOGGER.error("ValueError: Error writing multiple registers: %s", exception_error)
|
|
623
|
+
except (ModbusException, struct.error) as exception_error:
|
|
624
|
+
_LOGGER.error("ModbusException: Error writing multiple registers: %s", exception_error)
|
|
625
|
+
except TimeoutError:
|
|
626
|
+
_LOGGER.error("Timeout writing multiple registers to device %s", unit)
|
|
627
|
+
except asyncio.CancelledError as err:
|
|
628
|
+
_LOGGER.error("Operation cancelled writing multiple registers to device %s: %s", unit, err)
|
|
629
|
+
except Exception as e:
|
|
630
|
+
_LOGGER.error("Unexpected error writing multiple registers: %s - %s", type(e).__name__, e)
|
|
631
|
+
finally:
|
|
632
|
+
end_time = time.perf_counter()
|
|
633
|
+
_LOGGER.debug(
|
|
634
|
+
"FC16 write completed in %.3f seconds.",
|
|
635
|
+
end_time - start_time,
|
|
636
|
+
)
|
|
637
|
+
return result
|
|
638
|
+
|
|
639
|
+
async def write_registers(self, unit: int | str, address: int, values: list[int]):
|
|
640
|
+
"""Write multiple registers async (FC16).
|
|
641
|
+
|
|
642
|
+
Returns None immediately when suspended.
|
|
643
|
+
|
|
644
|
+
Args:
|
|
645
|
+
unit: Device address (1-247).
|
|
646
|
+
address: Starting register address.
|
|
647
|
+
values: List of 16-bit integer values to write.
|
|
648
|
+
"""
|
|
649
|
+
if self._suspended:
|
|
650
|
+
return None
|
|
651
|
+
async with self._lock:
|
|
652
|
+
result = await self._loop.run_in_executor(
|
|
653
|
+
self._executor, self.write_registers_blocking, unit, address, values
|
|
654
|
+
)
|
|
655
|
+
if self._inter_device_delay > 0:
|
|
656
|
+
await asyncio.sleep(self._inter_device_delay)
|
|
657
|
+
return result
|
|
658
|
+
|
|
659
|
+
async def write_registers_direct(self, unit: int | str, address: int, values: list[int]):
|
|
660
|
+
"""Write multiple registers bypassing the suspend check (FC16).
|
|
661
|
+
|
|
662
|
+
Used by Tools API for manual writes while coordinators are
|
|
663
|
+
suspended. Still acquires the UART lock to serialize access.
|
|
664
|
+
|
|
665
|
+
Args:
|
|
666
|
+
unit: Device address (1-247).
|
|
667
|
+
address: Starting register address.
|
|
668
|
+
values: List of 16-bit integer values to write.
|
|
669
|
+
"""
|
|
670
|
+
async with self._lock:
|
|
671
|
+
result = await self._loop.run_in_executor(
|
|
672
|
+
self._executor,
|
|
673
|
+
self.write_registers_blocking,
|
|
674
|
+
unit,
|
|
675
|
+
address,
|
|
676
|
+
values,
|
|
677
|
+
)
|
|
678
|
+
if self._inter_device_delay > 0:
|
|
679
|
+
await asyncio.sleep(self._inter_device_delay)
|
|
680
|
+
return result
|