boneIO 0.11.0.dev5__tar.gz → 0.11.0.dev6__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 (274) hide show
  1. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/PKG-INFO +1 -1
  2. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/const.py +2 -0
  3. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/config.py +18 -1
  4. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/filter.py +3 -2
  5. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/ha_discovery.py +1 -1
  6. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/loader.py +3 -0
  7. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/util.py +26 -1
  8. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/yaml_util.py +34 -1
  9. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/manager.py +72 -47
  10. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/liquid-sensor.json +11 -0
  11. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/sensor.py +80 -1
  12. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/single_sensor.py +50 -0
  13. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/runner.py +13 -9
  14. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/schema/actions.yaml +12 -10
  15. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/schema/schema.yaml +27 -2
  16. boneio-0.11.0.dev6/boneio/version.py +2 -0
  17. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/binary_sensor.schema.json +10 -6
  18. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/config.schema.json +55 -16
  19. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/event.schema.json +15 -9
  20. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/modbus_sensors.schema.json +30 -0
  21. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/mqtt.schema.json +0 -1
  22. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/pyproject.toml +1 -1
  23. boneio-0.11.0.dev5/boneio/version.py +0 -2
  24. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/LICENSE +0 -0
  25. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/README.md +0 -0
  26. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/__init__.py +0 -0
  27. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/boards/0.7/input.yaml +0 -0
  28. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/boards/0.7/output_24_16.yaml +0 -0
  29. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/boards/0.7/output_32_10.yaml +0 -0
  30. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/boards/0.7/output_cover.yaml +0 -0
  31. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/boards/0.7/output_cover_mix.yaml +0 -0
  32. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/boards/0.8/input.yaml +0 -0
  33. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/boards/0.8/output_24_16.yaml +0 -0
  34. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/boards/0.8/output_32_10.yaml +0 -0
  35. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/boards/0.8/output_cover.yaml +0 -0
  36. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/boards/0.8/output_cover_mix.yaml +0 -0
  37. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/bonecli.py +0 -0
  38. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/cover/__init__.py +0 -0
  39. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/cover/cover.py +0 -0
  40. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/cover/previous.py +0 -0
  41. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/cover/time_based.py +0 -0
  42. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/cover/venetian.py +0 -0
  43. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/24x16/adc.yaml +0 -0
  44. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/24x16/binary_sensor.yaml +0 -0
  45. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/24x16/config.yaml +0 -0
  46. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/24x16/event.yaml +0 -0
  47. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/24x16/mqtt.yaml +0 -0
  48. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/24x16/output24x16A.yaml +0 -0
  49. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/32x10/adc.yaml +0 -0
  50. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/32x10/binary_sensor.yaml +0 -0
  51. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/32x10/config.yaml +0 -0
  52. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/32x10/event.yaml +0 -0
  53. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/32x10/mqtt.yaml +0 -0
  54. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/32x10/output32x10A.yaml +0 -0
  55. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/__init__.py +0 -0
  56. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/cover/adc.yaml +0 -0
  57. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/cover/binary_sensor.yaml +0 -0
  58. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/cover/config.yaml +0 -0
  59. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/cover/cover.yaml +0 -0
  60. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/cover/event.yaml +0 -0
  61. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/cover/mqtt.yaml +0 -0
  62. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/cover/outputCover.yaml +0 -0
  63. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/cover_mix/adc.yaml +0 -0
  64. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/cover_mix/binary_sensor.yaml +0 -0
  65. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/cover_mix/config.yaml +0 -0
  66. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/cover_mix/cover.yaml +0 -0
  67. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/cover_mix/event.yaml +0 -0
  68. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/cover_mix/mqtt.yaml +0 -0
  69. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/cover_mix/outputCoverMix.yaml +0 -0
  70. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/different_configs/adc.yaml +0 -0
  71. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/different_configs/all_binary_sensor.yaml +0 -0
  72. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/different_configs/binary_sensor.yaml +0 -0
  73. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/different_configs/binary_sensor_v_0_7.yaml +0 -0
  74. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/different_configs/config_24_16.yaml +0 -0
  75. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/different_configs/event_all.yaml +0 -0
  76. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/different_configs/event_v_0_7.yaml +0 -0
  77. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/different_configs/led32x4A.yaml +0 -0
  78. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/different_configs/output24x16A.yaml +0 -0
  79. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/different_configs/output24x16A_v0.3.yaml +0 -0
  80. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/different_configs/output32x10A.yaml +0 -0
  81. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/example_config/different_configs/output32x5A.yaml +0 -0
  82. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/fonts/danube__.ttf +0 -0
  83. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/group/__init__.py +0 -0
  84. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/group/output.py +0 -0
  85. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/__init__.py +0 -0
  86. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/async_updater.py +0 -0
  87. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/click_timer.py +0 -0
  88. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/events.py +0 -0
  89. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/exceptions.py +0 -0
  90. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/gpio.py +0 -0
  91. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/gpiod.py +0 -0
  92. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/interlock.py +0 -0
  93. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/logger.py +0 -0
  94. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/mqtt.py +0 -0
  95. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/oled.py +0 -0
  96. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/onewire/W1ThermSensor.py +0 -0
  97. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/onewire/__init__.py +0 -0
  98. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/onewire/ds2482.py +0 -0
  99. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/onewire/onewire.py +0 -0
  100. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/pcf8575.py +0 -0
  101. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/queue.py +0 -0
  102. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/schema_converter.py +0 -0
  103. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/sensor/ina_219_smbus.py +0 -0
  104. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/state_manager.py +0 -0
  105. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/stats.py +0 -0
  106. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/helper/timeperiod.py +0 -0
  107. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/input/__init__.py +0 -0
  108. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/input/gpio.py +0 -0
  109. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/input/gpio_new.py +0 -0
  110. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/message_bus/__init__.py +0 -0
  111. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/message_bus/basic.py +0 -0
  112. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/message_bus/local.py +0 -0
  113. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/message_bus/mqtt.py +0 -0
  114. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/__init__.py +0 -0
  115. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/client.py +0 -0
  116. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/cwt.json +0 -0
  117. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/dts1964_3f.json +0 -0
  118. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/modbuscli.py +0 -0
  119. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/orno-or-we-517.json +0 -0
  120. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/pt100.json +0 -0
  121. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/r4dcb08.json +0 -0
  122. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/sdm120.json +0 -0
  123. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/sdm630.json +0 -0
  124. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/sht20.json +0 -0
  125. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/sht30.json +0 -0
  126. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/socomec_e03.json +0 -0
  127. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/socomec_e23.json +0 -0
  128. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/sofar.json +0 -0
  129. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/modbus/utils.py +0 -0
  130. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/models/__init__.py +0 -0
  131. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/models/files.py +0 -0
  132. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/models/logs.py +0 -0
  133. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/oled.py +0 -0
  134. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/relay/__init__.py +0 -0
  135. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/relay/basic.py +0 -0
  136. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/relay/gpio.py +0 -0
  137. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/relay/mcp.py +0 -0
  138. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/relay/pca.py +0 -0
  139. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/relay/pcf.py +0 -0
  140. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/schema/actions_sensor.yaml +0 -0
  141. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/schema/actions_switch.yaml +0 -0
  142. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/schema/filters.yaml +0 -0
  143. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/schema/filters_adc.yaml +0 -0
  144. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/schema/id.yaml +0 -0
  145. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/schema/temp_unit.yaml +0 -0
  146. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/schema/update_interval.yaml +0 -0
  147. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/sensor/__init__.py +0 -0
  148. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/sensor/adc.py +0 -0
  149. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/sensor/gpio.py +0 -0
  150. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/sensor/gpio_new.py +0 -0
  151. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/sensor/ina219.py +0 -0
  152. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/sensor/serial_number.py +0 -0
  153. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/sensor/temp/__init__.py +0 -0
  154. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/sensor/temp/dallas.py +0 -0
  155. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/sensor/temp/lm75.py +0 -0
  156. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/sensor/temp/mcp9808.py +0 -0
  157. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/app.py +0 -0
  158. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/abap-BrgZPUOV.js +0 -0
  159. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/apex-DyP6w7ZV.js +0 -0
  160. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/azcli-BaLxmfj-.js +0 -0
  161. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/bat-CFOPXBzS.js +0 -0
  162. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/bicep-BfEKNvv3.js +0 -0
  163. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/cameligo-BFG1Mk7z.js +0 -0
  164. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/clojure-DTECt2xU.js +0 -0
  165. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/codicon-DCmgc-ay.ttf +0 -0
  166. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/coffee-CDGzqUPQ.js +0 -0
  167. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/cpp-CLLBncYj.js +0 -0
  168. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/csharp-dUCx_-0o.js +0 -0
  169. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/csp-5Rap-vPy.js +0 -0
  170. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/css-D3h14YRZ.js +0 -0
  171. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/cssMode-C5afUc0K.js +0 -0
  172. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/cypher-DrQuvNYM.js +0 -0
  173. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/dart-CFKIUWau.js +0 -0
  174. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/dockerfile-Zznr-cwX.js +0 -0
  175. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/ecl-Ce3n6wWz.js +0 -0
  176. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/editor.worker-oRlJJsnX.js +0 -0
  177. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/elixir-deUWdS0T.js +0 -0
  178. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/flow9-i9-g7ZhI.js +0 -0
  179. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/freemarker2-emRcpycN.js +0 -0
  180. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/fsharp-CzKuDChf.js +0 -0
  181. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/go-Cphgjts3.js +0 -0
  182. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/graphql-Cg7bfA9N.js +0 -0
  183. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/handlebars-mMSD-c9g.js +0 -0
  184. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/hcl-0cvrggvQ.js +0 -0
  185. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/html-Clq5L_-r.js +0 -0
  186. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/htmlMode-CYqwdxDX.js +0 -0
  187. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/index-BcJKL9Rz.js +0 -0
  188. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/index-DzcnWIxb.css +0 -0
  189. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/ini-Drc7WvVn.js +0 -0
  190. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/java-B_fMsGYe.js +0 -0
  191. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/javascript-BR7Nbw1G.js +0 -0
  192. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/json.worker-BnUULff4.js +0 -0
  193. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/jsonMode-aJvzz7xf.js +0 -0
  194. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/julia-Bqgm2twL.js +0 -0
  195. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/kotlin-BSkB5QuD.js +0 -0
  196. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/less-BsTHnhdd.js +0 -0
  197. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/lexon-YWi4-JPR.js +0 -0
  198. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/liquid-BNyvmcbu.js +0 -0
  199. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/lua-nf6ki56Z.js +0 -0
  200. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/m3-Cpb6xl2v.js +0 -0
  201. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/markdown-DSZPf7rp.js +0 -0
  202. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/mdx-pWhQfMuK.js +0 -0
  203. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/mips-B_c3zf-v.js +0 -0
  204. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/msdax-rUNN04Wq.js +0 -0
  205. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/mysql-DDwshQtU.js +0 -0
  206. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/objective-c-B5zXfXm9.js +0 -0
  207. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/pascal-CXOwvkN_.js +0 -0
  208. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/pascaligo-Bc-ZgV77.js +0 -0
  209. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/perl-CwNk8-XU.js +0 -0
  210. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/pgsql-tGk8EFnU.js +0 -0
  211. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/php-CpIb_Oan.js +0 -0
  212. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/pla-B03wrqEc.js +0 -0
  213. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/postiats-BKlk5iyT.js +0 -0
  214. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/powerquery-Bhzvs7bI.js +0 -0
  215. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/powershell-Dd3NCNK9.js +0 -0
  216. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/protobuf-COyEY5Pt.js +0 -0
  217. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/pug-BaJupSGV.js +0 -0
  218. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/python-CVtAQrrC.js +0 -0
  219. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/qsharp-DXyYeYxl.js +0 -0
  220. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/r-CdQndTaG.js +0 -0
  221. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/razor-BBiV-C6e.js +0 -0
  222. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/redis-CVwtpugi.js +0 -0
  223. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/redshift-25W9uPmb.js +0 -0
  224. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/restructuredtext-DfzH4Xui.js +0 -0
  225. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/ruby-Cp1zYvxS.js +0 -0
  226. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/rust-D5C2fndG.js +0 -0
  227. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/sb-CDntyWJ8.js +0 -0
  228. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/scala-BoFRg7Ot.js +0 -0
  229. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/scheme-Bio4gycK.js +0 -0
  230. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/scss-4Ik7cdeQ.js +0 -0
  231. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/shell-CX-rkNHf.js +0 -0
  232. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/solidity-Tw7wswEv.js +0 -0
  233. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/sophia-C5WLch3f.js +0 -0
  234. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/sparql-DHaeiCBh.js +0 -0
  235. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/sql-CCSDG5nI.js +0 -0
  236. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/st-pnP8ivHi.js +0 -0
  237. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/swift-DwJ7jVG9.js +0 -0
  238. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/systemverilog-B9Xyijhd.js +0 -0
  239. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/tcl-DnHyzjbg.js +0 -0
  240. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/tsMode-COZIvtMx.js +0 -0
  241. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/twig-CPajHgWi.js +0 -0
  242. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/typescript-DKdGc2VX.js +0 -0
  243. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/typespec-D-MeaMDU.js +0 -0
  244. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/vb-DgyLZaXg.js +0 -0
  245. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/wgsl-BIv9DU6q.js +0 -0
  246. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/xml-CTK9ybeu.js +0 -0
  247. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/yaml-ggTgJ1wa.js +0 -0
  248. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/assets/yaml.worker-DSHdx_mx.js +0 -0
  249. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/boneio.svg +0 -0
  250. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/boneio_fav.svg +0 -0
  251. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/frontend-dist/index.html +0 -0
  252. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/adc.schema.json +0 -0
  253. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/boneio.schema.json +0 -0
  254. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/cover.schema.json +0 -0
  255. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/dallas.schema.json +0 -0
  256. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/ds2482.schema.json +0 -0
  257. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/ina219.schema.json +0 -0
  258. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/lm75.schema.json +0 -0
  259. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/logger.schema.json +0 -0
  260. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/mcp23017.schema.json +0 -0
  261. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/mcp9808.schema.json +0 -0
  262. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/modbus.schema.json +0 -0
  263. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/oled.schema.json +0 -0
  264. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/output.schema.json +0 -0
  265. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/output_group.schema.json +0 -0
  266. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/pca9685.schema.json +0 -0
  267. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/pcf8575.schema.json +0 -0
  268. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/sensor.schema.json +0 -0
  269. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/schema/web.schema.json +0 -0
  270. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/web_server.py +0 -0
  271. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/boneio/webui/websocket_manager.py +0 -0
  272. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/tests/32_5_config.yaml +0 -0
  273. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/tests/bandit.yaml +0 -0
  274. {boneio-0.11.0.dev5 → boneio-0.11.0.dev6}/tests/relay_32_5.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: boneio
