boneio 1.4.0.dev3__tar.gz → 1.4.0.dev5__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 (457) hide show
  1. {boneio-1.4.0.dev3/boneio.egg-info → boneio-1.4.0.dev5}/PKG-INFO +1 -1
  2. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/cover/cover.py +6 -0
  3. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/cover/venetian.py +11 -4
  4. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/irrigation/controller.py +101 -4
  5. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/output/remote.py +224 -3
  6. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/irrigation.py +23 -2
  7. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/manager.py +130 -4
  8. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/remote.py +58 -0
  9. boneio-1.4.0.dev5/boneio/core/messaging/lox.py +326 -0
  10. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/integration/homeassistant.py +84 -0
  11. boneio-1.4.0.dev5/boneio/integration/lox_template.py +367 -0
  12. boneio-1.4.0.dev5/boneio/modbus/devices/hvac/eht-topventil-plus.json +243 -0
  13. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/schema/actions.yaml +11 -0
  14. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/schema/remote_outputs.yaml +95 -0
  15. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/schema/schema.yaml +22 -1
  16. boneio-1.4.0.dev5/boneio/version.py +2 -0
  17. boneio-1.4.0.dev3/boneio/webui/frontend-dist/assets/ConfigEditor-B7qJAsAx.js → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/ConfigEditor-A8cWujvP.js +1 -1
  18. boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/aiConfig-DxFilBWK.js +2 -0
  19. boneio-1.4.0.dev3/boneio/webui/frontend-dist/assets/aiWizardPrompt-r-xmvrUB.js → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/aiWizardPrompt-CrWwS7zb.js +1 -1
  20. boneio-1.4.0.dev3/boneio/webui/frontend-dist/assets/index-D-R9QzIP.css → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/index-BtCN44rd.css +1 -1
  21. boneio-1.4.0.dev3/boneio/webui/frontend-dist/assets/index-BVRhWldF.js → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/index-ChujUEJh.js +62 -6
  22. boneio-1.4.0.dev3/boneio/webui/frontend-dist/assets/useTranslation-VOFZRLzq.js → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/useTranslation-CxUU9LHE.js +2 -2
  23. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/index.html +4 -4
  24. {boneio-1.4.0.dev3/boneio/webui → boneio-1.4.0.dev5/boneio/webui/frontend-dist}/schema/binary_sensor.schema.json +44 -0
  25. {boneio-1.4.0.dev3/boneio/webui → boneio-1.4.0.dev5/boneio/webui/frontend-dist}/schema/config.schema.json +330 -0
  26. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/event.schema.json +154 -0
  27. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/irrigation.schema.json +9 -0
  28. {boneio-1.4.0.dev3/boneio/webui → boneio-1.4.0.dev5/boneio/webui/frontend-dist}/schema/modbus_devices.schema.json +3 -0
  29. boneio-1.4.0.dev5/boneio/webui/frontend-dist/schema/remote_outputs.schema.json +225 -0
  30. {boneio-1.4.0.dev3/boneio/webui → boneio-1.4.0.dev5/boneio/webui/frontend-dist}/schema/template.schema.json +9 -0
  31. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/sw.js +1 -1
  32. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/config.py +26 -7
  33. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/irrigation.py +217 -0
  34. {boneio-1.4.0.dev3/boneio/webui/frontend-dist → boneio-1.4.0.dev5/boneio/webui}/schema/binary_sensor.schema.json +44 -0
  35. {boneio-1.4.0.dev3/boneio/webui/frontend-dist → boneio-1.4.0.dev5/boneio/webui}/schema/config.schema.json +330 -0
  36. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/event.schema.json +154 -0
  37. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/irrigation.schema.json +9 -0
  38. {boneio-1.4.0.dev3/boneio/webui/frontend-dist → boneio-1.4.0.dev5/boneio/webui}/schema/modbus_devices.schema.json +3 -0
  39. boneio-1.4.0.dev5/boneio/webui/schema/remote_outputs.schema.json +225 -0
  40. {boneio-1.4.0.dev3/boneio/webui/frontend-dist → boneio-1.4.0.dev5/boneio/webui}/schema/template.schema.json +9 -0
  41. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5/boneio.egg-info}/PKG-INFO +1 -1
  42. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio.egg-info/SOURCES.txt +7 -7
  43. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/pyproject.toml +1 -0
  44. boneio-1.4.0.dev3/boneio/core/messaging/lox.py +0 -221
  45. boneio-1.4.0.dev3/boneio/core/messaging/loxone.py +0 -181
  46. boneio-1.4.0.dev3/boneio/integration/lox_template.py +0 -243
  47. boneio-1.4.0.dev3/boneio/version.py +0 -2
  48. boneio-1.4.0.dev3/boneio/webui/frontend-dist/assets/aiConfig-Dq5oh99L.js +0 -2
  49. boneio-1.4.0.dev3/boneio/webui/frontend-dist/schema/remote_outputs.schema.json +0 -114
  50. boneio-1.4.0.dev3/boneio/webui/schema/remote_outputs.schema.json +0 -114
  51. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/LICENSE +0 -0
  52. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/MANIFEST.in +0 -0
  53. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/README.md +0 -0
  54. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/__init__.py +0 -0
  55. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.2/input.yaml +0 -0
  56. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.2/output_24_16.yaml +0 -0
  57. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.2/output_32_10.yaml +0 -0
  58. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.2/output_32_5.yaml +0 -0
  59. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.2/output_cover.yaml +0 -0
  60. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.2/output_cover_mix.yaml +0 -0
  61. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.3/input.yaml +0 -0
  62. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.3/output_24_16.yaml +0 -0
  63. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.3/output_32_10.yaml +0 -0
  64. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.3/output_32_5.yaml +0 -0
  65. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.3/output_cover.yaml +0 -0
  66. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.3/output_cover_mix.yaml +0 -0
  67. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.4/input.yaml +0 -0
  68. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.4/output_24_16.yaml +0 -0
  69. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.4/output_32_10.yaml +0 -0
  70. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.4/output_32_5.yaml +0 -0
  71. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.4/output_cover.yaml +0 -0
  72. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.4/output_cover_mix.yaml +0 -0
  73. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.5/input.yaml +0 -0
  74. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.5/output_24_16.yaml +0 -0
  75. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.5/output_32_10.yaml +0 -0
  76. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.5/output_cover.yaml +0 -0
  77. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.5/output_cover_mix.yaml +0 -0
  78. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.6/input.yaml +0 -0
  79. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.6/output_24_16.yaml +0 -0
  80. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.6/output_32_10.yaml +0 -0
  81. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.6/output_cover.yaml +0 -0
  82. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.6/output_cover_mix.yaml +0 -0
  83. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.7/input.yaml +0 -0
  84. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.7/output_24_16.yaml +0 -0
  85. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.7/output_32_10.yaml +0 -0
  86. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.7/output_48_4.yaml +0 -0
  87. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.7/output_cover.yaml +0 -0
  88. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.7/output_cover_mix.yaml +0 -0
  89. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.8/input.yaml +0 -0
  90. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.8/output_24_16.yaml +0 -0
  91. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.8/output_32_10.yaml +0 -0
  92. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.8/output_48_4.yaml +0 -0
  93. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.8/output_cover.yaml +0 -0
  94. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/boards/0.8/output_cover_mix.yaml +0 -0
  95. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/bonecli.py +0 -0
  96. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/__init__.py +0 -0
  97. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/cover/__init__.py +0 -0
  98. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/cover/time_based.py +0 -0
  99. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/group/__init__.py +0 -0
  100. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/group/output_group.py +0 -0
  101. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/input/__init__.py +0 -0
  102. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/input/binary_sensor.py +0 -0
  103. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/input/detectors.py +0 -0
  104. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/input/event.py +0 -0
  105. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/input/remote/__init__.py +0 -0
  106. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/input/remote/base.py +0 -0
  107. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/input/remote/esphome.py +0 -0
  108. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/irrigation/__init__.py +0 -0
  109. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/irrigation/water_source.py +0 -0
  110. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/output/__init__.py +0 -0
  111. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/output/basic.py +0 -0
  112. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/output/mcp.py +0 -0
  113. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/output/pca.py +0 -0
  114. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/output/pcf.py +0 -0
  115. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/sensor/__init__.py +0 -0
  116. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/sensor/virtual_energy.py +0 -0
  117. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/template/__init__.py +0 -0
  118. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/template/alarm_panel.py +0 -0
  119. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/template/gate_cover.py +0 -0
  120. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/components/template/thermostat.py +0 -0
  121. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/const.py +0 -0
  122. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/__init__.py +0 -0
  123. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/cloud/__init__.py +0 -0
  124. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/cloud/data/__init__.py +0 -0
  125. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/cloud/data/docker-compose-cloud.yaml +0 -0
  126. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/cloud/data/docker-compose.yaml +0 -0
  127. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/cloud/data/init-certs-cloud.sh +0 -0
  128. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/cloud/registration.py +0 -0
  129. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/cloud/secrets.py +0 -0
  130. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/config/__init__.py +0 -0
  131. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/config/config_helper.py +0 -0
  132. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/config/migrations/__init__.py +0 -0
  133. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/config/migrations/v1_proxy_port.py +0 -0
  134. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/config/migrations/v2_transition.py +0 -0
  135. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/config/package-lock.json +0 -0
  136. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/config/package.json +0 -0
  137. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/config/schema_converter.py +0 -0
  138. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/config/yaml_util.py +0 -0
  139. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/discovery.py +0 -0
  140. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/events/__init__.py +0 -0
  141. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/events/bus.py +0 -0
  142. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/__init__.py +0 -0
  143. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/action_conditions.py +0 -0
  144. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/canopen.py +0 -0
  145. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/covers.py +0 -0
  146. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/display.py +0 -0
  147. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/inputs.py +0 -0
  148. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/modbus.py +0 -0
  149. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/outputs.py +0 -0
  150. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/remote_input_registrar.py +0 -0
  151. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/sensors.py +0 -0
  152. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/templates/__init__.py +0 -0
  153. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/templates/alarm.py +0 -0
  154. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/templates/gate_cover.py +0 -0
  155. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/templates/thermostat.py +0 -0
  156. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/templates.py +0 -0
  157. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/manager/update.py +0 -0
  158. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/messaging/__init__.py +0 -0
  159. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/messaging/basic.py +0 -0
  160. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/messaging/basic_mqtt.py +0 -0
  161. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/messaging/composite.py +0 -0
  162. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/messaging/local.py +0 -0
  163. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/messaging/mqtt.py +0 -0
  164. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/messaging/queue.py +0 -0
  165. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/remote/__init__.py +0 -0
  166. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/remote/base.py +0 -0
  167. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/remote/can.py +0 -0
  168. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/remote/esphome.py +0 -0
  169. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/remote/mqtt.py +0 -0
  170. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/remote/wled.py +0 -0
  171. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/sensor/__init__.py +0 -0
  172. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/sensor/base.py +0 -0
  173. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/sensor/system.py +0 -0
  174. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/state/__init__.py +0 -0
  175. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/state/manager.py +0 -0
  176. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/system/__init__.py +0 -0
  177. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/system/host_data.py +0 -0
  178. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/system/monitor.py +0 -0
  179. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/utils/__init__.py +0 -0
  180. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/utils/async_updater.py +0 -0
  181. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/utils/conditions.py +0 -0
  182. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/utils/filter.py +0 -0
  183. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/utils/font_util.py +0 -0
  184. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/utils/logger.py +0 -0
  185. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/utils/timeperiod.py +0 -0
  186. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/core/utils/util.py +0 -0
  187. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/24x16/adc.yaml +0 -0
  188. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/24x16/binary_sensor.yaml +0 -0
  189. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/24x16/config.yaml +0 -0
  190. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/24x16/event.yaml +0 -0
  191. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/24x16/mqtt.yaml +0 -0
  192. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/24x16/output24x16A.yaml +0 -0
  193. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/32x10/adc.yaml +0 -0
  194. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/32x10/binary_sensor.yaml +0 -0
  195. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/32x10/config.yaml +0 -0
  196. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/32x10/event.yaml +0 -0
  197. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/32x10/mqtt.yaml +0 -0
  198. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/32x10/output32x10A.yaml +0 -0
  199. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/48x4/adc.yaml +0 -0
  200. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/48x4/binary_sensor.yaml +0 -0
  201. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/48x4/config.yaml +0 -0
  202. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/48x4/event.yaml +0 -0
  203. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/48x4/mqtt.yaml +0 -0
  204. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/48x4/output48x4A.yaml +0 -0
  205. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/__init__.py +0 -0
  206. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/can_master.yaml +0 -0
  207. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/can_slave.yaml +0 -0
  208. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/cover/adc.yaml +0 -0
  209. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/cover/binary_sensor.yaml +0 -0
  210. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/cover/config.yaml +0 -0
  211. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/cover/cover.yaml +0 -0
  212. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/cover/event.yaml +0 -0
  213. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/cover/mqtt.yaml +0 -0
  214. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/cover/outputCover.yaml +0 -0
  215. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/adc.yaml +0 -0
  216. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/binary_sensor.yaml +0 -0
  217. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/config.yaml +0 -0
  218. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/cover.yaml +0 -0
  219. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/event.yaml +0 -0
  220. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/mqtt.yaml +0 -0
  221. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/outputCoverMix.yaml +0 -0
  222. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/adc.yaml +0 -0
  223. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/all_binary_sensor.yaml +0 -0
  224. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/binary_sensor.yaml +0 -0
  225. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/binary_sensor_v_0_7.yaml +0 -0
  226. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/config_24_16.yaml +0 -0
  227. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/event_all.yaml +0 -0
  228. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/event_v_0_7.yaml +0 -0
  229. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/led32x4A.yaml +0 -0
  230. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/output24x16A.yaml +0 -0
  231. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/output24x16A_v0.3.yaml +0 -0
  232. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/output32x10A.yaml +0 -0
  233. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/output32x5A.yaml +0 -0
  234. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/exceptions.py +0 -0
  235. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/__init__.py +0 -0
  236. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/analog/__init__.py +0 -0
  237. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/analog/adc.py +0 -0
  238. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/can/__init__.py +0 -0
  239. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/can/bridge.py +0 -0
  240. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/can/client.py +0 -0
  241. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/can/interface.py +0 -0
  242. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/can/node.py +0 -0
  243. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/can/node_id.py +0 -0
  244. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/can/test_od.py +0 -0
  245. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/display/__init__.py +0 -0
  246. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/display/early_oled.py +0 -0
  247. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/display/fonts/danube__.ttf +0 -0
  248. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/display/oled.py +0 -0
  249. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/gpio/__init__.py +0 -0
  250. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/gpio/expanders/__init__.py +0 -0
  251. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/gpio/expanders/mcp23017.py +0 -0
  252. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/gpio/expanders/pca9685.py +0 -0
  253. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/gpio/expanders/pcf8575.py +0 -0
  254. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/gpio/input/__init__.py +0 -0
  255. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/gpio/input/base.py +0 -0
  256. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/gpio/input/manager.py +0 -0
  257. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/i2c/__init__.py +0 -0
  258. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/i2c/bus.py +0 -0
  259. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/i2c/ina219.py +0 -0
  260. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/i2c/ina219_driver.py +0 -0
  261. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/i2c/mcp9808.py +0 -0
  262. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/i2c/pct2075.py +0 -0
  263. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/onewire/__init__.py +0 -0
  264. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/onewire/bus.py +0 -0
  265. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/onewire/dallas.py +0 -0
  266. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/onewire/ds2482.py +0 -0
  267. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/sensor/__init__.py +0 -0
  268. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/sensor/temperature/__init__.py +0 -0
  269. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/sensor/temperature/base.py +0 -0
  270. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/sensor/temperature/mcp9808.py +0 -0
  271. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/hardware/sensor/temperature/pct2075.py +0 -0
  272. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/integration/__init__.py +0 -0
  273. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/integration/interlock.py +0 -0
  274. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/__init__.py +0 -0
  275. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/actions.py +0 -0
  276. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/MANIFEST.sha256 +0 -0
  277. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/docker/daemon.json +0 -0
  278. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/docker/nodered/docker-compose.yaml +0 -0
  279. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/docker/nodered/nginx/default.conf +0 -0
  280. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/docker/nodered/node-red/settings.js +0 -0
  281. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/journald/journald.conf +0 -0
  282. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/mosquitto/boneio.conf +0 -0
  283. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/sudoers/boneio +0 -0
  284. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/systemd/boneio-oled-boot.service +0 -0
  285. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/systemd/boneio.service +0 -0
  286. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/systemd/set-hostname-once.service +0 -0
  287. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/usr-local-bin/set-hostname-once.sh +0 -0
  288. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/usr-sbin/oled_boot_splash.py +0 -0
  289. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/usr-sbin/oled_boot_splash.sh +0 -0
  290. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/usr-sbin/oled_msg.py +0 -0
  291. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/assets/usr-sbin/oled_msg.sh +0 -0
  292. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/bootstrap/boneio-migrate +0 -0
  293. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/bootstrap/install-helper.sh +0 -0
  294. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/bootstrap/sudoers-migrate +0 -0
  295. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/runner.py +0 -0
  296. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/versions/__init__.py +0 -0
  297. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/versions/v1_3_0_baseline.py +0 -0
  298. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/versions/v1_3_1_fix_oled_boot.py +0 -0
  299. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/versions/v1_3_2_cleanup_can_sudoers.py +0 -0
  300. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/migrations/versions/v1_4_0_fix_mqtt_sudoers.py +0 -0
  301. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/__init__.py +0 -0
  302. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/cli.py +0 -0
  303. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/client.py +0 -0
  304. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/coordinator.py +0 -0
  305. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/__init__.py +0 -0
  306. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/le-03mw.json +0 -0
  307. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/le-03mwct.json +0 -0
  308. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/orno-or-we-517.json +0 -0
  309. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/sdm120.json +0 -0
  310. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/sdm630.json +0 -0
  311. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/socomec_e03.json +0 -0
  312. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/socomec_e23.json +0 -0
  313. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/hvac/fujitsu-ac.json +0 -0
  314. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/hvac/ventclear.json +0 -0
  315. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/inverters/sofar.json +0 -0
  316. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/inverters/thessla.json +0 -0
  317. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/other/esp32_relay_x4_modbus.json +0 -0
  318. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/other/n4dsc08.json +0 -0
  319. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/other/r4dcb08.json +0 -0
  320. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/other/wanas415.json +0 -0
  321. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/boneio-edge-temp.json +0 -0
  322. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/cwt.json +0 -0
  323. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/dts1964_3f.json +0 -0
  324. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/dyp-a12-ultrasonic.json +0 -0
  325. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/gdfs.json +0 -0
  326. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/gdfx.json +0 -0
  327. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/liquid-sensor.json +0 -0
  328. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/pt100.json +0 -0
  329. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/sht20.json +0 -0
  330. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/sht30.json +0 -0
  331. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/entities/__init__.py +0 -0
  332. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/entities/base.py +0 -0
  333. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/entities/derived/__init__.py +0 -0
  334. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/entities/derived/numeric.py +0 -0
  335. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/entities/derived/select.py +0 -0
  336. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/entities/derived/switch.py +0 -0
  337. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/entities/derived/text.py +0 -0
  338. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/entities/sensor/__init__.py +0 -0
  339. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/entities/sensor/binary.py +0 -0
  340. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/entities/sensor/numeric.py +0 -0
  341. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/entities/sensor/text.py +0 -0
  342. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/entities/writeable/__init__.py +0 -0
  343. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/entities/writeable/binary.py +0 -0
  344. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/entities/writeable/numeric.py +0 -0
  345. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/modbus/utils.py +0 -0
  346. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/models/__init__.py +0 -0
  347. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/models/actions.py +0 -0
  348. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/models/events.py +0 -0
  349. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/models/files.py +0 -0
  350. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/models/logs.py +0 -0
  351. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/models/mqtt.py +0 -0
  352. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/models/state.py +0 -0
  353. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/runner.py +0 -0
  354. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/schema/actions_sensor.yaml +0 -0
  355. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/schema/actions_switch.yaml +0 -0
  356. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/schema/condition.yaml +0 -0
  357. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/schema/filters.yaml +0 -0
  358. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/schema/filters_adc.yaml +0 -0
  359. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/schema/id.yaml +0 -0
  360. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/schema/remote_devices.yaml +0 -0
  361. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/schema/remote_inputs.yaml +0 -0
  362. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/schema/temp_unit.yaml +0 -0
  363. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/schema/update_interval.yaml +0 -0
  364. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/action_validation.py +0 -0
  365. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/app.py +0 -0
  366. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/codicon-DCmgc-ay.ttf +0 -0
  367. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/editor.worker-BVjSvWeP.js +0 -0
  368. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/json.worker-CqOJL4FD.js +0 -0
  369. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/monaco-B9WiNxkw.css +0 -0
  370. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/monaco-CAZoGZNF.js +0 -0
  371. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/rolldown-runtime-Dw2cE7zH.js +0 -0
  372. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/vendor-BD5Ml_Uz.js +0 -0
  373. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/workbox-window.prod.es5-BJd1pjeW.js +0 -0
  374. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/yaml.worker-nZQZSRZ7.js +0 -0
  375. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/boneio-192.png +0 -0
  376. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/boneio-512.png +0 -0
  377. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/boneio.svg +0 -0
  378. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/boneio_fav.svg +0 -0
  379. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/adc.schema.json +0 -0
  380. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/areas.schema.json +0 -0
  381. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/boneio.schema.json +0 -0
  382. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/can.schema.json +0 -0
  383. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/cover.schema.json +0 -0
  384. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/dallas.schema.json +0 -0
  385. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/ds2482.schema.json +0 -0
  386. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/ina219.schema.json +0 -0
  387. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/lm75.schema.json +0 -0
  388. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/logger.schema.json +0 -0
  389. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/lox_udp.schema.json +0 -0
  390. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/mcp23017.schema.json +0 -0
  391. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/mcp9808.schema.json +0 -0
  392. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/modbus.schema.json +0 -0
  393. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/mqtt.schema.json +0 -0
  394. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/oled.schema.json +0 -0
  395. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/output.schema.json +0 -0
  396. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/output_group.schema.json +0 -0
  397. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/pca9685.schema.json +0 -0
  398. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/pcf8575.schema.json +0 -0
  399. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/remote_devices.schema.json +0 -0
  400. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/remote_inputs.schema.json +0 -0
  401. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/sensor.schema.json +0 -0
  402. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/virtual_energy_sensor.schema.json +0 -0
  403. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/web.schema.json +0 -0
  404. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/workbox-4eca85ba.js +0 -0
  405. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/middleware/__init__.py +0 -0
  406. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/middleware/auth.py +0 -0
  407. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/__init__.py +0 -0
  408. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/auth.py +0 -0
  409. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/caddy.py +0 -0
  410. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/can.py +0 -0
  411. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/covers.py +0 -0
  412. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/migrations.py +0 -0
  413. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/modbus.py +0 -0
  414. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/outputs.py +0 -0
  415. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/remote_devices.py +0 -0
  416. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/sensors.py +0 -0
  417. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/system.py +0 -0
  418. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/templates.py +0 -0
  419. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/timezone_sudoers.py +0 -0
  420. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/tools.py +0 -0
  421. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/routes/update.py +0 -0
  422. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/adc.schema.json +0 -0
  423. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/areas.schema.json +0 -0
  424. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/boneio.schema.json +0 -0
  425. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/can.schema.json +0 -0
  426. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/cover.schema.json +0 -0
  427. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/dallas.schema.json +0 -0
  428. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/ds2482.schema.json +0 -0
  429. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/ina219.schema.json +0 -0
  430. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/lm75.schema.json +0 -0
  431. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/logger.schema.json +0 -0
  432. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/lox_udp.schema.json +0 -0
  433. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/mcp23017.schema.json +0 -0
  434. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/mcp9808.schema.json +0 -0
  435. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/modbus.schema.json +0 -0
  436. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/mqtt.schema.json +0 -0
  437. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/oled.schema.json +0 -0
  438. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/output.schema.json +0 -0
  439. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/output_group.schema.json +0 -0
  440. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/pca9685.schema.json +0 -0
  441. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/pcf8575.schema.json +0 -0
  442. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/remote_devices.schema.json +0 -0
  443. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/remote_inputs.schema.json +0 -0
  444. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/sensor.schema.json +0 -0
  445. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/virtual_energy_sensor.schema.json +0 -0
  446. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/schema/web.schema.json +0 -0
  447. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/services/__init__.py +0 -0
  448. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/services/logs.py +0 -0
  449. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/web_server.py +0 -0
  450. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio/webui/websocket_manager.py +0 -0
  451. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio.egg-info/dependency_links.txt +0 -0
  452. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio.egg-info/entry_points.txt +0 -0
  453. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio.egg-info/requires.txt +0 -0
  454. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/boneio.egg-info/top_level.txt +0 -0
  455. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/setup.cfg +0 -0
  456. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/setup.py +0 -0
  457. {boneio-1.4.0.dev3 → boneio-1.4.0.dev5}/tests/test_py313_compatibility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boneio
