boneio 1.5.0.dev2__tar.gz → 1.5.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 (470) hide show
  1. {boneio-1.5.0.dev2/boneio.egg-info → boneio-1.5.0.dev4}/PKG-INFO +1 -1
  2. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/cover/cover.py +2 -2
  3. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/input/detectors.py +45 -0
  4. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/irrigation/controller.py +16 -1
  5. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/schema_converter.py +25 -1
  6. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/yaml_util.py +31 -19
  7. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/irrigation.py +3 -3
  8. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/manager.py +34 -1
  9. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/input/manager.py +52 -0
  10. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/client.py +100 -0
  11. boneio-1.5.0.dev4/boneio/modbus/devices/energy_meters/dts1964_3f.json +247 -0
  12. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/energy_meters/le-03mw.json +369 -365
  13. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/energy_meters/le-03mwct.json +369 -365
  14. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/energy_meters/orno-or-we-517.json +6 -1
  15. boneio-1.5.0.dev4/boneio/modbus/devices/energy_meters/sdm120.json +130 -0
  16. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/energy_meters/sdm630.json +5 -0
  17. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/energy_meters/socomec_e03.json +74 -11
  18. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/energy_meters/socomec_e23.json +124 -18
  19. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/hvac/eht-topventil-plus.json +37 -8
  20. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/hvac/fujitsu-ac.json +7 -2
  21. {boneio-1.5.0.dev2/boneio/modbus/devices/inverters → boneio-1.5.0.dev4/boneio/modbus/devices/hvac}/thessla.json +7 -2
  22. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/hvac/ventclear.json +8 -3
  23. {boneio-1.5.0.dev2/boneio/modbus/devices/other → boneio-1.5.0.dev4/boneio/modbus/devices/hvac}/wanas415.json +5 -2
  24. boneio-1.5.0.dev4/boneio/modbus/devices/inverters/sofar.json +396 -0
  25. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/other/esp32_relay_x4_modbus.json +7 -2
  26. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/other/n4dsc08.json +7 -2
  27. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/other/r4dcb08.json +70 -9
  28. boneio-1.5.0.dev4/boneio/modbus/devices/sensors/boneio-edge-temp.json +163 -0
  29. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/sensors/cwt.json +28 -4
  30. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/sensors/dyp-a12-ultrasonic.json +14 -2
  31. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/sensors/gdfs.json +7 -2
  32. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/sensors/gdfx.json +7 -2
  33. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/sensors/liquid-sensor.json +18 -3
  34. boneio-1.5.0.dev4/boneio/modbus/devices/sensors/pt100.json +33 -0
  35. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/sensors/sht20.json +27 -4
  36. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/sensors/sht30.json +27 -4
  37. boneio-1.5.0.dev4/boneio/modbus/mock_coordinator.py +283 -0
  38. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/schema.yaml +1 -27
  39. boneio-1.5.0.dev4/boneio/version.py +2 -0
  40. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/app.py +7 -0
  41. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/dashboard_cards.py +39 -0
  42. boneio-1.5.0.dev2/boneio/webui/frontend-dist/assets/ConfigEditor-DVdxuuOd.js → boneio-1.5.0.dev4/boneio/webui/frontend-dist/assets/ConfigEditor-DSm0FS9G.js +1 -1
  43. boneio-1.5.0.dev2/boneio/webui/frontend-dist/assets/aiWizardPrompt-Qk4nus2t.js → boneio-1.5.0.dev4/boneio/webui/frontend-dist/assets/aiWizardPrompt-ChA7lLsf.js +1 -1
  44. boneio-1.5.0.dev4/boneio/webui/frontend-dist/assets/index-BT7TrtpF.css +2 -0
  45. boneio-1.5.0.dev2/boneio/webui/frontend-dist/assets/index-Bz9etcWZ.js → boneio-1.5.0.dev4/boneio/webui/frontend-dist/assets/index-wbedWLv9.js +35 -35
  46. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/index.html +2 -2
  47. {boneio-1.5.0.dev2/boneio/webui → boneio-1.5.0.dev4/boneio/webui/frontend-dist}/schema/config.schema.json +7 -1
  48. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/modbus_devices.schema.json +7 -1
  49. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/sw.js +1 -1
  50. boneio-1.5.0.dev4/boneio/webui/hvac_svg_templates.py +240 -0
  51. boneio-1.5.0.dev4/boneio/webui/modbus_card_templates.py +576 -0
  52. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/__init__.py +3 -0
  53. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/dashboard.py +33 -35
  54. boneio-1.5.0.dev4/boneio/webui/routes/dev_fake_device.py +703 -0
  55. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/modbus.py +120 -1
  56. {boneio-1.5.0.dev2/boneio/webui/frontend-dist → boneio-1.5.0.dev4/boneio/webui}/schema/config.schema.json +7 -1
  57. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/modbus_devices.schema.json +7 -1
  58. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4/boneio.egg-info}/PKG-INFO +1 -1
  59. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio.egg-info/SOURCES.txt +11 -7
  60. boneio-1.5.0.dev2/boneio/modbus/devices/energy_meters/sdm120.json +0 -126
  61. boneio-1.5.0.dev2/boneio/modbus/devices/inverters/sofar.json +0 -267
  62. boneio-1.5.0.dev2/boneio/modbus/devices/sensors/boneio-edge-temp.json +0 -148
  63. boneio-1.5.0.dev2/boneio/modbus/devices/sensors/dts1964_3f.json +0 -242
  64. boneio-1.5.0.dev2/boneio/modbus/devices/sensors/pt100.json +0 -21
  65. boneio-1.5.0.dev2/boneio/version.py +0 -2
  66. boneio-1.5.0.dev2/boneio/webui/frontend-dist/assets/index-CJECcrbK.css +0 -2
  67. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/LICENSE +0 -0
  68. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/MANIFEST.in +0 -0
  69. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/README.md +0 -0
  70. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/__init__.py +0 -0
  71. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.2/input.yaml +0 -0
  72. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.2/output_24_16.yaml +0 -0
  73. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.2/output_32_10.yaml +0 -0
  74. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.2/output_32_5.yaml +0 -0
  75. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.2/output_cover.yaml +0 -0
  76. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.2/output_cover_mix.yaml +0 -0
  77. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.3/input.yaml +0 -0
  78. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.3/output_24_16.yaml +0 -0
  79. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.3/output_32_10.yaml +0 -0
  80. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.3/output_32_5.yaml +0 -0
  81. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.3/output_cover.yaml +0 -0
  82. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.3/output_cover_mix.yaml +0 -0
  83. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.4/input.yaml +0 -0
  84. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.4/output_24_16.yaml +0 -0
  85. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.4/output_32_10.yaml +0 -0
  86. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.4/output_32_5.yaml +0 -0
  87. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.4/output_cover.yaml +0 -0
  88. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.4/output_cover_mix.yaml +0 -0
  89. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.5/input.yaml +0 -0
  90. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.5/output_24_16.yaml +0 -0
  91. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.5/output_32_10.yaml +0 -0
  92. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.5/output_cover.yaml +0 -0
  93. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.5/output_cover_mix.yaml +0 -0
  94. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.6/input.yaml +0 -0
  95. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.6/output_24_16.yaml +0 -0
  96. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.6/output_32_10.yaml +0 -0
  97. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.6/output_cover.yaml +0 -0
  98. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.6/output_cover_mix.yaml +0 -0
  99. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.7/input.yaml +0 -0
  100. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.7/output_24_16.yaml +0 -0
  101. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.7/output_32_10.yaml +0 -0
  102. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.7/output_48_4.yaml +0 -0
  103. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.7/output_cover.yaml +0 -0
  104. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.7/output_cover_mix.yaml +0 -0
  105. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.8/input.yaml +0 -0
  106. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.8/output_24_16.yaml +0 -0
  107. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.8/output_32_10.yaml +0 -0
  108. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.8/output_48_4.yaml +0 -0
  109. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.8/output_cover.yaml +0 -0
  110. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/boards/0.8/output_cover_mix.yaml +0 -0
  111. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/bonecli.py +0 -0
  112. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/__init__.py +0 -0
  113. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/cover/__init__.py +0 -0
  114. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/cover/time_based.py +0 -0
  115. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/cover/venetian.py +0 -0
  116. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/group/__init__.py +0 -0
  117. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/group/output_group.py +0 -0
  118. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/input/__init__.py +0 -0
  119. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/input/binary_sensor.py +0 -0
  120. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/input/event.py +0 -0
  121. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/input/remote/__init__.py +0 -0
  122. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/input/remote/base.py +0 -0
  123. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/input/remote/esphome.py +0 -0
  124. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/irrigation/__init__.py +0 -0
  125. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/irrigation/water_source.py +0 -0
  126. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/output/__init__.py +0 -0
  127. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/output/basic.py +0 -0
  128. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/output/mcp.py +0 -0
  129. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/output/pca.py +0 -0
  130. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/output/pcf.py +0 -0
  131. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/output/remote.py +0 -0
  132. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/sensor/__init__.py +0 -0
  133. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/sensor/virtual_energy.py +0 -0
  134. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/template/__init__.py +0 -0
  135. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/template/alarm_panel.py +0 -0
  136. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/template/gate_cover.py +0 -0
  137. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/components/template/thermostat.py +0 -0
  138. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/const.py +0 -0
  139. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/__init__.py +0 -0
  140. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/cloud/__init__.py +0 -0
  141. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/cloud/data/__init__.py +0 -0
  142. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/cloud/data/docker-compose-cloud.yaml +0 -0
  143. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/cloud/data/docker-compose.yaml +0 -0
  144. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/cloud/data/init-certs-cloud.sh +0 -0
  145. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/cloud/registration.py +0 -0
  146. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/cloud/secrets.py +0 -0
  147. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/__init__.py +0 -0
  148. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/config_helper.py +0 -0
  149. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/migrations/__init__.py +0 -0
  150. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/migrations/v1_proxy_port.py +0 -0
  151. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/migrations/v2_transition.py +0 -0
  152. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/package-lock.json +0 -0
  153. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/config/package.json +0 -0
  154. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/discovery.py +0 -0
  155. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/events/__init__.py +0 -0
  156. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/events/bus.py +0 -0
  157. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/__init__.py +0 -0
  158. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/action_conditions.py +0 -0
  159. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/canopen.py +0 -0
  160. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/covers.py +0 -0
  161. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/display.py +0 -0
  162. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/inputs.py +0 -0
  163. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/modbus.py +0 -0
  164. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/outputs.py +0 -0
  165. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/remote.py +0 -0
  166. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/remote_input_registrar.py +0 -0
  167. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/sensors.py +0 -0
  168. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/templates/__init__.py +0 -0
  169. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/templates/alarm.py +0 -0
  170. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/templates/gate_cover.py +0 -0
  171. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/templates/thermostat.py +0 -0
  172. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/templates.py +0 -0
  173. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/manager/update.py +0 -0
  174. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/__init__.py +0 -0
  175. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/basic.py +0 -0
  176. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/basic_mqtt.py +0 -0
  177. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/composite.py +0 -0
  178. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/local.py +0 -0
  179. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/lox.py +0 -0
  180. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/mqtt.py +0 -0
  181. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/messaging/queue.py +0 -0
  182. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/remote/__init__.py +0 -0
  183. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/remote/base.py +0 -0
  184. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/remote/can.py +0 -0
  185. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/remote/esphome.py +0 -0
  186. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/remote/mqtt.py +0 -0
  187. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/remote/wled.py +0 -0
  188. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/sensor/__init__.py +0 -0
  189. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/sensor/base.py +0 -0
  190. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/sensor/system.py +0 -0
  191. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/state/__init__.py +0 -0
  192. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/state/manager.py +0 -0
  193. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/system/__init__.py +0 -0
  194. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/system/host_data.py +0 -0
  195. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/system/monitor.py +0 -0
  196. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/__init__.py +0 -0
  197. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/async_updater.py +0 -0
  198. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/conditions.py +0 -0
  199. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/filter.py +0 -0
  200. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/font_util.py +0 -0
  201. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/logger.py +0 -0
  202. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/timeperiod.py +0 -0
  203. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/core/utils/util.py +0 -0
  204. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/24x16/adc.yaml +0 -0
  205. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/24x16/binary_sensor.yaml +0 -0
  206. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/24x16/config.yaml +0 -0
  207. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/24x16/event.yaml +0 -0
  208. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/24x16/mqtt.yaml +0 -0
  209. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/24x16/output24x16A.yaml +0 -0
  210. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/32x10/adc.yaml +0 -0
  211. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/32x10/binary_sensor.yaml +0 -0
  212. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/32x10/config.yaml +0 -0
  213. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/32x10/event.yaml +0 -0
  214. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/32x10/mqtt.yaml +0 -0
  215. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/32x10/output32x10A.yaml +0 -0
  216. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/48x4/adc.yaml +0 -0
  217. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/48x4/binary_sensor.yaml +0 -0
  218. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/48x4/config.yaml +0 -0
  219. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/48x4/event.yaml +0 -0
  220. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/48x4/mqtt.yaml +0 -0
  221. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/48x4/output48x4A.yaml +0 -0
  222. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/__init__.py +0 -0
  223. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/can_master.yaml +0 -0
  224. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/can_slave.yaml +0 -0
  225. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover/adc.yaml +0 -0
  226. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover/binary_sensor.yaml +0 -0
  227. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover/config.yaml +0 -0
  228. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover/cover.yaml +0 -0
  229. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover/event.yaml +0 -0
  230. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover/mqtt.yaml +0 -0
  231. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover/outputCover.yaml +0 -0
  232. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover_mix/adc.yaml +0 -0
  233. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover_mix/binary_sensor.yaml +0 -0
  234. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover_mix/config.yaml +0 -0
  235. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover_mix/cover.yaml +0 -0
  236. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover_mix/event.yaml +0 -0
  237. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover_mix/mqtt.yaml +0 -0
  238. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/cover_mix/outputCoverMix.yaml +0 -0
  239. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/adc.yaml +0 -0
  240. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/all_binary_sensor.yaml +0 -0
  241. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/binary_sensor.yaml +0 -0
  242. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/binary_sensor_v_0_7.yaml +0 -0
  243. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/config_24_16.yaml +0 -0
  244. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/event_all.yaml +0 -0
  245. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/event_v_0_7.yaml +0 -0
  246. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/led32x4A.yaml +0 -0
  247. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/output24x16A.yaml +0 -0
  248. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/output24x16A_v0.3.yaml +0 -0
  249. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/output32x10A.yaml +0 -0
  250. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/example_config/different_configs/output32x5A.yaml +0 -0
  251. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/exceptions.py +0 -0
  252. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/__init__.py +0 -0
  253. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/analog/__init__.py +0 -0
  254. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/analog/adc.py +0 -0
  255. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/can/__init__.py +0 -0
  256. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/can/bridge.py +0 -0
  257. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/can/client.py +0 -0
  258. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/can/interface.py +0 -0
  259. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/can/node.py +0 -0
  260. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/can/node_id.py +0 -0
  261. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/can/test_od.py +0 -0
  262. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/display/__init__.py +0 -0
  263. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/display/early_oled.py +0 -0
  264. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/display/fonts/danube__.ttf +0 -0
  265. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/display/oled.py +0 -0
  266. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/__init__.py +0 -0
  267. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/expanders/__init__.py +0 -0
  268. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/expanders/mcp23017.py +0 -0
  269. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/expanders/pca9685.py +0 -0
  270. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/expanders/pcf8575.py +0 -0
  271. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/input/__init__.py +0 -0
  272. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/gpio/input/base.py +0 -0
  273. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/i2c/__init__.py +0 -0
  274. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/i2c/bus.py +0 -0
  275. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/i2c/ina219.py +0 -0
  276. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/i2c/ina219_driver.py +0 -0
  277. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/i2c/mcp9808.py +0 -0
  278. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/i2c/pct2075.py +0 -0
  279. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/onewire/__init__.py +0 -0
  280. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/onewire/bus.py +0 -0
  281. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/onewire/dallas.py +0 -0
  282. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/onewire/ds2482.py +0 -0
  283. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/sensor/__init__.py +0 -0
  284. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/sensor/temperature/__init__.py +0 -0
  285. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/sensor/temperature/base.py +0 -0
  286. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/sensor/temperature/mcp9808.py +0 -0
  287. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/hardware/sensor/temperature/pct2075.py +0 -0
  288. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/integration/__init__.py +0 -0
  289. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/integration/homeassistant.py +0 -0
  290. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/integration/interlock.py +0 -0
  291. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/integration/lox_template.py +0 -0
  292. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/__init__.py +0 -0
  293. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/actions.py +0 -0
  294. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/MANIFEST.sha256 +0 -0
  295. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/docker/daemon.json +0 -0
  296. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/docker/nodered/caddy/502.html +0 -0
  297. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/docker/nodered/caddy/init-certs.sh +0 -0
  298. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/docker/nodered/docker-compose.yaml +0 -0
  299. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/docker/nodered/nginx/default.conf +0 -0
  300. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/docker/nodered/node-red/settings.js +0 -0
  301. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/journald/journald.conf +0 -0
  302. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/mosquitto/boneio.conf +0 -0
  303. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/sudoers/boneio +0 -0
  304. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/systemd/boneio-oled-boot.service +0 -0
  305. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/systemd/boneio-oled-shutdown.service +0 -0
  306. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/systemd/boneio.service +0 -0
  307. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/systemd/set-hostname-once.service +0 -0
  308. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/usr-local-bin/set-hostname-once.sh +0 -0
  309. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/usr-sbin/oled_boot_splash.py +0 -0
  310. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/usr-sbin/oled_boot_splash.sh +0 -0
  311. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/usr-sbin/oled_msg.py +0 -0
  312. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/assets/usr-sbin/oled_msg.sh +0 -0
  313. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/bootstrap/boneio-migrate +0 -0
  314. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/bootstrap/install-helper.sh +0 -0
  315. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/bootstrap/sudoers-migrate +0 -0
  316. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/runner.py +0 -0
  317. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/__init__.py +0 -0
  318. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/v1_3_0_baseline.py +0 -0
  319. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/v1_3_1_fix_oled_boot.py +0 -0
  320. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/v1_3_2_cleanup_can_sudoers.py +0 -0
  321. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/v1_4_0_fix_mqtt_sudoers.py +0 -0
  322. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/v1_4_3_oled_shutdown.py +0 -0
  323. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/v1_4_4_caddy.py +0 -0
  324. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/migrations/versions/v1_5_0_fix_oled_fifo_permissions.py +0 -0
  325. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/__init__.py +0 -0
  326. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/cli.py +0 -0
  327. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/coordinator.py +0 -0
  328. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/devices/__init__.py +0 -0
  329. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/__init__.py +0 -0
  330. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/base.py +0 -0
  331. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/derived/__init__.py +0 -0
  332. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/derived/numeric.py +0 -0
  333. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/derived/select.py +0 -0
  334. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/derived/switch.py +0 -0
  335. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/derived/text.py +0 -0
  336. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/sensor/__init__.py +0 -0
  337. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/sensor/binary.py +0 -0
  338. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/sensor/numeric.py +0 -0
  339. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/sensor/text.py +0 -0
  340. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/writeable/__init__.py +0 -0
  341. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/writeable/binary.py +0 -0
  342. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/entities/writeable/numeric.py +0 -0
  343. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/modbus/utils.py +0 -0
  344. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/models/__init__.py +0 -0
  345. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/models/actions.py +0 -0
  346. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/models/events.py +0 -0
  347. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/models/files.py +0 -0
  348. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/models/logs.py +0 -0
  349. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/models/mqtt.py +0 -0
  350. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/models/state.py +0 -0
  351. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/runner.py +0 -0
  352. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/actions.yaml +0 -0
  353. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/actions_sensor.yaml +0 -0
  354. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/actions_switch.yaml +0 -0
  355. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/condition.yaml +0 -0
  356. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/filters.yaml +0 -0
  357. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/filters_adc.yaml +0 -0
  358. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/id.yaml +0 -0
  359. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/remote_devices.yaml +0 -0
  360. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/remote_inputs.yaml +0 -0
  361. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/remote_outputs.yaml +0 -0
  362. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/temp_unit.yaml +0 -0
  363. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/schema/update_interval.yaml +0 -0
  364. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/action_validation.py +0 -0
  365. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/codicon-ngg6Pgfi.ttf +0 -0
  366. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/css.worker-CvXBzhp8.js +0 -0
  367. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/editor.worker-Cn2oRESe.js +0 -0
  368. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/html.worker-BO6WuOEO.js +0 -0
  369. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/json.worker-BkJRGcCJ.js +0 -0
  370. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/monaco-61yH0vfd.js +0 -0
  371. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/monaco-Br_kD0ds.css +0 -0
  372. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/rolldown-runtime-QTnfLwEv.js +0 -0
  373. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/ts.worker-B0J26iPs.js +0 -0
  374. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/vendor-pmGLHP0_.js +0 -0
  375. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/workbox-window.prod.es5-Bd17z0YL.js +0 -0
  376. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/assets/yaml.worker-BKRoXlmz.js +0 -0
  377. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/boneio-192.png +0 -0
  378. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/boneio-512.png +0 -0
  379. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/boneio.svg +0 -0
  380. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/boneio_fav.svg +0 -0
  381. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/adc.schema.json +0 -0
  382. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/areas.schema.json +0 -0
  383. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/binary_sensor.schema.json +0 -0
  384. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/boneio.schema.json +0 -0
  385. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/can.schema.json +0 -0
  386. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/cover.schema.json +0 -0
  387. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/dallas.schema.json +0 -0
  388. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/ds2482.schema.json +0 -0
  389. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/event.schema.json +0 -0
  390. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/ina219.schema.json +0 -0
  391. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/irrigation.schema.json +0 -0
  392. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/lm75.schema.json +0 -0
  393. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/logger.schema.json +0 -0
  394. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/lox_udp.schema.json +0 -0
  395. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/mcp23017.schema.json +0 -0
  396. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/mcp9808.schema.json +0 -0
  397. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/modbus.schema.json +0 -0
  398. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/mqtt.schema.json +0 -0
  399. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/oled.schema.json +0 -0
  400. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/output.schema.json +0 -0
  401. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/output_group.schema.json +0 -0
  402. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/pca9685.schema.json +0 -0
  403. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/pcf8575.schema.json +0 -0
  404. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/remote_devices.schema.json +0 -0
  405. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/remote_inputs.schema.json +0 -0
  406. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/remote_outputs.schema.json +0 -0
  407. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/sensor.schema.json +0 -0
  408. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/template.schema.json +0 -0
  409. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/virtual_energy_sensor.schema.json +0 -0
  410. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/schema/web.schema.json +0 -0
  411. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/frontend-dist/workbox-4918f2f6.js +0 -0
  412. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/middleware/__init__.py +0 -0
  413. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/middleware/auth.py +0 -0
  414. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/auth.py +0 -0
  415. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/caddy.py +0 -0
  416. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/can.py +0 -0
  417. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/config.py +0 -0
  418. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/covers.py +0 -0
  419. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/irrigation.py +0 -0
  420. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/migrations.py +0 -0
  421. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/outputs.py +0 -0
  422. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/remote_devices.py +0 -0
  423. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/sensors.py +0 -0
  424. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/system.py +0 -0
  425. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/templates.py +0 -0
  426. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/timezone_sudoers.py +0 -0
  427. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/tools.py +0 -0
  428. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/routes/update.py +0 -0
  429. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/adc.schema.json +0 -0
  430. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/areas.schema.json +0 -0
  431. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/binary_sensor.schema.json +0 -0
  432. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/boneio.schema.json +0 -0
  433. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/can.schema.json +0 -0
  434. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/cover.schema.json +0 -0
  435. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/dallas.schema.json +0 -0
  436. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/ds2482.schema.json +0 -0
  437. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/event.schema.json +0 -0
  438. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/ina219.schema.json +0 -0
  439. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/irrigation.schema.json +0 -0
  440. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/lm75.schema.json +0 -0
  441. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/logger.schema.json +0 -0
  442. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/lox_udp.schema.json +0 -0
  443. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/mcp23017.schema.json +0 -0
  444. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/mcp9808.schema.json +0 -0
  445. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/modbus.schema.json +0 -0
  446. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/mqtt.schema.json +0 -0
  447. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/oled.schema.json +0 -0
  448. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/output.schema.json +0 -0
  449. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/output_group.schema.json +0 -0
  450. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/pca9685.schema.json +0 -0
  451. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/pcf8575.schema.json +0 -0
  452. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/remote_devices.schema.json +0 -0
  453. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/remote_inputs.schema.json +0 -0
  454. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/remote_outputs.schema.json +0 -0
  455. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/sensor.schema.json +0 -0
  456. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/template.schema.json +0 -0
  457. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/virtual_energy_sensor.schema.json +0 -0
  458. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/schema/web.schema.json +0 -0
  459. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/services/__init__.py +0 -0
  460. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/services/logs.py +0 -0
  461. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/web_server.py +0 -0
  462. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio/webui/websocket_manager.py +0 -0
  463. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio.egg-info/dependency_links.txt +0 -0
  464. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio.egg-info/entry_points.txt +0 -0
  465. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio.egg-info/requires.txt +0 -0
  466. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/boneio.egg-info/top_level.txt +0 -0
  467. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/pyproject.toml +0 -0
  468. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/setup.cfg +0 -0
  469. {boneio-1.5.0.dev2 → boneio-1.5.0.dev4}/setup.py +0 -0
  470. {boneio-1.5.0.dev2 → boneio-1.5.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.5.0.dev2
3
+ Version: 1.5.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
@@ -386,8 +386,8 @@ class BaseCover(BaseCoverABC, BasicMqtt):
386
386
  **json_position,
387
387
  )