3
- Version: 0.11.0.dev5
3
+ Version: 0.11.0.dev6
4
4
  Summary: Python App for BoneIO
5
5
  License: GNU General Public License v3.0
6
6
  Author-email: Paweł Szafer <pszafer@gmail.com>
@@ -32,6 +32,8 @@ PCA = "pca"
32
32
  GPIO_MODE = "gpio_mode"
33
33
  ACTIONS = "actions"
34
34
  ACTION = "action"
35
+ OUTPUT_OVER_MQTT = "output_over_mqtt"
36
+ COVER_OVER_MQTT = "cover_over_mqtt"
35
37
  SWITCH = "switch"
36
38
  LIGHT = "light"
37
39
  BUTTON = "button"
@@ -3,6 +3,7 @@ Module to provide basic config options.
3
3
  """
4
4
  from __future__ import annotations
5
5
 
6
+ import logging
6
7
  from _collections_abc import dict_values
7
8
  from typing import Union
8
9
 
@@ -18,6 +19,9 @@ from boneio.const import (
18
19
  SWITCH,
19
20
  VALVE,
20
21
  )
22
+ from boneio.helper.util import sanitize_mqtt_topic
23
+
24
+ _LOGGER = logging.getLogger(__name__)
21
25
 
22
26
 
23
27
  class ConfigHelper:
@@ -28,9 +32,12 @@ class ConfigHelper:
28
32
  device_type: str = "boneIO Black",
29
33
  ha_discovery: bool = True,
30
34
  ha_discovery_prefix: str = HOMEASSISTANT,
35
+ network_info: dict = None,
36
+ is_web_active: bool = False,
31
37
  ):
32
38
  self._name = name
33
- self._topic_prefix = topic_prefix if topic_prefix else name
39
+ sanitized_topic_prefix = sanitize_mqtt_topic(topic_prefix) if topic_prefix else sanitize_mqtt_topic(name)
40
+ self._topic_prefix = sanitized_topic_prefix
34
41
  self._ha_discovery = ha_discovery
35
42
  self._ha_discovery_prefix = ha_discovery_prefix
36
43
  self._device_type = device_type
@@ -46,6 +53,16 @@ class ConfigHelper:
46
53
  VALVE: {},
47
54
  }
48
55
  self.manager_ready: bool = False
56
+ self._network_info = network_info
57
+ self._is_web_active = is_web_active
58
+
59
+ @property
60
+ def network_info(self) -> dict:
61
+ return self._network_info
62
+
63
+ @property
64
+ def is_web_active(self) -> bool:
65
+ return self._is_web_active
49
66
 
50
67
  @property
51
68
  def topic_prefix(self) -> str:
@@ -1,8 +1,9 @@
1
1
  """Filter class to adjust sensor values."""
2
2
 
3
3
  from __future__ import annotations
4
- from typing import Optional
4
+
5
5
  import logging
6
+ from typing import Optional
6
7
 
7
8
  _LOGGER = logging.getLogger(__name__)
8
9
 
@@ -13,7 +14,7 @@ FILTERS = {
13
14
  "multiply": lambda x, y: x * y if x else x,
14
15
  "filter_out": lambda x, y: None if x == y else x,
15
16
  "filter_out_greater": lambda x, y: None if x > y else x,
16
- "filter_out_lower": lambda x, y: None if x < y else x,
17
+ "filter_out_lower": lambda x, y: None if x < y else x
17
18
  }
18
19
 
19
20
 
@@ -233,7 +233,7 @@ def modbus_sensor_availabilty_message(
233
233
  "identifiers": [id],
234
234
  "manufacturer": "boneIO",
235
235
  "model": model,
236
- "name": f"boneIO {name.upper()}",
236
+ "name": name,
237
237
  "sw_version": __version__,
238
238
  },
239
239
  "name": sensor_id,
@@ -235,6 +235,8 @@ def create_modbus_sensors(manager: Manager, message_bus: MessageBus, sensors, **
235
235
  for sensor in sensors:
236
236
  name = sensor.get(ID)
237
237
  id = name.replace(" ", "")
238
+ print("name to check", name)
239
+ additional_data = sensor.get("data", {})
238
240
  try:
239
241
  modbus_sensors[id.lower()] = ModbusSensor(
240
242
  address=sensor[ADDRESS],
@@ -247,6 +249,7 @@ def create_modbus_sensors(manager: Manager, message_bus: MessageBus, sensors, **
247
249
  UPDATE_INTERVAL, TimePeriod(seconds=60)
248
250
  ),
249
251
  sensors_filters=sensor.get("sensors_filters", {}),
252
+ additional_data=additional_data,
250
253
  **kwargs,
251
254
  )
252
255
  except FileNotFoundError as err:
@@ -19,7 +19,7 @@ def is_callback(func: Callable[..., Any]) -> bool:
19
19
 
20
20
 
21
21
  def strip_accents(s):
22
-
22
+ """Remove accents and spaces from a string."""
23
23
  return "".join(
24
24
  c
25
25
  for c in unicodedata.normalize("NFD", s)
@@ -27,6 +27,31 @@ def strip_accents(s):
27
27
  )
28
28
 
29
29
 
30
+ def sanitize_mqtt_topic(name: str) -> str:
31
+ """
32
+ Sanitize a string to be used as an MQTT topic:
33
+ - Replace spaces with underscores
34
+ - Remove Polish diacritics
35
+ - Remove/replace forbidden characters (leave only a-z, A-Z, 0-9, '_', '-')
36
+ Args:
37
+ name (str): Input string
38
+ Returns:
39
+ str: Sanitized string
40
+ """
41
+ import re
42
+ from .logger import _LOGGER
43
+
44
+ original = name
45
+ # Zamień spacje na podkreślenia
46
+ name = name.replace(' ', '_')
47
+ # Usuń polskie znaki
48
+ name = strip_accents(name)
49
+ # Zostaw tylko dozwolone znaki
50
+ name = re.sub(r'[^a-zA-Z0-9_-]', '', name)
51
+ _LOGGER.debug(f"Sanitized MQTT topic: '{original}' -> '{name}'")
52
+ return name
53
+
54
+
30
55
  def open_json(path: str, model: str) -> dict:
31
56
  """Open json file."""
32
57
  file = f"{os.path.join(path)}/{model}.json"
@@ -430,6 +430,40 @@ class CustomValidator(Validator):
430
430
  def _normalize_coerce_actions_output(self, value):
431
431
  return str(value).upper()
432
432
 
433
+ def _normalize_coerce_length_to_meters(self, value) -> float:
434
+ """
435
+ Convert a length value to meters.
436
+ Accepts:
437
+ - Numeric values (int, float) - assumed to be in meters
438
+ - Strings with units: 'm', 'cm', 'mm'
439
+ Examples:
440
+ 5 -> 5.0
441
+ '5m' -> 5.0
442
+ '500cm' -> 5.0
443
+ '2000mm' -> 2.0
444
+ """
445
+ if value is None:
446
+ return None
447
+ if isinstance(value, (int, float)):
448
+ return float(value)
449
+ value = str(value).strip().lower()
450
+ match = re.match(r"^([-+]?[0-9]*\.?[0-9]*)\s*(m|cm|mm)?$", value)
451
+ if not match:
452
+ raise ValueError(f"Invalid length value: {value}")
453
+ num = float(match.group(1))
454
+ unit = match.group(2) or "m"
455
+ if unit == "m":
456
+ multiplier = 1.0
457
+ elif unit == "cm":
458
+ multiplier = 0.01
459
+ elif unit == "mm":
460
+ multiplier = 0.001
461
+ else:
462
+ raise ValueError(f"Unknown unit for length value: {unit}")
463
+ result = num * multiplier
464
+ _LOGGER.debug(f"Parsed length value '{value}' as {result} m")
465
+ return result
466
+
433
467
  def _normalize_coerce_positive_time_period(self, value) -> TimePeriod:
434
468
  """Validate and transform time period with time unit and integer value."""
435
469
  if isinstance(value, int):
@@ -529,7 +563,6 @@ class CustomValidator(Validator):
529
563
  '2.5MW' -> 2500000.0
530
564
  Returns float (watts) or raises ValueError if invalid.
531
565
  """
