boneio 1.4.0.dev4__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 (454) hide show
  1. {boneio-1.4.0.dev4/boneio.egg-info → boneio-1.4.0.dev5}/PKG-INFO +1 -1
  2. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/irrigation/controller.py +101 -4
  3. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/irrigation.py +23 -2
  4. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/manager.py +1 -1
  5. boneio-1.4.0.dev5/boneio/core/messaging/lox.py +326 -0
  6. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/integration/homeassistant.py +84 -0
  7. boneio-1.4.0.dev5/boneio/integration/lox_template.py +367 -0
  8. boneio-1.4.0.dev5/boneio/modbus/devices/hvac/eht-topventil-plus.json +243 -0
  9. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/remote_outputs.yaml +3 -1
  10. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/schema.yaml +22 -1
  11. boneio-1.4.0.dev5/boneio/version.py +2 -0
  12. boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/ConfigEditor-BBQ49dou.js → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/ConfigEditor-A8cWujvP.js +1 -1
  13. boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/aiConfig-BwEuqxu2.js → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/aiConfig-DxFilBWK.js +2 -2
  14. boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/aiWizardPrompt-CEIyLZ8l.js → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/aiWizardPrompt-CrWwS7zb.js +1 -1
  15. boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/index-D-R9QzIP.css → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/index-BtCN44rd.css +1 -1
  16. boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/index-CfQ35RrC.js → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/index-ChujUEJh.js +62 -6
  17. boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/useTranslation-ChbxfQ44.js → boneio-1.4.0.dev5/boneio/webui/frontend-dist/assets/useTranslation-CxUU9LHE.js +2 -2
  18. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/index.html +4 -4
  19. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/config.schema.json +21 -3
  20. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/irrigation.schema.json +9 -0
  21. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/modbus_devices.schema.json +3 -0
  22. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/remote_outputs.schema.json +0 -3
  23. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/template.schema.json +9 -0
  24. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/sw.js +1 -1
  25. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/irrigation.py +217 -0
  26. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/config.schema.json +21 -3
  27. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/irrigation.schema.json +9 -0
  28. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/modbus_devices.schema.json +3 -0
  29. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/remote_outputs.schema.json +0 -3
  30. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/template.schema.json +9 -0
  31. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5/boneio.egg-info}/PKG-INFO +1 -1
  32. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio.egg-info/SOURCES.txt +7 -7
  33. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/pyproject.toml +1 -0
  34. boneio-1.4.0.dev4/boneio/core/messaging/lox.py +0 -221
  35. boneio-1.4.0.dev4/boneio/core/messaging/loxone.py +0 -181
  36. boneio-1.4.0.dev4/boneio/integration/lox_template.py +0 -243
  37. boneio-1.4.0.dev4/boneio/version.py +0 -2
  38. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/LICENSE +0 -0
  39. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/MANIFEST.in +0 -0
  40. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/README.md +0 -0
  41. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/__init__.py +0 -0
  42. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.2/input.yaml +0 -0
  43. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.2/output_24_16.yaml +0 -0
  44. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.2/output_32_10.yaml +0 -0
  45. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.2/output_32_5.yaml +0 -0
  46. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.2/output_cover.yaml +0 -0
  47. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.2/output_cover_mix.yaml +0 -0
  48. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.3/input.yaml +0 -0
  49. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.3/output_24_16.yaml +0 -0
  50. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.3/output_32_10.yaml +0 -0
  51. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.3/output_32_5.yaml +0 -0
  52. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.3/output_cover.yaml +0 -0
  53. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.3/output_cover_mix.yaml +0 -0
  54. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.4/input.yaml +0 -0
  55. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.4/output_24_16.yaml +0 -0
  56. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.4/output_32_10.yaml +0 -0
  57. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.4/output_32_5.yaml +0 -0
  58. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.4/output_cover.yaml +0 -0
  59. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.4/output_cover_mix.yaml +0 -0
  60. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.5/input.yaml +0 -0
  61. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.5/output_24_16.yaml +0 -0
  62. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.5/output_32_10.yaml +0 -0
  63. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.5/output_cover.yaml +0 -0
  64. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.5/output_cover_mix.yaml +0 -0
  65. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.6/input.yaml +0 -0
  66. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.6/output_24_16.yaml +0 -0
  67. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.6/output_32_10.yaml +0 -0
  68. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.6/output_cover.yaml +0 -0
  69. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.6/output_cover_mix.yaml +0 -0
  70. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.7/input.yaml +0 -0
  71. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.7/output_24_16.yaml +0 -0
  72. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.7/output_32_10.yaml +0 -0
  73. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.7/output_48_4.yaml +0 -0
  74. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.7/output_cover.yaml +0 -0
  75. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.7/output_cover_mix.yaml +0 -0
  76. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.8/input.yaml +0 -0
  77. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.8/output_24_16.yaml +0 -0
  78. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.8/output_32_10.yaml +0 -0
  79. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.8/output_48_4.yaml +0 -0
  80. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.8/output_cover.yaml +0 -0
  81. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/boards/0.8/output_cover_mix.yaml +0 -0
  82. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/bonecli.py +0 -0
  83. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/__init__.py +0 -0
  84. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/cover/__init__.py +0 -0
  85. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/cover/cover.py +0 -0
  86. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/cover/time_based.py +0 -0
  87. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/cover/venetian.py +0 -0
  88. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/group/__init__.py +0 -0
  89. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/group/output_group.py +0 -0
  90. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/input/__init__.py +0 -0
  91. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/input/binary_sensor.py +0 -0
  92. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/input/detectors.py +0 -0
  93. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/input/event.py +0 -0
  94. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/input/remote/__init__.py +0 -0
  95. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/input/remote/base.py +0 -0
  96. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/input/remote/esphome.py +0 -0
  97. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/irrigation/__init__.py +0 -0
  98. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/irrigation/water_source.py +0 -0
  99. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/output/__init__.py +0 -0
  100. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/output/basic.py +0 -0
  101. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/output/mcp.py +0 -0
  102. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/output/pca.py +0 -0
  103. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/output/pcf.py +0 -0
  104. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/output/remote.py +0 -0
  105. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/sensor/__init__.py +0 -0
  106. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/sensor/virtual_energy.py +0 -0
  107. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/template/__init__.py +0 -0
  108. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/template/alarm_panel.py +0 -0
  109. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/template/gate_cover.py +0 -0
  110. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/components/template/thermostat.py +0 -0
  111. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/const.py +0 -0
  112. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/__init__.py +0 -0
  113. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/cloud/__init__.py +0 -0
  114. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/cloud/data/__init__.py +0 -0
  115. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/cloud/data/docker-compose-cloud.yaml +0 -0
  116. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/cloud/data/docker-compose.yaml +0 -0
  117. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/cloud/data/init-certs-cloud.sh +0 -0
  118. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/cloud/registration.py +0 -0
  119. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/cloud/secrets.py +0 -0
  120. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/__init__.py +0 -0
  121. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/config_helper.py +0 -0
  122. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/migrations/__init__.py +0 -0
  123. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/migrations/v1_proxy_port.py +0 -0
  124. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/migrations/v2_transition.py +0 -0
  125. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/package-lock.json +0 -0
  126. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/package.json +0 -0
  127. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/schema_converter.py +0 -0
  128. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/config/yaml_util.py +0 -0
  129. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/discovery.py +0 -0
  130. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/events/__init__.py +0 -0
  131. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/events/bus.py +0 -0
  132. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/__init__.py +0 -0
  133. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/action_conditions.py +0 -0
  134. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/canopen.py +0 -0
  135. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/covers.py +0 -0
  136. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/display.py +0 -0
  137. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/inputs.py +0 -0
  138. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/modbus.py +0 -0
  139. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/outputs.py +0 -0
  140. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/remote.py +0 -0
  141. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/remote_input_registrar.py +0 -0
  142. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/sensors.py +0 -0
  143. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/templates/__init__.py +0 -0
  144. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/templates/alarm.py +0 -0
  145. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/templates/gate_cover.py +0 -0
  146. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/templates/thermostat.py +0 -0
  147. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/templates.py +0 -0
  148. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/manager/update.py +0 -0
  149. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/messaging/__init__.py +0 -0
  150. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/messaging/basic.py +0 -0
  151. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/messaging/basic_mqtt.py +0 -0
  152. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/messaging/composite.py +0 -0
  153. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/messaging/local.py +0 -0
  154. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/messaging/mqtt.py +0 -0
  155. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/messaging/queue.py +0 -0
  156. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/remote/__init__.py +0 -0
  157. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/remote/base.py +0 -0
  158. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/remote/can.py +0 -0
  159. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/remote/esphome.py +0 -0
  160. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/remote/mqtt.py +0 -0
  161. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/remote/wled.py +0 -0
  162. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/sensor/__init__.py +0 -0
  163. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/sensor/base.py +0 -0
  164. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/sensor/system.py +0 -0
  165. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/state/__init__.py +0 -0
  166. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/state/manager.py +0 -0
  167. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/system/__init__.py +0 -0
  168. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/system/host_data.py +0 -0
  169. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/system/monitor.py +0 -0
  170. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/__init__.py +0 -0
  171. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/async_updater.py +0 -0
  172. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/conditions.py +0 -0
  173. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/filter.py +0 -0
  174. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/font_util.py +0 -0
  175. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/logger.py +0 -0
  176. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/timeperiod.py +0 -0
  177. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/core/utils/util.py +0 -0
  178. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/24x16/adc.yaml +0 -0
  179. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/24x16/binary_sensor.yaml +0 -0
  180. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/24x16/config.yaml +0 -0
  181. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/24x16/event.yaml +0 -0
  182. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/24x16/mqtt.yaml +0 -0
  183. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/24x16/output24x16A.yaml +0 -0
  184. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/32x10/adc.yaml +0 -0
  185. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/32x10/binary_sensor.yaml +0 -0
  186. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/32x10/config.yaml +0 -0
  187. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/32x10/event.yaml +0 -0
  188. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/32x10/mqtt.yaml +0 -0
  189. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/32x10/output32x10A.yaml +0 -0
  190. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/48x4/adc.yaml +0 -0
  191. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/48x4/binary_sensor.yaml +0 -0
  192. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/48x4/config.yaml +0 -0
  193. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/48x4/event.yaml +0 -0
  194. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/48x4/mqtt.yaml +0 -0
  195. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/48x4/output48x4A.yaml +0 -0
  196. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/__init__.py +0 -0
  197. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/can_master.yaml +0 -0
  198. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/can_slave.yaml +0 -0
  199. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover/adc.yaml +0 -0
  200. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover/binary_sensor.yaml +0 -0
  201. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover/config.yaml +0 -0
  202. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover/cover.yaml +0 -0
  203. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover/event.yaml +0 -0
  204. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover/mqtt.yaml +0 -0
  205. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover/outputCover.yaml +0 -0
  206. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/adc.yaml +0 -0
  207. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/binary_sensor.yaml +0 -0
  208. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/config.yaml +0 -0
  209. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/cover.yaml +0 -0
  210. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/event.yaml +0 -0
  211. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/mqtt.yaml +0 -0
  212. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/cover_mix/outputCoverMix.yaml +0 -0
  213. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/adc.yaml +0 -0
  214. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/all_binary_sensor.yaml +0 -0
  215. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/binary_sensor.yaml +0 -0
  216. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/binary_sensor_v_0_7.yaml +0 -0
  217. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/config_24_16.yaml +0 -0
  218. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/event_all.yaml +0 -0
  219. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/event_v_0_7.yaml +0 -0
  220. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/led32x4A.yaml +0 -0
  221. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/output24x16A.yaml +0 -0
  222. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/output24x16A_v0.3.yaml +0 -0
  223. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/output32x10A.yaml +0 -0
  224. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/example_config/different_configs/output32x5A.yaml +0 -0
  225. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/exceptions.py +0 -0
  226. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/__init__.py +0 -0
  227. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/analog/__init__.py +0 -0
  228. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/analog/adc.py +0 -0
  229. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/can/__init__.py +0 -0
  230. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/can/bridge.py +0 -0
  231. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/can/client.py +0 -0
  232. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/can/interface.py +0 -0
  233. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/can/node.py +0 -0
  234. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/can/node_id.py +0 -0
  235. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/can/test_od.py +0 -0
  236. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/display/__init__.py +0 -0
  237. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/display/early_oled.py +0 -0
  238. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/display/fonts/danube__.ttf +0 -0
  239. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/display/oled.py +0 -0
  240. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/__init__.py +0 -0
  241. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/expanders/__init__.py +0 -0
  242. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/expanders/mcp23017.py +0 -0
  243. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/expanders/pca9685.py +0 -0
  244. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/expanders/pcf8575.py +0 -0
  245. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/input/__init__.py +0 -0
  246. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/input/base.py +0 -0
  247. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/gpio/input/manager.py +0 -0
  248. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/i2c/__init__.py +0 -0
  249. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/i2c/bus.py +0 -0
  250. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/i2c/ina219.py +0 -0
  251. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/i2c/ina219_driver.py +0 -0
  252. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/i2c/mcp9808.py +0 -0
  253. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/i2c/pct2075.py +0 -0
  254. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/onewire/__init__.py +0 -0
  255. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/onewire/bus.py +0 -0
  256. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/onewire/dallas.py +0 -0
  257. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/onewire/ds2482.py +0 -0
  258. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/sensor/__init__.py +0 -0
  259. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/sensor/temperature/__init__.py +0 -0
  260. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/sensor/temperature/base.py +0 -0
  261. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/sensor/temperature/mcp9808.py +0 -0
  262. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/hardware/sensor/temperature/pct2075.py +0 -0
  263. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/integration/__init__.py +0 -0
  264. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/integration/interlock.py +0 -0
  265. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/__init__.py +0 -0
  266. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/actions.py +0 -0
  267. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/MANIFEST.sha256 +0 -0
  268. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/docker/daemon.json +0 -0
  269. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/docker/nodered/docker-compose.yaml +0 -0
  270. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/docker/nodered/nginx/default.conf +0 -0
  271. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/docker/nodered/node-red/settings.js +0 -0
  272. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/journald/journald.conf +0 -0
  273. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/mosquitto/boneio.conf +0 -0
  274. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/sudoers/boneio +0 -0
  275. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/systemd/boneio-oled-boot.service +0 -0
  276. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/systemd/boneio.service +0 -0
  277. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/systemd/set-hostname-once.service +0 -0
  278. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/usr-local-bin/set-hostname-once.sh +0 -0
  279. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/usr-sbin/oled_boot_splash.py +0 -0
  280. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/usr-sbin/oled_boot_splash.sh +0 -0
  281. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/usr-sbin/oled_msg.py +0 -0
  282. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/assets/usr-sbin/oled_msg.sh +0 -0
  283. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/bootstrap/boneio-migrate +0 -0
  284. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/bootstrap/install-helper.sh +0 -0
  285. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/bootstrap/sudoers-migrate +0 -0
  286. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/runner.py +0 -0
  287. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/versions/__init__.py +0 -0
  288. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/versions/v1_3_0_baseline.py +0 -0
  289. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/versions/v1_3_1_fix_oled_boot.py +0 -0
  290. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/versions/v1_3_2_cleanup_can_sudoers.py +0 -0
  291. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/migrations/versions/v1_4_0_fix_mqtt_sudoers.py +0 -0
  292. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/__init__.py +0 -0
  293. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/cli.py +0 -0
  294. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/client.py +0 -0
  295. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/coordinator.py +0 -0
  296. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/__init__.py +0 -0
  297. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/le-03mw.json +0 -0
  298. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/le-03mwct.json +0 -0
  299. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/orno-or-we-517.json +0 -0
  300. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/sdm120.json +0 -0
  301. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/sdm630.json +0 -0
  302. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/socomec_e03.json +0 -0
  303. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/energy_meters/socomec_e23.json +0 -0
  304. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/hvac/fujitsu-ac.json +0 -0
  305. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/hvac/ventclear.json +0 -0
  306. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/inverters/sofar.json +0 -0
  307. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/inverters/thessla.json +0 -0
  308. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/other/esp32_relay_x4_modbus.json +0 -0
  309. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/other/n4dsc08.json +0 -0
  310. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/other/r4dcb08.json +0 -0
  311. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/other/wanas415.json +0 -0
  312. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/boneio-edge-temp.json +0 -0
  313. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/cwt.json +0 -0
  314. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/dts1964_3f.json +0 -0
  315. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/dyp-a12-ultrasonic.json +0 -0
  316. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/gdfs.json +0 -0
  317. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/gdfx.json +0 -0
  318. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/liquid-sensor.json +0 -0
  319. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/pt100.json +0 -0
  320. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/sht20.json +0 -0
  321. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/devices/sensors/sht30.json +0 -0
  322. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/__init__.py +0 -0
  323. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/base.py +0 -0
  324. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/derived/__init__.py +0 -0
  325. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/derived/numeric.py +0 -0
  326. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/derived/select.py +0 -0
  327. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/derived/switch.py +0 -0
  328. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/derived/text.py +0 -0
  329. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/sensor/__init__.py +0 -0
  330. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/sensor/binary.py +0 -0
  331. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/sensor/numeric.py +0 -0
  332. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/sensor/text.py +0 -0
  333. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/writeable/__init__.py +0 -0
  334. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/writeable/binary.py +0 -0
  335. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/entities/writeable/numeric.py +0 -0
  336. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/modbus/utils.py +0 -0
  337. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/models/__init__.py +0 -0
  338. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/models/actions.py +0 -0
  339. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/models/events.py +0 -0
  340. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/models/files.py +0 -0
  341. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/models/logs.py +0 -0
  342. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/models/mqtt.py +0 -0
  343. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/models/state.py +0 -0
  344. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/runner.py +0 -0
  345. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/actions.yaml +0 -0
  346. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/actions_sensor.yaml +0 -0
  347. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/actions_switch.yaml +0 -0
  348. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/condition.yaml +0 -0
  349. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/filters.yaml +0 -0
  350. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/filters_adc.yaml +0 -0
  351. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/id.yaml +0 -0
  352. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/remote_devices.yaml +0 -0
  353. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/remote_inputs.yaml +0 -0
  354. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/temp_unit.yaml +0 -0
  355. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/schema/update_interval.yaml +0 -0
  356. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/action_validation.py +0 -0
  357. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/app.py +0 -0
  358. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/codicon-DCmgc-ay.ttf +0 -0
  359. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/editor.worker-BVjSvWeP.js +0 -0
  360. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/json.worker-CqOJL4FD.js +0 -0
  361. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/monaco-B9WiNxkw.css +0 -0
  362. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/monaco-CAZoGZNF.js +0 -0
  363. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/rolldown-runtime-Dw2cE7zH.js +0 -0
  364. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/vendor-BD5Ml_Uz.js +0 -0
  365. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/workbox-window.prod.es5-BJd1pjeW.js +0 -0
  366. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/assets/yaml.worker-nZQZSRZ7.js +0 -0
  367. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/boneio-192.png +0 -0
  368. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/boneio-512.png +0 -0
  369. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/boneio.svg +0 -0
  370. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/boneio_fav.svg +0 -0
  371. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/adc.schema.json +0 -0
  372. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/areas.schema.json +0 -0
  373. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/binary_sensor.schema.json +0 -0
  374. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/boneio.schema.json +0 -0
  375. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/can.schema.json +0 -0
  376. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/cover.schema.json +0 -0
  377. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/dallas.schema.json +0 -0
  378. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/ds2482.schema.json +0 -0
  379. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/event.schema.json +0 -0
  380. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/ina219.schema.json +0 -0
  381. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/lm75.schema.json +0 -0
  382. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/logger.schema.json +0 -0
  383. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/lox_udp.schema.json +0 -0
  384. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/mcp23017.schema.json +0 -0
  385. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/mcp9808.schema.json +0 -0
  386. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/modbus.schema.json +0 -0
  387. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/mqtt.schema.json +0 -0
  388. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/oled.schema.json +0 -0
  389. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/output.schema.json +0 -0
  390. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/output_group.schema.json +0 -0
  391. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/pca9685.schema.json +0 -0
  392. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/pcf8575.schema.json +0 -0
  393. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/remote_devices.schema.json +0 -0
  394. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/remote_inputs.schema.json +0 -0
  395. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/sensor.schema.json +0 -0
  396. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/virtual_energy_sensor.schema.json +0 -0
  397. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/schema/web.schema.json +0 -0
  398. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/frontend-dist/workbox-4eca85ba.js +0 -0
  399. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/middleware/__init__.py +0 -0
  400. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/middleware/auth.py +0 -0
  401. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/__init__.py +0 -0
  402. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/auth.py +0 -0
  403. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/caddy.py +0 -0
  404. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/can.py +0 -0
  405. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/config.py +0 -0
  406. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/covers.py +0 -0
  407. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/migrations.py +0 -0
  408. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/modbus.py +0 -0
  409. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/outputs.py +0 -0
  410. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/remote_devices.py +0 -0
  411. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/sensors.py +0 -0
  412. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/system.py +0 -0
  413. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/templates.py +0 -0
  414. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/timezone_sudoers.py +0 -0
  415. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/tools.py +0 -0
  416. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/routes/update.py +0 -0
  417. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/adc.schema.json +0 -0
  418. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/areas.schema.json +0 -0
  419. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/binary_sensor.schema.json +0 -0
  420. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/boneio.schema.json +0 -0
  421. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/can.schema.json +0 -0
  422. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/cover.schema.json +0 -0
  423. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/dallas.schema.json +0 -0
  424. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/ds2482.schema.json +0 -0
  425. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/event.schema.json +0 -0
  426. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/ina219.schema.json +0 -0
  427. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/lm75.schema.json +0 -0
  428. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/logger.schema.json +0 -0
  429. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/lox_udp.schema.json +0 -0
  430. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/mcp23017.schema.json +0 -0
  431. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/mcp9808.schema.json +0 -0
  432. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/modbus.schema.json +0 -0
  433. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/mqtt.schema.json +0 -0
  434. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/oled.schema.json +0 -0
  435. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/output.schema.json +0 -0
  436. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/output_group.schema.json +0 -0
  437. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/pca9685.schema.json +0 -0
  438. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/pcf8575.schema.json +0 -0
  439. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/remote_devices.schema.json +0 -0
  440. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/remote_inputs.schema.json +0 -0
  441. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/sensor.schema.json +0 -0
  442. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/virtual_energy_sensor.schema.json +0 -0
  443. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/schema/web.schema.json +0 -0
  444. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/services/__init__.py +0 -0
  445. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/services/logs.py +0 -0
  446. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/web_server.py +0 -0
  447. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio/webui/websocket_manager.py +0 -0
  448. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio.egg-info/dependency_links.txt +0 -0
  449. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio.egg-info/entry_points.txt +0 -0
  450. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio.egg-info/requires.txt +0 -0
  451. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/boneio.egg-info/top_level.txt +0 -0
  452. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/setup.cfg +0 -0
  453. {boneio-1.4.0.dev4 → boneio-1.4.0.dev5}/setup.py +0 -0
  454. {boneio-1.4.0.dev4 → 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.dev4
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
@@ -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()
@@ -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
+ )
@@ -611,7 +611,7 @@ class Manager:
611
611
  self,