388
388
  self._event_bus.trigger_event(CoverEvent(entity_id=self.id, state=event))
389
- self._message_bus.send_message(topic=f"{self._send_topic}/state", payload=state)
390
- self._message_bus.send_message(topic=f"{self._send_topic}/pos", payload=json.dumps(json_position))
389
+ self._message_bus.send_message(topic=f"{self._send_topic}/state", payload=state, retain=True)
390
+ self._message_bus.send_message(topic=f"{self._send_topic}/pos", payload=json.dumps(json_position), retain=True)
391
391
 
392
392
  @property
393
393
  def saved_position(self) -> SavedPositionDict:
@@ -109,6 +109,7 @@ class MultiClickDetector:
109
109
  self._pin = pin
110
110
  self._max_long_press_seconds = max_long_press_seconds
111
111
  self._state = ClickState()
112
+ self._boot_press_suppressed = False # Set by GpioManager._seed_initial_states
112
113
 
113
114
  # Pre-compute which click types should be delayed in exclusive mode
114
115
  # based on enabled sequences
@@ -491,6 +492,21 @@ class MultiClickDetector:
491
492
  )
492
493
  return
493
494
 
495
+ # Boot-press suppression: if GpioManager detected this pin was
496
+ # LOW at startup, the first FALLING_EDGE is a phantom boot event.
497
+ # Record the timestamp (for debounce) but do NOT schedule timers.
498
+ if self._boot_press_suppressed:
499
+ _LOGGER.info(
500
+ "Suppressing phantom boot press on %s (%s) — recording timestamp only",
501
+ self._name,
502
+ self._pin,
503
+ )
504
+ self._state.last_press_ts = timestamp_s
505
+ self._state.last_press_loop_ts = None
506
+ self._state.last_release_ts = None
507
+ self._boot_press_suppressed = False
508
+ return
509
+
494
510
  _LOGGER.debug("PRESSED: %s (%s)", self._name, self._pin)