532
- import re
533
566
  if value is None:
534
567
  return None
535
568
  if isinstance(value, (int, float)):
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import asyncio
4
4
  import logging
5
5
  from collections import deque
6
- from typing import Callable, Coroutine, List, Optional, Set
6
+ from typing import Callable, Coroutine, List, Optional, Set, Tuple
7
7
 
8
8
  from board import SCL, SDA
9
9
  from busio import I2C
@@ -15,6 +15,7 @@ from boneio.const import (
15
15
  BUTTON,
16
16
  CLOSE,
17
17
  COVER,
18
+ COVER_OVER_MQTT,
18
19
  DALLAS,
19
20
  DS2482,
20
21
  EVENT_ENTITY,
@@ -30,12 +31,12 @@ from boneio.const import (
30
31
  MODBUS,
31
32
  MQTT,
32
33
  NONE,
33
- OFF,
34
34
  ON,
35
35
  ONEWIRE,
36
36
  ONLINE,
37
37
  OPEN,
38
38
  OUTPUT,
39
+ OUTPUT_OVER_MQTT,
39
40
  PCA,
40
41
  PCF,
41
42
  PIN,
@@ -45,7 +46,6 @@ from boneio.const import (
45
46
  STATE,
46
47
  STOP,
47
48
  SWITCH,
48
- TOGGLE,
49
49
  TOPIC,
50
50
  UART,
51
51
  UARTS,
@@ -88,6 +88,7 @@ from boneio.helper.yaml_util import load_config_from_file
88
88
  from boneio.message_bus import MessageBus
89
89
  from boneio.modbus.client import Modbus
90
90
  from boneio.models import OutputState
91
+ from boneio.relay.basic import BasicRelay
91
92
  from boneio.sensor.temp import TempSensor
92
93
 
93
94
  _LOGGER = logging.getLogger(__name__)
@@ -126,7 +127,6 @@ class Manager:
126
127
  cover: list = [],
127
128
  web_active: bool = False,
128
129
  web_port: int = 8090,
129
- network_state: Optional[dict] = None,
130
130
  ) -> None:
131
131
  """Initialize the manager."""
132
132
  _LOGGER.info("Initializing manager module.")
@@ -140,7 +140,6 @@ class Manager:
140
140
  self._event_bus = event_bus
141
141
  self._is_web_on = web_active
142
142
  self._web_bind_port = web_port
143
- self._network_info = network_state
144
143
 
145
144
  self._message_bus: MessageBus = message_bus
146
145
 
@@ -153,7 +152,7 @@ class Manager:
153
152
  self._mcp = {}
154
153
  self._pcf = {}
155
154
  self._pca = {}
156
- self._outputs = {}
155
+ self._outputs: dict[str, BasicRelay] = {}
157
156
  self._configured_output_groups = {}
158
157
  self._interlock_manager = SoftwareInterlockManager()
159
158
 
@@ -722,19 +721,21 @@ class Manager:
722
721
  """Get PCF by it's id."""
723
722
  return self._pcf
724
723
 
725
- def get_output_and_action(self, device_id, action, action_output, action_cover):
724
+ def get_output_and_action(
725
+ self, entity_id: str, action: str, action_output: str, action_cover: str
726
+ ) -> Tuple[BasicRelay, str]:
726
727
  """Get output device and its action based on configuration."""
727
728
  if action == OUTPUT:
728
729
  return (
729
730
  self._outputs.get(
730
- strip_accents(device_id),
731
- self._configured_output_groups.get(device_id),
731
+ strip_accents(entity_id),
732
+ self._configured_output_groups.get(entity_id),
732
733
  ),
733
734
  relay_actions.get(action_output),
734
735
  )
735
736
  else:
736
737
  return (
737
- self._covers.get(strip_accents(device_id)),
738
+ self._covers.get(strip_accents(entity_id)),
738
739
  cover_actions.get(action_cover),
739
740
  )
740
741
 
@@ -751,6 +752,32 @@ class Manager:
751
752
  actions = gpio.get_actions_of_click(click_type=x)
752
753
  topic = f"{self._config_helper.topic_prefix}/{gpio.input_type}/{gpio.pin}"
753
754
 
755
+ async def invoke_action_on_output(
756
+ entity_id: str, action_output: str, action: str, action_cover: str
757
+ ):
758
+ output, action_to_execute = self.get_output_and_action(
759
+ entity_id=entity_id,
760
+ action=action,
761
+ action_output=action_output,
762
+ action_cover=action_cover,
763
+ )
764
+ if output and action_to_execute:
765
+ _LOGGER.debug(
766
+ "Executing action %s for output %s", action_to_execute, output.name
767
+ )
768
+ _f = getattr(output, action_to_execute)
769
+ if _f:
770
+ await _f(**extra_data)
771
+ else:
772
+ if not action_to_execute:
773
+ _LOGGER.warning(
774
+ "Action doesn't exists %s, %s, %s. Check spelling",
775
+ action_definition,
776
+ actions,
777
+ )
778
+ if not output:
779
+ _LOGGER.warning("Device %s for action not found", entity_id)
780
+
754
781
  def generate_payload():
755
782
  if gpio.input_type == INPUT:
756
783
  if duration:
@@ -759,48 +786,47 @@ class Manager:
759
786
  return x
760
787
 
761
788
  for action_definition in actions:
762
- device_id = action_definition.get("pin")
789
+ entity_id = action_definition.get("pin")
763
790
  action = action_definition.get("action")
764
791
  action_output = action_definition.get("action_output")
765
792
  action_cover = action_definition.get("action_cover")
793
+ extra_data = action_definition.get("data", {})
766
794
  if action == MQTT:
767
795
  action_topic = action_definition.get(TOPIC)
768
796
  action_payload = action_definition.get("action_mqtt_msg")
769
- action_boneio = action_definition.get("action_mqtt_boneio")
770
- action_output = action_definition.get("action_output")
771
- pin = action_definition.get("pin")
772
- if action_boneio and pin and action_output in (TOGGLE, ON, OFF):
773
- self.send_message(
774
- topic=f"{action_boneio}/cmd/relay{pin}",
775
- payload=action_output,
776
- retain=False,
777
- )
778
797
  if action_topic and action_payload:
779
798
  self.send_message(
780
799
  topic=action_topic, payload=action_payload, retain=False
781
800
  )
782
801
  continue
783
- extra_data = action_definition.get("data", {})
784
- output, action = self.get_output_and_action(
785
- device_id=device_id,
786
- action=action,
787
- action_output=action_output,
788
- action_cover=action_cover,
789
- )
790
- if output and action:
791
- _LOGGER.debug("Executing action %s for output %s", action, output.name)
792
- _f = getattr(output, action)
793
- if _f:
794
- await _f(**extra_data)
795
- else:
796
- if not action:
797
- _LOGGER.warning(
798
- "Action doesn't exists %s, %s, %s. Check spelling",
799
- action_definition,
800
- actions,
802
+ elif action == OUTPUT or action == COVER:
803
+ await invoke_action_on_output(
804
+ entity_id=entity_id,
805
+ action_output=action_output,
806
+ action=action,
807
+ action_cover=action_cover,
808
+ )
809
+ elif action == OUTPUT_OVER_MQTT:
810
+ boneio_id = action_definition.get("boneio_id")
811
+ if relay_actions.get(action_output.upper()):
812
+ self.send_message(
813
+ topic=f"{boneio_id}/cmd/relay/{entity_id}/set",
814
+ payload=action_output,
815
+ retain=False,
801
816
  )
802
- if not output:
803
- _LOGGER.warning("Device %s for action not found", device_id)
817
+ else:
818
+ _LOGGER.warning("Desired action %s does not exists", action_output)
819
+ elif action == COVER_OVER_MQTT:
820
+ boneio_id = action_definition.get("boneio_id")
821
+ if cover_actions.get(action_cover.upper()):
822
+ self.send_message(
823
+ topic=f"{boneio_id}/cmd/cover/{entity_id}/set",
824
+ payload=action_cover,
825
+ retain=False,
826
+ )
827
+ else:
828
+ _LOGGER.warning("Desired action %s does not exists", action_cover)
829
+
804
830
  payload = generate_payload()
805
831
  _LOGGER.debug("Sending message %s for input %s", payload, topic)
806
832
  self.send_message(topic=topic, payload=payload, retain=False)
@@ -976,13 +1002,12 @@ class Manager:
976
1002
  if not self._config_helper.ha_discovery:
977
1003
  return
978
1004
  topic_prefix = topic_prefix or self._config_helper.topic_prefix
979
- if self._host_data:
980
- web_url = self._host_data.web_url
981
- else:
982
- if self._network_info and IP in self._network_info:
983
- web_url = f"http://{self._network_info[IP]}:{self._web_bind_port}"
984
- else:
985
- web_url = None
1005
+ web_url = None
1006
+ if self._config_helper.is_web_active:
1007
+ if self._host_data:
1008
+ web_url = self._host_data.web_url
1009
+ elif self._config_helper.network_info and IP in self._config_helper.network_info:
1010
+ web_url = f"http://{self._config_helper.network_info[IP]}:{self._web_bind_port}"
986
1011
  payload = availability_msg_func(
987
1012
  topic=topic_prefix,
988
1013
  id=id,
@@ -33,5 +33,16 @@
33
33
  }
34
34
  ]
35
35
  }
36
+ ],
37
+ "additional_sensors": [
38
+ {
39
+ "name": "Measurement Volume",
40
+ "source": "measurement_value",
41
+ "unit_of_measurement": "l",
42
+ "device_class": "volume_storage",
43
+ "state_class": "measurement",
44
+ "formula": "width * length * X * 10",
45
+ "config_keys": ["width", "length"]
46
+ }
36
47
  ]
