boneio 1.4.0.dev3__tar.gz → 1.4.0.dev4__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 (453) hide show
  1. {boneio-1.4.0.dev3/boneio.egg-info → boneio-1.4.0.dev4}/PKG-INFO +1 -1
  2. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/cover/cover.py +6 -0
  3. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/cover/venetian.py +11 -4
  4. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/output/remote.py +224 -3
  5. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/manager.py +129 -3
  6. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/remote.py +58 -0
  7. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/schema/actions.yaml +11 -0
  8. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/schema/remote_outputs.yaml +93 -0
  9. boneio-1.4.0.dev4/boneio/version.py +2 -0
  10. boneio-1.4.0.dev3/boneio/webui/frontend-dist/assets/ConfigEditor-B7qJAsAx.js → boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/ConfigEditor-BBQ49dou.js +1 -1
  11. boneio-1.4.0.dev3/boneio/webui/frontend-dist/assets/aiConfig-Dq5oh99L.js → boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/aiConfig-BwEuqxu2.js +1 -1
  12. boneio-1.4.0.dev3/boneio/webui/frontend-dist/assets/aiWizardPrompt-r-xmvrUB.js → boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/aiWizardPrompt-CEIyLZ8l.js +1 -1
  13. boneio-1.4.0.dev3/boneio/webui/frontend-dist/assets/index-BVRhWldF.js → boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/index-CfQ35RrC.js +4 -4
  14. boneio-1.4.0.dev3/boneio/webui/frontend-dist/assets/useTranslation-VOFZRLzq.js → boneio-1.4.0.dev4/boneio/webui/frontend-dist/assets/useTranslation-ChbxfQ44.js +2 -2
  15. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/index.html +3 -3
  16. {boneio-1.4.0.dev3/boneio/webui → boneio-1.4.0.dev4/boneio/webui/frontend-dist}/schema/binary_sensor.schema.json +44 -0
  17. {boneio-1.4.0.dev3/boneio/webui → boneio-1.4.0.dev4/boneio/webui/frontend-dist}/schema/config.schema.json +312 -0
  18. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/event.schema.json +154 -0
  19. boneio-1.4.0.dev4/boneio/webui/frontend-dist/schema/remote_outputs.schema.json +228 -0
  20. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/sw.js +1 -1
  21. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/config.py +26 -7
  22. {boneio-1.4.0.dev3/boneio/webui/frontend-dist → boneio-1.4.0.dev4/boneio/webui}/schema/binary_sensor.schema.json +44 -0
  23. {boneio-1.4.0.dev3/boneio/webui/frontend-dist → boneio-1.4.0.dev4/boneio/webui}/schema/config.schema.json +312 -0
  24. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/event.schema.json +154 -0
  25. boneio-1.4.0.dev4/boneio/webui/schema/remote_outputs.schema.json +228 -0
  26. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4/boneio.egg-info}/PKG-INFO +1 -1
  27. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio.egg-info/SOURCES.txt +5 -5
  28. boneio-1.4.0.dev3/boneio/version.py +0 -2
  29. boneio-1.4.0.dev3/boneio/webui/frontend-dist/schema/remote_outputs.schema.json +0 -114
  30. boneio-1.4.0.dev3/boneio/webui/schema/remote_outputs.schema.json +0 -114
  31. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/LICENSE +0 -0
  32. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/MANIFEST.in +0 -0
  33. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/README.md +0 -0
  34. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/__init__.py +0 -0
  35. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.2/input.yaml +0 -0
  36. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.2/output_24_16.yaml +0 -0
  37. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.2/output_32_10.yaml +0 -0
  38. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.2/output_32_5.yaml +0 -0
  39. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.2/output_cover.yaml +0 -0
  40. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.2/output_cover_mix.yaml +0 -0
  41. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.3/input.yaml +0 -0
  42. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.3/output_24_16.yaml +0 -0
  43. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.3/output_32_10.yaml +0 -0
  44. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.3/output_32_5.yaml +0 -0
  45. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.3/output_cover.yaml +0 -0
  46. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.3/output_cover_mix.yaml +0 -0
  47. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.4/input.yaml +0 -0
  48. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.4/output_24_16.yaml +0 -0
  49. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.4/output_32_10.yaml +0 -0
  50. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.4/output_32_5.yaml +0 -0
  51. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.4/output_cover.yaml +0 -0
  52. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.4/output_cover_mix.yaml +0 -0
  53. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.5/input.yaml +0 -0
  54. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.5/output_24_16.yaml +0 -0
  55. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.5/output_32_10.yaml +0 -0
  56. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.5/output_cover.yaml +0 -0
  57. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.5/output_cover_mix.yaml +0 -0
  58. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.6/input.yaml +0 -0
  59. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.6/output_24_16.yaml +0 -0
  60. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.6/output_32_10.yaml +0 -0
  61. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.6/output_cover.yaml +0 -0
  62. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.6/output_cover_mix.yaml +0 -0
  63. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.7/input.yaml +0 -0
  64. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.7/output_24_16.yaml +0 -0
  65. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.7/output_32_10.yaml +0 -0
  66. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.7/output_48_4.yaml +0 -0
  67. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.7/output_cover.yaml +0 -0
  68. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.7/output_cover_mix.yaml +0 -0
  69. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.8/input.yaml +0 -0
  70. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.8/output_24_16.yaml +0 -0
  71. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.8/output_32_10.yaml +0 -0
  72. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.8/output_48_4.yaml +0 -0
  73. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.8/output_cover.yaml +0 -0
  74. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/boards/0.8/output_cover_mix.yaml +0 -0
  75. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/bonecli.py +0 -0
  76. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/__init__.py +0 -0
  77. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/cover/__init__.py +0 -0
  78. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/cover/time_based.py +0 -0
  79. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/group/__init__.py +0 -0
  80. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/group/output_group.py +0 -0
  81. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/input/__init__.py +0 -0
  82. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/input/binary_sensor.py +0 -0
  83. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/input/detectors.py +0 -0
  84. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/input/event.py +0 -0
  85. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/input/remote/__init__.py +0 -0
  86. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/input/remote/base.py +0 -0
  87. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/input/remote/esphome.py +0 -0
  88. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/irrigation/__init__.py +0 -0
  89. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/irrigation/controller.py +0 -0
  90. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/irrigation/water_source.py +0 -0
  91. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/output/__init__.py +0 -0
  92. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/output/basic.py +0 -0
  93. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/output/mcp.py +0 -0
  94. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/output/pca.py +0 -0
  95. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/output/pcf.py +0 -0
  96. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/sensor/__init__.py +0 -0
  97. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/sensor/virtual_energy.py +0 -0
  98. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/template/__init__.py +0 -0
  99. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/template/alarm_panel.py +0 -0
  100. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/template/gate_cover.py +0 -0
  101. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/components/template/thermostat.py +0 -0
  102. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/const.py +0 -0
  103. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/__init__.py +0 -0
  104. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/cloud/__init__.py +0 -0
  105. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/cloud/data/__init__.py +0 -0
  106. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/cloud/data/docker-compose-cloud.yaml +0 -0
  107. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/cloud/data/docker-compose.yaml +0 -0
  108. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/cloud/data/init-certs-cloud.sh +0 -0
  109. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/cloud/registration.py +0 -0
  110. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/cloud/secrets.py +0 -0
  111. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/config/__init__.py +0 -0
  112. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/config/config_helper.py +0 -0
  113. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/config/migrations/__init__.py +0 -0
  114. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/config/migrations/v1_proxy_port.py +0 -0
  115. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/config/migrations/v2_transition.py +0 -0
  116. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/config/package-lock.json +0 -0
  117. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/config/package.json +0 -0
  118. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/config/schema_converter.py +0 -0
  119. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/config/yaml_util.py +0 -0
  120. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/discovery.py +0 -0
  121. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/events/__init__.py +0 -0
  122. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/events/bus.py +0 -0
  123. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/__init__.py +0 -0
  124. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/action_conditions.py +0 -0
  125. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/canopen.py +0 -0
  126. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/covers.py +0 -0
  127. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/display.py +0 -0
  128. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/inputs.py +0 -0
  129. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/irrigation.py +0 -0
  130. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/modbus.py +0 -0
  131. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/outputs.py +0 -0
  132. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/remote_input_registrar.py +0 -0
  133. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/sensors.py +0 -0
  134. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/templates/__init__.py +0 -0
  135. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/templates/alarm.py +0 -0
  136. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/templates/gate_cover.py +0 -0
  137. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/templates/thermostat.py +0 -0
  138. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/templates.py +0 -0
  139. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/manager/update.py +0 -0
  140. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/messaging/__init__.py +0 -0
  141. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/messaging/basic.py +0 -0
  142. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/messaging/basic_mqtt.py +0 -0
  143. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/messaging/composite.py +0 -0
  144. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/messaging/local.py +0 -0
  145. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/messaging/lox.py +0 -0
  146. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/messaging/loxone.py +0 -0
  147. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/messaging/mqtt.py +0 -0
  148. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/messaging/queue.py +0 -0
  149. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/remote/__init__.py +0 -0
  150. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/remote/base.py +0 -0
  151. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/remote/can.py +0 -0
  152. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/remote/esphome.py +0 -0
  153. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/remote/mqtt.py +0 -0
  154. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/remote/wled.py +0 -0
  155. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/sensor/__init__.py +0 -0
  156. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/sensor/base.py +0 -0
  157. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/sensor/system.py +0 -0
  158. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/state/__init__.py +0 -0
  159. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/state/manager.py +0 -0
  160. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/system/__init__.py +0 -0
  161. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/system/host_data.py +0 -0
  162. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/system/monitor.py +0 -0
  163. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/utils/__init__.py +0 -0
  164. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/utils/async_updater.py +0 -0
  165. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/utils/conditions.py +0 -0
  166. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/utils/filter.py +0 -0
  167. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/utils/font_util.py +0 -0
  168. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/utils/logger.py +0 -0
  169. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/utils/timeperiod.py +0 -0
  170. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/core/utils/util.py +0 -0
  171. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/24x16/adc.yaml +0 -0
  172. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/24x16/binary_sensor.yaml +0 -0
  173. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/24x16/config.yaml +0 -0
  174. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/24x16/event.yaml +0 -0
  175. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/24x16/mqtt.yaml +0 -0
  176. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/24x16/output24x16A.yaml +0 -0
  177. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/32x10/adc.yaml +0 -0
  178. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/32x10/binary_sensor.yaml +0 -0
  179. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/32x10/config.yaml +0 -0
  180. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/32x10/event.yaml +0 -0
  181. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/32x10/mqtt.yaml +0 -0
  182. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/32x10/output32x10A.yaml +0 -0
  183. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/48x4/adc.yaml +0 -0
  184. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/48x4/binary_sensor.yaml +0 -0
  185. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/48x4/config.yaml +0 -0
  186. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/48x4/event.yaml +0 -0
  187. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/48x4/mqtt.yaml +0 -0
  188. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/48x4/output48x4A.yaml +0 -0
  189. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/__init__.py +0 -0
  190. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/can_master.yaml +0 -0
  191. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/can_slave.yaml +0 -0
  192. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/cover/adc.yaml +0 -0
  193. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/cover/binary_sensor.yaml +0 -0
  194. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/cover/config.yaml +0 -0
  195. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/cover/cover.yaml +0 -0
  196. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/cover/event.yaml +0 -0
  197. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/cover/mqtt.yaml +0 -0
  198. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/cover/outputCover.yaml +0 -0
  199. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/cover_mix/adc.yaml +0 -0
  200. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/cover_mix/binary_sensor.yaml +0 -0
  201. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/cover_mix/config.yaml +0 -0
  202. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/cover_mix/cover.yaml +0 -0
  203. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/cover_mix/event.yaml +0 -0
  204. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/cover_mix/mqtt.yaml +0 -0
  205. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/cover_mix/outputCoverMix.yaml +0 -0
  206. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/different_configs/adc.yaml +0 -0
  207. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/different_configs/all_binary_sensor.yaml +0 -0
  208. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/different_configs/binary_sensor.yaml +0 -0
  209. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/different_configs/binary_sensor_v_0_7.yaml +0 -0
  210. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/different_configs/config_24_16.yaml +0 -0
  211. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/different_configs/event_all.yaml +0 -0
  212. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/different_configs/event_v_0_7.yaml +0 -0
  213. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/different_configs/led32x4A.yaml +0 -0
  214. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/different_configs/output24x16A.yaml +0 -0
  215. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/different_configs/output24x16A_v0.3.yaml +0 -0
  216. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/different_configs/output32x10A.yaml +0 -0
  217. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/example_config/different_configs/output32x5A.yaml +0 -0
  218. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/exceptions.py +0 -0
  219. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/__init__.py +0 -0
  220. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/analog/__init__.py +0 -0
  221. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/analog/adc.py +0 -0
  222. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/can/__init__.py +0 -0
  223. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/can/bridge.py +0 -0
  224. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/can/client.py +0 -0
  225. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/can/interface.py +0 -0
  226. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/can/node.py +0 -0
  227. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/can/node_id.py +0 -0
  228. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/can/test_od.py +0 -0
  229. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/display/__init__.py +0 -0
  230. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/display/early_oled.py +0 -0
  231. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/display/fonts/danube__.ttf +0 -0
  232. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/display/oled.py +0 -0
  233. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/gpio/__init__.py +0 -0
  234. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/gpio/expanders/__init__.py +0 -0
  235. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/gpio/expanders/mcp23017.py +0 -0
  236. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/gpio/expanders/pca9685.py +0 -0
  237. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/gpio/expanders/pcf8575.py +0 -0
  238. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/gpio/input/__init__.py +0 -0
  239. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/gpio/input/base.py +0 -0
  240. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/gpio/input/manager.py +0 -0
  241. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/i2c/__init__.py +0 -0
  242. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/i2c/bus.py +0 -0
  243. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/i2c/ina219.py +0 -0
  244. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/i2c/ina219_driver.py +0 -0
  245. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/i2c/mcp9808.py +0 -0
  246. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/i2c/pct2075.py +0 -0
  247. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/onewire/__init__.py +0 -0
  248. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/onewire/bus.py +0 -0
  249. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/onewire/dallas.py +0 -0
  250. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/onewire/ds2482.py +0 -0
  251. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/sensor/__init__.py +0 -0
  252. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/sensor/temperature/__init__.py +0 -0
  253. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/sensor/temperature/base.py +0 -0
  254. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/sensor/temperature/mcp9808.py +0 -0
  255. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/hardware/sensor/temperature/pct2075.py +0 -0
  256. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/integration/__init__.py +0 -0
  257. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/integration/homeassistant.py +0 -0
  258. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/integration/interlock.py +0 -0
  259. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/integration/lox_template.py +0 -0
  260. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/__init__.py +0 -0
  261. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/actions.py +0 -0
  262. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/MANIFEST.sha256 +0 -0
  263. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/docker/daemon.json +0 -0
  264. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/docker/nodered/docker-compose.yaml +0 -0
  265. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/docker/nodered/nginx/default.conf +0 -0
  266. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/docker/nodered/node-red/settings.js +0 -0
  267. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/journald/journald.conf +0 -0
  268. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/mosquitto/boneio.conf +0 -0
  269. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/sudoers/boneio +0 -0
  270. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/systemd/boneio-oled-boot.service +0 -0
  271. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/systemd/boneio.service +0 -0
  272. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/systemd/set-hostname-once.service +0 -0
  273. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/usr-local-bin/set-hostname-once.sh +0 -0
  274. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/usr-sbin/oled_boot_splash.py +0 -0
  275. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/usr-sbin/oled_boot_splash.sh +0 -0
  276. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/usr-sbin/oled_msg.py +0 -0
  277. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/assets/usr-sbin/oled_msg.sh +0 -0
  278. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/bootstrap/boneio-migrate +0 -0
  279. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/bootstrap/install-helper.sh +0 -0
  280. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/bootstrap/sudoers-migrate +0 -0
  281. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/runner.py +0 -0
  282. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/versions/__init__.py +0 -0
  283. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/versions/v1_3_0_baseline.py +0 -0
  284. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/versions/v1_3_1_fix_oled_boot.py +0 -0
  285. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/versions/v1_3_2_cleanup_can_sudoers.py +0 -0
  286. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/migrations/versions/v1_4_0_fix_mqtt_sudoers.py +0 -0
  287. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/__init__.py +0 -0
  288. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/cli.py +0 -0
  289. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/client.py +0 -0
  290. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/coordinator.py +0 -0
  291. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/__init__.py +0 -0
  292. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/energy_meters/le-03mw.json +0 -0
  293. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/energy_meters/le-03mwct.json +0 -0
  294. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/energy_meters/orno-or-we-517.json +0 -0
  295. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/energy_meters/sdm120.json +0 -0
  296. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/energy_meters/sdm630.json +0 -0
  297. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/energy_meters/socomec_e03.json +0 -0
  298. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/energy_meters/socomec_e23.json +0 -0
  299. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/hvac/fujitsu-ac.json +0 -0
  300. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/hvac/ventclear.json +0 -0
  301. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/inverters/sofar.json +0 -0
  302. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/inverters/thessla.json +0 -0
  303. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/other/esp32_relay_x4_modbus.json +0 -0
  304. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/other/n4dsc08.json +0 -0
  305. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/other/r4dcb08.json +0 -0
  306. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/other/wanas415.json +0 -0
  307. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/sensors/boneio-edge-temp.json +0 -0
  308. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/sensors/cwt.json +0 -0
  309. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/sensors/dts1964_3f.json +0 -0
  310. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/sensors/dyp-a12-ultrasonic.json +0 -0
  311. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/sensors/gdfs.json +0 -0
  312. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/sensors/gdfx.json +0 -0
  313. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/sensors/liquid-sensor.json +0 -0
  314. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/sensors/pt100.json +0 -0
  315. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/sensors/sht20.json +0 -0
  316. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/devices/sensors/sht30.json +0 -0
  317. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/entities/__init__.py +0 -0
  318. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/entities/base.py +0 -0
  319. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/entities/derived/__init__.py +0 -0
  320. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/entities/derived/numeric.py +0 -0
  321. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/entities/derived/select.py +0 -0
  322. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/entities/derived/switch.py +0 -0
  323. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/entities/derived/text.py +0 -0
  324. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/entities/sensor/__init__.py +0 -0
  325. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/entities/sensor/binary.py +0 -0
  326. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/entities/sensor/numeric.py +0 -0
  327. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/entities/sensor/text.py +0 -0
  328. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/entities/writeable/__init__.py +0 -0
  329. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/entities/writeable/binary.py +0 -0
  330. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/entities/writeable/numeric.py +0 -0
  331. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/modbus/utils.py +0 -0
  332. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/models/__init__.py +0 -0
  333. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/models/actions.py +0 -0
  334. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/models/events.py +0 -0
  335. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/models/files.py +0 -0
  336. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/models/logs.py +0 -0
  337. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/models/mqtt.py +0 -0
  338. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/models/state.py +0 -0
  339. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/runner.py +0 -0
  340. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/schema/actions_sensor.yaml +0 -0
  341. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/schema/actions_switch.yaml +0 -0
  342. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/schema/condition.yaml +0 -0
  343. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/schema/filters.yaml +0 -0
  344. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/schema/filters_adc.yaml +0 -0
  345. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/schema/id.yaml +0 -0
  346. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/schema/remote_devices.yaml +0 -0
  347. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/schema/remote_inputs.yaml +0 -0
  348. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/schema/schema.yaml +0 -0
  349. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/schema/temp_unit.yaml +0 -0
  350. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/schema/update_interval.yaml +0 -0
  351. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/action_validation.py +0 -0
  352. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/app.py +0 -0
  353. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/assets/codicon-DCmgc-ay.ttf +0 -0
  354. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/assets/editor.worker-BVjSvWeP.js +0 -0
  355. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/assets/index-D-R9QzIP.css +0 -0
  356. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/assets/json.worker-CqOJL4FD.js +0 -0
  357. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/assets/monaco-B9WiNxkw.css +0 -0
  358. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/assets/monaco-CAZoGZNF.js +0 -0
  359. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/assets/rolldown-runtime-Dw2cE7zH.js +0 -0
  360. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/assets/vendor-BD5Ml_Uz.js +0 -0
  361. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/assets/workbox-window.prod.es5-BJd1pjeW.js +0 -0
  362. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/assets/yaml.worker-nZQZSRZ7.js +0 -0
  363. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/boneio-192.png +0 -0
  364. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/boneio-512.png +0 -0
  365. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/boneio.svg +0 -0
  366. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/boneio_fav.svg +0 -0
  367. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/adc.schema.json +0 -0
  368. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/areas.schema.json +0 -0
  369. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/boneio.schema.json +0 -0
  370. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/can.schema.json +0 -0
  371. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/cover.schema.json +0 -0
  372. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/dallas.schema.json +0 -0
  373. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/ds2482.schema.json +0 -0
  374. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/ina219.schema.json +0 -0
  375. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/irrigation.schema.json +0 -0
  376. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/lm75.schema.json +0 -0
  377. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/logger.schema.json +0 -0
  378. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/lox_udp.schema.json +0 -0
  379. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/mcp23017.schema.json +0 -0
  380. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/mcp9808.schema.json +0 -0
  381. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/modbus.schema.json +0 -0
  382. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/modbus_devices.schema.json +0 -0
  383. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/mqtt.schema.json +0 -0
  384. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/oled.schema.json +0 -0
  385. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/output.schema.json +0 -0
  386. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/output_group.schema.json +0 -0
  387. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/pca9685.schema.json +0 -0
  388. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/pcf8575.schema.json +0 -0
  389. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/remote_devices.schema.json +0 -0
  390. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/remote_inputs.schema.json +0 -0
  391. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/sensor.schema.json +0 -0
  392. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/template.schema.json +0 -0
  393. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/virtual_energy_sensor.schema.json +0 -0
  394. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/schema/web.schema.json +0 -0
  395. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/frontend-dist/workbox-4eca85ba.js +0 -0
  396. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/middleware/__init__.py +0 -0
  397. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/middleware/auth.py +0 -0
  398. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/__init__.py +0 -0
  399. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/auth.py +0 -0
  400. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/caddy.py +0 -0
  401. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/can.py +0 -0
  402. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/covers.py +0 -0
  403. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/irrigation.py +0 -0
  404. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/migrations.py +0 -0
  405. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/modbus.py +0 -0
  406. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/outputs.py +0 -0
  407. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/remote_devices.py +0 -0
  408. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/sensors.py +0 -0
  409. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/system.py +0 -0
  410. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/templates.py +0 -0
  411. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/timezone_sudoers.py +0 -0
  412. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/tools.py +0 -0
  413. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/routes/update.py +0 -0
  414. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/adc.schema.json +0 -0
  415. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/areas.schema.json +0 -0
  416. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/boneio.schema.json +0 -0
  417. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/can.schema.json +0 -0
  418. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/cover.schema.json +0 -0
  419. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/dallas.schema.json +0 -0
  420. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/ds2482.schema.json +0 -0
  421. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/ina219.schema.json +0 -0
  422. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/irrigation.schema.json +0 -0
  423. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/lm75.schema.json +0 -0
  424. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/logger.schema.json +0 -0
  425. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/lox_udp.schema.json +0 -0
  426. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/mcp23017.schema.json +0 -0
  427. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/mcp9808.schema.json +0 -0
  428. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/modbus.schema.json +0 -0
  429. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/modbus_devices.schema.json +0 -0
  430. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/mqtt.schema.json +0 -0
  431. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/oled.schema.json +0 -0
  432. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/output.schema.json +0 -0
  433. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/output_group.schema.json +0 -0
  434. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/pca9685.schema.json +0 -0
  435. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/pcf8575.schema.json +0 -0
  436. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/remote_devices.schema.json +0 -0
  437. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/remote_inputs.schema.json +0 -0
  438. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/sensor.schema.json +0 -0
  439. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/template.schema.json +0 -0
  440. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/virtual_energy_sensor.schema.json +0 -0
  441. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/schema/web.schema.json +0 -0
  442. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/services/__init__.py +0 -0
  443. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/services/logs.py +0 -0
  444. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/web_server.py +0 -0
  445. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio/webui/websocket_manager.py +0 -0
  446. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio.egg-info/dependency_links.txt +0 -0
  447. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio.egg-info/entry_points.txt +0 -0
  448. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio.egg-info/requires.txt +0 -0
  449. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/boneio.egg-info/top_level.txt +0 -0
  450. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/pyproject.toml +0 -0
  451. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/setup.cfg +0 -0
  452. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/setup.py +0 -0
  453. {boneio-1.4.0.dev3 → boneio-1.4.0.dev4}/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.dev4
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",
@@ -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
  # ------------------------------------------------------------------
