boneio 1.0.0.dev7__tar.gz → 1.0.0.dev8__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.0.0.dev7/boneio.egg-info → boneio-1.0.0.dev8}/PKG-INFO +1 -1
- boneio-1.0.0.dev8/boneio/components/output/basic.py +229 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/sensor/__init__.py +2 -0
- boneio-1.0.0.dev8/boneio/components/sensor/virtual_energy.py +292 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/const.py +1 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/config/config_helper.py +12 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/config/yaml_util.py +15 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/manager/inputs.py +36 -6
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/manager/manager.py +19 -1
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/manager/modbus.py +1 -1
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/manager/outputs.py +25 -63
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/manager/sensors.py +485 -2
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/state/manager.py +63 -9
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/gpio/expanders/mcp23017.py +115 -48
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/i2c/bus.py +38 -33
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/integration/__init__.py +2 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/integration/homeassistant.py +60 -8
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/cli.py +2 -2
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/coordinator.py +9 -14
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/energy_meters/socomec_e03.json +1 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/energy_meters/socomec_e23.json +1 -0
- boneio-1.0.0.dev8/boneio/modbus/devices/inverters/sofar.json +267 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/sensors/dts1964_3f.json +60 -54
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/sensors/pt100.json +3 -3
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/entities/base.py +11 -19
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/entities/derived/numeric.py +2 -2
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/entities/derived/select.py +0 -1
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/entities/derived/switch.py +0 -1
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/entities/derived/text.py +0 -1
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/entities/sensor/numeric.py +14 -15
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/entities/sensor/text.py +2 -6
- boneio-1.0.0.dev8/boneio/modbus/utils.py +6 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/runner.py +5 -2
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/schema/schema.yaml +84 -16
- boneio-1.0.0.dev8/boneio/version.py +2 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/app.py +114 -151
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/cssMode-ClVp1zRM.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/cssMode-BKR9s_Lh.js +1 -1
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/freemarker2-Dpc6FVoU.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/freemarker2-Culjpl1V.js +1 -1
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/handlebars-3T51HdyE.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/handlebars-DvFXDtCi.js +1 -1
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/html-Cqlv8Ey8.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/html-CRZebHSg.js +1 -1
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/htmlMode-kKBBldLZ.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/htmlMode-w52oBlKZ.js +1 -1
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/index-ClokVTBs.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/index-CrPqznir.js +214 -214
- boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/index-DYGCuZw-.css +1 -0
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/javascript-jIes5V6e.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/javascript-1_d307wM.js +1 -1
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/jsonMode-DUk1WXAK.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/jsonMode-SK3Ov5KI.js +1 -1
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/liquid-CklSeh78.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/liquid-BY2M9Ltg.js +1 -1
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/mdx-Q44kPz7v.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/mdx-CYoqZppc.js +1 -1
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/python-CX3wo97z.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/python-BRjt52qX.js +1 -1
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/razor-B3VfV1vo.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/razor-CM_wFXDY.js +1 -1
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/tsMode-BVdbrg1F.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/tsMode-DyZ1xUFQ.js +1 -1
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/typescript-C3sLeWbM.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/typescript-CeE-9TVF.js +1 -1
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/xml-DyAfOafQ.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/xml-DYrg3tVz.js +1 -1
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/yaml-DZVmC1BT.js → boneio-1.0.0.dev8/boneio/webui/frontend-dist/assets/yaml-CKAkvRms.js +1 -1
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/index.html +2 -2
- {boneio-1.0.0.dev7/boneio/webui/schema → boneio-1.0.0.dev8/boneio/webui/frontend-dist/schem}/adc.schema.json +8 -8
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/areas.schema.json +4 -4
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/binary_sensor.schema.json +18 -18
- {boneio-1.0.0.dev7/boneio/webui/schema → boneio-1.0.0.dev8/boneio/webui/frontend-dist/schem}/boneio.schema.json +2 -2
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/config.schema.json +242 -170
- {boneio-1.0.0.dev7/boneio/webui/schema → boneio-1.0.0.dev8/boneio/webui/frontend-dist/schem}/cover.schema.json +4 -4
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/ds2482.schema.json +4 -4
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/event.schema.json +24 -24
- {boneio-1.0.0.dev7/boneio/webui/schema → boneio-1.0.0.dev8/boneio/webui/frontend-dist/schem}/ina219.schema.json +12 -12
- {boneio-1.0.0.dev7/boneio/webui/schema → boneio-1.0.0.dev8/boneio/webui/frontend-dist/schem}/lm75.schema.json +8 -8
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/logger.schema.json +2 -2
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/mcp23017.schema.json +4 -4
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/mcp9808.schema.json +8 -8
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/modbus.schema.json +2 -2
- {boneio-1.0.0.dev7/boneio/webui/schema → boneio-1.0.0.dev8/boneio/webui/frontend-dist/schem}/modbus_devices.schema.json +16 -16
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/mqtt.schema.json +4 -4
- {boneio-1.0.0.dev7/boneio/webui/schema → boneio-1.0.0.dev8/boneio/webui/frontend-dist/schem}/oled.schema.json +8 -8
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/output.schema.json +6 -16
- {boneio-1.0.0.dev7/boneio/webui/schema → boneio-1.0.0.dev8/boneio/webui/frontend-dist/schem}/output_group.schema.json +6 -6
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/pca9685.schema.json +4 -4
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/pcf8575.schema.json +4 -4
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/sensor.schema.json +8 -8
- boneio-1.0.0.dev8/boneio/webui/frontend-dist/schem/virtual_energy_sensor.schema.json +79 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/web.schema.json +13 -4
- {boneio-1.0.0.dev7/boneio/webui/frontend-dist/schem → boneio-1.0.0.dev8/boneio/webui/schema}/adc.schema.json +8 -8
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/areas.schema.json +4 -4
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/binary_sensor.schema.json +18 -18
- {boneio-1.0.0.dev7/boneio/webui/frontend-dist/schem → boneio-1.0.0.dev8/boneio/webui/schema}/boneio.schema.json +2 -2
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/config.schema.json +242 -170
- {boneio-1.0.0.dev7/boneio/webui/frontend-dist/schem → boneio-1.0.0.dev8/boneio/webui/schema}/cover.schema.json +4 -4
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/ds2482.schema.json +4 -4
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/event.schema.json +24 -24
- {boneio-1.0.0.dev7/boneio/webui/frontend-dist/schem → boneio-1.0.0.dev8/boneio/webui/schema}/ina219.schema.json +12 -12
- {boneio-1.0.0.dev7/boneio/webui/frontend-dist/schem → boneio-1.0.0.dev8/boneio/webui/schema}/lm75.schema.json +8 -8
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/logger.schema.json +2 -2
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/mcp23017.schema.json +4 -4
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/mcp9808.schema.json +8 -8
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/modbus.schema.json +2 -2
- {boneio-1.0.0.dev7/boneio/webui/frontend-dist/schem → boneio-1.0.0.dev8/boneio/webui/schema}/modbus_devices.schema.json +16 -16
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/mqtt.schema.json +4 -4
- {boneio-1.0.0.dev7/boneio/webui/frontend-dist/schem → boneio-1.0.0.dev8/boneio/webui/schema}/oled.schema.json +8 -8
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/output.schema.json +6 -16
- {boneio-1.0.0.dev7/boneio/webui/frontend-dist/schem → boneio-1.0.0.dev8/boneio/webui/schema}/output_group.schema.json +6 -6
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/pca9685.schema.json +4 -4
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/pcf8575.schema.json +4 -4
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/sensor.schema.json +8 -8
- boneio-1.0.0.dev8/boneio/webui/schema/virtual_energy_sensor.schema.json +79 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/web.schema.json +13 -4
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8/boneio.egg-info}/PKG-INFO +1 -1
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio.egg-info/SOURCES.txt +20 -17
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/pyproject.toml +4 -0
- boneio-1.0.0.dev7/boneio/components/output/basic.py +0 -399
- boneio-1.0.0.dev7/boneio/modbus/devices/inverters/sofar.json +0 -150
- boneio-1.0.0.dev7/boneio/modbus/utils.py +0 -73
- boneio-1.0.0.dev7/boneio/version.py +0 -2
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/index-UMDOLcBJ.css +0 -1
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/LICENSE +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/MANIFEST.in +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/README.md +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.4/input.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.4/output_24_16.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.4/output_32_10.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.4/output_32_5.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.4/output_cover.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.4/output_cover_mix.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.7/input.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.7/output_24_16.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.7/output_32_10.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.7/output_cover.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.7/output_cover_mix.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.8/input.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.8/output_24_16.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.8/output_32_10.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.8/output_cover.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/boards/0.8/output_cover_mix.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/bonecli.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/cover/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/cover/cover.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/cover/previous.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/cover/time_based.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/cover/venetian.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/group/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/group/output_group.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/input/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/input/binary_sensor.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/input/detectors.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/input/event.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/output/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/output/mcp.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/output/pca.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/output/pcf.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/components/sensor/system.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/config/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/config/loader.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/config/package-lock.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/config/package.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/config/schema_converter.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/events/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/events/bus.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/manager/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/manager/covers.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/manager/display.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/messaging/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/messaging/basic.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/messaging/basic_mqtt.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/messaging/local.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/messaging/mqtt.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/messaging/queue.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/sensor/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/sensor/base.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/sensor/system.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/state/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/system/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/system/host_data.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/system/monitor.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/utils/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/utils/async_updater.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/utils/filter.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/utils/font_util.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/utils/logger.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/utils/timeperiod.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/core/utils/util.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/24x16/adc.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/24x16/binary_sensor.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/24x16/config.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/24x16/event.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/24x16/mqtt.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/24x16/output24x16A.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/32x10/adc.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/32x10/binary_sensor.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/32x10/config.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/32x10/event.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/32x10/mqtt.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/32x10/output32x10A.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/cover/adc.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/cover/binary_sensor.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/cover/config.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/cover/cover.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/cover/event.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/cover/mqtt.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/cover/outputCover.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/cover_mix/adc.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/cover_mix/binary_sensor.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/cover_mix/config.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/cover_mix/cover.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/cover_mix/event.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/cover_mix/mqtt.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/cover_mix/outputCoverMix.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/different_configs/adc.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/different_configs/all_binary_sensor.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/different_configs/binary_sensor.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/different_configs/binary_sensor_v_0_7.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/different_configs/config_24_16.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/different_configs/event_all.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/different_configs/event_v_0_7.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/different_configs/led32x4A.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/different_configs/output24x16A.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/different_configs/output24x16A_v0.3.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/different_configs/output32x10A.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/example_config/different_configs/output32x5A.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/exceptions.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/analog/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/analog/adc.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/display/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/display/fonts/danube__.ttf +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/display/oled.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/gpio/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/gpio/expanders/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/gpio/expanders/pca9685.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/gpio/expanders/pcf8575.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/gpio/input/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/gpio/input/base.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/gpio/input/manager.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/i2c/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/i2c/ina219.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/i2c/ina219_driver.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/i2c/mcp9808.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/i2c/pct2075.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/onewire/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/onewire/bus.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/onewire/dallas.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/onewire/ds2482.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/sensor/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/sensor/temperature/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/sensor/temperature/base.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/sensor/temperature/mcp9808.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/hardware/sensor/temperature/pct2075.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/integration/interlock.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/client.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/energy_meters/orno-or-we-517.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/energy_meters/sdm120.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/energy_meters/sdm630.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/hvac/fujitsu-ac.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/hvac/ventclear.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/inverters/thessla.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/other/r4dcb08.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/other/wanas415.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/sensors/cwt.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/sensors/liquid-sensor.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/sensors/sht20.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/devices/sensors/sht30.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/entities/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/entities/derived/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/entities/sensor/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/entities/sensor/binary.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/entities/writeable/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/entities/writeable/binary.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/modbus/entities/writeable/numeric.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/models/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/models/actions.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/models/events.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/models/files.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/models/logs.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/models/mqtt.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/models/state.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/schema/actions.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/schema/actions_sensor.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/schema/actions_switch.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/schema/filters.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/schema/filters_adc.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/schema/id.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/schema/temp_unit.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/schema/update_interval.yaml +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/abap-CRCWOmpq.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/apex-DnsZk_dE.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/azcli-1IWB1ccx.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/bat-DPkNLes8.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/bicep-Corcdgou.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/cameligo-CGrWLZr3.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/clojure-D9WOWImG.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/codicon-DCmgc-ay.ttf +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/coffee-B7EJu28W.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/cpp-SEyurbux.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/csharp-BoL64M5l.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/csp-C46ZqvIl.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/css-DQU6DXDx.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/cypher-D84EuPTj.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/dart-D8lhlL1r.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/dockerfile-DLk6rpji.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/ecl-BO6FnfXk.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/editor.worker-DsAeyiJ5.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/elixir-BRjLKONM.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/flow9-Cac8vKd7.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/fsharp-fd1GTHhf.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/go-O9LJTZXk.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/graphql-LQdxqEYJ.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/hcl-DxDQ3s82.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/ini-BvajGCUy.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/java-SYsfObOQ.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/json.worker-DaRII17c.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/julia-DQXNmw_w.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/kotlin-qQ0MG-9I.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/less-GGFNNJHn.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/lexon-Canl7DCW.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/lua-D28Ae8-K.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/m3-DPitgjJI.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/markdown-B811l8j2.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/mips-CdjsipkG.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/msdax-CYqgjx_P.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/mysql-BHd6q0vd.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/objective-c-B1aVtJYH.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/pascal-BhNW15KB.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/pascaligo-5jv8CcQD.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/perl-DlYyT36c.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/pgsql-Dy0bjov7.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/php-120yhfDK.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/pla-CjnFlu4u.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/postiats-CQpG440k.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/powerquery-DdJtto1Z.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/powershell-Bu_VLpJB.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/protobuf-IBS6jZEB.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/pug-kFxLfcjb.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/qsharp-q7JyzKFN.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/r-BIFz-_sK.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/redis-CHOsPHWR.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/redshift-CBifECDb.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/restructuredtext-CghPJEOS.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/ruby-CYWGW-b1.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/rust-DMDD0SHb.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/sb-BYAiYHFx.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/scala-Bqvq8jcR.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/scheme-Dhb-2j9p.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/scss-CTwUZ5N7.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/shell-CsDZo4DB.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/solidity-CME5AdoB.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/sophia-RYC1BQQz.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/sparql-KEyrF7De.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/sql-BdTr02Mf.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/st-C7iG7M4S.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/swift-D7IUmUK8.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/systemverilog-DgMryOEJ.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/tcl-PloMZuKG.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/twig-BfRIq3la.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/typespec-CzxlYoT_.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/vb-BwAE3J76.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/wgsl-B_1kOXbF.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/assets/yaml.worker-BTE-_K6g.js +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/boneio.svg +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/boneio_fav.svg +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/frontend-dist/schem/dallas.schema.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/middleware/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/middleware/auth.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/routes/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/routes/auth.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/routes/config.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/routes/covers.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/routes/modbus.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/routes/outputs.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/routes/sensors.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/routes/system.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/routes/update.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/schema/dallas.schema.json +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/services/__init__.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/services/logs.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/web_server.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio/webui/websocket_manager.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio.egg-info/dependency_links.txt +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio.egg-info/entry_points.txt +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio.egg-info/requires.txt +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/boneio.egg-info/top_level.txt +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/setup.cfg +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/setup.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/tests/test_i2c_smbus2.py +0 -0
- {boneio-1.0.0.dev7 → boneio-1.0.0.dev8}/tests/test_py313_compatibility.py +0 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"""Basic Output module (formerly BasicRelay)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import asyncio
|
|
5
|
+
import logging
|
|
6
|
+
import time
|
|
7
|
+
|
|
8
|
+
from boneio.const import COVER, LIGHT, NONE, OFF, ON, RELAY, STATE, SWITCH
|
|
9
|
+
from boneio.core.messaging import BasicMqtt
|
|
10
|
+
from boneio.models.events import OutputEvent
|
|
11
|
+
from boneio.core.events import EventBus, async_track_point_in_time, utcnow
|
|
12
|
+
from boneio.integration.interlock import SoftwareInterlockManager
|
|
13
|
+
from boneio.core.utils import callback
|
|
14
|
+
from boneio.models import OutputState
|
|
15
|
+
|
|
16
|
+
_LOGGER = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class BasicOutput(BasicMqtt):
|
|
20
|
+
"""Basic output class (relay, switch, light, PWM).
|
|
21
|
+
|
|
22
|
+
Formerly known as BasicRelay. This class represents any controllable
|
|
23
|
+
output device in the BoneIO system.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
# Subclasses (e.g. MCPOutput) will override these
|
|
27
|
+
_pin_id: int = -1
|
|
28
|
+
_expander_id: str | None = None
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
id: str,
|
|
33
|
+
event_bus: EventBus,
|
|
34
|
+
topic_prefix: str,
|
|
35
|
+
name: str | None = None,
|
|
36
|
+
output_type=SWITCH,
|
|
37
|
+
restored_state: bool = False,
|
|
38
|
+
topic_type: str = RELAY,
|
|
39
|
+
interlock_manager: SoftwareInterlockManager | None = None,
|
|
40
|
+
interlock_groups: list[str] = [],
|
|
41
|
+
**kwargs,
|
|
42
|
+
) -> None:
|
|
43
|
+
"""Initialize Basic output."""
|
|
44
|
+
self._momentary_turn_on = kwargs.pop("momentary_turn_on", None)
|
|
45
|
+
self._momentary_turn_off = kwargs.pop("momentary_turn_off", None)
|
|
46
|
+
super().__init__(id=id, name=name or id, topic_type=topic_type, topic_prefix=topic_prefix, **kwargs)
|
|
47
|
+
self._output_type: str = output_type
|
|
48
|
+
self._event_bus: EventBus = event_bus
|
|
49
|
+
self._interlock_manager: SoftwareInterlockManager | None = interlock_manager
|
|
50
|
+
self._interlock_groups: list[str] = interlock_groups
|
|
51
|
+
if output_type == COVER:
|
|
52
|
+
self._momentary_turn_on = None
|
|
53
|
+
self._momentary_turn_off = None
|
|
54
|
+
self._state = ON if restored_state else OFF
|
|
55
|
+
self._momentary_action = None
|
|
56
|
+
self._last_timestamp = 0.0
|
|
57
|
+
self._loop = asyncio.get_running_loop()
|
|
58
|
+
|
|
59
|
+
# HA area/room assignment (set by OutputManager)
|
|
60
|
+
self.area: str | None = None
|
|
61
|
+
|
|
62
|
+
def set_interlock(self, interlock_manager: SoftwareInterlockManager, interlock_groups: list[str]):
|
|
63
|
+
"""Set interlock manager and groups."""
|
|
64
|
+
self._interlock_manager = interlock_manager
|
|
65
|
+
self._interlock_groups = interlock_groups
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def is_mcp_type(self) -> bool:
|
|
69
|
+
"""Check if relay is mcp type."""
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def output_type(self) -> str:
|
|
74
|
+
"""HA type."""
|
|
75
|
+
return self._output_type
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def is_light(self) -> bool:
|
|
79
|
+
"""Check if HA type is light"""
|
|
80
|
+
return self._output_type == LIGHT
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def id(self) -> str:
|
|
84
|
+
"""Id of the relay.
|
|
85
|
+
Has to be trimmed out of spaces because of MQTT handling in HA."""
|
|
86
|
+
return self._id or str(self._pin_id) or ""
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def name(self) -> str:
|
|
90
|
+
"""Not trimmed id."""
|
|
91
|
+
return self._name or str(self._pin_id) or ""
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def pin_id(self) -> str | None:
|
|
95
|
+
"""Pin ID as string for OutputState model."""
|
|
96
|
+
return str(self._pin_id) if self._pin_id is not None else None
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def state(self) -> str:
|
|
100
|
+
"""Is relay active."""
|
|
101
|
+
return self._state
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def last_timestamp(self) -> float:
|
|
106
|
+
return self._last_timestamp
|
|
107
|
+
|
|
108
|
+
def payload(self) -> dict[str, str | float | int | None]:
|
|
109
|
+
"""Return payload for MQTT message.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Dictionary with state information for MQTT publishing.
|
|
113
|
+
"""
|
|
114
|
+
return {STATE: self.state}
|
|
115
|
+
|
|
116
|
+
async def async_send_state(self, optimized_value: str | None = None) -> None:
|
|
117
|
+
"""Send state to Mqtt on action asynchronously."""
|
|
118
|
+
if optimized_value:
|
|
119
|
+
state = optimized_value
|
|
120
|
+
else:
|
|
121
|
+
state = ON if self.is_active else OFF
|
|
122
|
+
self._state = state
|
|
123
|
+
if self.output_type not in (COVER, NONE):
|
|
124
|
+
self._message_bus.send_message(
|
|
125
|
+
topic=self._send_topic,
|
|
126
|
+
payload={STATE: state},
|
|
127
|
+
retain=True,
|
|
128
|
+
)
|
|
129
|
+
if optimized_value:
|
|
130
|
+
return
|
|
131
|
+
self._last_timestamp = time.time()
|
|
132
|
+
output_state = OutputState(
|
|
133
|
+
id=self.id,
|
|
134
|
+
name=self.name,
|
|
135
|
+
state=state,
|
|
136
|
+
type=self.output_type,
|
|
137
|
+
pin=self.pin_id,
|
|
138
|
+
timestamp=self.last_timestamp,
|
|
139
|
+
expander_id=self.expander_id,
|
|
140
|
+
area=self.area,
|
|
141
|
+
interlock_groups=self._interlock_groups,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
output_event = OutputEvent(
|
|
145
|
+
entity_id=self.id,
|
|
146
|
+
state=output_state,
|
|
147
|
+
)
|
|
148
|
+
self._event_bus.trigger_event(output_event)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def check_interlock(self) -> bool:
|
|
152
|
+
if self._interlock_manager is not None and self._interlock_groups:
|
|
153
|
+
return self._interlock_manager.can_turn_on(self, self._interlock_groups)
|
|
154
|
+
return True
|
|
155
|
+
|
|
156
|
+
async def async_turn_on(self, timestamp=None) -> None:
|
|
157
|
+
"""Turn on the relay asynchronously."""
|
|
158
|
+
can_turn_on = self.check_interlock()
|
|
159
|
+
if can_turn_on:
|
|
160
|
+
await self._loop.run_in_executor(None, self.turn_on, timestamp)
|
|
161
|
+
else:
|
|
162
|
+
_LOGGER.warning(f"Interlock active: cannot turn on {self.id}.")
|
|
163
|
+
#Workaround for HA is sendind state ON/OFF without physically changing the relay.
|
|
164
|
+
asyncio.create_task(self.async_send_state(optimized_value=ON))
|
|
165
|
+
await asyncio.sleep(0.01)
|
|
166
|
+
asyncio.create_task(self.async_send_state())
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
async def async_turn_off(self, timestamp=None) -> None:
|
|
170
|
+
"""Turn off the relay asynchronously."""
|
|
171
|
+
await self._loop.run_in_executor(None, self.turn_off, timestamp)
|
|
172
|
+
await self.async_send_state()
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
async def async_toggle(self, timestamp=None) -> None:
|
|
176
|
+
"""Toggle relay."""
|
|
177
|
+
now = time.time()
|
|
178
|
+
_LOGGER.debug("Toggle relay %s, state: %s, at %s.", self.name, self.state, now)
|
|
179
|
+
if self.state == ON:
|
|
180
|
+
await self.async_turn_off(timestamp=timestamp)
|
|
181
|
+
else:
|
|
182
|
+
await self.async_turn_on(timestamp=timestamp)
|
|
183
|
+
|
|
184
|
+
def turn_on(self, timestamp=None) -> None:
|
|
185
|
+
"""Call turn on action."""
|
|
186
|
+
raise NotImplementedError
|
|
187
|
+
|
|
188
|
+
def turn_off(self, timestamp=None) -> None:
|
|
189
|
+
"""Call turn off action."""
|
|
190
|
+
raise NotImplementedError
|
|
191
|
+
|
|
192
|
+
def set_brightness(self, value: int) -> None:
|
|
193
|
+
"""Set brightness (only supported on PWM outputs like PCA9685)."""
|
|
194
|
+
_LOGGER.warning("set_brightness not supported for %s output type", self.output_type)
|
|
195
|
+
|
|
196
|
+
def _execute_momentary_turn(self, momentary_type: str) -> None:
|
|
197
|
+
"""Execute momentary action."""
|
|
198
|
+
if self._momentary_action:
|
|
199
|
+
_LOGGER.debug("Cancelling momentary action for %s", self.name)
|
|
200
|
+
self._momentary_action()
|
|
201
|
+
(action, delayed_action) = (
|
|
202
|
+
(self.async_turn_off, self._momentary_turn_on)
|
|
203
|
+
if momentary_type == ON
|
|
204
|
+
else (self.async_turn_on, self._momentary_turn_off)
|
|
205
|
+
)
|
|
206
|
+
if delayed_action:
|
|
207
|
+
_LOGGER.debug("Applying momentary action for %s in %s", self.name, delayed_action.as_timedelta)
|
|
208
|
+
self._momentary_action = async_track_point_in_time(
|
|
209
|
+
loop=self._loop,
|
|
210
|
+
job=self._momentary_callback,
|
|
211
|
+
point_in_time=utcnow() + delayed_action.as_timedelta,
|
|
212
|
+
action=action,
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
@callback
|
|
216
|
+
async def _momentary_callback(self, timestamp, action):
|
|
217
|
+
_LOGGER.info("Momentary callback at %s for output %s", timestamp, self.name)
|
|
218
|
+
await action(timestamp=timestamp)
|
|
219
|
+
self._momentary_action = None
|
|
220
|
+
|
|
221
|
+
@property
|
|
222
|
+
def is_active(self) -> bool:
|
|
223
|
+
"""Is active check."""
|
|
224
|
+
raise NotImplementedError
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def expander_id(self) -> str | None:
|
|
228
|
+
"""Retrieve parent Expander ID (set by subclasses like MCPOutput)."""
|
|
229
|
+
return self._expander_id
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"""Virtual Energy Sensor module.
|
|
2
|
+
|
|
3
|
+
Creates virtual power/energy or water flow sensors linked to outputs.
|
|
4
|
+
When the linked output is ON, the sensor calculates consumption based on
|
|
5
|
+
configured power_usage or flow_rate.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import json
|
|
11
|
+
import logging
|
|
12
|
+
import time
|
|
13
|
+
from typing import TYPE_CHECKING
|
|
14
|
+
|
|
15
|
+
from boneio.const import ON
|
|
16
|
+
from boneio.models import SensorState
|
|
17
|
+
from boneio.models.events import SensorEvent
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from boneio.core.messaging.basic import MessageBus
|
|
21
|
+
from boneio.core.events.bus import EventBus
|
|
22
|
+
from boneio.components.output.basic import BasicOutput
|
|
23
|
+
|
|
24
|
+
_LOGGER = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class VirtualEnergySensor:
|
|
28
|
+
"""Virtual energy/water sensor linked to an output.
|
|
29
|
+
|
|
30
|
+
Tracks energy consumption (Wh) or water consumption (L) based on
|
|
31
|
+
configured power_usage (W) or flow_rate (L/h) when the linked output is ON.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
id: Unique sensor identifier
|
|
35
|
+
name: Display name for Home Assistant
|
|
36
|
+
output: The output to track
|
|
37
|
+
message_bus: MessageBus for MQTT communication
|
|
38
|
+
loop: Event loop
|
|
39
|
+
topic_prefix: MQTT topic prefix
|
|
40
|
+
sensor_type: 'power' or 'water'
|
|
41
|
+
power_usage: Power consumption in Watts (for sensor_type='power')
|
|
42
|
+
flow_rate: Flow rate in L/h (for sensor_type='water')
|
|
43
|
+
area: Optional area ID for HA sub-device
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
def __init__(
|
|
47
|
+
self,
|
|
48
|
+
id: str,
|
|
49
|
+
name: str,
|
|
50
|
+
output: BasicOutput,
|
|
51
|
+
message_bus: MessageBus,
|
|
52
|
+
event_bus: "EventBus",
|
|
53
|
+
loop: asyncio.AbstractEventLoop,
|
|
54
|
+
topic_prefix: str,
|
|
55
|
+
sensor_type: str,
|
|
56
|
+
power_usage: float | None = None,
|
|
57
|
+
flow_rate: float | None = None,
|
|
58
|
+
area: str | None = None,
|
|
59
|
+
):
|
|
60
|
+
self._id = id
|
|
61
|
+
self._name = name
|
|
62
|
+
self._output = output
|
|
63
|
+
self._loop = loop or asyncio.get_running_loop()
|
|
64
|
+
self._message_bus = message_bus
|
|
65
|
+
self._event_bus = event_bus
|
|
66
|
+
self._topic_prefix = topic_prefix
|
|
67
|
+
self._sensor_type = sensor_type
|
|
68
|
+
self._power_usage = power_usage
|
|
69
|
+
self._flow_rate = flow_rate
|
|
70
|
+
self._area = area
|
|
71
|
+
|
|
72
|
+
self._virtual_sensors_task = None
|
|
73
|
+
|
|
74
|
+
# Counters
|
|
75
|
+
self._energy_consumed_Wh = 0.0
|
|
76
|
+
self._water_consumed_L = 0.0
|
|
77
|
+
self._last_on_timestamp = time.time() if self._output.state == ON else None
|
|
78
|
+
|
|
79
|
+
# MQTT topic for this sensor
|
|
80
|
+
self._sensor_topic = f"{topic_prefix}/energy/{id}"
|
|
81
|
+
|
|
82
|
+
# Subscribe to restore state from MQTT
|
|
83
|
+
self._subscribe_restore_state()
|
|
84
|
+
|
|
85
|
+
_LOGGER.info(
|
|
86
|
+
"Initialized VirtualEnergySensor: id=%s, name=%s, output=%s, type=%s",
|
|
87
|
+
id, name, output.id, sensor_type
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def id(self) -> str:
|
|
92
|
+
"""Get sensor ID."""
|
|
93
|
+
return self._id
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def name(self) -> str:
|
|
97
|
+
"""Get sensor name."""
|
|
98
|
+
return self._name
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def output_id(self) -> str:
|
|
102
|
+
"""Get linked output ID."""
|
|
103
|
+
return self._output.id
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def sensor_type(self) -> str:
|
|
107
|
+
"""Get sensor type ('power' or 'water')."""
|
|
108
|
+
return self._sensor_type
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def area(self) -> str | None:
|
|
112
|
+
"""Get area ID."""
|
|
113
|
+
return self._area
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def power_usage(self) -> float | None:
|
|
117
|
+
"""Get power usage in Watts."""
|
|
118
|
+
return self._power_usage
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def flow_rate(self) -> float | None:
|
|
122
|
+
"""Get flow rate in L/h."""
|
|
123
|
+
return self._flow_rate
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def last_on_timestamp(self) -> float | None:
|
|
127
|
+
"""Get timestamp when output was last turned ON."""
|
|
128
|
+
return self._last_on_timestamp
|
|
129
|
+
|
|
130
|
+
def start_tracking(self):
|
|
131
|
+
"""Start tracking consumption (called when output turns ON)."""
|
|
132
|
+
self._last_on_timestamp = time.time()
|
|
133
|
+
if self._virtual_sensors_task is not None and not self._virtual_sensors_task.done():
|
|
134
|
+
return # Already running
|
|
135
|
+
self._virtual_sensors_task = self._loop.create_task(self._tracking_loop())
|
|
136
|
+
_LOGGER.debug("Started tracking for virtual sensor %s", self._id)
|
|
137
|
+
|
|
138
|
+
def stop_tracking(self):
|
|
139
|
+
"""Stop tracking consumption (called when output turns OFF)."""
|
|
140
|
+
# Update one last time before stopping
|
|
141
|
+
self._update_consumption()
|
|
142
|
+
self._last_on_timestamp = None
|
|
143
|
+
|
|
144
|
+
if self._virtual_sensors_task is not None:
|
|
145
|
+
self._virtual_sensors_task.cancel()
|
|
146
|
+
self._virtual_sensors_task = None
|
|
147
|
+
|
|
148
|
+
# Send final state
|
|
149
|
+
self._send_state()
|
|
150
|
+
_LOGGER.debug("Stopped tracking for virtual sensor %s", self._id)
|
|
151
|
+
|
|
152
|
+
async def _tracking_loop(self):
|
|
153
|
+
"""Periodically update and send state every 30 seconds while output is ON."""
|
|
154
|
+
try:
|
|
155
|
+
while self._output.state == ON:
|
|
156
|
+
self._update_consumption()
|
|
157
|
+
self._send_state()
|
|
158
|
+
await asyncio.sleep(30)
|
|
159
|
+
except asyncio.CancelledError:
|
|
160
|
+
pass
|
|
161
|
+
|
|
162
|
+
def _update_consumption(self):
|
|
163
|
+
"""Update consumption counters based on elapsed time."""
|
|
164
|
+
now = time.time()
|
|
165
|
+
if self._output.state == ON and self._last_on_timestamp is not None:
|
|
166
|
+
elapsed = now - self._last_on_timestamp
|
|
167
|
+
|
|
168
|
+
if self._sensor_type == "power" and self._power_usage is not None:
|
|
169
|
+
self._energy_consumed_Wh += (self._power_usage * elapsed) / 3600.0
|
|
170
|
+
_LOGGER.debug(
|
|
171
|
+
"Energy updated for %s: %.4f Wh",
|
|
172
|
+
self._id, self._energy_consumed_Wh
|
|
173
|
+
)
|
|
174
|
+
elif self._sensor_type == "water" and self._flow_rate is not None:
|
|
175
|
+
self._water_consumed_L += (self._flow_rate * elapsed) / 3600.0
|
|
176
|
+
_LOGGER.debug(
|
|
177
|
+
"Water updated for %s: %.4f L",
|
|
178
|
+
self._id, self._water_consumed_L
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
self._last_on_timestamp = now
|
|
182
|
+
|
|
183
|
+
def _subscribe_restore_state(self):
|
|
184
|
+
"""Subscribe to retained MQTT topic to restore state on startup."""
|
|
185
|
+
async def on_message(_topic, payload):
|
|
186
|
+
try:
|
|
187
|
+
data = json.loads(payload)
|
|
188
|
+
if isinstance(data, dict):
|
|
189
|
+
if "energy" in data:
|
|
190
|
+
self._energy_consumed_Wh = float(data["energy"])
|
|
191
|
+
_LOGGER.info(
|
|
192
|
+
"Restored energy state for %s: %.4f Wh",
|
|
193
|
+
self._id, self._energy_consumed_Wh
|
|
194
|
+
)
|
|
195
|
+
if "water" in data:
|
|
196
|
+
self._water_consumed_L = float(data["water"])
|
|
197
|
+
_LOGGER.info(
|
|
198
|
+
"Restored water state for %s: %.4f L",
|
|
199
|
+
self._id, self._water_consumed_L
|
|
200
|
+
)
|
|
201
|
+
except Exception as e:
|
|
202
|
+
_LOGGER.warning("Failed to restore state for %s: %s", self._id, e)
|
|
203
|
+
finally:
|
|
204
|
+
await self._message_bus.unsubscribe_and_stop_listen(self._sensor_topic)
|
|
205
|
+
|
|
206
|
+
if self._message_bus is not None:
|
|
207
|
+
asyncio.create_task(
|
|
208
|
+
self._message_bus.subscribe_and_listen(self._sensor_topic, on_message)
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
def get_current_power(self) -> float:
|
|
212
|
+
"""Get current power usage in W (0 if output is OFF)."""
|
|
213
|
+
if self._sensor_type != "power":
|
|
214
|
+
return 0.0
|
|
215
|
+
return (self._power_usage or 0.0) if self._output.state == ON else 0.0
|
|
216
|
+
|
|
217
|
+
def get_total_energy(self) -> float:
|
|
218
|
+
"""Get total energy consumed in Wh."""
|
|
219
|
+
return round(self._energy_consumed_Wh, 3)
|
|
220
|
+
|
|
221
|
+
def get_current_flow_rate(self) -> float:
|
|
222
|
+
"""Get current flow rate in L/h (0 if output is OFF)."""
|
|
223
|
+
if self._sensor_type != "water":
|
|
224
|
+
return 0.0
|
|
225
|
+
return (self._flow_rate or 0.0) if self._output.state == ON else 0.0
|
|
226
|
+
|
|
227
|
+
def get_total_water(self) -> float:
|
|
228
|
+
"""Get total water consumed in L."""
|
|
229
|
+
return round(self._water_consumed_L, 3)
|
|
230
|
+
|
|
231
|
+
def _send_state(self):
|
|
232
|
+
"""Send current state to MQTT and EventBus (for WebSocket/frontend)."""
|
|
233
|
+
payload = {}
|
|
234
|
+
timestamp = int(time.time())
|
|
235
|
+
|
|
236
|
+
if self._sensor_type == "power":
|
|
237
|
+
payload["power"] = self.get_current_power()
|
|
238
|
+
payload["energy"] = self.get_total_energy()
|
|
239
|
+
|
|
240
|
+
# Send SensorEvents to frontend via EventBus
|
|
241
|
+
self._event_bus.trigger_event(SensorEvent(
|
|
242
|
+
entity_id=f"{self._id}_power",
|
|
243
|
+
state=SensorState(
|
|
244
|
+
id=f"{self._id}_power",
|
|
245
|
+
name=f"{self._name} Power",
|
|
246
|
+
state=self.get_current_power(),
|
|
247
|
+
unit="W",
|
|
248
|
+
timestamp=timestamp,
|
|
249
|
+
)
|
|
250
|
+
))
|
|
251
|
+
self._event_bus.trigger_event(SensorEvent(
|
|
252
|
+
entity_id=f"{self._id}_energy",
|
|
253
|
+
state=SensorState(
|
|
254
|
+
id=f"{self._id}_energy",
|
|
255
|
+
name=f"{self._name} Energy",
|
|
256
|
+
state=self.get_total_energy(),
|
|
257
|
+
unit="Wh",
|
|
258
|
+
timestamp=timestamp,
|
|
259
|
+
)
|
|
260
|
+
))
|
|
261
|
+
elif self._sensor_type == "water":
|
|
262
|
+
payload["volume_flow_rate"] = self.get_current_flow_rate()
|
|
263
|
+
payload["water"] = self.get_total_water()
|
|
264
|
+
|
|
265
|
+
# Send SensorEvents to frontend via EventBus
|
|
266
|
+
self._event_bus.trigger_event(SensorEvent(
|
|
267
|
+
entity_id=f"{self._id}_flow",
|
|
268
|
+
state=SensorState(
|
|
269
|
+
id=f"{self._id}_flow",
|
|
270
|
+
name=f"{self._name} Flow Rate",
|
|
271
|
+
state=self.get_current_flow_rate(),
|
|
272
|
+
unit="L/h",
|
|
273
|
+
timestamp=timestamp,
|
|
274
|
+
)
|
|
275
|
+
))
|
|
276
|
+
self._event_bus.trigger_event(SensorEvent(
|
|
277
|
+
entity_id=f"{self._id}_water",
|
|
278
|
+
state=SensorState(
|
|
279
|
+
id=f"{self._id}_water",
|
|
280
|
+
name=f"{self._name} Water",
|
|
281
|
+
state=self.get_total_water(),
|
|
282
|
+
unit="L",
|
|
283
|
+
timestamp=timestamp,
|
|
284
|
+
)
|
|
285
|
+
))
|
|
286
|
+
|
|
287
|
+
self._message_bus.send_message(
|
|
288
|
+
topic=self._sensor_topic,
|
|
289
|
+
payload=payload,
|
|
290
|
+
retain=True,
|
|
291
|
+
)
|
|
292
|
+
_LOGGER.debug("Sent state for %s: %s", self._id, payload)
|
|
@@ -38,6 +38,7 @@ class ConfigHelper:
|
|
|
38
38
|
network_info: dict = {},
|
|
39
39
|
is_web_active: bool = False,
|
|
40
40
|
web_port: int = 8090,
|
|
41
|
+
nginx_proxy_port: int | None = None,
|
|
41
42
|
config_file_path: str | None = None,
|
|
42
43
|
):
|
|
43
44
|
self._name = name
|
|
@@ -47,6 +48,7 @@ class ConfigHelper:
|
|
|
47
48
|
self._ha_discovery_prefix = ha_discovery_prefix
|
|
48
49
|
self._device_type = device_type
|
|
49
50
|
self._web_port = web_port
|
|
51
|
+
self._nginx_proxy_port = nginx_proxy_port
|
|
50
52
|
self._fetch_old_discovery = None
|
|
51
53
|
self._autodiscovery_messages = {
|
|
52
54
|
SWITCH: {},
|
|
@@ -113,6 +115,16 @@ class ConfigHelper:
|
|
|
113
115
|
def web_port(self) -> int:
|
|
114
116
|
return self._web_port
|
|
115
117
|
|
|
118
|
+
@property
|
|
119
|
+
def nginx_proxy_port(self) -> int | None:
|
|
120
|
+
"""Get nginx proxy port if configured."""
|
|
121
|
+
return self._nginx_proxy_port
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def ha_configuration_port(self) -> int:
|
|
125
|
+
"""Get port for HA discovery URL. Uses nginx_proxy_port if set, otherwise web_port."""
|
|
126
|
+
return self._nginx_proxy_port if self._nginx_proxy_port else self._web_port
|
|
127
|
+
|
|
116
128
|
@property
|
|
117
129
|
def topic_prefix(self) -> str:
|
|
118
130
|
return self._topic_prefix
|
|
@@ -892,6 +892,21 @@ def update_config_section(config_file: str, section: str, data: dict | list) ->
|
|
|
892
892
|
|
|
893
893
|
_LOGGER.info(f"Updating section '{section}' with data: {data}")
|
|
894
894
|
|
|
895
|
+
# Special handling for mcp23017 - convert hex strings to integers
|
|
896
|
+
# This ensures YAML writes them as integers which are then read back as hex
|
|
897
|
+
if section == 'mcp23017' and isinstance(data, list):
|
|
898
|
+
for entry in data:
|
|
899
|
+
if isinstance(entry, dict) and 'address' in entry:
|
|
900
|
+
addr = entry['address']
|
|
901
|
+
if isinstance(addr, str):
|
|
902
|
+
if addr.startswith('0x') or addr.startswith('0X'):
|
|
903
|
+
entry['address'] = int(addr, 16)
|
|
904
|
+
else:
|
|
905
|
+
try:
|
|
906
|
+
entry['address'] = int(addr, 10)
|
|
907
|
+
except ValueError:
|
|
908
|
+
pass # Keep as string if conversion fails
|
|
909
|
+
|
|
895
910
|
# Strip default values to keep YAML clean
|
|
896
911
|
cleaned_data = strip_default_values(data, {}, section)
|
|
897
912
|
_LOGGER.info(f"Cleaned data (defaults removed): {cleaned_data}")
|
|
@@ -422,8 +422,6 @@ class InputManager:
|
|
|
422
422
|
- Removing deleted inputs (from internal state and HA Discovery)
|
|
423
423
|
- Adding inputs that use already-registered GPIO pins (e.g., moving from event to binary_sensor)
|
|
424
424
|
"""
|
|
425
|
-
import asyncio
|
|
426
|
-
|
|
427
425
|
_LOGGER.info("Reloading input configuration")
|
|
428
426
|
|
|
429
427
|
# Get new config
|
|
@@ -491,9 +489,42 @@ class InputManager:
|
|
|
491
489
|
# - Add new inputs if their GPIO pin is already registered
|
|
492
490
|
self._configure_inputs(reload_config=True)
|
|
493
491
|
|
|
494
|
-
#
|
|
495
|
-
|
|
496
|
-
self.
|
|
492
|
+
# Broadcast all input states to WebSocket clients
|
|
493
|
+
# Global listeners will receive these events for all inputs (including new ones)
|
|
494
|
+
self._broadcast_all_input_states()
|
|
495
|
+
|
|
496
|
+
def _broadcast_all_input_states(self) -> None:
|
|
497
|
+
"""Broadcast current state of all inputs via WebSocket.
|
|
498
|
+
|
|
499
|
+
This is called after reload to ensure frontend receives
|
|
500
|
+
the updated input list immediately.
|
|
501
|
+
"""
|
|
502
|
+
import time
|
|
503
|
+
from boneio.models import InputState
|
|
504
|
+
from boneio.models.events import InputEvent
|
|
505
|
+
|
|
506
|
+
timestamp = time.time()
|
|
507
|
+
|
|
508
|
+
for input_ in self._inputs.values():
|
|
509
|
+
try:
|
|
510
|
+
input_state = InputState(
|
|
511
|
+
name=input_.name,
|
|
512
|
+
state=input_.last_state,
|
|
513
|
+
type=input_.input_type,
|
|
514
|
+
pin=input_.pin,
|
|
515
|
+
timestamp=timestamp,
|
|
516
|
+
boneio_input=input_.boneio_input,
|
|
517
|
+
area=input_.area
|
|
518
|
+
)
|
|
519
|
+
event = InputEvent(
|
|
520
|
+
entity_id=input_.id,
|
|
521
|
+
state=input_state,
|
|
522
|
+
click_type=None,
|
|
523
|
+
duration=None
|
|
524
|
+
)
|
|
525
|
+
self._manager._event_bus.trigger_event(event)
|
|
526
|
+
except Exception as e:
|
|
527
|
+
_LOGGER.debug("Error broadcasting input state %s: %s", input_.id, e)
|
|
497
528
|
|
|
498
529
|
def _remove_input_ha_discovery(self, input_id: str, old_area: str | None = None) -> None:
|
|
499
530
|
"""Remove HA Discovery entries for an input.
|
|
@@ -591,7 +622,6 @@ class InputManager:
|
|
|
591
622
|
# Get the input instance and retrieve actions for this click type
|
|
592
623
|
input_instance = self._inputs.get(event.entity_id)
|
|
593
624
|
if not input_instance:
|
|
594
|
-
print(self._inputs)
|
|
595
625
|
_LOGGER.warning("Input %s not found for event handling", event.entity_id)
|
|
596
626
|
return
|
|
597
627
|
|