37
48
  }
@@ -28,7 +28,7 @@ from boneio.helper.util import open_json
28
28
  from boneio.models import SensorState
29
29
 
30
30
  from .client import VALUE_TYPES, Modbus
31
- from .single_sensor import SingleSensor
31
+ from .single_sensor import SingleAdditionalSensor, SingleSensor
32
32
  from .utils import CONVERT_METHODS, REGISTERS_BASE
33
33
 
34
34
  _LOGGER = logging.getLogger(__name__)
@@ -49,6 +49,7 @@ class ModbusSensor(BasicMqtt, AsyncUpdater, Filter):
49
49
  config_helper: ConfigHelper,
50
50
  event_bus: EventBus,
51
51
  id: str = DefaultName,
52
+ additional_data: dict = {},
52
53
  **kwargs,
53
54
  ):
54
55
  """Initialize Modbus sensor class."""
@@ -69,6 +70,11 @@ class ModbusSensor(BasicMqtt, AsyncUpdater, Filter):
69
70
  k.lower(): v for k, v in sensors_filters.items()
70
71
  }
71
72
  self._modbus_sensors: List[Dict[str, SingleSensor]] = []
73
+ self._additional_sensors: List[Dict[str, SingleAdditionalSensor]] = []
74
+ self._additional_sensors_by_source_name: Dict[str, List[SingleAdditionalSensor]] = {}
75
+ self._additional_data = additional_data
76
+ print("aaa", additional_data)
77
+ # Standard sensors
72
78
  for index, data in enumerate(self._db[REGISTERS_BASE]):