3
- Version: 1.4.0.dev3
3
+ Version: 1.4.0.dev5
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
@@ -192,6 +192,12 @@ class BaseCover(BaseCoverABC, BasicMqtt):
192
192
  self._movement_thread = None
193
193
  self._stop_event = threading.Event()
194
194
 
195
+ # Flag set by action executor to signal this call originates from a button action.
196
+ # Used by VenetianCover to conditionally skip tilt restore.
197
+ self._from_action: bool = False
198
+ # When True, tilt restore is explicitly requested by the action definition.
199
+ self._action_tilt_restore: bool = False
200
+
195
201
  self._event_bus.add_sigterm_listener(self.on_exit)
196
202
 
197
203
  with suppress(RuntimeError):
@@ -35,7 +35,7 @@ class VenetianCover(BaseCover, BaseVenetianCoverABC):
35
35
  actuator_activation_duration: Actuator activation time (unused).
36
36
  restored_state: Persisted position/tilt from disk.
37
37
  tilt_restore_after_close: If True, restore previous tilt
38
- position after closing the cover.
38
+ position after closing the cover (UI/HA calls).
39
39
  """
40
40
  self._tilt_duration = tilt_duration.total_milliseconds # Czas trwania ruchu lameli
41
41
  self._initial_tilt_position = float(restored_state.get("tilt", DEFAULT_RESTORED_STATE["tilt"]))
@@ -300,10 +300,17 @@ class VenetianCover(BaseCover, BaseVenetianCoverABC):
300
300
  def _save_tilt_for_restore(self) -> None:
301
301
  """Save current tilt position for later restoration.
