boneIO 1.1.1.dev1__tar.gz → 1.2.0.dev1__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.1.1.dev1/boneio.egg-info → boneio-1.2.0.dev1}/PKG-INFO +1 -1
- boneio-1.2.0.dev1/boneio/core/cloud/__init__.py +5 -0
- boneio-1.2.0.dev1/boneio/core/cloud/data/init-certs-cloud.sh +154 -0
- boneio-1.2.0.dev1/boneio/core/cloud/registration.py +454 -0
- boneio-1.2.0.dev1/boneio/core/cloud/secrets.py +56 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/config/config_helper.py +32 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/config/yaml_util.py +96 -0
- boneio-1.2.0.dev1/boneio/example_config/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/runner.py +27 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/schema/schema.yaml +30 -0
- boneio-1.2.0.dev1/boneio/version.py +2 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/app.py +74 -5
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/cssMode-SLqjH3qK.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/cssMode-CiCRy8oh.js +1 -1
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/freemarker2-DXMvZO7c.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/freemarker2-CTpscDup.js +1 -1
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/handlebars-DldmTvGn.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/handlebars-CT6ctFwd.js +1 -1
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/html-BeFUXNc_.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/html-De15ux6k.js +1 -1
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/htmlMode-D4OnYTmf.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/htmlMode-DEBxJqOc.js +1 -1
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/index-AE1j15fF.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/index-BmBRIx27.js +212 -212
- boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/index-jeVCQb5d.css +1 -0
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/javascript-tD5AV0w8.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/javascript-DLPEXty3.js +1 -1
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/jsonMode-D8KZNSNi.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/jsonMode-Bq6LVq6M.js +1 -1
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/liquid-B4w537sW.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/liquid-CyAziv-e.js +1 -1
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/mdx-DB1izvJl.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/mdx-rdvLT30i.js +1 -1
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/python-CG6dl7EF.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/python-IsDchUF3.js +1 -1
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/razor-BqVac-Wv.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/razor-Dqhz4KTK.js +1 -1
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/tsMode-CvBEEAxI.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/tsMode-BPlRYnYg.js +1 -1
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/typescript-BIvQiQJr.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/typescript-gTU2cHDi.js +1 -1
- boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/workbox-window.prod.es5-vqzQaGvo.js +2 -0
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/xml-BtFDS-MH.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/xml-BhXsIMpb.js +1 -1
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/yaml-D0Bwrhp9.js → boneio-1.2.0.dev1/boneio/webui/frontend-dist/assets/yaml-BA6LfVaz.js +1 -1
- boneio-1.2.0.dev1/boneio/webui/frontend-dist/boneio-192.png +0 -0
- boneio-1.2.0.dev1/boneio/webui/frontend-dist/boneio-512.png +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/index.html +9 -2
- {boneio-1.1.1.dev1/boneio/webui/schema → boneio-1.2.0.dev1/boneio/webui/frontend-dist/schem}/adc.schema.json +2 -2
- {boneio-1.1.1.dev1/boneio/webui/schema → boneio-1.2.0.dev1/boneio/webui/frontend-dist/schem}/binary_sensor.schema.json +22 -22
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/boneio.schema.json +2 -2
- {boneio-1.1.1.dev1/boneio/webui/schema → boneio-1.2.0.dev1/boneio/webui/frontend-dist/schem}/config.schema.json +236 -194
- {boneio-1.1.1.dev1/boneio/webui/schema → boneio-1.2.0.dev1/boneio/webui/frontend-dist/schem}/cover.schema.json +8 -8
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/event.schema.json +78 -78
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/ina219.schema.json +4 -4
- {boneio-1.1.1.dev1/boneio/webui/schema → boneio-1.2.0.dev1/boneio/webui/frontend-dist/schem}/lm75.schema.json +4 -4
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/mcp23017.schema.json +4 -4
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/mcp9808.schema.json +4 -4
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/modbus.schema.json +6 -6
- {boneio-1.1.1.dev1/boneio/webui/schema → boneio-1.2.0.dev1/boneio/webui/frontend-dist/schem}/modbus_devices.schema.json +8 -8
- {boneio-1.1.1.dev1/boneio/webui/schema → boneio-1.2.0.dev1/boneio/webui/frontend-dist/schem}/mqtt.schema.json +2 -2
- {boneio-1.1.1.dev1/boneio/webui/schema → boneio-1.2.0.dev1/boneio/webui/frontend-dist/schem}/oled.schema.json +2 -2
- {boneio-1.1.1.dev1/boneio/webui/schema → boneio-1.2.0.dev1/boneio/webui/frontend-dist/schem}/output.schema.json +8 -8
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/pca9685.schema.json +4 -4
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/pcf8575.schema.json +4 -4
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/remote_devices.schema.json +26 -26
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/sensor.schema.json +2 -2
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/web.schema.json +46 -4
- boneio-1.2.0.dev1/boneio/webui/frontend-dist/sw.js +1 -0
- boneio-1.2.0.dev1/boneio/webui/frontend-dist/workbox-226dbdbf.js +1 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/routes/system.py +92 -1
- {boneio-1.1.1.dev1/boneio/webui/frontend-dist/schem → boneio-1.2.0.dev1/boneio/webui/schema}/adc.schema.json +2 -2
- {boneio-1.1.1.dev1/boneio/webui/frontend-dist/schem → boneio-1.2.0.dev1/boneio/webui/schema}/binary_sensor.schema.json +22 -22
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/boneio.schema.json +2 -2
- {boneio-1.1.1.dev1/boneio/webui/frontend-dist/schem → boneio-1.2.0.dev1/boneio/webui/schema}/config.schema.json +236 -194
- {boneio-1.1.1.dev1/boneio/webui/frontend-dist/schem → boneio-1.2.0.dev1/boneio/webui/schema}/cover.schema.json +8 -8
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/event.schema.json +78 -78
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/ina219.schema.json +4 -4
- {boneio-1.1.1.dev1/boneio/webui/frontend-dist/schem → boneio-1.2.0.dev1/boneio/webui/schema}/lm75.schema.json +4 -4
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/mcp23017.schema.json +4 -4
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/mcp9808.schema.json +4 -4
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/modbus.schema.json +6 -6
- {boneio-1.1.1.dev1/boneio/webui/frontend-dist/schem → boneio-1.2.0.dev1/boneio/webui/schema}/modbus_devices.schema.json +8 -8
- {boneio-1.1.1.dev1/boneio/webui/frontend-dist/schem → boneio-1.2.0.dev1/boneio/webui/schema}/mqtt.schema.json +2 -2
- {boneio-1.1.1.dev1/boneio/webui/frontend-dist/schem → boneio-1.2.0.dev1/boneio/webui/schema}/oled.schema.json +2 -2
- {boneio-1.1.1.dev1/boneio/webui/frontend-dist/schem → boneio-1.2.0.dev1/boneio/webui/schema}/output.schema.json +8 -8
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/pca9685.schema.json +4 -4
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/pcf8575.schema.json +4 -4
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/remote_devices.schema.json +26 -26
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/sensor.schema.json +2 -2
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/web.schema.json +46 -4
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1/boneio.egg-info}/PKG-INFO +1 -1
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio.egg-info/SOURCES.txt +27 -17
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/pyproject.toml +1 -1
- boneio-1.1.1.dev1/boneio/version.py +0 -2
- boneio-1.1.1.dev1/boneio/webui/frontend-dist/assets/index-D0XGmf2O.css +0 -1
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/LICENSE +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/MANIFEST.in +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/README.md +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.2/input.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.2/output_24_16.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.2/output_32_10.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.2/output_32_5.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.2/output_cover.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.2/output_cover_mix.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.3/input.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.3/output_24_16.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.3/output_32_10.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.3/output_32_5.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.3/output_cover.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.3/output_cover_mix.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.4/input.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.4/output_24_16.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.4/output_32_10.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.4/output_32_5.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.4/output_cover.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.4/output_cover_mix.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.5/input.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.5/output_24_16.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.5/output_32_10.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.5/output_cover.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.5/output_cover_mix.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.6/input.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.6/output_24_16.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.6/output_32_10.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.6/output_cover.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.6/output_cover_mix.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.7/input.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.7/output_24_16.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.7/output_32_10.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.7/output_cover.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.7/output_cover_mix.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.8/input.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.8/output_24_16.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.8/output_32_10.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.8/output_cover.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/boards/0.8/output_cover_mix.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/bonecli.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/cover/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/cover/cover.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/cover/previous.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/cover/time_based.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/cover/venetian.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/group/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/group/output_group.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/input/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/input/binary_sensor.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/input/detectors.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/input/event.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/output/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/output/basic.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/output/mcp.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/output/pca.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/output/pcf.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/sensor/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/components/sensor/virtual_energy.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/const.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/__init__.py +0 -0
- {boneio-1.1.1.dev1/boneio/example_config → boneio-1.2.0.dev1/boneio/core/cloud/data}/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/config/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/config/package-lock.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/config/package.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/config/schema_converter.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/discovery.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/events/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/events/bus.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/manager/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/manager/covers.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/manager/display.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/manager/inputs.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/manager/manager.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/manager/modbus.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/manager/outputs.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/manager/remote.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/manager/sensors.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/manager/update.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/messaging/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/messaging/basic.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/messaging/basic_mqtt.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/messaging/local.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/messaging/mqtt.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/messaging/queue.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/remote/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/remote/base.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/remote/esphome.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/remote/mqtt.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/remote/wled.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/sensor/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/sensor/base.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/sensor/system.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/state/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/state/manager.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/system/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/system/host_data.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/system/monitor.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/utils/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/utils/async_updater.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/utils/filter.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/utils/font_util.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/utils/logger.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/utils/timeperiod.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/core/utils/util.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/24x16/adc.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/24x16/binary_sensor.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/24x16/config.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/24x16/event.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/24x16/mqtt.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/24x16/output24x16A.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/32x10/adc.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/32x10/binary_sensor.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/32x10/config.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/32x10/event.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/32x10/mqtt.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/32x10/output32x10A.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/cover/adc.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/cover/binary_sensor.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/cover/config.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/cover/cover.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/cover/event.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/cover/mqtt.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/cover/outputCover.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/cover_mix/adc.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/cover_mix/binary_sensor.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/cover_mix/config.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/cover_mix/cover.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/cover_mix/event.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/cover_mix/mqtt.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/cover_mix/outputCoverMix.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/different_configs/adc.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/different_configs/all_binary_sensor.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/different_configs/binary_sensor.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/different_configs/binary_sensor_v_0_7.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/different_configs/config_24_16.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/different_configs/event_all.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/different_configs/event_v_0_7.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/different_configs/led32x4A.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/different_configs/output24x16A.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/different_configs/output24x16A_v0.3.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/different_configs/output32x10A.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/example_config/different_configs/output32x5A.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/exceptions.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/analog/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/analog/adc.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/display/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/display/fonts/danube__.ttf +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/display/oled.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/gpio/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/gpio/expanders/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/gpio/expanders/mcp23017.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/gpio/expanders/pca9685.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/gpio/expanders/pcf8575.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/gpio/input/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/gpio/input/base.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/gpio/input/manager.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/i2c/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/i2c/bus.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/i2c/ina219.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/i2c/ina219_driver.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/i2c/mcp9808.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/i2c/pct2075.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/onewire/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/onewire/bus.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/onewire/dallas.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/onewire/ds2482.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/sensor/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/sensor/temperature/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/sensor/temperature/base.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/sensor/temperature/mcp9808.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/hardware/sensor/temperature/pct2075.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/integration/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/integration/homeassistant.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/integration/interlock.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/cli.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/client.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/coordinator.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/energy_meters/le-03mw.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/energy_meters/le-03mwct.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/energy_meters/orno-or-we-517.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/energy_meters/sdm120.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/energy_meters/sdm630.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/energy_meters/socomec_e03.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/energy_meters/socomec_e23.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/hvac/fujitsu-ac.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/hvac/ventclear.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/inverters/sofar.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/inverters/thessla.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/other/n4dsc08.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/other/r4dcb08.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/other/wanas415.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/sensors/cwt.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/sensors/dts1964_3f.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/sensors/dyp-a12-ultrasonic.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/sensors/liquid-sensor.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/sensors/pt100.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/sensors/sht20.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/devices/sensors/sht30.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/entities/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/entities/base.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/entities/derived/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/entities/derived/numeric.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/entities/derived/select.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/entities/derived/switch.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/entities/derived/text.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/entities/sensor/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/entities/sensor/binary.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/entities/sensor/numeric.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/entities/sensor/text.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/entities/writeable/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/entities/writeable/binary.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/entities/writeable/numeric.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/modbus/utils.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/models/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/models/actions.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/models/events.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/models/files.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/models/logs.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/models/mqtt.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/models/state.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/schema/actions.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/schema/actions_sensor.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/schema/actions_switch.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/schema/filters.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/schema/filters_adc.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/schema/id.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/schema/remote_devices.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/schema/temp_unit.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/schema/update_interval.yaml +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/abap-CRCWOmpq.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/apex-DnsZk_dE.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/azcli-1IWB1ccx.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/bat-DPkNLes8.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/bicep-Corcdgou.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/cameligo-CGrWLZr3.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/clojure-D9WOWImG.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/codicon-DCmgc-ay.ttf +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/coffee-B7EJu28W.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/cpp-SEyurbux.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/csharp-BoL64M5l.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/csp-C46ZqvIl.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/css-DQU6DXDx.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/cypher-D84EuPTj.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/dart-D8lhlL1r.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/dockerfile-DLk6rpji.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/ecl-BO6FnfXk.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/editor.worker-DsAeyiJ5.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/elixir-BRjLKONM.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/flow9-Cac8vKd7.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/fsharp-fd1GTHhf.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/go-O9LJTZXk.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/graphql-LQdxqEYJ.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/hcl-DxDQ3s82.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/ini-BvajGCUy.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/java-SYsfObOQ.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/json.worker-DaRII17c.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/julia-DQXNmw_w.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/kotlin-qQ0MG-9I.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/less-GGFNNJHn.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/lexon-Canl7DCW.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/lua-D28Ae8-K.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/m3-DPitgjJI.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/markdown-B811l8j2.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/mips-CdjsipkG.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/msdax-CYqgjx_P.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/mysql-BHd6q0vd.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/objective-c-B1aVtJYH.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/pascal-BhNW15KB.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/pascaligo-5jv8CcQD.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/perl-DlYyT36c.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/pgsql-Dy0bjov7.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/php-120yhfDK.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/pla-CjnFlu4u.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/postiats-CQpG440k.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/powerquery-DdJtto1Z.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/powershell-Bu_VLpJB.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/protobuf-IBS6jZEB.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/pug-kFxLfcjb.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/qsharp-q7JyzKFN.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/r-BIFz-_sK.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/redis-CHOsPHWR.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/redshift-CBifECDb.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/restructuredtext-CghPJEOS.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/ruby-CYWGW-b1.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/rust-DMDD0SHb.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/sb-BYAiYHFx.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/scala-Bqvq8jcR.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/scheme-Dhb-2j9p.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/scss-CTwUZ5N7.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/shell-CsDZo4DB.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/solidity-CME5AdoB.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/sophia-RYC1BQQz.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/sparql-KEyrF7De.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/sql-BdTr02Mf.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/st-C7iG7M4S.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/swift-D7IUmUK8.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/systemverilog-DgMryOEJ.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/tcl-PloMZuKG.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/twig-BfRIq3la.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/typespec-CzxlYoT_.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/vb-BwAE3J76.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/wgsl-B_1kOXbF.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/assets/yaml.worker-BTE-_K6g.js +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/boneio.svg +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/boneio_fav.svg +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/areas.schema.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/dallas.schema.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/ds2482.schema.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/logger.schema.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/output_group.schema.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/frontend-dist/schem/virtual_energy_sensor.schema.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/middleware/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/middleware/auth.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/routes/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/routes/auth.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/routes/caddy.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/routes/config.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/routes/covers.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/routes/modbus.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/routes/outputs.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/routes/remote_devices.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/routes/sensors.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/routes/update.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/areas.schema.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/dallas.schema.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/ds2482.schema.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/logger.schema.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/output_group.schema.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/schema/virtual_energy_sensor.schema.json +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/services/__init__.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/services/logs.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/web_server.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio/webui/websocket_manager.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio.egg-info/dependency_links.txt +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio.egg-info/entry_points.txt +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio.egg-info/requires.txt +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/boneio.egg-info/top_level.txt +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/setup.cfg +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/setup.py +0 -0
- {boneio-1.1.1.dev1 → boneio-1.2.0.dev1}/tests/test_py313_compatibility.py +0 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Script for Caddy with cloud wildcard SSL certificate (PWA mode)
|
|
3
|
+
# This version adds a *.black.boneio.app HTTPS block using the wildcard cert
|
|
4
|
+
# downloaded by boneIO Cloud Registration.
|
|
5
|
+
#
|
|
6
|
+
# Used when cloud_registration is enabled in boneio config.
|
|
7
|
+
# Falls back to self-signed cert for hostname-based access.
|
|
8
|
+
|
|
9
|
+
HOSTNAME_FILE="/data/last_hostname"
|
|
10
|
+
CURRENT_HOSTNAME="${HOST_HOSTNAME:-$(cat /etc/host_hostname 2>/dev/null || hostname)}"
|
|
11
|
+
|
|
12
|
+
echo "Current hostname: $CURRENT_HOSTNAME"
|
|
13
|
+
echo "Cloud mode: wildcard SSL cert for *.black.boneio.app"
|
|
14
|
+
|
|
15
|
+
# Check if hostname changed (for self-signed cert regeneration)
|
|
16
|
+
if [ -f "$HOSTNAME_FILE" ]; then
|
|
17
|
+
LAST_HOSTNAME=$(cat "$HOSTNAME_FILE")
|
|
18
|
+
if [ "$LAST_HOSTNAME" != "$CURRENT_HOSTNAME" ]; then
|
|
19
|
+
echo "Hostname changed from $LAST_HOSTNAME to $CURRENT_HOSTNAME"
|
|
20
|
+
echo "Removing old self-signed certificates..."
|
|
21
|
+
rm -rf /data/caddy/certificates/local/*
|
|
22
|
+
rm -rf /data/caddy/pki/*
|
|
23
|
+
rm -rf /config/caddy/*
|
|
24
|
+
fi
|
|
25
|
+
else
|
|
26
|
+
echo "First run on this device, clearing any existing certificates..."
|
|
27
|
+
rm -rf /data/caddy/certificates/local/*
|
|
28
|
+
rm -rf /data/caddy/pki/*
|
|
29
|
+
rm -rf /config/caddy/*
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
echo "$CURRENT_HOSTNAME" > "$HOSTNAME_FILE"
|
|
33
|
+
|
|
34
|
+
# Check if wildcard cert exists
|
|
35
|
+
if [ -f "/data/ssl/fullchain.pem" ] && [ -f "/data/ssl/privkey.pem" ]; then
|
|
36
|
+
echo "Wildcard SSL certificate found, enabling PWA HTTPS block"
|
|
37
|
+
CLOUD_BLOCK="
|
|
38
|
+
# HTTPS with wildcard cert for PWA (*.black.boneio.app)
|
|
39
|
+
*.black.boneio.app {
|
|
40
|
+
tls /data/ssl/fullchain.pem /data/ssl/privkey.pem
|
|
41
|
+
|
|
42
|
+
handle_errors {
|
|
43
|
+
@502-504 expression {err.status_code} >= 502 && {err.status_code} <= 504
|
|
44
|
+
handle @502-504 {
|
|
45
|
+
root * /srv
|
|
46
|
+
rewrite * /502.html
|
|
47
|
+
file_server
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
handle /nodered-status {
|
|
52
|
+
header Content-Type application/json
|
|
53
|
+
header X-NodeRed-Available \"true\"
|
|
54
|
+
header Access-Control-Expose-Headers \"X-NodeRed-Available\"
|
|
55
|
+
respond \`{\"available\": true}\` 200
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
handle /nodered/* {
|
|
59
|
+
reverse_proxy node-red:1880 {
|
|
60
|
+
header_up X-Forwarded-Proto {scheme}
|
|
61
|
+
header_down X-NodeRed-Available \"true\"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
handle {
|
|
66
|
+
reverse_proxy host.docker.internal:8090 {
|
|
67
|
+
header_up X-Forwarded-Proto {scheme}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
"
|
|
72
|
+
else
|
|
73
|
+
echo "WARNING: Wildcard SSL certificate not found at /data/ssl/"
|
|
74
|
+
echo "PWA HTTPS block will not be enabled until certificate is downloaded"
|
|
75
|
+
CLOUD_BLOCK=""
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Generate Caddyfile
|
|
79
|
+
cat > /tmp/Caddyfile << EOF
|
|
80
|
+
{
|
|
81
|
+
# Global options
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# HTTP - serve directly
|
|
85
|
+
:80 {
|
|
86
|
+
handle_errors {
|
|
87
|
+
@502-504 expression {err.status_code} >= 502 && {err.status_code} <= 504
|
|
88
|
+
handle @502-504 {
|
|
89
|
+
root * /srv
|
|
90
|
+
rewrite * /502.html
|
|
91
|
+
file_server
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
handle /nodered-status {
|
|
96
|
+
header Content-Type application/json
|
|
97
|
+
header X-NodeRed-Available "true"
|
|
98
|
+
header Access-Control-Expose-Headers "X-NodeRed-Available"
|
|
99
|
+
respond \`{"available": true}\` 200
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
handle /nodered/* {
|
|
103
|
+
reverse_proxy node-red:1880 {
|
|
104
|
+
header_up X-Forwarded-Proto {scheme}
|
|
105
|
+
header_down X-NodeRed-Available "true"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
handle {
|
|
110
|
+
reverse_proxy host.docker.internal:8090 {
|
|
111
|
+
header_up X-Forwarded-Proto {scheme}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
# HTTPS with hostname-based self-signed certificate (always available)
|
|
117
|
+
https://, ${CURRENT_HOSTNAME} {
|
|
118
|
+
tls internal
|
|
119
|
+
|
|
120
|
+
handle_errors {
|
|
121
|
+
@502-504 expression {err.status_code} >= 502 && {err.status_code} <= 504
|
|
122
|
+
handle @502-504 {
|
|
123
|
+
root * /srv
|
|
124
|
+
rewrite * /502.html
|
|
125
|
+
file_server
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
handle /nodered-status {
|
|
130
|
+
header Content-Type application/json
|
|
131
|
+
header X-NodeRed-Available "true"
|
|
132
|
+
header Access-Control-Expose-Headers "X-NodeRed-Available"
|
|
133
|
+
respond \`{"available": true}\` 200
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
handle /nodered/* {
|
|
137
|
+
reverse_proxy node-red:1880 {
|
|
138
|
+
header_up X-Forwarded-Proto {scheme}
|
|
139
|
+
header_down X-NodeRed-Available "true"
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
handle {
|
|
144
|
+
reverse_proxy host.docker.internal:8090 {
|
|
145
|
+
header_up X-Forwarded-Proto {scheme}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
${CLOUD_BLOCK}
|
|
151
|
+
EOF
|
|
152
|
+
|
|
153
|
+
# Start Caddy with generated config
|
|
154
|
+
exec caddy run --config /tmp/Caddyfile --adapter caddyfile
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cloud registration module for boneIO Black.
|
|
3
|
+
|
|
4
|
+
Handles DNS registration with boneIO Cloud API and SSL certificate management
|
|
5
|
+
for PWA support with custom subdomains.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import base64
|
|
10
|
+
import hashlib
|
|
11
|
+
import hmac
|
|
12
|
+
import logging
|
|
13
|
+
import os
|
|
14
|
+
import shutil
|
|
15
|
+
import subprocess
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Optional
|
|
18
|
+
|
|
19
|
+
import aiohttp
|
|
20
|
+
|
|
21
|
+
from boneio.core.cloud.secrets import MASTER_SECRET as DEFAULT_MASTER_SECRET
|
|
22
|
+
|
|
23
|
+
_LOGGER = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
# Cloud API configuration
|
|
26
|
+
CLOUD_API_URL = "https://api.boneio.app"
|
|
27
|
+
|
|
28
|
+
# SSL certificate paths (relative to home dir, writable by boneio app)
|
|
29
|
+
_DOCKER_DIR = Path.home() / "docker" / "nodered"
|
|
30
|
+
CERT_DIR = _DOCKER_DIR / "caddy" / "ssl"
|
|
31
|
+
CERT_FILE = CERT_DIR / "fullchain.pem"
|
|
32
|
+
KEY_FILE = CERT_DIR / "privkey.pem"
|
|
33
|
+
|
|
34
|
+
# Caddy configuration paths
|
|
35
|
+
CADDY_CONFIG_DIR = _DOCKER_DIR / "caddy"
|
|
36
|
+
CADDY_DEFAULT_CONFIG = CADDY_CONFIG_DIR / "Caddyfile"
|
|
37
|
+
CADDY_CLOUD_CONFIG = CADDY_CONFIG_DIR / "Caddyfile.cloud"
|
|
38
|
+
CADDY_ACTIVE_CONFIG = CADDY_CONFIG_DIR / "Caddyfile"
|
|
39
|
+
|
|
40
|
+
# Registration interval (1 hour)
|
|
41
|
+
REGISTRATION_INTERVAL = 3600
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class CloudRegistration:
|
|
45
|
+
"""
|
|
46
|
+
Manages cloud registration for boneIO Black devices.
|
|
47
|
+
|
|
48
|
+
Registers device DNS with cloud API and downloads SSL certificates
|
|
49
|
+
for PWA support.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def __init__(
|
|
53
|
+
self,
|
|
54
|
+
serial_number: str,
|
|
55
|
+
local_ip: str,
|
|
56
|
+
master_secret: str = DEFAULT_MASTER_SECRET,
|
|
57
|
+
enabled: bool = True,
|
|
58
|
+
) -> None:
|
|
59
|
+
"""
|
|
60
|
+
Initialize cloud registration.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
serial_number: Device serial number (e.g., 'blkf8dc18')
|
|
64
|
+
local_ip: Local IP address of the device
|
|
65
|
+
master_secret: Shared secret for HMAC device authentication.
|
|
66
|
+
Defaults to the build-time injected secret from secrets.py.
|
|
67
|
+
enabled: Whether cloud registration is enabled
|
|
68
|
+
"""
|
|
69
|
+
self._serial = serial_number
|
|
70
|
+
self._local_ip = local_ip
|
|
71
|
+
self._master_secret = master_secret
|
|
72
|
+
self._enabled = enabled
|
|
73
|
+
self._domain: Optional[str] = None
|
|
74
|
+
self._task: Optional[asyncio.Task] = None
|
|
75
|
+
self._session: Optional[aiohttp.ClientSession] = None
|
|
76
|
+
self._last_error: Optional[str] = None
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def domain(self) -> Optional[str]:
|
|
80
|
+
"""Get the registered domain name."""
|
|
81
|
+
return self._domain
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def enabled(self) -> bool:
|
|
85
|
+
"""Check if cloud registration is enabled."""
|
|
86
|
+
return self._enabled
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def last_error(self) -> Optional[str]:
|
|
90
|
+
"""Get the last error message, if any."""
|
|
91
|
+
return self._last_error
|
|
92
|
+
|
|
93
|
+
async def start(self) -> None:
|
|
94
|
+
"""Start the cloud registration service."""
|
|
95
|
+
if not self._enabled:
|
|
96
|
+
_LOGGER.info("Cloud registration is disabled")
|
|
97
|
+
return
|
|
98
|
+
|
|
99
|
+
_LOGGER.info("Starting cloud registration for %s", self._serial)
|
|
100
|
+
_LOGGER.debug(
|
|
101
|
+
"Master secret starts with: '%s...' (len=%d)",
|
|
102
|
+
self._master_secret[:4] if self._master_secret else "NONE",
|
|
103
|
+
len(self._master_secret) if self._master_secret else 0,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Create SSL directory if it doesn't exist
|
|
107
|
+
CERT_DIR.mkdir(parents=True, exist_ok=True)
|
|
108
|
+
|
|
109
|
+
# Start registration loop
|
|
110
|
+
self._task = asyncio.create_task(self._registration_loop())
|
|
111
|
+
|
|
112
|
+
async def stop(self) -> None:
|
|
113
|
+
"""Stop the cloud registration service."""
|
|
114
|
+
if self._task:
|
|
115
|
+
self._task.cancel()
|
|
116
|
+
try:
|
|
117
|
+
await self._task
|
|
118
|
+
except asyncio.CancelledError:
|
|
119
|
+
pass
|
|
120
|
+
self._task = None
|
|
121
|
+
|
|
122
|
+
if self._session:
|
|
123
|
+
await self._session.close()
|
|
124
|
+
self._session = None
|
|
125
|
+
|
|
126
|
+
def _compute_token(self) -> str:
|
|
127
|
+
"""Compute HMAC-SHA256 auth token from master secret and serial.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Hex-encoded HMAC token string
|
|
131
|
+
"""
|
|
132
|
+
return hmac.new(
|
|
133
|
+
self._master_secret.encode(),
|
|
134
|
+
self._serial.encode(),
|
|
135
|
+
hashlib.sha256,
|
|
136
|
+
).hexdigest()
|
|
137
|
+
|
|
138
|
+
def _auth_headers(self) -> dict[str, str]:
|
|
139
|
+
"""Get authorization headers for cloud API requests.
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Dict with Authorization header
|
|
143
|
+
"""
|
|
144
|
+
return {"Authorization": f"Bearer {self._compute_token()}"}
|
|
145
|
+
|
|
146
|
+
async def _get_session(self) -> aiohttp.ClientSession:
|
|
147
|
+
"""Get or create aiohttp session."""
|
|
148
|
+
if self._session is None or self._session.closed:
|
|
149
|
+
self._session = aiohttp.ClientSession(
|
|
150
|
+
timeout=aiohttp.ClientTimeout(total=30)
|
|
151
|
+
)
|
|
152
|
+
return self._session
|
|
153
|
+
|
|
154
|
+
async def _registration_loop(self) -> None:
|
|
155
|
+
"""Main registration loop - registers DNS and fetches cert periodically."""
|
|
156
|
+
while True:
|
|
157
|
+
try:
|
|
158
|
+
# Register DNS
|
|
159
|
+
success = await self._register_dns()
|
|
160
|
+
if success:
|
|
161
|
+
_LOGGER.info("DNS registration successful: %s", self._domain)
|
|
162
|
+
|
|
163
|
+
# Fetch certificate if not present or needs refresh
|
|
164
|
+
if not self._cert_exists() or await self._cert_needs_refresh():
|
|
165
|
+
cert_fetched = await self._fetch_certificate()
|
|
166
|
+
|
|
167
|
+
# Switch to cloud Caddy config if cert was fetched and not already active
|
|
168
|
+
if cert_fetched and not self.is_cloud_config_active():
|
|
169
|
+
_LOGGER.info("Switching Caddy to cloud configuration...")
|
|
170
|
+
await self._switch_to_cloud_config()
|
|
171
|
+
else:
|
|
172
|
+
_LOGGER.warning("DNS registration failed, will retry")
|
|
173
|
+
|
|
174
|
+
except asyncio.CancelledError:
|
|
175
|
+
raise
|
|
176
|
+
except Exception as e:
|
|
177
|
+
_LOGGER.error("Cloud registration error: %s", e)
|
|
178
|
+
|
|
179
|
+
# Wait before next registration
|
|
180
|
+
await asyncio.sleep(REGISTRATION_INTERVAL)
|
|
181
|
+
|
|
182
|
+
async def _register_dns(self) -> bool:
|
|
183
|
+
"""
|
|
184
|
+
Register device DNS with cloud API.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
True if registration was successful
|
|
188
|
+
"""
|
|
189
|
+
try:
|
|
190
|
+
session = await self._get_session()
|
|
191
|
+
|
|
192
|
+
payload = {
|
|
193
|
+
"serial": self._serial,
|
|
194
|
+
"ip": self._local_ip,
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async with session.post(
|
|
198
|
+
f"{CLOUD_API_URL}/register",
|
|
199
|
+
json=payload,
|
|
200
|
+
headers=self._auth_headers(),
|
|
201
|
+
) as response:
|
|
202
|
+
if response.status == 200:
|
|
203
|
+
data = await response.json()
|
|
204
|
+
self._domain = data.get("domain")
|
|
205
|
+
return True
|
|
206
|
+
elif response.status == 429:
|
|
207
|
+
# Rate limited - wait longer
|
|
208
|
+
data = await response.json()
|
|
209
|
+
retry_after = data.get("retryAfter", 3600)
|
|
210
|
+
_LOGGER.warning(
|
|
211
|
+
"Rate limited, retry after %d seconds", retry_after
|
|
212
|
+
)
|
|
213
|
+
return False
|
|
214
|
+
else:
|
|
215
|
+
body = await response.text()
|
|
216
|
+
_LOGGER.error(
|
|
217
|
+
"DNS registration failed (HTTP %d): %s",
|
|
218
|
+
response.status,
|
|
219
|
+
body,
|
|
220
|
+
)
|
|
221
|
+
return False
|
|
222
|
+
|
|
223
|
+
except aiohttp.ClientError as e:
|
|
224
|
+
_LOGGER.error("Failed to connect to cloud API: %s", e)
|
|
225
|
+
return False
|
|
226
|
+
|
|
227
|
+
async def _fetch_certificate(self) -> bool:
|
|
228
|
+
"""
|
|
229
|
+
Fetch SSL certificate from cloud API.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
True if certificate was fetched successfully
|
|
233
|
+
"""
|
|
234
|
+
try:
|
|
235
|
+
session = await self._get_session()
|
|
236
|
+
|
|
237
|
+
async with session.get(
|
|
238
|
+
f"{CLOUD_API_URL}/cert",
|
|
239
|
+
params={"serial": self._serial},
|
|
240
|
+
headers=self._auth_headers(),
|
|
241
|
+
) as response:
|
|
242
|
+
if response.status == 200:
|
|
243
|
+
data = await response.json()
|
|
244
|
+
|
|
245
|
+
# Decode and save certificate
|
|
246
|
+
cert_data = base64.b64decode(data["cert"])
|
|
247
|
+
key_data = base64.b64decode(data["key"])
|
|
248
|
+
|
|
249
|
+
CERT_FILE.write_bytes(cert_data)
|
|
250
|
+
KEY_FILE.write_bytes(key_data)
|
|
251
|
+
|
|
252
|
+
# Set proper permissions for key file
|
|
253
|
+
os.chmod(KEY_FILE, 0o600)
|
|
254
|
+
|
|
255
|
+
_LOGGER.info(
|
|
256
|
+
"SSL certificate saved, expires: %s",
|
|
257
|
+
data.get("expiresAt", "unknown")
|
|
258
|
+
)
|
|
259
|
+
return True
|
|
260
|
+
elif response.status == 503:
|
|
261
|
+
_LOGGER.warning("Certificate not yet available from cloud")
|
|
262
|
+
return False
|
|
263
|
+
else:
|
|
264
|
+
_LOGGER.error("Failed to fetch certificate: %d", response.status)
|
|
265
|
+
return False
|
|
266
|
+
|
|
267
|
+
except aiohttp.ClientError as e:
|
|
268
|
+
_LOGGER.error("Failed to fetch certificate: %s", e)
|
|
269
|
+
return False
|
|
270
|
+
except Exception as e:
|
|
271
|
+
_LOGGER.error("Error saving certificate: %s", e)
|
|
272
|
+
return False
|
|
273
|
+
|
|
274
|
+
def _cert_exists(self) -> bool:
|
|
275
|
+
"""Check if certificate files exist."""
|
|
276
|
+
return CERT_FILE.exists() and KEY_FILE.exists()
|
|
277
|
+
|
|
278
|
+
async def _cert_needs_refresh(self) -> bool:
|
|
279
|
+
"""
|
|
280
|
+
Check if certificate needs to be refreshed.
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
True if cert is older than 30 days or doesn't exist
|
|
284
|
+
"""
|
|
285
|
+
if not self._cert_exists():
|
|
286
|
+
return True
|
|
287
|
+
|
|
288
|
+
try:
|
|
289
|
+
# Check cert file age
|
|
290
|
+
import time
|
|
291
|
+
cert_age = time.time() - CERT_FILE.stat().st_mtime
|
|
292
|
+
# Refresh if older than 30 days
|
|
293
|
+
return cert_age > (30 * 24 * 3600)
|
|
294
|
+
except Exception:
|
|
295
|
+
return True
|
|
296
|
+
|
|
297
|
+
def update_ip(self, new_ip: str) -> None:
|
|
298
|
+
"""
|
|
299
|
+
Update local IP address.
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
new_ip: New local IP address
|
|
303
|
+
"""
|
|
304
|
+
if new_ip != self._local_ip:
|
|
305
|
+
_LOGGER.info("Local IP changed: %s -> %s", self._local_ip, new_ip)
|
|
306
|
+
self._local_ip = new_ip
|
|
307
|
+
|
|
308
|
+
def _ensure_cloud_script(self) -> None:
|
|
309
|
+
"""
|
|
310
|
+
Copy init-certs-cloud.sh from package data to the Caddy config directory.
|
|
311
|
+
|
|
312
|
+
This ensures the script is always up-to-date after a pip upgrade,
|
|
313
|
+
even if the user never re-clones the full repo.
|
|
314
|
+
"""
|
|
315
|
+
dest = CADDY_CONFIG_DIR / "init-certs-cloud.sh"
|
|
316
|
+
try:
|
|
317
|
+
from importlib.resources import files
|
|
318
|
+
|
|
319
|
+
src = files("boneio.core.cloud.data").joinpath("init-certs-cloud.sh")
|
|
320
|
+
src_bytes = src.read_bytes()
|
|
321
|
+
|
|
322
|
+
# Only write if content differs or file missing
|
|
323
|
+
if not dest.exists() or dest.read_bytes() != src_bytes:
|
|
324
|
+
dest.write_bytes(src_bytes)
|
|
325
|
+
dest.chmod(0o755)
|
|
326
|
+
_LOGGER.info("Deployed init-certs-cloud.sh to %s", dest)
|
|
327
|
+
except Exception as e:
|
|
328
|
+
_LOGGER.warning("Could not deploy init-certs-cloud.sh: %s", e)
|
|
329
|
+
|
|
330
|
+
async def _switch_to_cloud_config(self) -> bool:
|
|
331
|
+
"""
|
|
332
|
+
Switch Caddy to cloud mode by updating docker-compose.yaml.
|
|
333
|
+
|
|
334
|
+
Changes:
|
|
335
|
+
- Deploys init-certs-cloud.sh from package to caddy dir
|
|
336
|
+
- Swaps init-certs.sh for init-certs-cloud.sh in docker-compose
|
|
337
|
+
- Adds SSL volume mount for wildcard certificate
|
|
338
|
+
- Recreates Caddy container with new config
|
|
339
|
+
|
|
340
|
+
Returns:
|
|
341
|
+
True if switch was successful
|
|
342
|
+
"""
|
|
343
|
+
# Ensure cloud script is deployed from package
|
|
344
|
+
self._ensure_cloud_script()
|
|
345
|
+
|
|
346
|
+
compose_file = _DOCKER_DIR / "docker-compose.yaml"
|
|
347
|
+
try:
|
|
348
|
+
if not compose_file.exists():
|
|
349
|
+
_LOGGER.error("docker-compose.yaml not found: %s", compose_file)
|
|
350
|
+
return False
|
|
351
|
+
|
|
352
|
+
content = compose_file.read_text()
|
|
353
|
+
|
|
354
|
+
# Already switched?
|
|
355
|
+
if "init-certs-cloud.sh" in content:
|
|
356
|
+
_LOGGER.debug("Cloud config already active in docker-compose.yaml")
|
|
357
|
+
return await self._recreate_caddy()
|
|
358
|
+
|
|
359
|
+
# Swap init-certs.sh -> init-certs-cloud.sh
|
|
360
|
+
if "init-certs.sh" not in content:
|
|
361
|
+
_LOGGER.error("init-certs.sh not found in docker-compose.yaml")
|
|
362
|
+
return False
|
|
363
|
+
|
|
364
|
+
# Backup original
|
|
365
|
+
backup = compose_file.with_suffix(".yaml.bak")
|
|
366
|
+
if not backup.exists():
|
|
367
|
+
shutil.copy2(compose_file, backup)
|
|
368
|
+
_LOGGER.info("Backed up docker-compose.yaml to %s", backup)
|
|
369
|
+
|
|
370
|
+
new_content = content.replace("init-certs.sh", "init-certs-cloud.sh")
|
|
371
|
+
|
|
372
|
+
# Add SSL volume if not present
|
|
373
|
+
if "./caddy/ssl:/data/ssl:ro" not in new_content:
|
|
374
|
+
new_content = new_content.replace(
|
|
375
|
+
" - /etc/hostname:/etc/host_hostname:ro",
|
|
376
|
+
" - /etc/hostname:/etc/host_hostname:ro\n"
|
|
377
|
+
" - ./caddy/ssl:/data/ssl:ro",
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
compose_file.write_text(new_content)
|
|
381
|
+
_LOGGER.info("Updated docker-compose.yaml for cloud mode")
|
|
382
|
+
|
|
383
|
+
return await self._recreate_caddy()
|
|
384
|
+
|
|
385
|
+
except PermissionError as e:
|
|
386
|
+
compose_path = str(compose_file)
|
|
387
|
+
self._last_error = (
|
|
388
|
+
f"Permission denied writing {compose_path}. "
|
|
389
|
+
f"Run via SSH: sudo chown $USER {compose_path}"
|
|
390
|
+
)
|
|
391
|
+
_LOGGER.error(
|
|
392
|
+
"Permission denied for %s. Fix with: sudo chown $USER %s",
|
|
393
|
+
compose_path,
|
|
394
|
+
compose_path,
|
|
395
|
+
)
|
|
396
|
+
return False
|
|
397
|
+
except Exception as e:
|
|
398
|
+
self._last_error = str(e)
|
|
399
|
+
_LOGGER.error("Failed to switch to cloud config: %s", e)
|
|
400
|
+
return False
|
|
401
|
+
|
|
402
|
+
async def _recreate_caddy(self) -> bool:
|
|
403
|
+
"""
|
|
404
|
+
Recreate Caddy container to apply new docker-compose config.
|
|
405
|
+
|
|
406
|
+
Uses 'docker compose up -d caddy' to pick up volume and entrypoint changes.
|
|
407
|
+
|
|
408
|
+
Returns:
|
|
409
|
+
True if recreate was successful
|
|
410
|
+
"""
|
|
411
|
+
compose_dir = str(_DOCKER_DIR)
|
|
412
|
+
try:
|
|
413
|
+
result = await asyncio.get_event_loop().run_in_executor(
|
|
414
|
+
None,
|
|
415
|
+
lambda: subprocess.run(
|
|
416
|
+
["docker", "compose", "up", "-d", "caddy"],
|
|
417
|
+
cwd=compose_dir,
|
|
418
|
+
capture_output=True,
|
|
419
|
+
timeout=60,
|
|
420
|
+
)
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
if result.returncode == 0:
|
|
424
|
+
_LOGGER.info("Caddy container recreated successfully")
|
|
425
|
+
return True
|
|
426
|
+
else:
|
|
427
|
+
_LOGGER.error(
|
|
428
|
+
"Failed to recreate Caddy: %s",
|
|
429
|
+
result.stderr.decode() if result.stderr else "Unknown error"
|
|
430
|
+
)
|
|
431
|
+
return False
|
|
432
|
+
|
|
433
|
+
except subprocess.TimeoutExpired:
|
|
434
|
+
_LOGGER.error("Caddy recreate timed out")
|
|
435
|
+
return False
|
|
436
|
+
except Exception as e:
|
|
437
|
+
_LOGGER.error("Failed to recreate Caddy: %s", e)
|
|
438
|
+
return False
|
|
439
|
+
|
|
440
|
+
def is_cloud_config_active(self) -> bool:
|
|
441
|
+
"""
|
|
442
|
+
Check if cloud init-certs script is active in docker-compose.
|
|
443
|
+
|
|
444
|
+
Returns:
|
|
445
|
+
True if cloud config is active
|
|
446
|
+
"""
|
|
447
|
+
try:
|
|
448
|
+
compose_file = _DOCKER_DIR / "docker-compose.yaml"
|
|
449
|
+
if not compose_file.exists():
|
|
450
|
+
return False
|
|
451
|
+
content = compose_file.read_text()
|
|
452
|
+
return "init-certs-cloud.sh" in content
|
|
453
|
+
except Exception:
|
|
454
|
+
return False
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cloud API secrets for boneIO Black.
|
|
3
|
+
|
|
4
|
+
The MASTER_SECRET is resolved in this order:
|
|
5
|
+
1. Environment variable BONEIO_MASTER_SECRET (already set in shell/systemd)
|
|
6
|
+
2. BONEIO_MASTER_SECRET from .env file in working directory or /home/boneio/
|
|
7
|
+
3. Build-time injected value (replaced by GitHub Actions during PyPI build)
|
|
8
|
+
|
|
9
|
+
For local development, set BONEIO_MASTER_SECRET in your .env file or shell.
|
|
10
|
+
DO NOT commit real secrets to this file.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
# This placeholder is replaced by GitHub Actions during build.
|
|
17
|
+
# See .github/workflows/publish-to-pypi.yaml
|
|
18
|
+
_BUILD_SECRET = "cd75f3bab398cf8a245e627a94bda915580eba8b6eddeb4a76b95a286ea2e8b5"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _load_env_secret() -> str:
|
|
22
|
+
"""Load BONEIO_MASTER_SECRET from environment or .env file.
|
|
23
|
+
|
|
24
|
+
Checks environment first, then looks for .env file in common locations.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
The master secret string (may be placeholder if not configured).
|
|
28
|
+
"""
|
|
29
|
+
# 1. Already in environment?
|
|
30
|
+
env_val = os.environ.get("BONEIO_MASTER_SECRET")
|
|
31
|
+
if env_val:
|
|
32
|
+
return env_val
|
|
33
|
+
|
|
34
|
+
# 2. Try .env files
|
|
35
|
+
env_paths = [
|
|
36
|
+
Path.cwd() / ".env",
|
|
37
|
+
Path.home() / ".env",
|
|
38
|
+
]
|
|
39
|
+
for env_path in env_paths:
|
|
40
|
+
if env_path.is_file():
|
|
41
|
+
try:
|
|
42
|
+
for line in env_path.read_text().splitlines():
|
|
43
|
+
line = line.strip()
|
|
44
|
+
if line.startswith("#") or "=" not in line:
|
|
45
|
+
continue
|
|
46
|
+
key, _, value = line.partition("=")
|
|
47
|
+
if key.strip() == "BONEIO_MASTER_SECRET":
|
|
48
|
+
return value.strip().strip("'\"")
|
|
49
|
+
except OSError:
|
|
50
|
+
continue
|
|
51
|
+
|
|
52
|
+
# 3. Fallback to build-time placeholder
|
|
53
|
+
return _BUILD_SECRET
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
MASTER_SECRET = _load_env_secret()
|