495
511
  self._state.last_press_ts = timestamp_s
496
512
  self._state.last_press_loop_ts = self._loop.time() # Store loop time for duration calc
@@ -552,6 +568,35 @@ class MultiClickDetector:
552
568
 
553
569
  press_duration_ms = (timestamp_s - self._state.last_press_ts) * 1000 if self._state.last_press_ts else 0
554
570
  _LOGGER.debug("RELEASED: %s (%s) after %.1f ms", self._name, self._pin, press_duration_ms)
571
+
572
+ # Guard: stale release from phantom press at boot.
573
+ # If time since press exceeds max_long_press_seconds, the press
574
+ # was a startup artifact (GPIO settling at boot), not a real user
575
+ # action. Reset the detector so the next real press is accepted.
576
+ if self._state.last_press_ts and press_duration_ms > self._max_long_press_seconds * 1000:
577
+ _LOGGER.warning(
578
+ "Stale release on %s (%s): %.1fs since press exceeds max %.0fs. "
579
+ "Likely phantom press from boot. Resetting detector.",
580
+ self._name,
581
+ self._pin,
582
+ press_duration_ms / 1000,
583
+ self._max_long_press_seconds,
584
+ )
585
+ self._state.last_press_ts = None
586
+ self._state.last_press_loop_ts = None
587
+ self._state.last_release_ts = timestamp_s
588
+ self._state.click_count = 0
589
+ if self._state.long_press_timer:
590
+ self._state.long_press_timer.cancel()
591
+ self._state.long_press_timer = None
592
+ self._state.long_press_scheduled_loop_ts = None
593
+ if self._state.long_hold_periodic_timer:
594
+ self._state.long_hold_periodic_timer.cancel()
595
+ self._state.long_hold_periodic_timer = None
596
+ self._state.executed_long_actions = set()
597
+ self._state.last_repeat_times = {}
598
+ return
599
+
555
600
  self._state.last_release_ts = timestamp_s