73
79
  base = data[BASE]
74
80
  self._modbus_sensors.append({})
@@ -98,6 +104,45 @@ class ModbusSensor(BasicMqtt, AsyncUpdater, Filter):
98
104
  self._modbus_sensors[index][
99
105
  single_sensor.decoded_name
100
106
  ] = single_sensor
107
+
108
+ # Additional sensors
109
+ if "additional_sensors" in self._db:
110
+ for additional in self._db["additional_sensors"]:
111
+ config_keys = additional.get("config_keys", [])
112
+ if not self._additional_data:
113
+ continue
114
+ if not all(k in self._additional_data for k in config_keys):
115
+ continue
116
+ source_sensor = None
117
+ for sensors in self._modbus_sensors:
118
+ for s in sensors.values():
119
+ if s.decoded_name == additional["source"].replace("_", ""):
120
+ source_sensor = s
121
+ break
122
+ if not source_sensor:
123
+ _LOGGER.warning("Source sensor '%s' for additional sensor '%s' not found.", additional["source"], additional["name"])
124
+ continue
125
+ single_sensor = SingleAdditionalSensor(
126
+ name=additional["name"],
127
+ parent={NAME: self._name, ID: self._id, MODEL: self._model},
128
+ register_address=-1,
129
+ base_address=base,
130
+ unit_of_measurement=additional.get("unit_of_measurement", "m3"),
131
+ state_class=additional.get("state_class", "measurement"),
132
+ device_class=additional.get("device_class", "volume"),
133
+ value_type=None,
134
+ return_type=None,
135
+ filters=[],
136
+ message_bus=self._message_bus,
137
+ config_helper=self._config_helper,
138
+ ha_filter=additional.get("ha_filter", "round(2)"),
139
+ formula=additional.get("formula", ""),
140
+ context_config = { k: v for k,v in self._additional_data.items() if k in config_keys },
141
+ )
142
+ self._additional_sensors.append({single_sensor.decoded_name: single_sensor})
143
+ if source_sensor.decoded_name not in self._additional_sensors_by_source_name:
144
+ self._additional_sensors_by_source_name[source_sensor.decoded_name] = []
145
+ self._additional_sensors_by_source_name[source_sensor.decoded_name].append(single_sensor)
101
146
  _LOGGER.info(
102
147
  "Available single sensors for %s: %s",
103
148
  self._name,
@@ -109,6 +154,18 @@ class ModbusSensor(BasicMqtt, AsyncUpdater, Filter):
109
154
  ]