612
612
  id: str,
613
613
  ha_type: str,
614
- payload: dict,
614
+ payload: dict[str, Any] | str,
615
615
  ) -> None:
616
616
  """Publish a pre-built HA autodiscovery payload.
617
617
 
@@ -0,0 +1,326 @@
1
+ """Lox UDP Client for BoneIO.
2
+
3
+ Implements the Loxone UDP protocol for bidirectional communication
4
+ between BoneIO and a Loxone Miniserver:
5
+
6
+ - Receiving commands from Miniserver (e.g. "OUT_04=ON")
7
+ - Sending state feedback to Miniserver (e.g. "OUT_04=ON", "cover1=50")
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import asyncio
13
+ import logging
14
+ from collections.abc import Awaitable, Callable
15
+ from typing import TYPE_CHECKING, Any
16
+
17
+ from boneio.core.messaging.basic import MessageBus
18
+
19
+ if TYPE_CHECKING:
20
+ from boneio.core.config import ConfigHelper
21
+ from boneio.core.manager import Manager
22
+ from boneio.integration.homeassistant import HomeAssistantDiscoveryMessage
23
+
24
+ _LOGGER = logging.getLogger(__name__)
25
+
26
+ # Entity types whose state changes should be forwarded to Loxone
27
+ _LOX_ENTITY_TYPES = frozenset(
28
+ ("output", "cover", "sensor", "event", "binary_sensor", "input")
29
+ )
30
+
31
+
32
+ class LoxUDPProtocol(asyncio.DatagramProtocol):
33
+ """Protocol for handling Lox UDP communication."""
34
+
35
+ def __init__(self, callback: Callable[[str, str], Awaitable[None]]):
36
+ self._callback = callback
37
+ self._loop = asyncio.get_running_loop()
38
+
39
+ def connection_made(self, transport: asyncio.DatagramTransport) -> None:
40
+ """Handle connection established."""
41
+ self.transport = transport
42
+
43
+ def datagram_received(self, data: bytes, addr: tuple[str, int]) -> None:
44
+ """Handle incoming datagram.
45
+
46
+ Expected message format: "device_id=value" or just "device_id".
47
+ """
48
+ try:
49
+ message = data.decode("utf-8").strip()
50
+ _LOGGER.debug("Received Lox UDP message: %s from %s", message, addr)
51
+
52
+ # Message format expected: "device=value" or just "device"
53
+ if "=" in message:
54
+ device, payload = message.split("=", 1)
55
+ else:
56
+ device = message
57
+ payload = "pressed"
58
+
59
+ self._loop.create_task(self._callback(device, payload))
60
+ except Exception as e:
61
+ _LOGGER.error("Error processing Lox UDP datagram: %s", e)
62
+
63
+
64
+ class LoxUDPClient(MessageBus):
65
+ """Represent a Lox UDP client.
66
+
67
+ This message bus translates between BoneIO's internal MQTT-style
68
+ topic/payload model and the simple "key=value" UDP protocol
69
+ expected by Loxone Miniserver.
70
+
71
+ Outgoing (BoneIO → Miniserver):
72
+ topic "boneio/{serial}/output/relay1" + payload {"state": "ON"}
73
+ → UDP datagram "relay1=ON" sent to Miniserver
74
+
75
+ Incoming (Miniserver → BoneIO):
76
+ UDP datagram "relay1=ON"
77
+ → routed to Manager as "boneio/{serial}/cmd/output/relay1/set" = "ON"
78
+ """
79
+
80
+ def __init__(
81
+ self,
82
+ config_helper: ConfigHelper,
83
+ host: str,
84
+ send_port: int,
85
+ listen_port: int,
86
+ ) -> None:
87
+ """Set up client.
88
+
89
+ Args:
90
+ config_helper: BoneIO configuration helper.
91
+ host: Loxone Miniserver IP address.
92
+ send_port: Port on Miniserver to send state feedback to.
93
+ listen_port: Port BoneIO listens on for commands from Miniserver.
94
+ """
95
+ self._manager: Manager | None = None
96
+ self._config_helper = config_helper
97
+ self.host = host
98
+ self.send_port = send_port
99
+ self.listen_port = listen_port
100
+ self._transport: asyncio.DatagramTransport | None = None
101
+ self._listeners: dict[str, Callable[[str, str], Awaitable[None]]] = {}
102
+ self._state = False
103
+
104
+ def send_message(
105
+ self,
106
+ topic: str,
107
+ payload: str | int | bytes | dict[str, Any] | HomeAssistantDiscoveryMessage | None,
108
+ retain: bool = False,
109
+ qos: int = 0,
110
+ ) -> None:
111
+ """Send a state update to Loxone Miniserver via UDP.
112
+
113
+ Converts BoneIO's MQTT-style topic/payload into a simple UDP
114
+ datagram in the format "device_id=state_value".
115
+
116
+ Topic format: boneio/{serial}/{entity_type}/{device_id}
117
+ or: boneio/{serial}/{entity_type}/{device_id}/state
118
+ or: boneio/{serial}/{entity_type}/{device_id}/pos
119
+
120
+ Args:
121
+ topic: MQTT-style topic string.
122
+ payload: State payload (dict, string, bytes, int, or None).
123
+ retain: Ignored for UDP.
124
+ qos: Ignored for UDP.
125
+ """
126
+ if payload is None:
127
+ return
128
+
129
+ topic_str = str(topic)
130
+ parts = topic_str.split("/")
131
+
132
+ # Need at least: prefix/serial/entity_type/device_id
133
+ if len(parts) < 4:
134
+ return
135
+
136
+ # Skip HA Discovery messages (homeassistant/*/config topics)
137
+ if parts[0] == "homeassistant" or topic_str.endswith("/config"):
138
+ return
139
+
140
+ # Skip command topics — we only send state feedback, not commands
141
+ if "cmd" in parts:
142
+ return
143
+
144
+ # Determine entity_type and device_id based on topic structure
145
+ # Standard: boneio/{serial}/{entity_type}/{device_id}
146
+ # With suffix: boneio/{serial}/{entity_type}/{device_id}/state
147
+ # With suffix: boneio/{serial}/{entity_type}/{device_id}/pos
148
+ entity_type = parts[2] if len(parts) >= 3 else ""
149
+ suffix = parts[-1] if len(parts) >= 5 else ""
150
+
151
+ # For topics with suffix (state/pos), device_id is parts[-2]
152
+ if suffix in ("state", "pos", "set"):
153
+ device_id = parts[-2]
154
+ else:
155
+ device_id = parts[-1]
156
+
157
+ # Skip non-relevant entity types
158
+ if entity_type not in _LOX_ENTITY_TYPES:
159
+ return
160
+
161
+ # Skip "set" suffix — those are incoming commands, not state feedback
162
+ if suffix == "set":
163
+ return
164
+
165
+ # Extract state value from payload
166
+ state_value = self._extract_state_value(payload)
167
+ if not state_value:
168
+ return
169
+
170
+ self._send_udp(device_id, state_value)
171
+
172
+ @staticmethod
173
+ def _extract_state_value(
174
+ payload: str | int | bytes | dict[str, Any] | HomeAssistantDiscoveryMessage,
175
+ ) -> str:
176
+ """Extract a simple state string from various payload formats.
177
+
178
+ Args:
179
+ payload: The message payload in any supported format.
180
+
181
+ Returns:
182
+ State value as string, or empty string if extraction fails.
183
+ """
184
+ if isinstance(payload, dict):
185
+ # Try standard keys: {"state": "ON"}, {"value": "50"}
186
+ state_value = payload.get("state", payload.get("value", ""))
187
+ if state_value:
188
+ return str(state_value)
189
+ # Fallback: use first value from dict
190
+ if payload:
191
+ return str(next(iter(payload.values()), ""))
192
+ return ""
193
+ if isinstance(payload, bytes):
194
+ return payload.decode("utf-8")
195
+ return str(payload)
196
+
197
+ def _send_udp(self, device_id: str, state_value: str) -> None:
198
+ """Send a UDP datagram to Loxone Miniserver.
199
+
200
+ Args:
201
+ device_id: Entity identifier (e.g. "relay1", "cover1").
202
+ state_value: State value string (e.g. "ON", "50").
203
+ """
204
+ try:
205
+ udp_msg = f"{device_id}={state_value}".encode()
206
+ if self._transport:
207
+ self._transport.sendto(udp_msg, (self.host, self.send_port))
208
+ _LOGGER.debug(
209
+ "Sent Lox UDP message: %s to %s:%s",
210
+ udp_msg.decode("utf-8"),
211
+ self.host,
212
+ self.send_port,
213
+ )
214
+ else:
215
+ _LOGGER.debug(
216
+ "Lox UDP transport not ready, dropping: %s",
217
+ udp_msg.decode("utf-8"),
218
+ )
219
+ except Exception as e:
220
+ _LOGGER.error("Error sending Lox UDP message: %s", e)
221
+
222
+ @property
223
+ def state(self) -> bool:
224
+ """State of Lox Client."""
225
+ return self._state
226
+
227
+ async def start_client(self) -> None:
228
+ """Start UDP server and client."""
229
+ try:
230
+ loop = asyncio.get_running_loop()
231
+ transport, protocol = await loop.create_datagram_endpoint(
232
+ lambda: LoxUDPProtocol(self._handle_incoming),
233
+ local_addr=("0.0.0.0", self.listen_port),
234
+ )
235
+ self._transport = transport
236
+ self._state = True
237
+ _LOGGER.info(
238
+ "Lox UDP client started. Listening on port %s, sending to %s:%s",
239
+ self.listen_port,
240
+ self.host,
241
+ self.send_port,
242
+ )
243
+
244
+ # Announce online status so Lox Miniserver knows we are alive
245
+ self._transport.sendto(b"boneio=online", (self.host, self.send_port))
246
+
247
+ while True:
248
+ await asyncio.sleep(3600)
249
+
250
+ except asyncio.CancelledError:
251
+ _LOGGER.info("Lox UDP client shutting down...")
252
+ except Exception as e:
253
+ _LOGGER.error("Failed to start Lox UDP client: %s", e)
254
+ self._state = False
255
+ finally:
256
+ if self._transport:
257
+ self._transport.close()
258
+
259
+ def set_manager(self, manager: Manager) -> None:
260
+ """Set manager reference for routing incoming commands."""
261
+ self._manager = manager
262
+
263
+ async def announce_offline(self) -> None:
264
+ """Announce offline status to Miniserver."""
265
+ if self._transport:
266
+ self._transport.sendto(b"boneio=offline", (self.host, self.send_port))
267
+
268
+ async def subscribe_and_listen(
269
+ self, topic: str, callback: Callable[[str, str], Awaitable[None]]
270
+ ) -> None:
271
+ """Register a listener for a topic pattern."""
272
+ self._listeners[topic] = callback
273
+
274
+ async def unsubscribe_and_stop_listen(self, topic: str) -> None:
275
+ """Unregister a listener."""
276
+ if topic in self._listeners:
277
+ del self._listeners[topic]
278
+
279
+ async def _handle_incoming(self, device: str, payload: str) -> None:
280
+ """Handle incoming Lox messages and route them to Manager.
281
+
282
+ Resolves the device name to an entity type (output/cover) and
283
+ forwards the command to the Manager's receive_message method.
284
+
285
+ Args:
286
+ device: Device identifier from UDP message (e.g. "relay1").
287
+ payload: Command value from UDP message (e.g. "ON").
288
+ """
289
+ _LOGGER.debug("Lox handle incoming: %s = %s", device, payload)
290
+
291
+ if not self._manager:
292
+ return
293
+
294
+ try:
295
+ cmd_prefix = self._config_helper.cmd_topic_prefix
296
+ msg_type = None
297
+
298
+ output = self._manager.outputs.get_output(
299
+ device
300
+ ) or self._manager.outputs.get_output_group(device)
301
+ if output:
302
+ msg_type = "output"
303
+ else:
304
+ cover = self._manager.covers.get_cover(device)
305
+ if cover:
306
+ msg_type = "cover"
307
+
308
+ if not msg_type:
309
+ _LOGGER.warning(
310
+ "Lox UDP device %s not found in outputs/covers", device
311
+ )
312
+ return
313
+
314
+ full_topic = f"{cmd_prefix}{msg_type}/{device}/set"
315
+
316
+ # Check explicit listeners
317
+ for listen_topic, callback in self._listeners.items():
318
+ if listen_topic == full_topic or (
319
+ listen_topic.endswith("/#")
320
+ and full_topic.startswith(listen_topic[:-2])
321
+ ):
322
+ await callback(full_topic, payload)
323
+
324
+ await self._manager.receive_message(full_topic, payload)
325
+ except Exception as e:
326
+ _LOGGER.error("Error passing Lox message to manager: %s", e)