556
601
 
557
602
  _LOGGER.debug(
@@ -419,6 +419,12 @@ class IrrigationController:
419
419
  )
420
420
 
421
421
  async def shutdown(self) -> None:
422
+ """Stop the active irrigation cycle without killing schedule tasks.
423
+
424
+ This method is safe to call from within a schedule task — it does NOT
425
+ cancel schedule loops. Use :meth:`full_stop` to tear down the
426
+ controller completely (including schedule tasks).
427
+ """
422
428
  _LOGGER.debug(
423
429
  "Irrigation %s shutdown called (state=%s, active_zone=%s). Caller: %s",
424
430
  self.id,
@@ -426,7 +432,6 @@ class IrrigationController:
426
432
  self._active_zone_idx,
427
433
  "".join(traceback.format_stack(limit=5)),
428
434
  )
429
- self.stop_schedules()
430
435
  self._cancel_pause_timer()
431
436
  await self._stop_current_zone()
432
437
  await self._handle_pump_stop_sequence()
@@ -437,6 +442,16 @@ class IrrigationController:
437
442
  self._single_zone_target_idx = None
438
443
  await self.publish_all_states()
439
444
 
445
+ async def full_stop(self) -> None:
446
+ """Fully stop the controller including schedule tasks.
447
+
448
+ Should only be called by the IrrigationManager when stopping
449
+ or reloading controllers — never from within a schedule task.
450
+ """
451
+ _LOGGER.info("Irrigation %s full_stop: stopping schedules and active cycle", self.id)
452
+ self.stop_schedules()
453
+ await self.shutdown()
454
+
440
455
  async def pause(self) -> None:
441
456
  if self._state != ControllerState.RUNNING or self._active_zone_idx is None:
442
457
  return
@@ -271,7 +271,31 @@ def main():
271
271
  # Load the schema
272
272
  with open(schema_file) as f:
273
273
  schema = yaml.load(f, Loader=BoneIOLoader)
274
-
274
+
275
+ # Dynamically inject modbus device models into the schema.
276
+ # NOTE: This is a standalone copy of the logic from yaml_util.py.
277
+ # We cannot import yaml_util here because it pulls in the full boneIO
278
+ # dependency graph (cerberus, pymodbus, smbus2 …) which is NOT installed
279
+ # in the CI environment that runs this converter script.
280
+ devices_dir = os.path.normpath(
281
+ os.path.join(script_dir, "..", "..", "modbus", "devices")
282
+ )
283
+ models: list[str] = []
284
+ if os.path.isdir(devices_dir):
285
+ for root, dirs, files in os.walk(devices_dir):
286
+ dirs[:] = [d for d in dirs if d != "__pycache__"]
287
+ for fname in files:
288
+ if fname.endswith(".json"):
289
+ models.append(fname[:-5])
290
+ models.sort()
291
+
292
+ try:
293
+ model_field = schema["modbus_devices"]["schema"]["schema"]["model"]
294
+ model_field["allowed"] = models
295
+ print(f"Injected {len(models)} modbus models into schema")
296
+ except (KeyError, TypeError):
297
+ print("WARNING: Could not inject modbus models into schema")
298
+
275
299
  # Convert and save the main schema
276
300
  json_schema = convert_cerberus_to_json_schema(schema)
277
301
  main_schema_file = os.path.join(output_dir, "config.schema.json")
@@ -26,12 +26,39 @@ _SCHEMA_CACHE = None
26
26
  _BOARD_CONFIG_CACHE = {}
27
27
 
28
28
 
29
+ def _get_modbus_device_models() -> list[str]:
30
+ """Scan modbus/devices/ directory and return filenames as model keys.
31
+
32
+ Only does os.walk (no JSON parsing) — <1ms even on BeagleBone.
33
+ """
34
+ devices_dir = os.path.normpath(os.path.join(os.path.dirname(__file__), "../../modbus/devices"))
35
+ models = []
36
+ if os.path.isdir(devices_dir):
37
+ for root, dirs, files in os.walk(devices_dir):
38
+ dirs[:] = [d for d in dirs if d != "__pycache__"]
39
+ for fname in files:
40
+ if fname.endswith(".json"):
41
+ models.append(fname[:-5])
42
+ return sorted(models)
43
+
44
+
45
+ def _inject_modbus_models(schema: dict) -> None:
46
+ """Dynamically set allowed modbus model values from device files."""
47
+ try:
48
+ model_field = schema["modbus_devices"]["schema"]["schema"]["model"]
49
+ model_field["allowed"] = _get_modbus_device_models()
50
+ _LOGGER.debug("Injected %d modbus models into schema", len(model_field["allowed"]))
51
+ except (KeyError, TypeError):
52
+ _LOGGER.warning("Could not inject modbus models into schema")
53
+
54
+
29
55
  def _get_schema():
30
56
  """Get schema from cache or load it if not cached."""
31
57
  global _SCHEMA_CACHE
32
58
  if _SCHEMA_CACHE is None:
33
59
  _LOGGER.debug("Loading schema from file (first time)")
34
60
  _SCHEMA_CACHE = load_yaml_file(schema_file)
61
+ _inject_modbus_models(_SCHEMA_CACHE)
35
62
  return _SCHEMA_CACHE
36
63
 
37
64
 
@@ -653,29 +680,14 @@ class CustomValidator(Validator):
653
680
  raise ValueError(f"Could not parse power value: {value}")
654
681
  num = float(match.group(1))
655
682
  unit = match.group(2) or "w"
656
- if unit in ("w", ""):
683
+ if unit in ("w", "", "wh"):
657
684
  multiplier = 1.0
658
- elif unit == "kw":
659
- multiplier = 1000.0
660
- elif unit == "mw":
661
- multiplier = 1_000_000.0
662
- elif unit == "gw":
663
- multiplier = 1_000_000_000.0
664
- elif unit == "mw":
665
- multiplier = 1_000_000.0
666
- elif unit == "kwh":
667
- # 1 kWh = 1000 W (for 1h). For config, treat as 1000W average.
685
+ elif unit in ("kw", "kwh"):
668
686
  multiplier = 1000.0
669
- elif unit == "mwh":
687
+ elif unit in ("mw", "mwh"):
670
688
  multiplier = 1_000_000.0
671
- elif unit == "gwh":
689
+ elif unit in ("gw", "gwh"):
672
690
  multiplier = 1_000_000_000.0
673
- elif unit == "mw":
674
- multiplier = 1_000_000.0
675
- elif unit == "wh":
676
- multiplier = 1.0
677
- elif unit == "mw" or unit == "mw" or unit == "mw" or unit == "mw" or unit == "mw" or unit == "mw":
678
- multiplier = 1_000_000.0
679
691
  else:
680
692
  _LOGGER.warning(f"Unknown unit for power value: {unit}")
681
693
  raise ValueError(f"Unknown unit for power value: {unit}")
@@ -226,7 +226,7 @@ class IrrigationManager:
226
226
  self._subscribed_topics.clear()
227
227
 
228
228
  for ctrl in self._controllers.values():
229
- await ctrl.shutdown()
229
+ await ctrl.full_stop()
230
230
 
231
231
  async def reload_irrigation(self) -> None:
232
232
  """Reload irrigation configuration from file.
@@ -256,7 +256,7 @@ class IrrigationManager:
256
256
  ctrl = self._controllers[ctrl_id]
257
257
  _LOGGER.info("Removing irrigation controller '%s'", ctrl_id)
258
258
  ctrl.stop_schedules()
259
- await ctrl.shutdown()
259
+ await ctrl.full_stop()
260
260
  # Remove HA discovery for this controller
261
261
  self._remove_discovery(ctrl)
262
262
  del self._controllers[ctrl_id]
@@ -271,7 +271,7 @@ class IrrigationManager:
271
271
  if ctrl_id in self._controllers:
272
272
  old_ctrl = self._controllers[ctrl_id]
273
273
  old_ctrl.stop_schedules()
274
- await old_ctrl.shutdown()
274
+ await old_ctrl.full_stop()
275
275
  del self._controllers[ctrl_id]
276
276
 
277
277
  # Build new controller
@@ -1692,7 +1692,9 @@ class Manager:
1692
1692
  async def reconnect_callback(self) -> None:
1693
1693
  """Function to invoke when connection to MQTT is (re-)established.
1694
1694
 
1695
- Sends online status to MQTT and starts template MQTT subscriptions.
1695
+ Sends online status to MQTT, resends all entity states with retain
1696
+ so that Home Assistant immediately knows device positions after a
1697
+ broker restart, and starts template MQTT subscriptions.
1696
1698
 
1697
1699
  IMPORTANT: This is called on every MQTT reconnect, not just the first
1698
1700
  connection. Schedule tasks must NOT be restarted here — they are
@@ -1708,10 +1710,41 @@ class Manager:
1708
1710
  # Immediately refresh OLED MQTT status (event-driven, no polling delay)
1709
1711
  self.display.notify_mqtt_state_changed()
1710
1712
 
1713
+ # Resend all entity states with retain so HA has correct state
1714
+ # after a broker restart (retained messages may have been lost).
1715
+ _LOGGER.info("Resending all entity states after MQTT reconnect.")
1716
+ await self._resend_all_states()
1717
+
1711
1718
  # Start template entities (subscribe to MQTT command topics)
1712
1719
  await self.templates.start()
1713
1720
  await self.irrigation.reconnect()
1714
1721
 
1722
+ async def _resend_all_states(self) -> None:
1723
+ """Resend current state of all entities via MQTT with retain.
1724
+
1725
+ Called on MQTT reconnect to ensure the broker has up-to-date
1726
+ retained messages after a broker restart. Each entity's
1727
+ ``send_state`` / ``async_send_state`` already publishes with
1728
+ ``retain=True``, so calling them here refreshes the broker's
1729
+ retained store.
1730
+ """
1731
+ # Resend output states
1732
+ for output in self.outputs.get_all_outputs().values():
1733
+ try:
1734
+ if output.output_type not in ("cover", "none"):
1735
+ await output.async_send_state()
1736
+ except Exception as e:
1737
+ _LOGGER.debug("Error resending output state %s: %s", output.id, e)
1738
+
1739
+ # Resend cover states (send_state now uses retain=True)
1740
+ self.covers._broadcast_all_states()
1741
+
1742
+ _LOGGER.info(
1743
+ "Resent states: %d outputs, %d covers.",
1744
+ len([o for o in self.outputs.get_all_outputs().values() if o.output_type not in ("cover", "none")]),
1745
+ len(self.covers.get_all_covers()),
1746
+ )
1747
+
1715
1748
  async def receive_message(self, topic: str, message: str) -> None:
1716
1749
  """Callback for receiving MQTT messages.
1717
1750
 
@@ -302,6 +302,58 @@ class GpioManager:
302
302
  _LOGGER.error("Error in on-start callback: %s", e)
303
303
  self._on_start_callbacks.clear()
304
304
 
305
+ # Seed detectors with current GPIO state to prevent phantom events
306
+ # at boot. Must run after on-start callbacks so detectors are ready.
307
+ self._seed_initial_states()
308
+
309
+ def _seed_initial_states(self) -> None:
310
+ """Read current GPIO states and seed detectors to prevent phantom presses.
311
+
312
+ At boot, some GPIO pins may already be LOW (e.g. button circuits pulling
313
+ down through pull-up resistors). gpiod generates a FALLING_EDGE for
314
+ this initial state, which the detector interprets as a real button
315
+ press — scheduling a long press timer that fires 400ms later and
316
+ triggers an action.
317
+
318
+ By setting ``_boot_press_suppressed`` on the detector, the first
319
+ FALLING_EDGE records the kernel timestamp (for debounce) but does
320
+ NOT schedule the long press timer. The subsequent RISING_EDGE
321
+ (when the user actually presses) is caught by the stale-release
322
+ guard and handled correctly.
323
+ """
324
+ from boneio.components.input.detectors import MultiClickDetector
325
+
326
+ seeded = 0
327
+ for chip, request in self._requests.items():
328
+ for (c, line), detector in self._detectors.items():
329
+ if c != chip:
330
+ continue
331
+ if not isinstance(detector, MultiClickDetector):
332
+ continue
333
+ try:
334
+ values = request.get_values([line])
335
+ pin_is_low = not bool(values[0])
336
+ except Exception as exc:
337
+ _LOGGER.debug(
338
+ "Could not read initial state for chip%d/line%d: %s",
339
+ chip, line, exc,
340
+ )
341
+ continue
342
+
343
+ if pin_is_low:
344
+ alias = self._aliases.get((chip, line), f"chip{chip}/line{line}")
345
+ _LOGGER.info(
346
+ "GPIO %s is LOW at startup — arming boot press suppression",
347
+ alias,
348
+ )
349
+ detector._boot_press_suppressed = True
350
+ seeded += 1
351
+
352
+ if seeded:
353
+ _LOGGER.info(
354
+ "Armed boot press suppression on %d GPIO detector(s)", seeded
355
+ )
356
+
305
357
  def _handle_gpiod_events(self, chip: int, request: gpiod.LineRequest) -> None:
306
358
  """Handle GPIO events from libgpiod.
307
359
 
@@ -578,3 +578,103 @@ class Modbus:
578
578
  if self._inter_device_delay > 0:
579
579
  await asyncio.sleep(self._inter_device_delay)
580
580
  return result
581
+
582
+ def write_registers_blocking(self, unit: int | str, address: int, values: list[int]):
583
+ """Write multiple registers blocking (synchronous) - FC16.
584
+
585
+ Sends a Modbus FC16 (Write Multiple Registers) request to write
586
+ a list of 16-bit values starting at the given register address.
587
+
588
+ Args:
589
+ unit: Device address (1-247).
590
+ address: Starting register address.
591
+ values: List of 16-bit integer values to write.
592
+
593
+ Returns:
594
+ Pymodbus response object on success, None on failure.
595
+ """
596
+ start_time = time.perf_counter()
597
+ result = None
598
+ try:
599
+ connected = self._pymodbus_connect()
600
+ if not connected:
601
+ _LOGGER.error("Can't connect to Modbus.")
602
+ return None
603
+
604
+ _LOGGER.debug(
605
+ "Writing %d registers starting at %s with values %s to device %s (FC16).",
606
+ len(values),
607
+ address,
608
+ values,
609
+ unit,
610
+ )
611
+
612
+ assert self._client is not None
613
+ result = self._client.write_registers(
614
+ address=address, values=values, device_id=int(unit)
615
+ )
616
+
617
+ if isinstance(result, ExceptionResponse):
618
+ _LOGGER.error("FC16 write operation failed: %s", result)
619
+ result = None
620
+
621
+ except ValueError as exception_error:
622
+ _LOGGER.error("ValueError: Error writing multiple registers: %s", exception_error)
623
+ except (ModbusException, struct.error) as exception_error:
624
+ _LOGGER.error("ModbusException: Error writing multiple registers: %s", exception_error)
625
+ except TimeoutError:
626
+ _LOGGER.error("Timeout writing multiple registers to device %s", unit)
627
+ except asyncio.CancelledError as err:
628
+ _LOGGER.error("Operation cancelled writing multiple registers to device %s: %s", unit, err)
629
+ except Exception as e:
630
+ _LOGGER.error("Unexpected error writing multiple registers: %s - %s", type(e).__name__, e)
631
+ finally:
632
+ end_time = time.perf_counter()
633
+ _LOGGER.debug(
634
+ "FC16 write completed in %.3f seconds.",
635
+ end_time - start_time,
636
+ )
637
+ return result
638
+
639
+ async def write_registers(self, unit: int | str, address: int, values: list[int]):
640
+ """Write multiple registers async (FC16).
641
+
642
+ Returns None immediately when suspended.
643
+
644
+ Args:
645
+ unit: Device address (1-247).
646
+ address: Starting register address.
647
+ values: List of 16-bit integer values to write.
648
+ """
649
+ if self._suspended:
650
+ return None
651
+ async with self._lock:
652
+ result = await self._loop.run_in_executor(
653
+ self._executor, self.write_registers_blocking, unit, address, values
654
+ )
655
+ if self._inter_device_delay > 0:
656
+ await asyncio.sleep(self._inter_device_delay)
657
+ return result
658
+
659
+ async def write_registers_direct(self, unit: int | str, address: int, values: list[int]):
660
+ """Write multiple registers bypassing the suspend check (FC16).
661
+
662
+ Used by Tools API for manual writes while coordinators are
663
+ suspended. Still acquires the UART lock to serialize access.
664
+
665
+ Args:
666
+ unit: Device address (1-247).
667
+ address: Starting register address.
668
+ values: List of 16-bit integer values to write.
669
+ """
670
+ async with self._lock:
671
+ result = await self._loop.run_in_executor(
672
+ self._executor,
673
+ self.write_registers_blocking,
674
+ unit,
675
+ address,
676
+ values,
677
+ )
678
+ if self._inter_device_delay > 0:
679
+ await asyncio.sleep(self._inter_device_delay)
680
+ return result