302
302
 
303
- Called before any closing movement when tilt_restore_after_close
304
- is enabled. Clears saved value if tilt is already at 0%.
303
+ Called before any closing movement. Determines whether to save
304
+ based on the call source:
305
+ - UI/HA calls: uses tilt_restore_after_close setting
306
+ - Action calls: uses _action_tilt_restore flag (set by executor)
305
307
  """
306
- if self._tilt_restore_after_close and self._tilt_position > 0:
308
+ if self._from_action:
309
+ should_restore = self._action_tilt_restore
310
+ else:
311
+ should_restore = self._tilt_restore_after_close
312
+
313
+ if should_restore and self._tilt_position > 0:
307
314
  self._tilt_before_close = self._tilt_position
308
315
  _LOGGER.debug(
309
316
  "VenetianCover %s: saving tilt=%d%% before close",
@@ -75,6 +75,7 @@ class IrrigationController:
75
75
  repeat: int = 0,
76
76
  auto_advance: bool = True,
77
77
  reverse: bool = False,
78
+ pause_timeout_s: int = 1800,
78
79
  ) -> None:
79
80
  """Initialize irrigation controller.
80
81
 
@@ -95,6 +96,8 @@ class IrrigationController:
95
96
  repeat: Number of cycle repeats.
96
97
  auto_advance: Automatically advance to next zone.
