boneio 1.0.0.dev6__tar.gz → 1.0.0.dev7__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.dev6/boneio.egg-info → boneio-1.0.0.dev7}/PKG-INFO +1 -1
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/cover/previous.py +12 -2
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/cover/time_based.py +10 -2
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/cover/venetian.py +12 -6
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/group/output_group.py +8 -2
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/manager/covers.py +47 -28
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/manager/inputs.py +50 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/gpio/expanders/mcp23017.py +38 -14
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/gpio/expanders/pca9685.py +69 -46
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/gpio/expanders/pcf8575.py +44 -11
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/coordinator.py +1 -1
- boneio-1.0.0.dev7/boneio/version.py +2 -0
- boneio-1.0.0.dev7/boneio/webui/app.py +658 -0
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/cssMode-28wsodaN.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/cssMode-ClVp1zRM.js +1 -1
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/freemarker2-DBoUEFeV.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/freemarker2-Dpc6FVoU.js +1 -1
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/handlebars-BMPQqMuK.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/handlebars-3T51HdyE.js +1 -1
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/html-C-J4vGDC.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/html-Cqlv8Ey8.js +1 -1
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/htmlMode-DLqnuXCj.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/htmlMode-kKBBldLZ.js +1 -1
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/index-CiuOrRV8.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/index-ClokVTBs.js +204 -204
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/index-UMDOLcBJ.css +1 -0
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/javascript-DjAp6HFu.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/javascript-jIes5V6e.js +1 -1
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/jsonMode-DuoTNxT6.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/jsonMode-DUk1WXAK.js +1 -1
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/liquid-1wqDC8lY.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/liquid-CklSeh78.js +1 -1
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/mdx-ou-zvMhp.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/mdx-Q44kPz7v.js +1 -1
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/python--YMY2ScQ.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/python-CX3wo97z.js +1 -1
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/razor-BRc3lsvv.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/razor-B3VfV1vo.js +1 -1
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/tsMode-D54D1lK6.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/tsMode-BVdbrg1F.js +1 -1
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/typescript-DLyjvYVj.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/typescript-C3sLeWbM.js +1 -1
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/xml-Cd_YftAm.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/xml-DyAfOafQ.js +1 -1
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/yaml-BhCMO_W9.js → boneio-1.0.0.dev7/boneio/webui/frontend-dist/assets/yaml-DZVmC1BT.js +1 -1
- boneio-1.0.0.dev7/boneio/webui/frontend-dist/index.html +21 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/binary_sensor.schema.json +8 -8
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/config.schema.json +50 -50
- {boneio-1.0.0.dev6/boneio/webui/schema → boneio-1.0.0.dev7/boneio/webui/frontend-dist/schem}/event.schema.json +12 -12
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/ina219.schema.json +2 -2
- {boneio-1.0.0.dev6/boneio/webui/schema → boneio-1.0.0.dev7/boneio/webui/frontend-dist/schem}/lm75.schema.json +2 -2
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/mcp23017.schema.json +2 -2
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/mcp9808.schema.json +2 -2
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/modbus.schema.json +6 -6
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/modbus_devices.schema.json +4 -4
- {boneio-1.0.0.dev6/boneio/webui/schema → boneio-1.0.0.dev7/boneio/webui/frontend-dist/schem}/mqtt.schema.json +2 -2
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/output.schema.json +4 -4
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/pca9685.schema.json +2 -2
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/pcf8575.schema.json +2 -2
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/web.schema.json +2 -2
- boneio-1.0.0.dev7/boneio/webui/middleware/__init__.py +5 -0
- boneio-1.0.0.dev7/boneio/webui/middleware/auth.py +155 -0
- boneio-1.0.0.dev7/boneio/webui/routes/__init__.py +21 -0
- boneio-1.0.0.dev7/boneio/webui/routes/auth.py +61 -0
- boneio-1.0.0.dev7/boneio/webui/routes/config.py +479 -0
- boneio-1.0.0.dev7/boneio/webui/routes/covers.py +122 -0
- boneio-1.0.0.dev7/boneio/webui/routes/modbus.py +466 -0
- boneio-1.0.0.dev7/boneio/webui/routes/outputs.py +109 -0
- boneio-1.0.0.dev7/boneio/webui/routes/sensors.py +118 -0
- boneio-1.0.0.dev7/boneio/webui/routes/system.py +161 -0
- boneio-1.0.0.dev7/boneio/webui/routes/update.py +461 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/binary_sensor.schema.json +8 -8
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/config.schema.json +50 -50
- {boneio-1.0.0.dev6/boneio/webui/frontend-dist/schem → boneio-1.0.0.dev7/boneio/webui/schema}/event.schema.json +12 -12
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/ina219.schema.json +2 -2
- {boneio-1.0.0.dev6/boneio/webui/frontend-dist/schem → boneio-1.0.0.dev7/boneio/webui/schema}/lm75.schema.json +2 -2
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/mcp23017.schema.json +2 -2
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/mcp9808.schema.json +2 -2
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/modbus.schema.json +6 -6
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/modbus_devices.schema.json +4 -4
- {boneio-1.0.0.dev6/boneio/webui/frontend-dist/schem → boneio-1.0.0.dev7/boneio/webui/schema}/mqtt.schema.json +2 -2
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/output.schema.json +4 -4
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/pca9685.schema.json +2 -2
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/pcf8575.schema.json +2 -2
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/web.schema.json +2 -2
- boneio-1.0.0.dev7/boneio/webui/services/__init__.py +15 -0
- boneio-1.0.0.dev7/boneio/webui/services/logs.py +242 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7/boneio.egg-info}/PKG-INFO +1 -1
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio.egg-info/SOURCES.txt +30 -17
- boneio-1.0.0.dev6/boneio/version.py +0 -2
- boneio-1.0.0.dev6/boneio/webui/app.py +0 -2602
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/assets/index-CaOLuaDD.css +0 -1
- boneio-1.0.0.dev6/boneio/webui/frontend-dist/index.html +0 -14
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/LICENSE +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/MANIFEST.in +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/README.md +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.4/input.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.4/output_24_16.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.4/output_32_10.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.4/output_32_5.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.4/output_cover.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.4/output_cover_mix.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.7/input.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.7/output_24_16.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.7/output_32_10.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.7/output_cover.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.7/output_cover_mix.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.8/input.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.8/output_24_16.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.8/output_32_10.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.8/output_cover.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/boards/0.8/output_cover_mix.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/bonecli.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/cover/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/cover/cover.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/group/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/input/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/input/binary_sensor.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/input/detectors.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/input/event.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/output/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/output/basic.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/output/mcp.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/output/pca.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/output/pcf.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/sensor/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/components/sensor/system.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/const.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/config/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/config/config_helper.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/config/loader.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/config/package-lock.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/config/package.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/config/schema_converter.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/config/yaml_util.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/events/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/events/bus.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/manager/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/manager/display.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/manager/manager.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/manager/modbus.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/manager/outputs.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/manager/sensors.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/messaging/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/messaging/basic.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/messaging/basic_mqtt.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/messaging/local.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/messaging/mqtt.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/messaging/queue.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/sensor/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/sensor/base.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/sensor/system.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/state/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/state/manager.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/system/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/system/host_data.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/system/monitor.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/utils/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/utils/async_updater.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/utils/filter.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/utils/font_util.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/utils/logger.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/utils/timeperiod.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/core/utils/util.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/24x16/adc.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/24x16/binary_sensor.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/24x16/config.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/24x16/event.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/24x16/mqtt.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/24x16/output24x16A.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/32x10/adc.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/32x10/binary_sensor.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/32x10/config.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/32x10/event.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/32x10/mqtt.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/32x10/output32x10A.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/cover/adc.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/cover/binary_sensor.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/cover/config.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/cover/cover.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/cover/event.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/cover/mqtt.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/cover/outputCover.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/cover_mix/adc.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/cover_mix/binary_sensor.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/cover_mix/config.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/cover_mix/cover.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/cover_mix/event.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/cover_mix/mqtt.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/cover_mix/outputCoverMix.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/different_configs/adc.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/different_configs/all_binary_sensor.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/different_configs/binary_sensor.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/different_configs/binary_sensor_v_0_7.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/different_configs/config_24_16.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/different_configs/event_all.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/different_configs/event_v_0_7.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/different_configs/led32x4A.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/different_configs/output24x16A.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/different_configs/output24x16A_v0.3.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/different_configs/output32x10A.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/example_config/different_configs/output32x5A.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/exceptions.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/analog/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/analog/adc.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/display/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/display/fonts/danube__.ttf +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/display/oled.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/gpio/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/gpio/expanders/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/gpio/input/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/gpio/input/base.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/gpio/input/manager.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/i2c/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/i2c/bus.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/i2c/ina219.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/i2c/ina219_driver.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/i2c/mcp9808.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/i2c/pct2075.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/onewire/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/onewire/bus.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/onewire/dallas.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/onewire/ds2482.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/sensor/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/sensor/temperature/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/sensor/temperature/base.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/sensor/temperature/mcp9808.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/hardware/sensor/temperature/pct2075.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/integration/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/integration/homeassistant.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/integration/interlock.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/cli.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/client.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/energy_meters/orno-or-we-517.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/energy_meters/sdm120.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/energy_meters/sdm630.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/energy_meters/socomec_e03.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/energy_meters/socomec_e23.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/hvac/fujitsu-ac.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/hvac/ventclear.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/inverters/sofar.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/inverters/thessla.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/other/r4dcb08.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/other/wanas415.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/sensors/cwt.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/sensors/dts1964_3f.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/sensors/liquid-sensor.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/sensors/pt100.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/sensors/sht20.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/devices/sensors/sht30.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/entities/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/entities/base.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/entities/derived/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/entities/derived/numeric.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/entities/derived/select.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/entities/derived/switch.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/entities/derived/text.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/entities/sensor/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/entities/sensor/binary.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/entities/sensor/numeric.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/entities/sensor/text.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/entities/writeable/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/entities/writeable/binary.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/entities/writeable/numeric.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/modbus/utils.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/models/__init__.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/models/actions.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/models/events.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/models/files.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/models/logs.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/models/mqtt.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/models/state.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/runner.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/schema/actions.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/schema/actions_sensor.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/schema/actions_switch.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/schema/filters.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/schema/filters_adc.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/schema/id.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/schema/schema.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/schema/temp_unit.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/schema/update_interval.yaml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/abap-CRCWOmpq.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/apex-DnsZk_dE.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/azcli-1IWB1ccx.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/bat-DPkNLes8.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/bicep-Corcdgou.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/cameligo-CGrWLZr3.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/clojure-D9WOWImG.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/codicon-DCmgc-ay.ttf +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/coffee-B7EJu28W.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/cpp-SEyurbux.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/csharp-BoL64M5l.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/csp-C46ZqvIl.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/css-DQU6DXDx.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/cypher-D84EuPTj.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/dart-D8lhlL1r.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/dockerfile-DLk6rpji.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/ecl-BO6FnfXk.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/editor.worker-DsAeyiJ5.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/elixir-BRjLKONM.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/flow9-Cac8vKd7.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/fsharp-fd1GTHhf.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/go-O9LJTZXk.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/graphql-LQdxqEYJ.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/hcl-DxDQ3s82.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/ini-BvajGCUy.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/java-SYsfObOQ.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/json.worker-DaRII17c.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/julia-DQXNmw_w.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/kotlin-qQ0MG-9I.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/less-GGFNNJHn.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/lexon-Canl7DCW.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/lua-D28Ae8-K.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/m3-DPitgjJI.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/markdown-B811l8j2.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/mips-CdjsipkG.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/msdax-CYqgjx_P.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/mysql-BHd6q0vd.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/objective-c-B1aVtJYH.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/pascal-BhNW15KB.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/pascaligo-5jv8CcQD.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/perl-DlYyT36c.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/pgsql-Dy0bjov7.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/php-120yhfDK.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/pla-CjnFlu4u.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/postiats-CQpG440k.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/powerquery-DdJtto1Z.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/powershell-Bu_VLpJB.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/protobuf-IBS6jZEB.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/pug-kFxLfcjb.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/qsharp-q7JyzKFN.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/r-BIFz-_sK.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/redis-CHOsPHWR.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/redshift-CBifECDb.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/restructuredtext-CghPJEOS.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/ruby-CYWGW-b1.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/rust-DMDD0SHb.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/sb-BYAiYHFx.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/scala-Bqvq8jcR.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/scheme-Dhb-2j9p.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/scss-CTwUZ5N7.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/shell-CsDZo4DB.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/solidity-CME5AdoB.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/sophia-RYC1BQQz.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/sparql-KEyrF7De.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/sql-BdTr02Mf.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/st-C7iG7M4S.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/swift-D7IUmUK8.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/systemverilog-DgMryOEJ.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/tcl-PloMZuKG.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/twig-BfRIq3la.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/typespec-CzxlYoT_.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/vb-BwAE3J76.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/wgsl-B_1kOXbF.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/assets/yaml.worker-BTE-_K6g.js +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/boneio.svg +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/boneio_fav.svg +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/adc.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/areas.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/boneio.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/cover.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/dallas.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/ds2482.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/logger.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/oled.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/output_group.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/frontend-dist/schem/sensor.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/adc.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/areas.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/boneio.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/cover.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/dallas.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/ds2482.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/logger.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/oled.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/output_group.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/schema/sensor.schema.json +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/web_server.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio/webui/websocket_manager.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio.egg-info/dependency_links.txt +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio.egg-info/entry_points.txt +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio.egg-info/requires.txt +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/boneio.egg-info/top_level.txt +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/pyproject.toml +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/setup.cfg +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/setup.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/tests/test_i2c_smbus2.py +0 -0
- {boneio-1.0.0.dev6 → boneio-1.0.0.dev7}/tests/test_py313_compatibility.py +0 -0
|
@@ -340,5 +340,15 @@ class PreviousCover(BasicMqtt):
|
|
|
340
340
|
return "previous"
|
|
341
341
|
|
|
342
342
|
def update_config_times(self, config: dict) -> None:
|
|
343
|
-
|
|
344
|
-
|
|
343
|
+
"""Update cover timing configuration.
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
config: Dictionary with timing values as TimePeriod objects.
|
|
347
|
+
Keys: open_time, close_time
|
|
348
|
+
"""
|
|
349
|
+
if "open_time" in config:
|
|
350
|
+
self._open_time = config["open_time"]
|
|
351
|
+
self._open = RelayHelper(relay=self._open.relay, time=config["open_time"])
|
|
352
|
+
if "close_time" in config:
|
|
353
|
+
self._close_time = config["close_time"]
|
|
354
|
+
self._close = RelayHelper(relay=self._close.relay, time=config["close_time"])
|
|
@@ -111,6 +111,14 @@ class TimeBasedCover(BaseCover):
|
|
|
111
111
|
return "time"
|
|
112
112
|
|
|
113
113
|
def update_config_times(self, config: dict) -> None:
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
"""Update cover timing configuration.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
config: Dictionary with timing values as TimePeriod objects.
|
|
118
|
+
Keys: open_time, close_time
|
|
119
|
+
"""
|
|
120
|
+
if "open_time" in config:
|
|
121
|
+
self._open_time = config["open_time"].total_milliseconds
|
|
122
|
+
if "close_time" in config:
|
|
123
|
+
self._close_time = config["close_time"].total_milliseconds
|
|
116
124
|
|
|
@@ -260,12 +260,18 @@ class VenetianCover(BaseCover, BaseVenetianCoverABC):
|
|
|
260
260
|
await self.set_tilt(tilt_position=0)
|
|
261
261
|
|
|
262
262
|
def update_config_times(self, config: dict) -> None:
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
263
|
+
"""Update cover timing configuration.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
config: Dictionary with timing values as TimePeriod objects.
|
|
267
|
+
Keys: open_time, close_time, tilt_duration
|
|
268
|
+
"""
|
|
269
|
+
if "open_time" in config:
|
|
270
|
+
self._open_time = config["open_time"].total_milliseconds
|
|
271
|
+
if "close_time" in config:
|
|
272
|
+
self._close_time = config["close_time"].total_milliseconds
|
|
273
|
+
if "tilt_duration" in config and config["tilt_duration"]:
|
|
274
|
+
self._tilt_duration = config["tilt_duration"].total_milliseconds
|
|
269
275
|
|
|
270
276
|
async def run_cover(
|
|
271
277
|
self,
|
|
@@ -86,20 +86,26 @@ class OutputGroup(BasicOutput):
|
|
|
86
86
|
async def async_turn_on(self, timestamp=None) -> None:
|
|
87
87
|
"""Turn on all members in the group.
|
|
88
88
|
|
|
89
|
+
Executes turn_on sequentially to prevent I2C bus contention
|
|
90
|
+
when multiple outputs are on the same GPIO expander.
|
|
91
|
+
|
|
89
92
|
Args:
|
|
90
93
|
timestamp: Optional timestamp for the operation
|
|
91
94
|
"""
|
|
92
95
|
for x in self._group_members:
|
|
93
|
-
|
|
96
|
+
await x.async_turn_on(timestamp=timestamp)
|
|
94
97
|
|
|
95
98
|
async def async_turn_off(self, timestamp=None) -> None:
|
|
96
99
|
"""Turn off all members in the group.
|
|
97
100
|
|
|
101
|
+
Executes turn_off sequentially to prevent I2C bus contention
|
|
102
|
+
when multiple outputs are on the same GPIO expander.
|
|
103
|
+
|
|
98
104
|
Args:
|
|
99
105
|
timestamp: Optional timestamp for the operation
|
|
100
106
|
"""
|
|
101
107
|
for x in self._group_members:
|
|
102
|
-
|
|
108
|
+
await x.async_turn_off(timestamp=timestamp)
|
|
103
109
|
|
|
104
110
|
@property
|
|
105
111
|
def is_active(self) -> bool:
|
|
@@ -110,26 +110,43 @@ class CoverManager:
|
|
|
110
110
|
# Update existing cover or create new one
|
|
111
111
|
if _id in self._covers:
|
|
112
112
|
_cover = self._covers[_id]
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
self._manager.send_ha_autodiscovery(
|
|
125
|
-
id=_cover.id,
|
|
126
|
-
name=_cover.name,
|
|
127
|
-
ha_type=COVER,
|
|
128
|
-
device_class=_config.get(DEVICE_CLASS),
|
|
129
|
-
area=_config.get("area"),
|
|
130
|
-
availability_msg_func=availability_msg_func,
|
|
113
|
+
new_platform = _config.get("platform", "previous")
|
|
114
|
+
|
|
115
|
+
# Check if platform (cover type) changed - need to recreate cover
|
|
116
|
+
current_kind = _cover.kind
|
|
117
|
+
new_kind = "venetian" if new_platform == "venetian" else ("time" if new_platform == "time_based" else "previous")
|
|
118
|
+
|
|
119
|
+
if current_kind != new_kind:
|
|
120
|
+
# Platform changed - remove old cover and create new one
|
|
121
|
+
_LOGGER.info(
|
|
122
|
+
"Cover %s platform changed from %s to %s, recreating cover",
|
|
123
|
+
_id, current_kind, new_kind
|
|
131
124
|
)
|
|
132
|
-
|
|
125
|
+
# Remove old HA autodiscovery
|
|
126
|
+
self._remove_cover_ha_discovery(_id)
|
|
127
|
+
# Remove old cover from dict (will be recreated below)
|
|
128
|
+
del self._covers[_id]
|
|
129
|
+
else:
|
|
130
|
+
# Same platform - just update times and autodiscovery
|
|
131
|
+
_cover.update_config_times(_config)
|
|
132
|
+
# Re-send HA autodiscovery with potentially new area
|
|
133
|
+
if _config.get(SHOW_HA, True):
|
|
134
|
+
# Remove old autodiscovery first (in case area changed)
|
|
135
|
+
self._remove_cover_ha_discovery(_id)
|
|
136
|
+
# Send new autodiscovery
|
|
137
|
+
if new_platform == "venetian":
|
|
138
|
+
availability_msg_func = ha_cover_with_tilt_availabilty_message
|
|
139
|
+
else:
|
|
140
|
+
availability_msg_func = ha_cover_availabilty_message
|
|
141
|
+
self._manager.send_ha_autodiscovery(
|
|
142
|
+
id=_cover.id,
|
|
143
|
+
name=_cover.name,
|
|
144
|
+
ha_type=COVER,
|
|
145
|
+
device_class=_config.get(DEVICE_CLASS),
|
|
146
|
+
area=_config.get("area"),
|
|
147
|
+
availability_msg_func=availability_msg_func,
|
|
148
|
+
)
|
|
149
|
+
continue
|
|
133
150
|
|
|
134
151
|
self._covers[_id] = self._configure_cover(
|
|
135
152
|
cover_id=_id,
|
|
@@ -197,7 +214,7 @@ class CoverManager:
|
|
|
197
214
|
restored_state=restored_state,
|
|
198
215
|
tilt_duration=tilt_duration,
|
|
199
216
|
actuator_activation_duration=config.get("actuator_activation_duration", TimePeriod(milliseconds=0)),
|
|
200
|
-
**{k: v for k, v in config.items() if k not in ("platform", "actuator_activation_duration", RESTORE_STATE, SHOW_HA, DEVICE_CLASS, NAME)},
|
|
217
|
+
**{k: v for k, v in config.items() if k not in ("platform", "actuator_activation_duration", "tilt_duration", RESTORE_STATE, SHOW_HA, DEVICE_CLASS, NAME)},
|
|
201
218
|
)
|
|
202
219
|
availability_msg_func = ha_cover_with_tilt_availabilty_message
|
|
203
220
|
elif platform == "time_based":
|
|
@@ -365,19 +382,21 @@ class CoverManager:
|
|
|
365
382
|
This is called after reload to ensure frontend receives
|
|
366
383
|
the state of all covers, including newly created ones.
|
|
367
384
|
|
|
368
|
-
Handles both PreviousCover (
|
|
369
|
-
(send_state with state and
|
|
385
|
+
Handles both PreviousCover (send_state with no args) and BaseCover
|
|
386
|
+
(send_state with state and json_position args) implementations.
|
|
370
387
|
"""
|
|
388
|
+
from boneio.components.cover import PreviousCover, TimeBasedCover, VenetianCover
|
|
389
|
+
|
|
371
390
|
for cover in self._covers.values():
|
|
372
391
|
try:
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
392
|
+
if isinstance(cover, PreviousCover):
|
|
393
|
+
# PreviousCover.send_state() takes no arguments
|
|
394
|
+
cover.send_state()
|
|
395
|
+
elif isinstance(cover, (TimeBasedCover, VenetianCover)):
|
|
396
|
+
# BaseCover.send_state(state, json_position) takes 2 arguments
|
|
378
397
|
cover.send_state(cover.state, cover.json_position)
|
|
379
398
|
except Exception as e:
|
|
380
|
-
_LOGGER.debug(
|
|
399
|
+
_LOGGER.debug("Error broadcasting cover state %s: %s", cover.id, e)
|
|
381
400
|
|
|
382
401
|
async def send_ha_autodiscovery(self) -> None:
|
|
383
402
|
"""Send Home Assistant autodiscovery for all covers."""
|
|
@@ -9,6 +9,7 @@ This module manages all input devices including:
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
import asyncio
|
|
12
|
+
import json
|
|
12
13
|
import logging
|
|
13
14
|
from typing import TYPE_CHECKING, Callable
|
|
14
15
|
|
|
@@ -22,6 +23,8 @@ from boneio.const import (
|
|
|
22
23
|
INPUT,
|
|
23
24
|
INPUT_SENSOR,
|
|
24
25
|
PIN,
|
|
26
|
+
PRESSED,
|
|
27
|
+
RELEASED,
|
|
25
28
|
SHOW_HA,
|
|
26
29
|
)
|
|
27
30
|
from boneio.exceptions import GPIOInputException
|
|
@@ -524,6 +527,50 @@ class InputManager:
|
|
|
524
527
|
# Remove from internal cache
|
|
525
528
|
self._manager._config_helper.remove_autodiscovery_msg(ha_type, topic)
|
|
526
529
|
|
|
530
|
+
def _publish_input_event_to_mqtt(
|
|
531
|
+
self, input_instance: GpioBaseClass, event: InputEvent
|
|
532
|
+
) -> None:
|
|
533
|
+
"""Publish input event to MQTT for Home Assistant.
|
|
534
|
+
|
|
535
|
+
For event buttons (input_type=INPUT): sends JSON with event_type
|
|
536
|
+
For binary sensors (input_type=INPUT_SENSOR): sends pressed/released state
|
|
537
|
+
|
|
538
|
+
Args:
|
|
539
|
+
input_instance: The input device instance
|
|
540
|
+
event: The input event data
|
|
541
|
+
"""
|
|
542
|
+
topic_prefix = self._manager._config_helper.topic_prefix
|
|
543
|
+
input_id = input_instance.id
|
|
544
|
+
input_type = input_instance.input_type
|
|
545
|
+
click_type = event.click_type
|
|
546
|
+
topic = f"{topic_prefix}/input/{input_id}"
|
|
547
|
+
|
|
548
|
+
if input_type == INPUT:
|
|
549
|
+
event_payload: dict[str, str | float | None] = {"event_type": click_type}
|
|
550
|
+
if event.duration is not None:
|
|
551
|
+
event_payload["duration"] = round(event.duration, 3)
|
|
552
|
+
|
|
553
|
+
self._manager.send_message(
|
|
554
|
+
topic=topic,
|
|
555
|
+
payload=json.dumps(event_payload),
|
|
556
|
+
)
|
|
557
|
+
_LOGGER.debug(
|
|
558
|
+
"Published event to MQTT: topic=%s, payload=%s",
|
|
559
|
+
topic, event_payload
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
elif input_type == INPUT_SENSOR:
|
|
563
|
+
payload = str(click_type) # "pressed" or "released"
|
|
564
|
+
|
|
565
|
+
self._manager.send_message(
|
|
566
|
+
topic=topic,
|
|
567
|
+
payload=payload,
|
|
568
|
+
)
|
|
569
|
+
_LOGGER.debug(
|
|
570
|
+
"Published binary sensor state to MQTT: topic=%s, payload=%s",
|
|
571
|
+
topic, payload
|
|
572
|
+
)
|
|
573
|
+
|
|
527
574
|
async def handle_input_event(self, event: InputEvent) -> None:
|
|
528
575
|
"""Handle input event from EventBus.
|
|
529
576
|
|
|
@@ -557,6 +604,9 @@ class InputManager:
|
|
|
557
604
|
len(actions)
|
|
558
605
|
)
|
|
559
606
|
|
|
607
|
+
# Send event to MQTT for Home Assistant
|
|
608
|
+
self._publish_input_event_to_mqtt(input_instance, event)
|
|
609
|
+
|
|
560
610
|
# Execute actions for this input event
|
|
561
611
|
if actions:
|
|
562
612
|
await self._manager.execute_actions(actions=actions)
|
|
@@ -7,6 +7,8 @@ This implementation is output-only for relay control.
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
import logging
|
|
10
|
+
import threading
|
|
11
|
+
import time
|
|
10
12
|
from typing import TYPE_CHECKING
|
|
11
13
|
|
|
12
14
|
if TYPE_CHECKING:
|
|
@@ -22,6 +24,10 @@ GPIOB = 0x13 # GPIO register for port B
|
|
|
22
24
|
OLATA = 0x14 # Output latch register for port A
|
|
23
25
|
OLATB = 0x15 # Output latch register for port B
|
|
24
26
|
|
|
27
|
+
# Minimum delay between I2C operations in seconds
|
|
28
|
+
# This prevents bus contention when switching multiple outputs rapidly
|
|
29
|
+
I2C_OPERATION_DELAY = 0.002 # 2ms
|
|
30
|
+
|
|
25
31
|
|
|
26
32
|
class MCP23017:
|
|
27
33
|
"""MCP23017 16-bit I2C GPIO expander driver.
|
|
@@ -54,10 +60,17 @@ class MCP23017:
|
|
|
54
60
|
self._i2c = i2c
|
|
55
61
|
self._address = address
|
|
56
62
|
|
|
63
|
+
# Lock for thread-safe pin operations
|
|
64
|
+
# This prevents race conditions when multiple outputs are switched simultaneously
|
|
65
|
+
self._lock = threading.Lock()
|
|
66
|
+
|
|
57
67
|
# Track output states (16 pins, 2 bytes)
|
|
58
68
|
self._port_a_state = 0x00 # Pins 0-7
|
|
59
69
|
self._port_b_state = 0x00 # Pins 8-15
|
|
60
70
|
|
|
71
|
+
# Timestamp of last I2C operation for rate limiting
|
|
72
|
+
self._last_operation_time = 0.0
|
|
73
|
+
|
|
61
74
|
# Lock the I2C bus for initialization
|
|
62
75
|
if not self._i2c.try_lock():
|
|
63
76
|
raise RuntimeError("Failed to lock I2C bus for MCP23017 initialization")
|
|
@@ -130,25 +143,36 @@ class MCP23017:
|
|
|
130
143
|
def _write_pin(self, pin_number: int, value: bool) -> None:
|
|
131
144
|
"""Write value to a pin.
|
|
132
145
|
|
|
146
|
+
Thread-safe operation with rate limiting to prevent I2C bus contention.
|
|
147
|
+
|
|
133
148
|
Args:
|
|
134
149
|
pin_number: Pin number (0-15)
|
|
135
150
|
value: Output state (True=HIGH, False=LOW)
|
|
136
151
|
"""
|
|
137
|
-
|
|
138
|
-
#
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
152
|
+
with self._lock:
|
|
153
|
+
# Rate limiting: ensure minimum delay between I2C operations
|
|
154
|
+
now = time.monotonic()
|
|
155
|
+
elapsed = now - self._last_operation_time
|
|
156
|
+
if elapsed < I2C_OPERATION_DELAY:
|
|
157
|
+
time.sleep(I2C_OPERATION_DELAY - elapsed)
|
|
158
|
+
|
|
159
|
+
if pin_number < 8:
|
|
160
|
+
# Port A (pins 0-7)
|
|
161
|
+
if value:
|
|
162
|
+
self._port_a_state |= (1 << pin_number) # Set bit
|
|
163
|
+
else:
|
|
164
|
+
self._port_a_state &= ~(1 << pin_number) # Clear bit
|
|
165
|
+
self._write_register(OLATA, self._port_a_state)
|
|
149
166
|
else:
|
|
150
|
-
|
|
151
|
-
|
|
167
|
+
# Port B (pins 8-15)
|
|
168
|
+
pin_bit = pin_number - 8
|
|
169
|
+
if value:
|
|
170
|
+
self._port_b_state |= (1 << pin_bit) # Set bit
|
|
171
|
+
else:
|
|
172
|
+
self._port_b_state &= ~(1 << pin_bit) # Clear bit
|
|
173
|
+
self._write_register(OLATB, self._port_b_state)
|
|
174
|
+
|
|
175
|
+
self._last_operation_time = time.monotonic()
|
|
152
176
|
|
|
153
177
|
def configure_pin_as_output(self, pin_number: int, value: bool = False) -> None:
|
|
154
178
|
"""Configure a pin as output and set initial value.
|
|
@@ -28,6 +28,7 @@ Each channel has 4 registers:
|
|
|
28
28
|
from __future__ import annotations
|
|
29
29
|
|
|
30
30
|
import logging
|
|
31
|
+
import threading
|
|
31
32
|
import time
|
|
32
33
|
from typing import TYPE_CHECKING
|
|
33
34
|
|
|
@@ -36,6 +37,10 @@ if TYPE_CHECKING:
|
|
|
36
37
|
|
|
37
38
|
_LOGGER = logging.getLogger(__name__)
|
|
38
39
|
|
|
40
|
+
# Minimum delay between I2C operations in seconds
|
|
41
|
+
# This prevents bus contention when switching multiple outputs rapidly
|
|
42
|
+
I2C_OPERATION_DELAY = 0.002 # 2ms
|
|
43
|
+
|
|
39
44
|
# Register addresses
|
|
40
45
|
MODE1 = 0x00
|
|
41
46
|
MODE2 = 0x01
|
|
@@ -188,6 +193,13 @@ class PCA9685:
|
|
|
188
193
|
self._address = address
|
|
189
194
|
self._reference_clock_speed = reference_clock_speed
|
|
190
195
|
|
|
196
|
+
# Lock for thread-safe channel operations
|
|
197
|
+
# This prevents race conditions when multiple outputs are switched simultaneously
|
|
198
|
+
self._lock = threading.Lock()
|
|
199
|
+
|
|
200
|
+
# Timestamp of last I2C operation for rate limiting
|
|
201
|
+
self._last_operation_time = 0.0
|
|
202
|
+
|
|
191
203
|
# Initialize channels container
|
|
192
204
|
self.channels = PCAChannels(self)
|
|
193
205
|
|
|
@@ -267,6 +279,8 @@ class PCA9685:
|
|
|
267
279
|
def _write_channel(self, channel: int, value: int) -> None:
|
|
268
280
|
"""Write PWM value to a channel (0-4095).
|
|
269
281
|
|
|
282
|
+
Thread-safe operation with rate limiting to prevent I2C bus contention.
|
|
283
|
+
|
|
270
284
|
Args:
|
|
271
285
|
channel: Channel number (0-15)
|
|
272
286
|
value: PWM value (0-4095, 12-bit)
|
|
@@ -277,52 +291,61 @@ class PCA9685:
|
|
|
277
291
|
if not 0 <= value <= 4095:
|
|
278
292
|
raise ValueError(f"PWM value must be 0-4095, got {value}")
|
|
279
293
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
#
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
294
|
+
with self._lock:
|
|
295
|
+
# Rate limiting: ensure minimum delay between I2C operations
|
|
296
|
+
now = time.monotonic()
|
|
297
|
+
elapsed = now - self._last_operation_time
|
|
298
|
+
if elapsed < I2C_OPERATION_DELAY:
|
|
299
|
+
time.sleep(I2C_OPERATION_DELAY - elapsed)
|
|
300
|
+
|
|
301
|
+
# Calculate register addresses for this channel
|
|
302
|
+
# Each channel has 4 registers: ON_L, ON_H, OFF_L, OFF_H
|
|
303
|
+
base_reg = LED0_ON_L + (channel * 4)
|
|
304
|
+
|
|
305
|
+
# For normal PWM:
|
|
306
|
+
# - ON time = 0 (start at beginning of cycle)
|
|
307
|
+
# - OFF time = value (turn off at specified point)
|
|
308
|
+
on_time = 0
|
|
309
|
+
off_time = value
|
|
310
|
+
|
|
311
|
+
# Special case: full off (value = 0)
|
|
312
|
+
if value == 0:
|
|
313
|
+
# Set bit 12 of OFF time to turn LED fully off
|
|
314
|
+
off_time = 0x1000
|
|
315
|
+
# Special case: full on (value = 4095)
|
|
316
|
+
elif value == 4095:
|
|
317
|
+
# Set bit 12 of ON time to turn LED fully on
|
|
318
|
+
on_time = 0x1000
|
|
319
|
+
off_time = 0
|
|
320
|
+
|
|
321
|
+
# Write 4 bytes: ON_L, ON_H, OFF_L, OFF_H
|
|
322
|
+
data = [
|
|
323
|
+
on_time & 0xFF, # ON_L
|
|
324
|
+
(on_time >> 8) & 0xFF, # ON_H
|
|
325
|
+
off_time & 0xFF, # OFF_L
|
|
326
|
+
(off_time >> 8) & 0xFF, # OFF_H
|
|
327
|
+
]
|
|
328
|
+
|
|
329
|
+
try:
|
|
330
|
+
self._i2c.write_i2c_block_data(self._address, base_reg, data)
|
|
331
|
+
_LOGGER.debug(
|
|
332
|
+
"PCA9685 0x%02X: Channel %d set to %d (ON=0x%04X, OFF=0x%04X)",
|
|
333
|
+
self._address,
|
|
334
|
+
channel,
|
|
335
|
+
value,
|
|
336
|
+
on_time,
|
|
337
|
+
off_time,
|
|
338
|
+
)
|
|
339
|
+
except Exception as e:
|
|
340
|
+
_LOGGER.error(
|
|
341
|
+
"Failed to write channel %d on PCA9685 at 0x%02X: %s",
|
|
342
|
+
channel,
|
|
343
|
+
self._address,
|
|
344
|
+
e,
|
|
345
|
+
)
|
|
346
|
+
raise
|
|
347
|
+
|
|
348
|
+
self._last_operation_time = time.monotonic()
|
|
326
349
|
|
|
327
350
|
def _read_channel(self, channel: int) -> int:
|
|
328
351
|
"""Read PWM value from a channel (0-4095).
|
|
@@ -22,6 +22,8 @@ For BoneIO, we use PCF8575 primarily for output (relay control).
|
|
|
22
22
|
from __future__ import annotations
|
|
23
23
|
|
|
24
24
|
import logging
|
|
25
|
+
import threading
|
|
26
|
+
import time
|
|
25
27
|
from typing import TYPE_CHECKING
|
|
26
28
|
|
|
27
29
|
if TYPE_CHECKING:
|
|
@@ -29,6 +31,10 @@ if TYPE_CHECKING:
|
|
|
29
31
|
|
|
30
32
|
_LOGGER = logging.getLogger(__name__)
|
|
31
33
|
|
|
34
|
+
# Minimum delay between I2C operations in seconds
|
|
35
|
+
# This prevents bus contention when switching multiple outputs rapidly
|
|
36
|
+
I2C_OPERATION_DELAY = 0.002 # 2ms
|
|
37
|
+
|
|
32
38
|
|
|
33
39
|
class PCF8575:
|
|
34
40
|
"""PCF8575 16-bit I2C GPIO expander.
|
|
@@ -61,11 +67,18 @@ class PCF8575:
|
|
|
61
67
|
self._i2c = i2c
|
|
62
68
|
self._address = address
|
|
63
69
|
|
|
70
|
+
# Lock for thread-safe pin operations
|
|
71
|
+
# This prevents race conditions when multiple outputs are switched simultaneously
|
|
72
|
+
self._lock = threading.Lock()
|
|
73
|
+
|
|
64
74
|
# State tracking for all 16 pins (2 bytes)
|
|
65
75
|
# Bit = 1: HIGH (output) or input with pull-up
|
|
66
76
|
# Bit = 0: LOW (output)
|
|
67
77
|
self._state = 0xFFFF # All pins HIGH (default state)
|
|
68
78
|
|
|
79
|
+
# Timestamp of last I2C operation for rate limiting
|
|
80
|
+
self._last_operation_time = 0.0
|
|
81
|
+
|
|
69
82
|
# Initialize device - write default state
|
|
70
83
|
self._write_state()
|
|
71
84
|
|
|
@@ -202,28 +215,48 @@ class PCF8575:
|
|
|
202
215
|
def _set_pin_output(self, pin: int, value: bool) -> None:
|
|
203
216
|
"""Set a pin to output mode with specified value.
|
|
204
217
|
|
|
218
|
+
Thread-safe operation with rate limiting to prevent I2C bus contention.
|
|
219
|
+
|
|
205
220
|
Args:
|
|
206
221
|
pin: Pin number (0-15)
|
|
207
222
|
value: Output value (True=HIGH, False=LOW)
|
|
208
223
|
"""
|
|
209
|
-
|
|
210
|
-
#
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
224
|
+
with self._lock:
|
|
225
|
+
# Rate limiting: ensure minimum delay between I2C operations
|
|
226
|
+
now = time.monotonic()
|
|
227
|
+
elapsed = now - self._last_operation_time
|
|
228
|
+
if elapsed < I2C_OPERATION_DELAY:
|
|
229
|
+
time.sleep(I2C_OPERATION_DELAY - elapsed)
|
|
230
|
+
|
|
231
|
+
if value:
|
|
232
|
+
# Set bit to 1 (HIGH)
|
|
233
|
+
self._state |= (1 << pin)
|
|
234
|
+
else:
|
|
235
|
+
# Clear bit to 0 (LOW)
|
|
236
|
+
self._state &= ~(1 << pin)
|
|
237
|
+
|
|
238
|
+
self._write_state()
|
|
239
|
+
self._last_operation_time = time.monotonic()
|
|
217
240
|
|
|
218
241
|
def _set_pin_input(self, pin: int) -> None:
|
|
219
242
|
"""Set a pin to input mode (enables pull-up).
|
|
220
243
|
|
|
244
|
+
Thread-safe operation with rate limiting.
|
|
245
|
+
|
|
221
246
|
Args:
|
|
222
247
|
pin: Pin number (0-15)
|
|
223
248
|
"""
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
249
|
+
with self._lock:
|
|
250
|
+
# Rate limiting: ensure minimum delay between I2C operations
|
|
251
|
+
now = time.monotonic()
|
|
252
|
+
elapsed = now - self._last_operation_time
|
|
253
|
+
if elapsed < I2C_OPERATION_DELAY:
|
|
254
|
+
time.sleep(I2C_OPERATION_DELAY - elapsed)
|
|
255
|
+
|
|
256
|
+
# Set bit to 1 to enable pull-up for input
|
|
257
|
+
self._state |= (1 << pin)
|
|
258
|
+
self._write_state()
|
|
259
|
+
self._last_operation_time = time.monotonic()
|
|
227
260
|
|
|
228
261
|
def _read_pin(self, pin: int) -> bool:
|
|
229
262
|
"""Read the current value of a pin.
|
|
@@ -428,7 +428,7 @@ class ModbusCoordinator(BasicMqtt, AsyncUpdater, Filter):
|
|
|
428
428
|
"""
|
|
429
429
|
return self._additional_entities_by_name.get(name)
|
|
430
430
|
|
|
431
|
-
def find_entity(self, entity_id: str) ->
|
|
431
|
+
def find_entity(self, entity_id: str) -> ModbusEntity | DerivedEntity | ModbusDerivedNumericSensor | ModbusDerivedTextSensor | ModbusDerivedSelect | ModbusDerivedSwitch | None:
|
|
432
432
|
"""Find entity by ID or decoded name in both regular and additional entities.
|
|
433
433
|
|
|
434
434
|
Args:
|