boneIO 1.2.0.dev6__tar.gz → 1.2.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 (433) hide show
  1. {boneio-1.2.0.dev6/boneio.egg-info → boneio-1.2.0.dev8}/PKG-INFO +1 -1
  2. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/input/detectors.py +14 -2
  3. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/manager/manager.py +69 -14
  4. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/manager/remote.py +106 -6
  5. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/manager/update.py +268 -6
  6. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/messaging/mqtt.py +8 -6
  7. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/remote/esphome.py +8 -0
  8. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/remote/wled.py +7 -6
  9. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/integration/homeassistant.py +1 -1
  10. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/schema/actions.yaml +35 -11
  11. boneio-1.2.0.dev8/boneio/version.py +2 -0
  12. boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/cssMode-xo2BdOZm.js +4 -0
  13. boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/editor.worker-B4pQIWZD.js +12 -0
  14. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/freemarker2-cdPkYRmQ.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/freemarker2-CpF78_ZW.js +1 -1
  15. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/handlebars-Cfxm9RW_.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/handlebars-CTxt7dmO.js +1 -1
  16. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/html-BHdohU2S.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/html-BU5yZ3BK.js +1 -1
  17. boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/htmlMode-Bi7QBmdE.js +4 -0
  18. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/index-BmuRpNYW.css → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/index-CyjBlAI7.css +1 -1
  19. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/index-B_8cgKDq.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/index-TnEo7N0a.js +245 -245
  20. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/javascript-cpZp1UNX.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/javascript-BTvyG1P5.js +1 -1
  21. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/json.worker-DaRII17c.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/json.worker-aFakAbRR.js +22 -22
  22. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/jsonMode-B0FgVMkj.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/jsonMode-HE9dW4cx.js +1 -1
  23. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/liquid-Z_DgQ0VL.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/liquid-BxuGpv1s.js +1 -1
  24. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/mdx-B8hjkANT.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/mdx-C04Q98IR.js +1 -1
  25. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/python-B-sOgkv5.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/python-CKNUIQdp.js +1 -1
  26. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/razor-32kHacmJ.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/razor-UrUJyAuF.js +1 -1
  27. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/tsMode-B4q7c15W.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/tsMode-AhPw7VFe.js +1 -1
  28. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/typescript-C5K4aTtA.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/typescript-CLXQgPoF.js +1 -1
  29. boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/workbox-window.prod.es5-BIl4cyR9.js +2 -0
  30. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/xml-BR1__-Hi.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/xml-DZmKn2me.js +1 -1
  31. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/yaml-Bp8ZLmkj.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/yaml-CGKDqmHX.js +1 -1
  32. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/yaml.worker-BTE-_K6g.js → boneio-1.2.0.dev8/boneio/webui/frontend-dist/assets/yaml.worker-DBeHcBRc.js +200 -200
  33. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/index.html +2 -2
  34. {boneio-1.2.0.dev6/boneio/webui/schema → boneio-1.2.0.dev8/boneio/webui/frontend-dist/schem}/adc.schema.json +8 -8
  35. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/areas.schema.json +4 -4
  36. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/binary_sensor.schema.json +90 -52
  37. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/boneio.schema.json +2 -2
  38. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/config.schema.json +616 -445
  39. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/cover.schema.json +4 -4
  40. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/ds2482.schema.json +4 -4
  41. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/event.schema.json +302 -169
  42. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/ina219.schema.json +14 -14
  43. {boneio-1.2.0.dev6/boneio/webui/schema → boneio-1.2.0.dev8/boneio/webui/frontend-dist/schem}/lm75.schema.json +10 -10
  44. {boneio-1.2.0.dev6/boneio/webui/schema → boneio-1.2.0.dev8/boneio/webui/frontend-dist/schem}/logger.schema.json +2 -2
  45. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/mcp23017.schema.json +6 -6
  46. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/mcp9808.schema.json +10 -10
  47. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/modbus.schema.json +8 -8
  48. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/modbus_devices.schema.json +22 -22
  49. {boneio-1.2.0.dev6/boneio/webui/schema → boneio-1.2.0.dev8/boneio/webui/frontend-dist/schem}/mqtt.schema.json +6 -6
  50. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/oled.schema.json +8 -8
  51. {boneio-1.2.0.dev6/boneio/webui/schema → boneio-1.2.0.dev8/boneio/webui/frontend-dist/schem}/output.schema.json +10 -10
  52. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/output_group.schema.json +6 -6
  53. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/pca9685.schema.json +6 -6
  54. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/pcf8575.schema.json +6 -6
  55. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/remote_devices.schema.json +64 -64
  56. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/sensor.schema.json +8 -8
  57. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/virtual_energy_sensor.schema.json +4 -4
  58. {boneio-1.2.0.dev6/boneio/webui/schema → boneio-1.2.0.dev8/boneio/webui/frontend-dist/schem}/web.schema.json +12 -12
  59. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/sw.js +1 -1
  60. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/routes/system.py +88 -14
  61. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/routes/update.py +44 -113
  62. {boneio-1.2.0.dev6/boneio/webui/frontend-dist/schem → boneio-1.2.0.dev8/boneio/webui/schema}/adc.schema.json +8 -8
  63. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/areas.schema.json +4 -4
  64. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/binary_sensor.schema.json +90 -52
  65. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/boneio.schema.json +2 -2
  66. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/config.schema.json +616 -445
  67. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/cover.schema.json +4 -4
  68. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/ds2482.schema.json +4 -4
  69. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/event.schema.json +302 -169
  70. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/ina219.schema.json +14 -14
  71. {boneio-1.2.0.dev6/boneio/webui/frontend-dist/schem → boneio-1.2.0.dev8/boneio/webui/schema}/lm75.schema.json +10 -10
  72. {boneio-1.2.0.dev6/boneio/webui/frontend-dist/schem → boneio-1.2.0.dev8/boneio/webui/schema}/logger.schema.json +2 -2
  73. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/mcp23017.schema.json +6 -6
  74. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/mcp9808.schema.json +10 -10
  75. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/modbus.schema.json +8 -8
  76. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/modbus_devices.schema.json +22 -22
  77. {boneio-1.2.0.dev6/boneio/webui/frontend-dist/schem → boneio-1.2.0.dev8/boneio/webui/schema}/mqtt.schema.json +6 -6
  78. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/oled.schema.json +8 -8
  79. {boneio-1.2.0.dev6/boneio/webui/frontend-dist/schem → boneio-1.2.0.dev8/boneio/webui/schema}/output.schema.json +10 -10
  80. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/output_group.schema.json +6 -6
  81. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/pca9685.schema.json +6 -6
  82. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/pcf8575.schema.json +6 -6
  83. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/remote_devices.schema.json +64 -64
  84. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/sensor.schema.json +8 -8
  85. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/virtual_energy_sensor.schema.json +4 -4
  86. {boneio-1.2.0.dev6/boneio/webui/frontend-dist/schem → boneio-1.2.0.dev8/boneio/webui/schema}/web.schema.json +12 -12
  87. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8/boneio.egg-info}/PKG-INFO +1 -1
  88. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio.egg-info/SOURCES.txt +21 -21
  89. boneio-1.2.0.dev6/boneio/version.py +0 -2
  90. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/cssMode-CvZwGOXM.js +0 -4
  91. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/editor.worker-DsAeyiJ5.js +0 -12
  92. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/htmlMode-D09isE-q.js +0 -4
  93. boneio-1.2.0.dev6/boneio/webui/frontend-dist/assets/workbox-window.prod.es5-vqzQaGvo.js +0 -2
  94. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/LICENSE +0 -0
  95. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/MANIFEST.in +0 -0
  96. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/README.md +0 -0
  97. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/__init__.py +0 -0
  98. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.2/input.yaml +0 -0
  99. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.2/output_24_16.yaml +0 -0
  100. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.2/output_32_10.yaml +0 -0
  101. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.2/output_32_5.yaml +0 -0
  102. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.2/output_cover.yaml +0 -0
  103. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.2/output_cover_mix.yaml +0 -0
  104. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.3/input.yaml +0 -0
  105. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.3/output_24_16.yaml +0 -0
  106. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.3/output_32_10.yaml +0 -0
  107. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.3/output_32_5.yaml +0 -0
  108. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.3/output_cover.yaml +0 -0
  109. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.3/output_cover_mix.yaml +0 -0
  110. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.4/input.yaml +0 -0
  111. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.4/output_24_16.yaml +0 -0
  112. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.4/output_32_10.yaml +0 -0
  113. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.4/output_32_5.yaml +0 -0
  114. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.4/output_cover.yaml +0 -0
  115. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.4/output_cover_mix.yaml +0 -0
  116. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.5/input.yaml +0 -0
  117. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.5/output_24_16.yaml +0 -0
  118. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.5/output_32_10.yaml +0 -0
  119. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.5/output_cover.yaml +0 -0
  120. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.5/output_cover_mix.yaml +0 -0
  121. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.6/input.yaml +0 -0
  122. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.6/output_24_16.yaml +0 -0
  123. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.6/output_32_10.yaml +0 -0
  124. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.6/output_cover.yaml +0 -0
  125. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.6/output_cover_mix.yaml +0 -0
  126. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.7/input.yaml +0 -0
  127. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.7/output_24_16.yaml +0 -0
  128. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.7/output_32_10.yaml +0 -0
  129. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.7/output_cover.yaml +0 -0
  130. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.7/output_cover_mix.yaml +0 -0
  131. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.8/input.yaml +0 -0
  132. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.8/output_24_16.yaml +0 -0
  133. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.8/output_32_10.yaml +0 -0
  134. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.8/output_cover.yaml +0 -0
  135. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/boards/0.8/output_cover_mix.yaml +0 -0
  136. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/bonecli.py +0 -0
  137. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/__init__.py +0 -0
  138. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/cover/__init__.py +0 -0
  139. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/cover/cover.py +0 -0
  140. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/cover/previous.py +0 -0
  141. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/cover/time_based.py +0 -0
  142. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/cover/venetian.py +0 -0
  143. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/group/__init__.py +0 -0
  144. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/group/output_group.py +0 -0
  145. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/input/__init__.py +0 -0
  146. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/input/binary_sensor.py +0 -0
  147. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/input/event.py +0 -0
  148. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/output/__init__.py +0 -0
  149. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/output/basic.py +0 -0
  150. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/output/mcp.py +0 -0
  151. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/output/pca.py +0 -0
  152. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/output/pcf.py +0 -0
  153. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/sensor/__init__.py +0 -0
  154. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/components/sensor/virtual_energy.py +0 -0
  155. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/const.py +0 -0
  156. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/__init__.py +0 -0
  157. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/cloud/__init__.py +0 -0
  158. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/cloud/data/__init__.py +0 -0
  159. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/cloud/data/docker-compose-cloud.yaml +0 -0
  160. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/cloud/data/docker-compose.yaml +0 -0
  161. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/cloud/data/init-certs-cloud.sh +0 -0
  162. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/cloud/registration.py +0 -0
  163. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/cloud/secrets.py +0 -0
  164. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/config/__init__.py +0 -0
  165. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/config/config_helper.py +0 -0
  166. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/config/package-lock.json +0 -0
  167. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/config/package.json +0 -0
  168. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/config/schema_converter.py +0 -0
  169. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/config/yaml_util.py +0 -0
  170. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/discovery.py +0 -0
  171. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/events/__init__.py +0 -0
  172. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/events/bus.py +0 -0
  173. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/manager/__init__.py +0 -0
  174. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/manager/covers.py +0 -0
  175. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/manager/display.py +0 -0
  176. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/manager/inputs.py +0 -0
  177. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/manager/modbus.py +0 -0
  178. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/manager/outputs.py +0 -0
  179. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/manager/sensors.py +0 -0
  180. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/messaging/__init__.py +0 -0
  181. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/messaging/basic.py +0 -0
  182. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/messaging/basic_mqtt.py +0 -0
  183. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/messaging/local.py +0 -0
  184. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/messaging/queue.py +0 -0
  185. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/remote/__init__.py +0 -0
  186. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/remote/base.py +0 -0
  187. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/remote/mqtt.py +0 -0
  188. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/sensor/__init__.py +0 -0
  189. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/sensor/base.py +0 -0
  190. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/sensor/system.py +0 -0
  191. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/state/__init__.py +0 -0
  192. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/state/manager.py +0 -0
  193. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/system/__init__.py +0 -0
  194. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/system/host_data.py +0 -0
  195. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/system/monitor.py +0 -0
  196. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/utils/__init__.py +0 -0
  197. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/utils/async_updater.py +0 -0
  198. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/utils/filter.py +0 -0
  199. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/utils/font_util.py +0 -0
  200. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/utils/logger.py +0 -0
  201. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/utils/timeperiod.py +0 -0
  202. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/core/utils/util.py +0 -0
  203. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/24x16/adc.yaml +0 -0
  204. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/24x16/binary_sensor.yaml +0 -0
  205. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/24x16/config.yaml +0 -0
  206. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/24x16/event.yaml +0 -0
  207. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/24x16/mqtt.yaml +0 -0
  208. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/24x16/output24x16A.yaml +0 -0
  209. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/32x10/adc.yaml +0 -0
  210. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/32x10/binary_sensor.yaml +0 -0
  211. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/32x10/config.yaml +0 -0
  212. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/32x10/event.yaml +0 -0
  213. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/32x10/mqtt.yaml +0 -0
  214. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/32x10/output32x10A.yaml +0 -0
  215. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/__init__.py +0 -0
  216. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/cover/adc.yaml +0 -0
  217. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/cover/binary_sensor.yaml +0 -0
  218. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/cover/config.yaml +0 -0
  219. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/cover/cover.yaml +0 -0
  220. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/cover/event.yaml +0 -0
  221. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/cover/mqtt.yaml +0 -0
  222. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/cover/outputCover.yaml +0 -0
  223. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/cover_mix/adc.yaml +0 -0
  224. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/cover_mix/binary_sensor.yaml +0 -0
  225. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/cover_mix/config.yaml +0 -0
  226. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/cover_mix/cover.yaml +0 -0
  227. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/cover_mix/event.yaml +0 -0
  228. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/cover_mix/mqtt.yaml +0 -0
  229. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/cover_mix/outputCoverMix.yaml +0 -0
  230. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/different_configs/adc.yaml +0 -0
  231. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/different_configs/all_binary_sensor.yaml +0 -0
  232. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/different_configs/binary_sensor.yaml +0 -0
  233. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/different_configs/binary_sensor_v_0_7.yaml +0 -0
  234. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/different_configs/config_24_16.yaml +0 -0
  235. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/different_configs/event_all.yaml +0 -0
  236. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/different_configs/event_v_0_7.yaml +0 -0
  237. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/different_configs/led32x4A.yaml +0 -0
  238. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/different_configs/output24x16A.yaml +0 -0
  239. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/different_configs/output24x16A_v0.3.yaml +0 -0
  240. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/different_configs/output32x10A.yaml +0 -0
  241. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/example_config/different_configs/output32x5A.yaml +0 -0
  242. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/exceptions.py +0 -0
  243. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/__init__.py +0 -0
  244. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/analog/__init__.py +0 -0
  245. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/analog/adc.py +0 -0
  246. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/display/__init__.py +0 -0
  247. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/display/fonts/danube__.ttf +0 -0
  248. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/display/oled.py +0 -0
  249. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/gpio/__init__.py +0 -0
  250. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/gpio/expanders/__init__.py +0 -0
  251. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/gpio/expanders/mcp23017.py +0 -0
  252. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/gpio/expanders/pca9685.py +0 -0
  253. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/gpio/expanders/pcf8575.py +0 -0
  254. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/gpio/input/__init__.py +0 -0
  255. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/gpio/input/base.py +0 -0
  256. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/gpio/input/manager.py +0 -0
  257. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/i2c/__init__.py +0 -0
  258. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/i2c/bus.py +0 -0
  259. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/i2c/ina219.py +0 -0
  260. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/i2c/ina219_driver.py +0 -0
  261. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/i2c/mcp9808.py +0 -0
  262. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/i2c/pct2075.py +0 -0
  263. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/onewire/__init__.py +0 -0
  264. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/onewire/bus.py +0 -0
  265. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/onewire/dallas.py +0 -0
  266. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/onewire/ds2482.py +0 -0
  267. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/sensor/__init__.py +0 -0
  268. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/sensor/temperature/__init__.py +0 -0
  269. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/sensor/temperature/base.py +0 -0
  270. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/sensor/temperature/mcp9808.py +0 -0
  271. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/hardware/sensor/temperature/pct2075.py +0 -0
  272. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/integration/__init__.py +0 -0
  273. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/integration/interlock.py +0 -0
  274. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/__init__.py +0 -0
  275. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/cli.py +0 -0
  276. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/client.py +0 -0
  277. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/coordinator.py +0 -0
  278. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/__init__.py +0 -0
  279. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/energy_meters/le-03mw.json +0 -0
  280. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/energy_meters/le-03mwct.json +0 -0
  281. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/energy_meters/orno-or-we-517.json +0 -0
  282. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/energy_meters/sdm120.json +0 -0
  283. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/energy_meters/sdm630.json +0 -0
  284. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/energy_meters/socomec_e03.json +0 -0
  285. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/energy_meters/socomec_e23.json +0 -0
  286. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/hvac/fujitsu-ac.json +0 -0
  287. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/hvac/ventclear.json +0 -0
  288. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/inverters/sofar.json +0 -0
  289. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/inverters/thessla.json +0 -0
  290. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/other/n4dsc08.json +0 -0
  291. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/other/r4dcb08.json +0 -0
  292. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/other/wanas415.json +0 -0
  293. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/sensors/cwt.json +0 -0
  294. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/sensors/dts1964_3f.json +0 -0
  295. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/sensors/dyp-a12-ultrasonic.json +0 -0
  296. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/sensors/liquid-sensor.json +0 -0
  297. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/sensors/pt100.json +0 -0
  298. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/sensors/sht20.json +0 -0
  299. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/devices/sensors/sht30.json +0 -0
  300. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/entities/__init__.py +0 -0
  301. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/entities/base.py +0 -0
  302. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/entities/derived/__init__.py +0 -0
  303. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/entities/derived/numeric.py +0 -0
  304. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/entities/derived/select.py +0 -0
  305. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/entities/derived/switch.py +0 -0
  306. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/entities/derived/text.py +0 -0
  307. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/entities/sensor/__init__.py +0 -0
  308. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/entities/sensor/binary.py +0 -0
  309. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/entities/sensor/numeric.py +0 -0
  310. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/entities/sensor/text.py +0 -0
  311. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/entities/writeable/__init__.py +0 -0
  312. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/entities/writeable/binary.py +0 -0
  313. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/entities/writeable/numeric.py +0 -0
  314. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/modbus/utils.py +0 -0
  315. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/models/__init__.py +0 -0
  316. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/models/actions.py +0 -0
  317. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/models/events.py +0 -0
  318. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/models/files.py +0 -0
  319. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/models/logs.py +0 -0
  320. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/models/mqtt.py +0 -0
  321. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/models/state.py +0 -0
  322. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/runner.py +0 -0
  323. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/schema/actions_sensor.yaml +0 -0
  324. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/schema/actions_switch.yaml +0 -0
  325. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/schema/filters.yaml +0 -0
  326. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/schema/filters_adc.yaml +0 -0
  327. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/schema/id.yaml +0 -0
  328. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/schema/remote_devices.yaml +0 -0
  329. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/schema/schema.yaml +0 -0
  330. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/schema/temp_unit.yaml +0 -0
  331. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/schema/update_interval.yaml +0 -0
  332. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/app.py +0 -0
  333. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/abap-CRCWOmpq.js +0 -0
  334. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/apex-DnsZk_dE.js +0 -0
  335. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/azcli-1IWB1ccx.js +0 -0
  336. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/bat-DPkNLes8.js +0 -0
  337. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/bicep-Corcdgou.js +0 -0
  338. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/cameligo-CGrWLZr3.js +0 -0
  339. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/clojure-D9WOWImG.js +0 -0
  340. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/codicon-DCmgc-ay.ttf +0 -0
  341. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/coffee-B7EJu28W.js +0 -0
  342. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/cpp-SEyurbux.js +0 -0
  343. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/csharp-BoL64M5l.js +0 -0
  344. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/csp-C46ZqvIl.js +0 -0
  345. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/css-DQU6DXDx.js +0 -0
  346. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/cypher-D84EuPTj.js +0 -0
  347. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/dart-D8lhlL1r.js +0 -0
  348. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/dockerfile-DLk6rpji.js +0 -0
  349. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/ecl-BO6FnfXk.js +0 -0
  350. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/elixir-BRjLKONM.js +0 -0
  351. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/flow9-Cac8vKd7.js +0 -0
  352. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/fsharp-fd1GTHhf.js +0 -0
  353. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/go-O9LJTZXk.js +0 -0
  354. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/graphql-LQdxqEYJ.js +0 -0
  355. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/hcl-DxDQ3s82.js +0 -0
  356. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/ini-BvajGCUy.js +0 -0
  357. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/java-SYsfObOQ.js +0 -0
  358. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/julia-DQXNmw_w.js +0 -0
  359. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/kotlin-qQ0MG-9I.js +0 -0
  360. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/less-GGFNNJHn.js +0 -0
  361. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/lexon-Canl7DCW.js +0 -0
  362. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/lua-D28Ae8-K.js +0 -0
  363. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/m3-DPitgjJI.js +0 -0
  364. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/markdown-B811l8j2.js +0 -0
  365. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/mips-CdjsipkG.js +0 -0
  366. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/msdax-CYqgjx_P.js +0 -0
  367. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/mysql-BHd6q0vd.js +0 -0
  368. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/objective-c-B1aVtJYH.js +0 -0
  369. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/pascal-BhNW15KB.js +0 -0
  370. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/pascaligo-5jv8CcQD.js +0 -0
  371. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/perl-DlYyT36c.js +0 -0
  372. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/pgsql-Dy0bjov7.js +0 -0
  373. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/php-120yhfDK.js +0 -0
  374. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/pla-CjnFlu4u.js +0 -0
  375. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/postiats-CQpG440k.js +0 -0
  376. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/powerquery-DdJtto1Z.js +0 -0
  377. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/powershell-Bu_VLpJB.js +0 -0
  378. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/protobuf-IBS6jZEB.js +0 -0
  379. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/pug-kFxLfcjb.js +0 -0
  380. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/qsharp-q7JyzKFN.js +0 -0
  381. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/r-BIFz-_sK.js +0 -0
  382. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/redis-CHOsPHWR.js +0 -0
  383. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/redshift-CBifECDb.js +0 -0
  384. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/restructuredtext-CghPJEOS.js +0 -0
  385. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/ruby-CYWGW-b1.js +0 -0
  386. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/rust-DMDD0SHb.js +0 -0
  387. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/sb-BYAiYHFx.js +0 -0
  388. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/scala-Bqvq8jcR.js +0 -0
  389. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/scheme-Dhb-2j9p.js +0 -0
  390. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/scss-CTwUZ5N7.js +0 -0
  391. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/shell-CsDZo4DB.js +0 -0
  392. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/solidity-CME5AdoB.js +0 -0
  393. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/sophia-RYC1BQQz.js +0 -0
  394. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/sparql-KEyrF7De.js +0 -0
  395. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/sql-BdTr02Mf.js +0 -0
  396. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/st-C7iG7M4S.js +0 -0
  397. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/swift-D7IUmUK8.js +0 -0
  398. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/systemverilog-DgMryOEJ.js +0 -0
  399. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/tcl-PloMZuKG.js +0 -0
  400. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/twig-BfRIq3la.js +0 -0
  401. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/typespec-CzxlYoT_.js +0 -0
  402. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/vb-BwAE3J76.js +0 -0
  403. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/assets/wgsl-B_1kOXbF.js +0 -0
  404. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/boneio-192.png +0 -0
  405. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/boneio-512.png +0 -0
  406. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/boneio.svg +0 -0
  407. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/boneio_fav.svg +0 -0
  408. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/schem/dallas.schema.json +0 -0
  409. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/frontend-dist/workbox-226dbdbf.js +0 -0
  410. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/middleware/__init__.py +0 -0
  411. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/middleware/auth.py +0 -0
  412. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/routes/__init__.py +0 -0
  413. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/routes/auth.py +0 -0
  414. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/routes/caddy.py +0 -0
  415. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/routes/config.py +0 -0
  416. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/routes/covers.py +0 -0
  417. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/routes/modbus.py +0 -0
  418. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/routes/outputs.py +0 -0
  419. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/routes/remote_devices.py +0 -0
  420. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/routes/sensors.py +0 -0
  421. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/schema/dallas.schema.json +0 -0
  422. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/services/__init__.py +0 -0
  423. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/services/logs.py +0 -0
  424. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/web_server.py +0 -0
  425. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio/webui/websocket_manager.py +0 -0
  426. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio.egg-info/dependency_links.txt +0 -0
  427. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio.egg-info/entry_points.txt +0 -0
  428. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio.egg-info/requires.txt +0 -0
  429. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/boneio.egg-info/top_level.txt +0 -0
  430. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/pyproject.toml +0 -0
  431. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/setup.cfg +0 -0
  432. {boneio-1.2.0.dev6 → boneio-1.2.0.dev8}/setup.py +0 -0
  433. {boneio-1.2.0.dev6 → boneio-1.2.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.2.0.dev6
3
+ Version: 1.2.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
@@ -470,7 +470,7 @@ class MultiClickDetector:
470
470
  elif event.event_type is event.Type.RISING_EDGE:
471
471
  # Button released (RISING_EDGE on BeagleBone with pull-up)
472
472
 
473
- # Software debounce
473
+ # Software debounce (release-vs-release)
474
474
  if self._state.last_release_ts and (timestamp_s - self._state.last_release_ts) < self._debounce_seconds:
475
475
  delta_ms = (timestamp_s - self._state.last_release_ts) * 1000
476
476
  _LOGGER.debug(
@@ -479,8 +479,20 @@ class MultiClickDetector:
479
479
  delta_ms,
480
480
  )
481
481
  return
482
+
483
+ # Cross-debounce: ignore release too close to press (bounce on rising edge)
484
+ if self._state.last_press_ts and (timestamp_s - self._state.last_press_ts) < self._debounce_seconds:
485
+ delta_ms = (timestamp_s - self._state.last_press_ts) * 1000
486
+ _LOGGER.debug(
487
+ "Ignoring bounced release on %s (%.3f ms since press, debounce %.3f ms)",
488
+ self._name,
489
+ delta_ms,
490
+ self._debounce_seconds * 1000,
491
+ )
492
+ return
482
493
 
483
- _LOGGER.debug("RELEASED: %s (%s)", self._name, self._pin)
494
+ press_duration_ms = (timestamp_s - self._state.last_press_ts) * 1000 if self._state.last_press_ts else 0
495
+ _LOGGER.debug("RELEASED: %s (%s) after %.1f ms", self._name, self._pin, press_duration_ms)
484
496
  self._state.last_release_ts = timestamp_s
485
497
 
486
498
  _LOGGER.debug(
@@ -440,7 +440,12 @@ class Manager:
440
440
  parsed_action[key] = action_definition[key]
441
441
  if action_definition.get("repeat"):
442
442
  parsed_action["repeat"] = True
443
- parsed_action["repeat_interval"] = action_definition.get("repeat_interval", 1000)
443
+ ri = action_definition.get("repeat_interval", 1000)
444
+ # TimePeriod object from schema validation -> convert to ms
445
+ if hasattr(ri, "total_milliseconds"):
446
+ parsed_action["repeat_interval"] = ri.total_milliseconds
447
+ else:
448
+ parsed_action["repeat_interval"] = ri
444
449
 
445
450
  parsed_actions = {}
446
451
  for click_type in actions:
@@ -552,6 +557,22 @@ class Manager:
552
557
  "output_id": output_id,
553
558
  "action_output": action_output,
554
559
  }
560
+ # Copy optional light/WLED parameters
561
+ for opt_key in (
562
+ "brightness", "color_temp", "rgb", "transition",
563
+ "effect", "palette", "effect_speed", "effect_intensity",
564
+ "colors", "presets",
565
+ ):
566
+ val = action_definition.get(opt_key)
567
+ if val is not None:
568
+ parsed_action[opt_key] = val
569
+ # Convert transition TimePeriod to float seconds
570
+ if "transition" in parsed_action:
571
+ t_val = parsed_action["transition"]
572
+ if hasattr(t_val, "total_in_seconds"):
573
+ parsed_action["transition"] = t_val.total_in_seconds
574
+ elif not isinstance(t_val, (int, float)):
575
+ parsed_action["transition"] = 0.0
555
576
  _copy_long_press_meta(parsed_action, action_definition)
556
577
  parsed_actions[click_type].append(parsed_action)
557
578
  continue
@@ -724,19 +745,53 @@ class Manager:
724
745
  remote_device_id = action_definition.get("remote_device")
725
746
  output_id = action_definition.get("output_id")
726
747
  action_output = action_definition.get("action_output", "TOGGLE")
727
- await self.remote_devices.control_output(
728
- device_id=remote_device_id,
729
- output_id=output_id,
730
- action=action_output,
731
- brightness=action_definition.get("brightness"),
732
- color_temp=action_definition.get("color_temp"),
733
- rgb=action_definition.get("rgb"),
734
- transition=action_definition.get("transition"),
735
- effect=action_definition.get("effect"),
736
- palette=action_definition.get("palette"),
737
- effect_speed=action_definition.get("effect_speed"),
738
- effect_intensity=action_definition.get("effect_intensity"),
739
- )
748
+
749
+ # Clamp transition to repeat_interval to avoid overlapping animations
750
+ transition_val = action_definition.get("transition")
751
+ if transition_val and action_definition.get("repeat"):
752
+ repeat_interval = action_definition.get("repeat_interval")
753
+ if repeat_interval:
754
+ ri_seconds = repeat_interval.total_in_seconds if hasattr(repeat_interval, "total_in_seconds") else repeat_interval / 1000.0
755
+ if transition_val > ri_seconds:
756
+ _LOGGER.debug(
757
+ "Clamping transition %.3fs to repeat_interval %.3fs",
758
+ transition_val, ri_seconds,
759
+ )
760
+ transition_val = ri_seconds
761
+ action_definition = {**action_definition, "transition": transition_val}
762
+
763
+ if action_output == "CYCLE_COLOR":
764
+ await self.remote_devices.cycle_color(
765
+ device_id=remote_device_id,
766
+ output_id=output_id,
767
+ colors=action_definition.get("colors", []),
768
+ action_idx=idx,
769
+ transition=action_definition.get("transition"),
770
+ )
771
+
772
+ elif action_output == "CYCLE_PRESET":
773
+ await self.remote_devices.cycle_preset(
774
+ device_id=remote_device_id,
775
+ output_id=output_id,
776
+ presets=action_definition.get("presets", []),
777
+ action_idx=idx,
778
+ transition=action_definition.get("transition"),
779
+ )
780
+
781
+ else:
782
+ await self.remote_devices.control_output(
783
+ device_id=remote_device_id,
784
+ output_id=output_id,
785
+ action=action_output,
786
+ brightness=action_definition.get("brightness"),
787
+ color_temp=action_definition.get("color_temp"),
788
+ rgb=action_definition.get("rgb"),
789
+ transition=action_definition.get("transition"),
790
+ effect=action_definition.get("effect"),
791
+ palette=action_definition.get("palette"),
792
+ effect_speed=action_definition.get("effect_speed"),
793
+ effect_intensity=action_definition.get("effect_intensity"),
794
+ )
740
795
 
741
796
  elif action == REMOTE_COVER:
742
797
  # Control cover on remote device (BoneIO MQTT or ESPHome API)
@@ -64,6 +64,9 @@ class RemoteDeviceManager:
64
64
  self._autodiscovered_devices: dict[str, MQTTRemoteDevice] = {}
65
65
  # Track devices that manage this boneIO (received via discovery/managed_by topic)
66
66
  self._managed_by_devices: dict[str, dict[str, Any]] = {}
67
+ # Cycle state for CYCLE_COLOR and CYCLE_PRESET actions
68
+ # Key: "device_id:output_id:type:action_idx", Value: current index
69
+ self._cycle_state: dict[str, int] = {}
67
70
 
68
71
  if remote_devices_config:
69
72
  self._configure_devices(remote_devices_config)
@@ -335,14 +338,18 @@ class RemoteDeviceManager:
335
338
  """Stop all persistent connections.
336
339
 
337
340
  This should be called during application shutdown.
341
+ Closes ESPHome connections and WLED aiohttp sessions.
338
342
  """
339
343
  for device_id, device in self._devices.items():
340
- if isinstance(device, ESPHomeRemoteDevice):
341
- try:
344
+ try:
345
+ if isinstance(device, ESPHomeRemoteDevice):
342
346
  await device.disconnect()
343
347
  _LOGGER.info("Stopped connection for ESPHome device '%s'", device_id)
344
- except Exception as e:
345
- _LOGGER.error("Failed to stop connection for ESPHome device '%s': %s", device_id, e)
348
+ elif isinstance(device, WLEDRemoteDevice):
349
+ await device.close()
350
+ _LOGGER.info("Closed session for WLED device '%s'", device_id)
351
+ except Exception as e:
352
+ _LOGGER.error("Failed to stop connection for device '%s': %s", device_id, e)
346
353
 
347
354
  def get_device(self, device_id: str) -> RemoteDevice | None:
348
355
  """Get remote device by ID.
@@ -372,7 +379,7 @@ class RemoteDeviceManager:
372
379
  color_temp: int | None = None,
373
380
  rgb: list[int] | tuple[int, int, int] | None = None,
374
381
  transition: float | None = None,
375
- effect: int | None = None,
382
+ effect: int | str | None = None,
376
383
  palette: int | None = None,
377
384
  effect_speed: int | None = None,
378
385
  effect_intensity: int | None = None,
@@ -391,7 +398,7 @@ class RemoteDeviceManager:
391
398
  color_temp: Color temperature in mireds - only for ESPHome lights
392
399
  rgb: RGB color as [R, G, B] list or tuple (0-255 each) - for ESPHome/WLED lights
393
400
  transition: Transition time in seconds - for ESPHome/WLED lights
394
- effect: WLED effect ID
401
+ effect: Effect name (str for ESPHome) or effect ID (int for WLED)
395
402
  palette: WLED color palette ID
396
403
  effect_speed: WLED effect speed (0-255)
397
404
  effect_intensity: WLED effect intensity (0-255)
@@ -413,6 +420,8 @@ class RemoteDeviceManager:
413
420
  rgb_tuple: tuple[int, int, int] | None = None
414
421
  if rgb and len(rgb) >= 3:
415
422
  rgb_tuple = (int(rgb[0]), int(rgb[1]), int(rgb[2]))
423
+ # For ESPHome, effect must be a string
424
+ esphome_effect = str(effect) if effect is not None else None
416
425
  return await device.control_light(
417
426
  light_id=output_id,
418
427
  action=action,
@@ -420,6 +429,7 @@ class RemoteDeviceManager:
420
429
  color_temp=color_temp,
421
430
  rgb=rgb_tuple,
422
431
  transition=transition if transition is not None else 0.0,
432
+ effect=esphome_effect,
423
433
  )
424
434
  # Otherwise treat as switch
425
435
  _LOGGER.debug("Controlling ESPHome switch '%s' on device '%s'", output_id, device_id)
@@ -456,6 +466,96 @@ class RemoteDeviceManager:
456
466
  message_bus=self._message_bus,
457
467
  )
458
468
 
469
+ async def cycle_color(
470
+ self,
471
+ device_id: str,
472
+ output_id: str,
473
+ colors: list[list[int]],
474
+ action_idx: int = 0,
475
+ transition: float | None = None,
476
+ ) -> bool:
477
+ """Cycle through a list of RGB colors on a remote device light.
478
+
479
+ Each call advances to the next color in the list, wrapping around.
480
+
481
+ Args:
482
+ device_id: ID of the remote device
483
+ output_id: ID of the light to control
484
+ colors: List of RGB colors, each as [R, G, B] (0-255)
485
+ action_idx: Action index for unique cycle state tracking
486
+ transition: Transition time in seconds
487
+
488
+ Returns:
489
+ True if command was sent successfully
490
+ """
491
+ if not colors:
492
+ _LOGGER.warning("CYCLE_COLOR: no colors defined for %s:%s", device_id, output_id)
493
+ return False
494
+
495
+ cycle_key = f"{device_id}:{output_id}:color:{action_idx}"
496
+ cycle_idx = self._cycle_state.get(cycle_key, 0) % len(colors)
497
+ rgb = colors[cycle_idx]
498
+ self._cycle_state[cycle_key] = cycle_idx + 1
499
+
500
+ _LOGGER.debug(
501
+ "CYCLE_COLOR: %s:%s -> color %d/%d = %s",
502
+ device_id, output_id, cycle_idx + 1, len(colors), rgb
503
+ )
504
+
505
+ return await self.control_output(
506
+ device_id=device_id,
507
+ output_id=output_id,
508
+ action="ON",
509
+ rgb=rgb,
510
+ transition=transition,
511
+ )
512
+
513
+ async def cycle_preset(
514
+ self,
515
+ device_id: str,
516
+ output_id: str,
517
+ presets: list[str | int],
518
+ action_idx: int = 0,
519
+ transition: float | None = None,
520
+ ) -> bool:
521
+ """Cycle through a list of effects/presets on a remote device light.
522
+
523
+ Each call advances to the next preset in the list, wrapping around.
524
+ For ESPHome: presets are effect name strings.
525
+ For WLED: presets are effect IDs (integers).
526
+
527
+ Args:
528
+ device_id: ID of the remote device
529
+ output_id: ID of the light to control
530
+ presets: List of effect names (str) or effect IDs (int)
531
+ action_idx: Action index for unique cycle state tracking
532
+ transition: Transition time in seconds
533
+
534
+ Returns:
535
+ True if command was sent successfully
536
+ """
537
+ if not presets:
538
+ _LOGGER.warning("CYCLE_PRESET: no presets defined for %s:%s", device_id, output_id)
539
+ return False
540
+
541
+ cycle_key = f"{device_id}:{output_id}:preset:{action_idx}"
542
+ cycle_idx = self._cycle_state.get(cycle_key, 0) % len(presets)
543
+ preset = presets[cycle_idx]
544
+ self._cycle_state[cycle_key] = cycle_idx + 1
545
+
546
+ _LOGGER.debug(
547
+ "CYCLE_PRESET: %s:%s -> preset %d/%d = %s",
548
+ device_id, output_id, cycle_idx + 1, len(presets), preset
549
+ )
550
+
551
+ return await self.control_output(
552
+ device_id=device_id,
553
+ output_id=output_id,
554
+ action="ON",
555
+ effect=preset,
556
+ transition=transition,
557
+ )
558
+
459
559
  async def control_cover(
460
560
  self,
461
561
  device_id: str,
@@ -6,13 +6,18 @@ and publishes the update status to Home Assistant via MQTT.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
+ import asyncio
9
10
  import json
10
11
  import logging
12
+ import os
13
+ import subprocess
14
+ from collections.abc import Callable
11
15
  from typing import TYPE_CHECKING
12
16
 
13
17
  from boneio.core.utils.async_updater import AsyncUpdater
14
18
  from boneio.core.utils.timeperiod import TimePeriod
15
19
  from boneio.version import __version__
20
+ from boneio.webui.services.logs import is_running_as_service
16
21
 
17
22
  if TYPE_CHECKING:
18
23
  from boneio.core.manager import Manager
@@ -52,6 +57,7 @@ class UpdateManager(AsyncUpdater):
52
57
  self._last_check_result: dict | None = None
53
58
  self._last_published_state: str | None = None
54
59
  self._ha_discovery_sent: bool = False
60
+ self._update_running: bool = False
55
61
 
56
62
  # Initialize AsyncUpdater (starts periodic task)
57
63
  super().__init__(manager=manager, update_interval=update_interval)
@@ -312,10 +318,16 @@ class UpdateManager(AsyncUpdater):
312
318
  """
313
319
  return self._last_check_result
314
320
 
321
+ @property
322
+ def update_running(self) -> bool:
323
+ """Whether an update is currently in progress."""
324
+ return self._update_running
325
+
315
326
  async def handle_install_command(self, payload: str) -> None:
316
327
  """Handle install command from Home Assistant.
317
328
 
318
329
  This is called when HA sends a message to the command topic.
330
+ Performs pip install of the latest version and restarts the service.
319
331
 
320
332
  Args:
321
333
  payload: MQTT payload (should be "INSTALL")
@@ -326,6 +338,14 @@ class UpdateManager(AsyncUpdater):
326
338
 
327
339
  _LOGGER.info("Received install command from Home Assistant")
328
340
 
341
+ if not is_running_as_service():
342
+ _LOGGER.warning("Update via MQTT is only available when running as a service")
343
+ return
344
+
345
+ if self._update_running:
346
+ _LOGGER.warning("Update already in progress, ignoring install command")
347
+ return
348
+
329
349
  # Check if update is available
330
350
  if not self._last_check_result:
331
351
  _LOGGER.warning("No update check result available, checking now...")
@@ -335,15 +355,257 @@ class UpdateManager(AsyncUpdater):
335
355
  _LOGGER.warning("No update available to install")
336
356
  return
337
357
 
338
- # Trigger update via existing update endpoint
339
- # Note: This requires the update API to be accessible
340
- # The actual installation is handled by /api/update endpoint
358
+ target_version = self._last_check_result.get("latest_version")
359
+
360
+ # Run update in background task to not block MQTT
361
+ asyncio.create_task(
362
+ self.perform_update(target_version=target_version)
363
+ )
364
+
365
+ async def perform_update(
366
+ self,
367
+ target_version: str | None = None,
368
+ on_progress: Callable[[int, str, str | None], None] | None = None,
369
+ ) -> None:
370
+ """Perform the actual update: pip install + restart.
371
+
372
+ This is the single update algorithm used by both MQTT (HA) and WebUI.
373
+
374
+ Handles pre-release versions by adding --pre flag.
375
+ Retries up to 3 times with 30s delay if pip install fails
376
+ (PyPI index may not have the version available immediately).
377
+
378
+ Args:
379
+ target_version: Version to install, or None for latest.
380
+ on_progress: Optional callback(progress_pct, step, log_msg).
381
+ Called at each stage so the caller can track progress.
382
+ If None, only MQTT progress is published.
383
+ """
384
+ if self._update_running:
385
+ _LOGGER.warning("Update already in progress")
386
+ return
387
+
388
+ self._update_running = True
389
+ current_version = __version__
341
390
  _LOGGER.info(
342
- "Update installation should be triggered via WebUI or API endpoint /api/update"
391
+ "Starting update from %s to %s",
392
+ current_version, target_version or "latest"
393
+ )
394
+
395
+ async def _report(progress: int, step: str, log_msg: str | None = None) -> None:
396
+ """Report progress to both MQTT and optional callback."""
397
+ await self._publish_update_progress(
398
+ current_version=current_version,
399
+ target_version=target_version,
400
+ progress=progress,
401
+ )
402
+ if on_progress:
403
+ on_progress(progress, step, log_msg)
404
+
405
+ try:
406
+ await _report(5, "Finding virtual environment...")
407
+
408
+ # Find virtual environment
409
+ possible_venv_paths = [
410
+ os.path.expanduser("~/boneio/venv"),
411
+ os.path.expanduser("~/venv"),
412
+ "/opt/boneio/venv",
413
+ ]
414
+
415
+ pip_path = None
416
+ venv_path = None
417
+ for path in possible_venv_paths:
418
+ pip_candidate = os.path.join(path, "bin", "pip")
419
+ if os.path.exists(pip_candidate):
420
+ venv_path = path
421
+ pip_path = pip_candidate
422
+ _LOGGER.info("Found venv pip at %s", pip_path)
423
+ break
424
+
425
+ if not pip_path:
426
+ _LOGGER.error("Virtual environment not found, cannot update")
427
+ await _report(0, "Failed", "Could not find virtual environment")
428
+ return
429
+
430
+ await _report(10, "Virtual environment found", f"Using venv at {venv_path}")
431
+ await _report(15, "Preparing update...", f"Current version: {current_version}")
432
+ await _report(30, "Upgrading pip...")
433
+
434
+ # Upgrade pip first
435
+ pip_upgrade = subprocess.run(
436
+ [pip_path, "install", "--upgrade", "pip"],
437
+ capture_output=True, text=True, timeout=120
438
+ )
439
+
440
+ if pip_upgrade.returncode == 0:
441
+ await _report(40, "Pip upgraded", "pip upgraded successfully")
442
+ else:
443
+ await _report(40, "Pip upgrade skipped", "pip upgrade failed, continuing...")
444
+
445
+ # Build pip install command
446
+ pip_cmd = [pip_path, "install", "--upgrade"]
447
+
448
+ # Add --pre flag for pre-release versions (dev, alpha, beta, rc)
449
+ needs_pre = False
450
+ if target_version and self._is_prerelease_version(target_version):
451
+ needs_pre = True
452
+ elif not target_version and self._is_prerelease_version(current_version):
453
+ needs_pre = True
454
+
455
+ if needs_pre:
456
+ pip_cmd.append("--pre")
457
+ await _report(42, "Using --pre flag", "Pre-release version detected")
458
+
459
+ if target_version:
460
+ pip_package = f"boneio=={target_version}"
461
+ else:
462
+ pip_package = "boneio"
463
+
464
+ pip_cmd.append(pip_package)
465
+
466
+ await _report(45, f"Downloading and installing {pip_package}...")
467
+
468
+ # Retry logic: PyPI may not have the version available immediately
469
+ max_retries = 3
470
+ retry_delay = 30 # seconds
471
+ result = None
472
+
473
+ for attempt in range(1, max_retries + 1):
474
+ await _report(
475
+ 45 + (attempt - 1) * 10,
476
+ f"Installing (attempt {attempt}/{max_retries})...",
477
+ f"Running: {' '.join(pip_cmd)}"
478
+ )
479
+
480
+ result = subprocess.run(
481
+ pip_cmd,
482
+ capture_output=True, text=True, timeout=300
483
+ )
484
+
485
+ if result.returncode == 0:
486
+ break
487
+
488
+ _LOGGER.warning(
489
+ "pip install attempt %d/%d failed: %s",
490
+ attempt, max_retries, result.stderr.strip()
491
+ )
492
+
493
+ if attempt < max_retries:
494
+ await _report(
495
+ 45 + attempt * 10,
496
+ f"Retrying in {retry_delay}s...",
497
+ f"Attempt {attempt} failed, PyPI index may not be ready"
498
+ )
499
+ await asyncio.sleep(retry_delay)
500
+
501
+ if not result or result.returncode != 0:
502
+ error_msg = result.stderr.strip() if result else "Unknown error"
503
+ _LOGGER.error(
504
+ "pip install failed after %d attempts: %s",
505
+ max_retries, error_msg
506
+ )
507
+ await _report(0, "Update failed", error_msg)
508
+ return
509
+
510
+ await _report(80, "BoneIO updated", "Package installed successfully")
511
+ await _report(85, "Verifying installation...")
512
+
513
+ # Verify installed version
514
+ version_result = subprocess.run(
515
+ [pip_path, "show", "boneio"],
516
+ capture_output=True, text=True
517
+ )
518
+ new_version = current_version
519
+ if version_result.returncode == 0:
520
+ for line in version_result.stdout.split('\n'):
521
+ if line.startswith('Version:'):
522
+ new_version = line.split(':')[1].strip()
523
+ break
524
+
525
+ _LOGGER.info(
526
+ "Update successful: %s -> %s. Restarting in 2 seconds...",
527
+ current_version, new_version
528
+ )
529
+
530
+ await _report(90, "Installation verified", f"Updated from {current_version} to {new_version}")
531
+ await _report(95, "Finalizing...")
532
+
533
+ # Publish final success state (no longer in progress)
534
+ current_version = new_version # update for final MQTT publish
535
+ await self._publish_update_progress(
536
+ current_version=new_version,
537
+ target_version=None,
538
+ progress=0,
539
+ )
540
+ if on_progress:
541
+ on_progress(100, "Update complete!", f"Restarting service in 2 seconds...")
542
+
543
+ await asyncio.sleep(2)
544
+
545
+ _LOGGER.info("Restarting BoneIO service after update...")
546
+ os._exit(0)
547
+
548
+ except subprocess.TimeoutExpired:
549
+ _LOGGER.error("Update process timed out")
550
+ await _report(0, "Timeout", "Update process timed out")
551
+ except Exception as e:
552
+ _LOGGER.error("Error during update: %s", e, exc_info=True)
553
+ await _report(0, "Error", f"Unexpected error: {e}")
554
+ finally:
555
+ self._update_running = False
556
+
557
+ @staticmethod
558
+ def _is_prerelease_version(version_str: str) -> bool:
559
+ """Check if version string is a pre-release (dev, alpha, beta, rc).
560
+
561
+ Args:
562
+ version_str: Version string to check
563
+
564
+ Returns:
565
+ True if version is a pre-release
566
+ """
567
+ ver_lower = version_str.lower()
568
+ return any(x in ver_lower for x in ['dev', 'alpha', 'beta', 'rc'])
569
+
570
+ async def _publish_update_progress(
571
+ self,
572
+ current_version: str,
573
+ target_version: str | None,
574
+ progress: int,
575
+ ) -> None:
576
+ """Publish update progress state to MQTT for HA.
577
+
578
+ HA update entity supports in_progress as:
579
+ - false/0: not updating
580
+ - true: updating (indeterminate)
581
+ - int 1-100: updating with progress percentage
582
+
583
+ Args:
584
+ current_version: Currently installed version
585
+ target_version: Version being installed (None if not updating)
586
+ progress: Update progress percentage (0 = not updating, 1-100 = in progress)
587
+ """
588
+ # HA interprets 0/false as "not updating", 1-100 as "updating with progress"
589
+ in_progress_value: int | bool = progress if progress > 0 else False
590
+
591
+ state_payload = {
592
+ "installed_version": current_version,
593
+ "latest_version": target_version or current_version,
594
+ "title": "boneIO Black Firmware",
595
+ "release_url": self._last_check_result.get("release_url", "") if self._last_check_result else "",
596
+ "release_summary": self._last_check_result.get("release_notes", "") if self._last_check_result else "",
597
+ "entity_picture": "http://boneio.eu/logo_fb_circle.png",
598
+ "in_progress": in_progress_value,
599
+ }
600
+
601
+ topic_prefix = self._manager._config_helper.topic_prefix
602
+ self._manager.send_message(
603
+ topic=f"{topic_prefix}/update/state",
604
+ payload=json.dumps(state_payload),
605
+ retain=True,
343
606
  )
344
607
 
345
- # TODO: Consider adding direct integration with update logic
346
- # For now, users should use the WebUI to trigger updates
608
+ _LOGGER.debug("Published update progress: %d%%", progress)
347
609
 
348
610
  async def send_ha_autodiscovery(self) -> None:
349
611
  """Send Home Assistant autodiscovery for Update entity."""
@@ -144,6 +144,9 @@ class MQTTClient(MessageBus):
144
144
  @override
145
145
  async def subscribe_and_listen(self, topic: str, callback: Callable[[str, str], Awaitable[None]]) -> None:
146
146
  self._mqtt_energy_listeners[topic] = callback
147
+ # Subscribe immediately if already connected
148
+ if self._connection_established:
149
+ await self.subscribe(topics=[topic])
147
150
 
148
151
  @override
149
152
  async def unsubscribe_and_stop_listen(self, topic: str) -> None:
@@ -327,12 +330,11 @@ class MQTTClient(MessageBus):
327
330
  topic=topic, payload=None, retain=True
328
331
  )
329
332
  break
330
- if message.topic.matches(f"{self._config_helper.topic_prefix}/energy/#"):
331
- callback_start = False
332
- for topic, listener_callback in self._mqtt_energy_listeners.items():
333
- if message.topic.matches(topic):
334
- await listener_callback(str(message.topic), payload)
335
- break
333
+ for topic, listener_callback in self._mqtt_energy_listeners.items():
334
+ if message.topic.matches(topic):
335
+ callback_start = False
336
+ await listener_callback(str(message.topic), payload)
337
+ break
336
338
  if callback_start:
337
339
  _LOGGER.debug(
338
340
  "Received message topic: %s, payload: %s",