boneio 1.0.0.dev6__tar.gz → 1.0.0.dev7__tar.gz

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