@@ -169,6 +169,10 @@ class Manager:
169
169
  # Used by the delay/delay_cancel_on action system (e.g. motion sensors)
170
170
  self._pending_delayed_actions: dict[str, list[asyncio.Task]] = {}
171
171
 
172
+ # Pending remote tilt restores: key = "device_id:cover_id" -> asyncio.Task
173
+ # Background tasks that wait for ESPHome cover IDLE then restore tilt
174
+ self._pending_tilt_restores: dict[str, asyncio.Task] = {}
175
+
172
176
  # Startup status tracking
173
177
  self._startup_status: str = "initializing"
174
178
  self._startup_complete: bool = False
@@ -1043,8 +1047,16 @@ class Manager:
1043
1047
  cover.name if hasattr(cover, "name") else entity_id,
1044
1048
  time.time() - start_time,
1045
1049
  )
1046
- _f = getattr(cover, action_to_execute)
1047
- await _f(**filtered_data)
1050
+ # Signal to cover that this call originates from an action.
1051
+ # If restore_tilt is set in the action definition, enable tilt restore.
1052
+ cover._from_action = True
1053
+ cover._action_tilt_restore = bool(action_definition.get("restore_tilt", False))
1054
+ try:
1055
+ _f = getattr(cover, action_to_execute)
1056
+ await _f(**filtered_data)
1057
+ finally:
1058
+ cover._from_action = False
1059
+ cover._action_tilt_restore = False
1048
1060
 