97
98
  reverse: Run zones in reverse order.
99
+ pause_timeout_s: Auto-shutdown after this many seconds in PAUSED state.
100
+ Default 1800 (30 minutes). Set 0 to disable.
98
101
  """
99
102
  self.id = id
100
103
  self.name = name
@@ -119,6 +122,8 @@ class IrrigationController:
119
122
  self._skip_next_run = False
120
123
 
121
124
  self._zone_timer_cancel = None
125
+ self._pause_timer_cancel = None
126
+ self._pause_timeout_s = max(0, pause_timeout_s)
122
127
  self._run_start_utc: datetime | None = None
123
128
  self._active_zone_idx: int | None = None
124
129
  self._active_zone_remaining_s: int | None = None
@@ -181,6 +186,10 @@ class IrrigationController:
181
186
  def _schedule_skip_cmd_topic(self, idx: int) -> str:
182
187
  return f"{self._topic_prefix}/cmd/{IRRIGATION}/{self.id}/schedule/{idx}/skip/set"
183
188
 
189
+ def _event_topic(self) -> str:
190
+ """MQTT topic for HA event entity notifications."""
191
+ return f"{self._topic_prefix}/{IRRIGATION}/{self.id}/event"
192
+
184
193
  def _state_key(self, suffix: str) -> str:
185
194
  return f"{self.id}/{suffix}"
186
195
 
@@ -223,6 +232,24 @@ class IrrigationController:
223
232
  _LOGGER.debug("Irrigation MQTT publish: topic='%s' payload=%s retain=%s", topic, payload, retain)
224
233
  self._message_bus.send_message(topic=topic, payload=payload, retain=retain)
225
234
 
235
+ def _publish_event(self, event_type: str, **attributes: Any) -> None:
236
+ """Publish an event to the HA event entity topic.
237
+
238
+ The payload follows the HA MQTT event entity format:
239
+ ``{"event_type": "...", ...extra attributes}``.
240
+
241
+ Events are NOT retained — they are instantaneous notifications.
242
+
243
+ Args:
244
+ event_type: One of the registered event types
245
+ (interlock_fault, cycle_complete, standby_blocked).
246
+ **attributes: Additional key-value pairs included in the event payload.
247
+ """
248
+ import json
249
+
250
+ payload = {"event_type": event_type, **attributes}
251
+ self._publish(self._event_topic(), json.dumps(payload), retain=False)
252
+
226
253
  def _ordered_zones(self) -> list[tuple[int, IrrigationZone]]:
227
254
  indexed = list(enumerate(self._zones))
228
255
  if self._reverse:
@@ -352,6 +379,7 @@ class IrrigationController:
352
379
  "".join(traceback.format_stack(limit=5)),
353
380
  )
354
381
  self.stop_schedules()
382
+ self._cancel_pause_timer()
355
383
  await self._stop_current_zone()
356
384
  await self._handle_pump_stop_sequence()
357
385
  self._state = ControllerState.IDLE
@@ -370,11 +398,13 @@ class IrrigationController:
370
398
  self._cancel_zone_timer()
371
399
  await self._stop_current_zone()
372
400
  self._state = ControllerState.PAUSED
401
+ self._arm_pause_timer()
373
402
  await self.publish_all_states()
374
403
 
375
404
  async def resume(self) -> None:
376
405
  if self._state != ControllerState.PAUSED or self._active_zone_idx is None:
377
406
  return
407
+ self._cancel_pause_timer()
378
408
  remaining = self._active_zone_remaining_s or self._current_zone_duration_seconds()
379
409
  await self._start_zone(self._active_zone_idx, override_duration=remaining)
380
410
 
@@ -400,6 +430,11 @@ class IrrigationController:
400
430
  )
401
431
  if self._standby:
402
432
  _LOGGER.info("Irrigation %s is in standby mode, not starting", self.id)
433
+ self._publish_event(
434
+ "standby_blocked",
435
+ controller=self.id,
436
+ message=f"Irrigation '{self.name}' start blocked: standby mode is active",
437
+ )
403
438
  return
404
439
 
405
440
  if self._state in (ControllerState.RUNNING, ControllerState.PAUSED):
@@ -428,6 +463,12 @@ class IrrigationController:
428
463
  )
429
464
  if self._standby:
430
465
  _LOGGER.info("Irrigation %s is in standby mode, not starting zone", self.id)
466
+ self._publish_event(
467
+ "standby_blocked",
468
+ controller=self.id,
469
+ zone=zone_id,
470
+ message=f"Irrigation '{self.name}' zone '{zone_id}' blocked: standby mode is active",
471
+ )
431
472
  return
432
473
 
433
474
  match_idx = None
@@ -551,6 +592,11 @@ class IrrigationController:
551
592
  await self._start_cycle_from_eligible()
552
593
  return
553
594
 
595
+ self._publish_event(
596
+ "cycle_complete",
597
+ controller=self.id,
598
+ message=f"Irrigation '{self.name}' cycle completed",
599
+ )
554
600
  await self.shutdown()
555
601
 
556
602
  def _ordered_zone_indices(self) -> list[int]:
@@ -718,8 +764,10 @@ class IrrigationController:
718
764
  async def _handle_interlock_fault(self, zone_id: str, source_id: str | None) -> None:
719
765
  """Handle interlock-blocked activation.
720
766
 
721
- Shuts down the controller and publishes a fault notification via MQTT
722
- so that Home Assistant (or other consumers) can alert the user.
767
+ Shuts down the controller and publishes both a retained fault status
768
+ message and a non-retained HA event notification via the event entity.
769
+ Home Assistant automations can listen to the event entity to trigger
770
+ mobile push notifications, Telegram messages, etc.
723
771
 
724
772
  Args:
725
773
  zone_id: ID of the zone that was being started.
@@ -734,13 +782,15 @@ class IrrigationController:
734
782
  source_info,
735
783
  )
736
784
 
737
- # Publish fault notification on MQTT
785
+ fault_message = f"Irrigation '{self.name}' stopped: output blocked by interlock (zone: {zone_id})"
786
+
787
+ # Publish retained fault status on MQTT (legacy topic)
738
788
  fault_payload = {
739
789
  "fault": "interlock_blocked",
740
790
  "controller": self.id,
741
791
  "zone": zone_id,
742
792
  "source": source_id or "",
743
- "message": f"Irrigation '{self.name}' stopped: output blocked by interlock (zone: {zone_id})",
793
+ "message": fault_message,
744
794
  }
745
795
  self._publish(
746
796
  f"{self._topic_prefix}/{IRRIGATION}/{self.id}/fault",
@@ -748,6 +798,15 @@ class IrrigationController:
748
798
  retain=False,
749
799
  )
750
800
 
801
+ # Publish HA event entity notification (non-retained, instantaneous)
802
+ self._publish_event(
803
+ "interlock_fault",
804
+ controller=self.id,
805
+ zone=zone_id,
806
+ source=source_id or "",
807
+ message=fault_message,
808
+ )
809
+
751
810
  await self.shutdown()
752
811
  await self.publish_all_states()
753
812
 
@@ -799,6 +858,44 @@ class IrrigationController:
799
858
  async def _zone_timer_callback(self, _timestamp: datetime) -> None:
800
859
  await self._advance_to_next_zone(force=False)
801
860
 
861
+ def _cancel_pause_timer(self) -> None:
862
+ """Cancel the pause timeout timer if active."""
863
+ if self._pause_timer_cancel is not None:
864
+ self._pause_timer_cancel()
865
+ self._pause_timer_cancel = None
866
+
867
+ def _arm_pause_timer(self) -> None:
868
+ """Arm an auto-shutdown timer for the PAUSED state.
869
+
870
+ If pause_timeout_s is 0, no timer is set (pause lasts indefinitely).
871
+ Otherwise, the controller will auto-shutdown after the configured timeout.
872
+ """
873
+ self._cancel_pause_timer()
874
+ if self._pause_timeout_s <= 0:
875
+ return
876
+ point = utcnow() + timedelta(seconds=self._pause_timeout_s)
877
+ self._pause_timer_cancel = async_track_point_in_time(
878
+ loop=self._event_bus._loop,
879
+ job=self._pause_timeout_callback,
880
+ point_in_time=point,
881
+ )
882
+ _LOGGER.info(
883
+ "Irrigation %s: pause timeout armed for %d seconds",
884
+ self.id,
885
+ self._pause_timeout_s,
886
+ )
887
+
888
+ async def _pause_timeout_callback(self, _timestamp: datetime) -> None:
889
+ """Handle pause timeout — auto-shutdown the controller."""
890
+ if self._state != ControllerState.PAUSED:
891
+ return
892
+ _LOGGER.warning(
893
+ "Irrigation %s: pause timeout expired after %d seconds, shutting down",
894
+ self.id,
895
+ self._pause_timeout_s,
896
+ )
897
+ await self.shutdown()
898
+
802
899
  async def handle_main_command(self, payload: str) -> None:
803
900
  cmd = payload.strip()
804
901
  upper = cmd.upper()
@@ -10,15 +10,21 @@ The actual hardware control is delegated to the parent ``ESPHomeDeviceManager``
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
+ import asyncio
13
14
  import logging
14
15
  import time
15
- from typing import Any
16
+ from typing import TYPE_CHECKING, Any
16
17
 
17
18
  from boneio.const import OFF, ON, SWITCH
18
- from boneio.core.events import EventBus
19
+ from boneio.core.events import EventBus, async_track_point_in_time, utcnow
20
+ from boneio.core.utils import callback
21
+ from boneio.core.utils.timeperiod import TimePeriod, parse_time_to_seconds
19
22
  from boneio.models import OutputState
20
23
  from boneio.models.events import OutputEvent
21
24
 
25
+ if TYPE_CHECKING:
26
+ from boneio.integration.interlock import SoftwareInterlockManager
27
+
22
28
  _LOGGER = logging.getLogger(__name__)
23
29
 
24
30
 
@@ -60,6 +66,16 @@ class RemoteOutputBase:
60
66
  show_in_ha: bool = False,
61
67
  area: str | None = None,
62
68
  on_disconnect: str = "ignore",
69
+ interlock_manager: SoftwareInterlockManager | None = None,
70
+ interlock_groups: list[str] | None = None,
71
+ enforce_interlock: bool = False,
72
+ momentary_turn_on: TimePeriod | None = None,
73
+ momentary_turn_off: TimePeriod | None = None,
74
+ adjustable_duration: bool = False,
75
+ duration_default: float = 60.0,
76
+ duration_min: float = 1.0,
77
+ duration_max: float = 3600.0,
78
+ duration_unit: str = "s",
63
79
  ) -> None:
64
80
  self._id = id
65
81
  self._name = name
@@ -72,10 +88,32 @@ class RemoteOutputBase:
72
88
  self.area: str | None = area
73
89
  self._on_disconnect = on_disconnect
74
90
 
91
+ # Interlock support (shared with local BasicOutput instances)
92
+ self._interlock_manager: SoftwareInterlockManager | None = interlock_manager
93
+ self._interlock_groups: list[str] = interlock_groups or []
94
+ self._enforce_interlock: bool = enforce_interlock
95
+
96
+ # Momentary actions (auto-off / auto-on after duration)
97
+ self._momentary_turn_on: TimePeriod | None = momentary_turn_on
98
+ self._momentary_turn_off: TimePeriod | None = momentary_turn_off
99
+ self._momentary_action: Any = None
100
+
101
+ # Adjustable duration (HA number entity slider)
102
+ self._adjustable_duration_enabled: bool = adjustable_duration
103
+ self._duration_min: float = max(1.0, duration_min)
104
+ self._duration_max: float = max(self._duration_min, duration_max)
105
+ self._duration_default: float = duration_default
106
+ self._duration_unit: str = duration_unit
107
+ self._adjustable_duration: float = max(self._duration_min, min(self._duration_max, self._duration_default))
108
+ # If adjustable_duration is on, momentary_turn_on is managed by the slider
109
+ if self._adjustable_duration_enabled:
110
+ self._momentary_turn_on = None
111
+
75
112
  self._state: str = OFF
76
113
  self._last_timestamp: float = 0.0
77
114
  self._available: bool = False
78
115
  self._brightness: int | None = None # 0-255, None if not a dimmable light
116
+ self._loop: asyncio.AbstractEventLoop | None = None
79
117
 