110
155
  ),
111
156
  )
157
+ if self._additional_sensors:
158
+ _LOGGER.info(
159
+ "Available additional sensors for %s: %s",
160
+ self._name,
161
+ ", ".join(
162
+ [
163
+ s.name
164
+ for sensors in self._additional_sensors
165
+ for s in sensors.values()
166
+ ]
167
+ ),
168
+ )
112
169
  self._event_bus = event_bus
113
170
  self._event_bus.add_haonline_listener(target=self.set_payload_offline)
114
171
  try:
@@ -134,6 +191,9 @@ class ModbusSensor(BasicMqtt, AsyncUpdater, Filter):
134
191
  for sensors in self._modbus_sensors:
135
192
  for sensor in sensors.values():
136
193
  sensor.send_ha_discovery()
194
+ for sensors in self._additional_sensors:
195
+ for sensor in sensors.values():
196
+ sensor.send_ha_discovery()
137
197
  return datetime.now()
138
198
 
139
199
  async def check_availability(self) -> None:
@@ -167,6 +227,15 @@ class ModbusSensor(BasicMqtt, AsyncUpdater, Filter):
167
227
  self._id,
168
228
  )
169
229
 
230
+ def _evaluate_formula(self, formula: str, context: dict) -> float:
231
+ """
232
+ Evaluate the formula for additional sensor using provided context.
233
+ Allowed names: X (value from source sensor), config (dict with config values)
234
+ """
235
+ code = compile(formula, "<string>", "eval")
236
+ return eval(code, {"__builtins__": {}}, context)
237
+
238
+
170
239
  async def async_update(self, timestamp: float) -> Optional[float]:
171
240
  """Fetch state periodically and send to MQTT."""
172
241
  update_interval = self._update_interval.total_in_seconds
@@ -238,6 +307,16 @@ class ModbusSensor(BasicMqtt, AsyncUpdater, Filter):
238
307
  )
239
308
  decoded_value = None
240
309
  sensor.set_value(value=decoded_value, timestamp=timestamp)
310
+ if self._additional_sensors and sensor.get_value() is not None:
311
+ if sensor.decoded_name in self._additional_sensors_by_source_name:
312
+ for additional_sensor in self._additional_sensors_by_source_name[sensor.decoded_name]:
313
+ context = {
314
+ "X": sensor.get_value(),
315
+ **additional_sensor.context
316
+ }
317
+ value = self._evaluate_formula(additional_sensor.formula, context)
318
+ additional_sensor.set_value(value=value, timestamp=timestamp)
319
+ output[additional_sensor.decoded_name] = additional_sensor.state
241
320
  output[sensor.decoded_name] = sensor.state
242
321
  await self._event_bus.async_trigger_event(
243
322
  event_type=MODBUS_SENSOR,
@@ -158,3 +158,53 @@ class SingleSensor(Filter):
158
158
  @property
159
159
  def last_timestamp(self) -> float:
160
160
  return self._timestamp
161
+
162
+
163
+ class SingleAdditionalSensor(SingleSensor):
164
+ def __init__(
165
+ self,
166
+ name: str,
167
+ parent: dict,
168
+ register_address: int,
169
+ base_address: int,
170
+ unit_of_measurement: str,
171
+ state_class: str,
172
+ device_class: str,
173
+ value_type: str,
174
+ return_type: str,
175
+ filters: list,
176
+ message_bus: MessageBus,
177
+ formula: str,
178
+ context_config: dict,
179
+ config_helper: ConfigHelper,
180
+ user_filters: Optional[list] = [],
181
+ ha_filter: str = "round(2)",
182
+ ) -> None:
183
+ super().__init__(
184
+ name=name,
185
+ parent=parent,
186
+ register_address=register_address,
187
+ base_address=base_address,
188
+ unit_of_measurement=unit_of_measurement,
189
+ state_class=state_class,
190
+ device_class=device_class,
191
+ value_type=value_type,
192
+ return_type=return_type,
193
+ filters=filters,
194
+ message_bus=message_bus,
195
+ config_helper=config_helper,
196
+ user_filters=user_filters,
197
+ ha_filter=ha_filter,
198
+ )
199
+ self._formula = formula
200
+ self._context_config = context_config
201
+
202
+ @property
203
+ def formula(self) -> str:
204
+ return self._formula
205
+
206
+ @property
207
+ def context(self) -> dict:
208
+ return self._context_config
209
+
210
+