1049
1061
  elif action == OUTPUT_OVER_MQTT:
1050
1062
  boneio_id = action_definition.get("boneio_id")
@@ -1127,6 +1139,21 @@ class Manager:
1127
1139
  assert entity_id and remote_device_id # guaranteed by guard above
1128
1140
  action_cover = action_definition.get("action_cover", "TOGGLE")
1129
1141
  extra_data = action_definition.get("extra_data", {})
1142
+ restore_tilt = action_definition.get("restore_tilt", False)
1143
+
1144
+ # Save tilt before executing action (ESPHome only)
1145
+ saved_tilt_pct: int | None = None
1146
+ if restore_tilt:
1147
+ cover_state = self.remote_devices.get_cover_state(
1148
+ remote_device_id, entity_id
1149
+ )
1150
+ if cover_state and cover_state.get("tilt") is not None:
1151
+ saved_tilt_pct = int(round(cover_state["tilt"] * 100))
1152
+ _LOGGER.debug(
1153
+ "Remote cover %s/%s: saving tilt=%d%% for restore",
1154
+ remote_device_id, entity_id, saved_tilt_pct,
1155
+ )
1156
+
1130
1157
  await self.remote_devices.control_cover(
1131
1158
  device_id=remote_device_id,
1132
1159
  cover_id=entity_id,
@@ -1134,6 +1161,19 @@ class Manager:
1134
1161
  **extra_data,
1135
1162
  )