80
118
  # Reference to remote device manager — set by register_remote_outputs().
81
119
  # May be None at startup if ESPHome devices load in background.
@@ -186,6 +224,34 @@ class RemoteOutputBase:
186
224
  self._id,
187
225
  )
188
226
 
227
+ # ------------------------------------------------------------------
228
+ # Interlock
229
+ # ------------------------------------------------------------------
230
+
231
+ def set_interlock(
232
+ self,
233
+ interlock_manager: SoftwareInterlockManager,
234
+ interlock_groups: list[str],
235
+ ) -> None:
236
+ """Set interlock manager and groups.
237
+
238
+ Args:
239
+ interlock_manager: Shared interlock manager instance.
240
+ interlock_groups: List of group names this output belongs to.
241
+ """
242
+ self._interlock_manager = interlock_manager
243
+ self._interlock_groups = interlock_groups
244
+
245
+ def check_interlock(self) -> bool:
246
+ """Check if this output can be turned on without violating interlocks.
247
+
248
+ Returns:
249
+ True if no interlock violation, False if blocked.
250
+ """
251
+ if self._interlock_manager is not None and self._interlock_groups:
252
+ return self._interlock_manager.can_turn_on(self, self._interlock_groups)
253
+ return True
254
+
189
255
  # ------------------------------------------------------------------
190
256
  # Core control methods (duck-type compatible with BasicOutput)
191
257
  # ------------------------------------------------------------------
@@ -193,12 +259,21 @@ class RemoteOutputBase:
193
259
  async def async_turn_on(self, timestamp: float | None = None) -> bool:
194
260
  """Turn on the remote output.
195
261
 
262
+ Checks interlock before sending the ON command. If another output
263
+ in the same interlock group is already ON, the request is rejected.
264
+ After successful ON, schedules momentary auto-OFF if configured.
265
+
196
266
  Args:
197
267
  timestamp: Optional timestamp for state tracking.
198
268
 
199
269
  Returns:
200
- True if the output was turned on, False on failure.
270
+ True if the output was turned on, False if blocked or failed.
201
271
  """
272
+ can_turn_on = self.check_interlock()
273
+ if not can_turn_on:
274
+ _LOGGER.warning("Interlock active: cannot turn on remote output '%s'", self._id)
275
+ return False
276
+
202
277
  if not self._resolve_device_manager():
203
278
  _LOGGER.error("Remote output '%s' has no device manager, cannot turn on", self._id)
204
279
  return False
@@ -211,6 +286,7 @@ class RemoteOutputBase:
211
286
  self._state = ON
212
287
  self._last_timestamp = timestamp or time.time()
213
288
  self._emit_state_event()
289
+ self._execute_momentary_turn(ON)
214
290
  _LOGGER.debug("Remote output '%s' turned ON", self._id)
215
291
  else:
216
292
  _LOGGER.warning("Failed to turn ON remote output '%s'", self._id)
@@ -219,6 +295,8 @@ class RemoteOutputBase:
219
295
  async def async_turn_off(self, timestamp: float | None = None) -> None:
220
296
  """Turn off the remote output.
221
297
 
298
+ After successful OFF, schedules momentary auto-ON if configured.
299
+
222
300
  Args:
223
301
  timestamp: Optional timestamp for state tracking.
224
302
  """
@@ -234,6 +312,7 @@ class RemoteOutputBase:
234
312
  self._state = OFF
235
313
  self._last_timestamp = timestamp or time.time()
236
314
  self._emit_state_event()
315
+ self._execute_momentary_turn(OFF)
237
316
  _LOGGER.debug("Remote output '%s' turned OFF", self._id)
238
317
  else:
239
318
  _LOGGER.warning("Failed to turn OFF remote output '%s'", self._id)
@@ -259,6 +338,10 @@ class RemoteOutputBase:
259
338
  Called by ESPHomeDeviceManager when it receives a state update
260
339
  for this output's entity.
261
340
 
341
+ If ``enforce_interlock`` is enabled and the output was turned ON
342
+ externally while violating an interlock, boneIO will immediately
343
+ send a turn-off command.
344
+
262
345
  Args:
263
346
  new_state: ``True`` if the output is now ON.
264
347
  brightness: Optional brightness value (0-255) for dimmable lights.
@@ -281,6 +364,15 @@ class RemoteOutputBase:
281
364
  self._brightness,
282
365
  )
283
366
 
367
+ # Enforce interlock: if turned ON externally and violating interlock,
368
+ # immediately send OFF command to the remote device.
369
+ if new_state and self._enforce_interlock and not self.check_interlock():
370
+ _LOGGER.warning(
371
+ "Remote output '%s' turned ON externally, violating interlock — forcing OFF",
372
+ self._id,
373
+ )
374
+ asyncio.ensure_future(self._enforce_interlock_off())
375
+
284
376
  async def async_set_brightness(self, brightness: int, timestamp: float | None = None) -> None:
285
377
  """Set brightness on the remote light output.
286
378
 
@@ -386,9 +478,138 @@ class RemoteOutputBase:
386
478
  area=self.area,
387
479
  remote=True,
388
480
  brightness=self._brightness,
481
+ interlock_groups=self._interlock_groups,
389
482
  )
390
483
  self._event_bus.trigger_event(OutputEvent(entity_id=self._id, state=output_state))
391
484
 
485
+ # ------------------------------------------------------------------
486
+ # Momentary actions (auto-off / auto-on after delay)
487
+ # ------------------------------------------------------------------
488
+
489
+ def _execute_momentary_turn(self, momentary_type: str) -> None:
490
+ """Schedule momentary action (auto-off after ON, or auto-on after OFF).
491
+
492
+ If adjustable_duration is enabled and this is a turn-ON action,
493
+ the slider value is used instead of the static momentary_turn_on.
494
+
495
+ Args:
496
+ momentary_type: ON or OFF.
497
+ """
498
+ if self._loop is None:
499
+ try:
500
+ self._loop = asyncio.get_running_loop()
501
+ except RuntimeError:
502
+ return
503
+
504
+ if self._momentary_action:
505
+ _LOGGER.debug("Cancelling momentary action for %s", self._name)
506
+ self._momentary_action()
507
+
508
+ if momentary_type == ON:
509
+ action = self.async_turn_off
510
+ if self._adjustable_duration_enabled:
511
+ delayed_action = TimePeriod(seconds=self._adjustable_duration)
512
+ else:
513
+ delayed_action = self._momentary_turn_on
514
+ else:
515
+ action = self.async_turn_on
516
+ delayed_action = self._momentary_turn_off
517
+
518
+ if delayed_action:
519
+ _LOGGER.debug(
520
+ "Scheduling momentary action for %s in %s",
521
+ self._name,
522
+ delayed_action.as_timedelta,
523
+ )
524
+ self._momentary_action = async_track_point_in_time(
525
+ loop=self._loop,
526
+ job=self._momentary_callback,
527
+ point_in_time=utcnow() + delayed_action.as_timedelta,
528
+ action=action,
529
+ )
530
+
531
+ @callback
532
+ async def _momentary_callback(self, timestamp: float, action: Any) -> None:
533
+ """Execute the scheduled momentary turn-on or turn-off."""
534
+ _LOGGER.info("Momentary callback at %s for remote output %s", timestamp, self._name)
535
+ await action(timestamp=timestamp)
536
+ self._momentary_action = None
537
+
538
+ # -- Adjustable duration -------------------------------------------------
539
+
540
+ @property
541
+ def adjustable_duration_enabled(self) -> bool:
542
+ """Whether this output has an adjustable duration (HA number entity)."""
543
+ return self._adjustable_duration_enabled
544
+
545
+ @property
546
+ def adjustable_duration(self) -> float:
547
+ """Current adjustable duration value in seconds."""
548
+ return self._adjustable_duration
549
+
550
+ @property
551
+ def duration_min(self) -> float:
552
+ """Minimum duration in seconds for HA slider."""
553
+ return self._duration_min
554
+
555
+ @property
556
+ def duration_max(self) -> float:
557
+ """Maximum duration in seconds for HA slider."""
558
+ return self._duration_max
559
+
560
+ @property
561
+ def duration_unit(self) -> str:
562
+ """Unit of measurement for HA number entity ('s' or 'min')."""
563
+ return self._duration_unit
564
+
565
+ def set_adjustable_duration(self, seconds: float) -> None:
566
+ """Set the adjustable duration value.
567
+
568
+ Clamps to [duration_min, duration_max].
569
+
570
+ Args:
571
+ seconds: New duration in seconds.
572
+ """
573
+ self._adjustable_duration = max(self._duration_min, min(self._duration_max, seconds))
574
+ _LOGGER.debug(
575
+ "Remote output '%s' adjustable duration set to %.1fs",
576
+ self.id,
577
+ self._adjustable_duration,
578
+ )
579
+
580
+ def restore_adjustable_duration(self, seconds: float) -> None:
581
+ """Restore persisted duration value.
582
+
583
+ Args:
584
+ seconds: Persisted duration value.
585
+ """
586
+ self._adjustable_duration = max(self._duration_min, min(self._duration_max, seconds))
587
+
588
+ async def _enforce_interlock_off(self) -> None:
589
+ """Send OFF command to remote device after interlock violation.
590
+
591
+ Called when the remote device reports ON state that violates an
592
+ active interlock group. Small delay allows the state to settle.
593
+ """
594
+ await asyncio.sleep(0.1) # Allow state to settle
595
+ if not self._resolve_device_manager():
596
+ _LOGGER.error(
597
+ "Cannot enforce interlock OFF on '%s': no device manager",
598
+ self._id,
599
+ )
600
+ return
601
+ success = await self._device_manager.control_output(
602
+ output_id=self._output_id,
603
+ action="OFF",
604
+ )
605
+ if success:
606
+ _LOGGER.info("Interlock enforced: remote output '%s' turned OFF", self._id)
607
+ else:
608
+ _LOGGER.error(
609
+ "Failed to enforce interlock OFF on remote output '%s'",
610
+ self._id,
611
+ )
612
+
392
613
  # ------------------------------------------------------------------
393
614
  # Properties (duck-type compatible with BasicOutput)
394
615
  # ------------------------------------------------------------------
@@ -11,11 +11,13 @@ from boneio.const import NEXT_VALVE, ON, PAUSE, RESUME
11
11
  from boneio.core.utils.timeperiod import parse_time_to_seconds
12
12
  from boneio.integration.homeassistant import (
13
13
  ha_irrigation_button_message,
14
+ ha_irrigation_event_message,
14
15
  ha_irrigation_main_switch_message,
15
16
  ha_irrigation_number_message,
16
17
  ha_irrigation_select_message,
17
18
  ha_irrigation_switch_message,
18
19
  ha_irrigation_timestamp_sensor_message,
20
+ ha_irrigation_valve_message,
19
21
  )
20
22
 
21
23
  if TYPE_CHECKING:
@@ -90,6 +92,7 @@ class IrrigationManager:
90
92
  repeat=int(cfg.get("repeat", 0)),
91
93
  auto_advance=bool(cfg.get("auto_advance", True)),
92
94
  reverse=bool(cfg.get("reverse", False)),
95
+ pause_timeout_s=int(parse_time_to_seconds(cfg.get("pause_timeout"), 1800)),
93
96
  )
94
97
 
95
98
  def _build_zone(self, zone_cfg: dict[str, Any]) -> IrrigationZone | None:
@@ -280,9 +283,10 @@ class IrrigationManager:
280
283
  (f"{ctrl.id}_next_valve", "button"),
281
284
  (f"{ctrl.id}_pause", "button"),
282
285
  (f"{ctrl.id}_resume", "button"),
286
+ (f"{ctrl.id}_event", "event"),
283
287
  ]
284
288
  for zone in ctrl.zones:
285
- discovery_ids.append((f"{ctrl.id}_zone_{zone.id}", "switch"))
289
+ discovery_ids.append((f"{ctrl.id}_zone_{zone.id}", "valve"))
286
290
  discovery_ids.append((f"{ctrl.id}_zone_{zone.id}_enabled", "switch"))
287
291
  discovery_ids.append((f"{ctrl.id}_zone_{zone.id}_duration", "number"))
288
292
  for idx in range(len(ctrl._schedule)):
@@ -506,10 +510,16 @@ class IrrigationManager:
506
510
  )
507
511
 
508
512
  for zone in ctrl.zones:
513
+ # Remove stale switch discovery (migration from switch → valve)
509
514
  self._manager.publish_ha_discovery(
510
515
  id=f"{ctrl.id}_zone_{zone.id}",
511
516
  ha_type="switch",
512
- payload=ha_irrigation_switch_message(
517
+ payload="",
518
+ )
519
+ self._manager.publish_ha_discovery(
520
+ id=f"{ctrl.id}_zone_{zone.id}",
521
+ ha_type="valve",
522
+ payload=ha_irrigation_valve_message(
513
523
  ctrl.id,
514
524
  ctrl.name,
515
525
  suffix=f"zone/{zone.id}",
@@ -584,3 +594,14 @@ class IrrigationManager:
584
594
  config_helper=cfg,
585
595
  ),
586
596
  )
597
+
598
+ # Event entity — fires on interlock faults, cycle completions, etc.
599
+ self._manager.publish_ha_discovery(
600
+ id=f"{ctrl.id}_event",
601
+ ha_type="event",
602
+ payload=ha_irrigation_event_message(
603
+ ctrl.id,
604
+ ctrl.name,
605
+ config_helper=cfg,
606
+ ),
607
+ )