boneio 1.0.0.dev7__tar.gz → 1.0.0.dev8__tar.gz

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