1136
1163
 
1164
+ # Schedule background tilt restore after movement completes
1165
+ if saved_tilt_pct is not None and saved_tilt_pct > 0:
1166
+ task_key = f"{remote_device_id}:{entity_id}"
1167
+ # Cancel any previous pending restore for the same cover
1168
+ old_task = self._pending_tilt_restores.get(task_key)
1169
+ if old_task and not old_task.done():
1170
+ old_task.cancel()
1171
+ self._pending_tilt_restores[task_key] = asyncio.create_task(
1172
+ self._restore_remote_tilt(
1173
+ remote_device_id, entity_id, saved_tilt_pct
1174
+ )
1175
+ )
1176
+
1137
1177
  async def _run_delayed_action(
1138
1178
  self, input_id: str, action_definition: dict, delay_seconds: float
1139
1179
  ) -> None:
@@ -1203,6 +1243,58 @@ class Manager:
1203
1243
  )
1204
1244
  return cancelled
1205
1245
 
1246
+ async def _restore_remote_tilt(
1247
+ self, device_id: str, cover_id: str, tilt_pct: int
1248
+ ) -> None:
1249
+ """Restore tilt position on a remote ESPHome cover after movement.
1250
+
1251
+ Waits for the cover to reach IDLE state, then sends a set_tilt
1252
+ command to restore the previously saved tilt position.
1253
+
1254
+ Args:
1255
+ device_id: Remote device ID
1256
+ cover_id: Cover entity ID on the remote device
1257
+ tilt_pct: Tilt position to restore (0-100)
1258
+ """
1259
+ task_key = f"{device_id}:{cover_id}"
1260
+ try:
1261
+ _LOGGER.debug(
1262
+ "Waiting for remote cover %s/%s to reach IDLE before restoring tilt=%d%%",
1263
+ device_id, cover_id, tilt_pct,
1264
+ )
1265
+ # Wait for cover to stop moving (up to 120s)
1266
+ if not await self.remote_devices.wait_for_cover_idle(device_id, cover_id):
1267
+ _LOGGER.warning(
1268
+ "Remote cover %s/%s did not reach IDLE, skipping tilt restore",
1269
+ device_id, cover_id,
1270
+ )
1271
+ return
1272
+
1273
+ # Small settle delay to avoid command overlap
1274
+ await asyncio.sleep(0.5)
1275
+
1276
+ _LOGGER.info(
1277
+ "Restoring tilt=%d%% on remote cover %s/%s",
1278
+ tilt_pct, device_id, cover_id,
1279
+ )
1280
+ await self.remote_devices.control_cover(
1281
+ device_id=device_id,
1282
+ cover_id=cover_id,
1283
+ action="TILT",
1284
+ tilt_position=tilt_pct,
1285
+ )
1286
+ except asyncio.CancelledError:
1287
+ _LOGGER.debug(
1288
+ "Remote tilt restore cancelled for %s/%s (new action triggered?)",
1289
+ device_id, cover_id,
1290
+ )
1291
+ except Exception:
1292
+ _LOGGER.exception(
1293
+ "Failed to restore tilt on remote cover %s/%s", device_id, cover_id
1294
+ )
1295
+ finally:
1296
+ self._pending_tilt_restores.pop(task_key, None)
1297
+
1206
1298
  def _reload_logger(self) -> None:
1207
1299
  """Reload logger configuration from config file.
1208
1300
 
@@ -1300,6 +1392,25 @@ class Manager:
1300
1392
  area = out_cfg.get("area")
1301
1393
  on_disconnect = str(out_cfg.get("on_disconnect", "ignore"))
1302
1394
 
1395
+ # Interlock configuration
1396
+ interlock_groups = out_cfg.get("interlock_group", [])
1397
+ if isinstance(interlock_groups, str):
1398
+ interlock_groups = [interlock_groups]
1399
+ enforce_interlock = bool(out_cfg.get("enforce_interlock", False))
1400
+
1401
+ # Momentary actions
1402
+ momentary_turn_on = out_cfg.get("momentary_turn_on")
1403
+ momentary_turn_off = out_cfg.get("momentary_turn_off")
1404
+
1405
+ # Adjustable duration
1406
+ adjustable_duration_enabled = bool(out_cfg.get("adjustable_duration", False))
1407
+ from boneio.core.utils.timeperiod import parse_time_to_seconds
1408
+
1409
+ dur_default = parse_time_to_seconds(out_cfg.get("duration_default"), 60.0)
1410
+ dur_min = max(1.0, parse_time_to_seconds(out_cfg.get("duration_min"), 1.0))
1411
+ dur_max = max(dur_min, parse_time_to_seconds(out_cfg.get("duration_max"), 3600.0))
1412
+ dur_unit = str(out_cfg.get("duration_unit", "s"))
1413
+
1303
1414
  # Check for duplicates
1304
1415
  if self.outputs.get_output(entity_id) is not None:
1305
1416
  _LOGGER.warning(
@@ -1319,8 +1430,22 @@ class Manager:
1319
1430
  show_in_ha=show_in_ha,
1320
1431
  area=area,
1321
1432
  on_disconnect=on_disconnect,
1433
+ interlock_manager=self.outputs._interlock_manager,
1434
+ interlock_groups=interlock_groups,
1435
+ enforce_interlock=enforce_interlock,
1436
+ momentary_turn_on=momentary_turn_on,
1437
+ momentary_turn_off=momentary_turn_off,
1438
+ adjustable_duration=adjustable_duration_enabled,
1439
+ duration_default=dur_default,
1440
+ duration_min=dur_min,
1441
+ duration_max=dur_max,
1442
+ duration_unit=dur_unit,
1322
1443
  )
1323
1444
 
1445
+ # Register in shared interlock manager
1446
+ if interlock_groups:
1447
+ self.outputs._interlock_manager.register(remote_output, interlock_groups)
1448
+
1324
1449
  # Set the device manager reference if the device is already loaded.
1325
1450
  # ESPHome devices may not be in _devices yet (loaded in background),
1326
1451
  # so _device_manager may remain None — resolved lazily in
@@ -1342,11 +1467,12 @@ class Manager:
1342
1467
  # Register in OutputManager so it's available everywhere
1343
1468
  self.outputs._outputs[entity_id] = remote_output # type: ignore[assignment]
1344
1469
  _LOGGER.info(
1345
- "Registered remote output: id='%s' device='%s' output='%s' type='%s'",
1470
+ "Registered remote output: id='%s' device='%s' output='%s' type='%s' interlock=%s",
1346
1471
  entity_id,
1347
1472
  device_id,
1348
1473
  output_id,
1349
1474
  output_type,
1475
+ interlock_groups or "none",
1350
1476
  )
1351
1477
 
1352
1478
  _LOGGER.info(
@@ -609,6 +609,64 @@ class RemoteDeviceManager:
609
609
  **kwargs,
610
610
  )
611
611
 
612
+ def get_cover_state(self, device_id: str, cover_id: str) -> dict[str, Any] | None:
613
+ """Get current cover state from an ESPHome remote device.
614
+
615
+ Returns the cached state dict containing position, tilt,
616
+ current_operation, and last_known_operation.
617
+
618
+ Args:
619
+ device_id: ID of the remote device
620
+ cover_id: ID of the cover
621
+
622
+ Returns:
623
+ State dictionary or None if device/cover not found or not ESPHome
624
+ """
625
+ device = self.get_device(device_id)
626
+ if not device or device.protocol != RemoteDeviceProtocol.ESPHOME_API:
627
+ return None
628
+ return cast(Any, device)._cover_states.get(cover_id)
629
+
630
+ async def wait_for_cover_idle(
631
+ self,
632
+ device_id: str,
633
+ cover_id: str,
634
+ timeout: float = 120.0,
635
+ poll_interval: float = 0.5,
636
+ ) -> bool:
637
+ """Wait for an ESPHome cover to reach IDLE state.
638
+
639
+ Polls the cached cover state until current_operation becomes 0 (IDLE)
640
+ or the timeout expires.
641
+
642
+ Args:
643
+ device_id: ID of the remote device
644
+ cover_id: ID of the cover to monitor
645
+ timeout: Maximum time to wait in seconds (default: 120s)
646
+ poll_interval: Time between polls in seconds (default: 0.5s)
647
+
648
+ Returns:
649
+ True if cover reached IDLE, False on timeout
650
+ """
651
+ device = self.get_device(device_id)
652
+ if not device or device.protocol != RemoteDeviceProtocol.ESPHOME_API:
653
+ return False
654
+
655
+ esphome = cast(Any, device)
656
+ start = asyncio.get_event_loop().time()
657
+
658
+ while asyncio.get_event_loop().time() - start < timeout:
659
+ state = esphome._cover_states.get(cover_id, {})
660
+ if state.get("current_operation", 0) == 0:
661
+ return True
662
+ await asyncio.sleep(poll_interval)
663
+
664
+ _LOGGER.warning(
665
+ "Timeout (%.0fs) waiting for cover '%s' on device '%s' to reach IDLE",
666
+ timeout, cover_id, device_id,
667
+ )
668
+ return False
669
+
612
670
  async def reload(self, remote_devices_config: list[dict[str, Any]] | None = None) -> None:
613
671
  """Reload remote devices from config.
614
672
 
@@ -69,6 +69,17 @@ schema:
69
69
  Position threshold for SMART_TOGGLE action.
70
70
  If cover position is at or below this value, it will always open.
71
71
  Above this value, normal toggle behavior applies.
72
+ restore_tilt:
73
+ type: boolean
74
+ required: False
75
+ default: false
76
+ meta:
77
+ label: Restore Tilt After Movement
78
+ description: |
79
+ When true, the previous tilt angle is saved before executing this cover action
80
+ and restored after the movement finishes. Only applies to venetian covers.
81
+ Example: pressing a button to close the blinds to 50% and then restoring
82
+ the slat angle to the previous value.
72
83
  action_output:
73
84
  type: string
74
85
  required_if: