boneio 1.2.0.dev27__tar.gz → 1.3.0.dev1__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 (461) hide show
  1. {boneio-1.2.0.dev27/boneio.egg-info → boneio-1.3.0.dev1}/PKG-INFO +2 -1
  2. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/const.py +1 -0
  3. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/config/config_helper.py +11 -0
  4. boneio-1.3.0.dev1/boneio/core/manager/canopen.py +552 -0
  5. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/manager/manager.py +30 -0
  6. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/manager/modbus.py +1 -0
  7. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/manager/remote.py +15 -0
  8. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/remote/__init__.py +2 -0
  9. boneio-1.3.0.dev1/boneio/core/remote/can.py +163 -0
  10. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/utils/filter.py +1 -0
  11. boneio-1.3.0.dev1/boneio/example_config/can_master.yaml +74 -0
  12. boneio-1.3.0.dev1/boneio/example_config/can_slave.yaml +47 -0
  13. boneio-1.3.0.dev1/boneio/hardware/can/__init__.py +9 -0
  14. boneio-1.3.0.dev1/boneio/hardware/can/bridge.py +159 -0
  15. boneio-1.3.0.dev1/boneio/hardware/can/client.py +339 -0
  16. boneio-1.3.0.dev1/boneio/hardware/can/interface.py +204 -0
  17. boneio-1.3.0.dev1/boneio/hardware/can/node.py +225 -0
  18. boneio-1.3.0.dev1/boneio/hardware/can/node_id.py +136 -0
  19. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/integration/homeassistant.py +29 -4
  20. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/coordinator.py +112 -5
  21. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/energy_meters/socomec_e03.json +6 -6
  22. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/energy_meters/socomec_e23.json +11 -11
  23. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/inverters/sofar.json +14 -14
  24. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/inverters/thessla.json +13 -1
  25. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/other/n4dsc08.json +24 -0
  26. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/other/r4dcb08.json +8 -8
  27. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/other/wanas415.json +27 -0
  28. boneio-1.3.0.dev1/boneio/modbus/devices/sensors/boneio-edge-temp.json +108 -0
  29. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/sensors/cwt.json +2 -2
  30. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/sensors/dyp-a12-ultrasonic.json +1 -1
  31. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/sensors/liquid-sensor.json +1 -1
  32. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/sensors/pt100.json +1 -1
  33. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/sensors/sht20.json +2 -2
  34. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/sensors/sht30.json +2 -2
  35. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/entities/base.py +36 -2
  36. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/entities/derived/select.py +1 -2
  37. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/entities/derived/switch.py +1 -1
  38. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/entities/derived/text.py +1 -1
  39. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/entities/sensor/binary.py +1 -1
  40. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/entities/sensor/text.py +1 -1
  41. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/entities/writeable/binary.py +1 -1
  42. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/entities/writeable/numeric.py +2 -2
  43. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/models/state.py +1 -0
  44. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/runner.py +16 -1
  45. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/schema/schema.yaml +96 -0
  46. boneio-1.3.0.dev1/boneio/version.py +2 -0
  47. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/app.py +2 -0
  48. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/cssMode-BzCozbpl.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/cssMode-DYzYCxj1.js +1 -1
  49. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/freemarker2-CtmThL1b.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/freemarker2-Bemoup4X.js +1 -1
  50. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/handlebars-fiiZvevB.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/handlebars-3t5vS37H.js +1 -1
  51. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/html-BimETABr.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/html-Cq68Vj92.js +1 -1
  52. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/htmlMode-DHLVYo-c.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/htmlMode-zRg51dux.js +1 -1
  53. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/index-DE7XXR7y.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/index-CedvLek6.js +202 -200
  54. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/index-B2dz9R2t.css → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/index-yfVmKD9N.css +1 -1
  55. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/javascript-YzZE0D4_.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/javascript-BeqHop1l.js +1 -1
  56. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/jsonMode-BQm48WQe.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/jsonMode-B_TKboJF.js +1 -1
  57. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/liquid-DVUhP52g.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/liquid-BK7PsOyv.js +1 -1
  58. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/mdx-DOQ104-j.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/mdx-Ckb8-VUx.js +1 -1
  59. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/python-4pYZo98W.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/python-CO1-gBqF.js +1 -1
  60. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/razor-Dq6QqksM.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/razor-Dx6x9ypa.js +1 -1
  61. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/tsMode-tYO0JGIQ.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/tsMode-Deid1skj.js +1 -1
  62. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/typescript-DSsPzLFv.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/typescript-JSH4I7cf.js +1 -1
  63. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/xml-CrUPqEEX.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/xml-BX_Opm8D.js +1 -1
  64. boneio-1.2.0.dev27/boneio/webui/frontend-dist/assets/yaml-9n910SQK.js → boneio-1.3.0.dev1/boneio/webui/frontend-dist/assets/yaml-BRsnPpO3.js +1 -1
  65. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/index.html +2 -2
  66. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/boneio.schema.json +22 -0
  67. boneio-1.3.0.dev1/boneio/webui/frontend-dist/schema/can.schema.json +132 -0
  68. {boneio-1.2.0.dev27/boneio/webui → boneio-1.3.0.dev1/boneio/webui/frontend-dist}/schema/config.schema.json +156 -0
  69. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/modbus_devices.schema.json +8 -0
  70. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/sw.js +1 -1
  71. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/routes/__init__.py +2 -0
  72. boneio-1.3.0.dev1/boneio/webui/routes/can.py +377 -0
  73. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/routes/config.py +45 -0
  74. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/routes/modbus.py +169 -1
  75. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/boneio.schema.json +22 -0
  76. boneio-1.3.0.dev1/boneio/webui/schema/can.schema.json +132 -0
  77. {boneio-1.2.0.dev27/boneio/webui/frontend-dist → boneio-1.3.0.dev1/boneio/webui}/schema/config.schema.json +156 -0
  78. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/modbus_devices.schema.json +8 -0
  79. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1/boneio.egg-info}/PKG-INFO +2 -1
  80. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio.egg-info/SOURCES.txt +30 -17
  81. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio.egg-info/requires.txt +1 -0
  82. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/pyproject.toml +2 -1
  83. boneio-1.2.0.dev27/boneio/modbus/devices/sensors/boneio-edge-temp.json +0 -50
  84. boneio-1.2.0.dev27/boneio/version.py +0 -2
  85. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/LICENSE +0 -0
  86. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/MANIFEST.in +0 -0
  87. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/README.md +0 -0
  88. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/__init__.py +0 -0
  89. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.2/input.yaml +0 -0
  90. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.2/output_24_16.yaml +0 -0
  91. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.2/output_32_10.yaml +0 -0
  92. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.2/output_32_5.yaml +0 -0
  93. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.2/output_cover.yaml +0 -0
  94. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.2/output_cover_mix.yaml +0 -0
  95. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.3/input.yaml +0 -0
  96. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.3/output_24_16.yaml +0 -0
  97. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.3/output_32_10.yaml +0 -0
  98. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.3/output_32_5.yaml +0 -0
  99. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.3/output_cover.yaml +0 -0
  100. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.3/output_cover_mix.yaml +0 -0
  101. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.4/input.yaml +0 -0
  102. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.4/output_24_16.yaml +0 -0
  103. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.4/output_32_10.yaml +0 -0
  104. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.4/output_32_5.yaml +0 -0
  105. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.4/output_cover.yaml +0 -0
  106. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.4/output_cover_mix.yaml +0 -0
  107. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.5/input.yaml +0 -0
  108. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.5/output_24_16.yaml +0 -0
  109. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.5/output_32_10.yaml +0 -0
  110. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.5/output_cover.yaml +0 -0
  111. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.5/output_cover_mix.yaml +0 -0
  112. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.6/input.yaml +0 -0
  113. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.6/output_24_16.yaml +0 -0
  114. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.6/output_32_10.yaml +0 -0
  115. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.6/output_cover.yaml +0 -0
  116. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.6/output_cover_mix.yaml +0 -0
  117. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.7/input.yaml +0 -0
  118. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.7/output_24_16.yaml +0 -0
  119. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.7/output_32_10.yaml +0 -0
  120. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.7/output_cover.yaml +0 -0
  121. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.7/output_cover_mix.yaml +0 -0
  122. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.8/input.yaml +0 -0
  123. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.8/output_24_16.yaml +0 -0
  124. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.8/output_32_10.yaml +0 -0
  125. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.8/output_cover.yaml +0 -0
  126. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/boards/0.8/output_cover_mix.yaml +0 -0
  127. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/bonecli.py +0 -0
  128. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/__init__.py +0 -0
  129. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/cover/__init__.py +0 -0
  130. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/cover/cover.py +0 -0
  131. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/cover/time_based.py +0 -0
  132. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/cover/venetian.py +0 -0
  133. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/group/__init__.py +0 -0
  134. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/group/output_group.py +0 -0
  135. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/input/__init__.py +0 -0
  136. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/input/binary_sensor.py +0 -0
  137. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/input/detectors.py +0 -0
  138. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/input/event.py +0 -0
  139. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/output/__init__.py +0 -0
  140. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/output/basic.py +0 -0
  141. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/output/mcp.py +0 -0
  142. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/output/pca.py +0 -0
  143. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/output/pcf.py +0 -0
  144. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/sensor/__init__.py +0 -0
  145. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/sensor/virtual_energy.py +0 -0
  146. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/template/__init__.py +0 -0
  147. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/template/alarm_panel.py +0 -0
  148. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/template/gate_cover.py +0 -0
  149. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/components/template/thermostat.py +0 -0
  150. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/__init__.py +0 -0
  151. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/cloud/__init__.py +0 -0
  152. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/cloud/data/__init__.py +0 -0
  153. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/cloud/data/docker-compose-cloud.yaml +0 -0
  154. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/cloud/data/docker-compose.yaml +0 -0
  155. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/cloud/data/init-certs-cloud.sh +0 -0
  156. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/cloud/registration.py +0 -0
  157. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/cloud/secrets.py +0 -0
  158. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/config/__init__.py +0 -0
  159. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/config/migrations/__init__.py +0 -0
  160. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/config/migrations/v1_proxy_port.py +0 -0
  161. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/config/migrations/v2_transition.py +0 -0
  162. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/config/package-lock.json +0 -0
  163. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/config/package.json +0 -0
  164. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/config/schema_converter.py +0 -0
  165. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/config/yaml_util.py +0 -0
  166. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/discovery.py +0 -0
  167. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/events/__init__.py +0 -0
  168. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/events/bus.py +0 -0
  169. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/manager/__init__.py +0 -0
  170. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/manager/covers.py +0 -0
  171. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/manager/display.py +0 -0
  172. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/manager/inputs.py +0 -0
  173. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/manager/outputs.py +0 -0
  174. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/manager/sensors.py +0 -0
  175. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/manager/templates/__init__.py +0 -0
  176. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/manager/templates/alarm.py +0 -0
  177. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/manager/templates/gate_cover.py +0 -0
  178. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/manager/templates/thermostat.py +0 -0
  179. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/manager/templates.py +0 -0
  180. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/manager/update.py +0 -0
  181. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/messaging/__init__.py +0 -0
  182. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/messaging/basic.py +0 -0
  183. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/messaging/basic_mqtt.py +0 -0
  184. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/messaging/local.py +0 -0
  185. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/messaging/mqtt.py +0 -0
  186. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/messaging/queue.py +0 -0
  187. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/remote/base.py +0 -0
  188. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/remote/esphome.py +0 -0
  189. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/remote/mqtt.py +0 -0
  190. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/remote/wled.py +0 -0
  191. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/sensor/__init__.py +0 -0
  192. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/sensor/base.py +0 -0
  193. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/sensor/system.py +0 -0
  194. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/state/__init__.py +0 -0
  195. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/state/manager.py +0 -0
  196. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/system/__init__.py +0 -0
  197. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/system/host_data.py +0 -0
  198. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/system/monitor.py +0 -0
  199. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/utils/__init__.py +0 -0
  200. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/utils/async_updater.py +0 -0
  201. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/utils/font_util.py +0 -0
  202. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/utils/logger.py +0 -0
  203. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/utils/timeperiod.py +0 -0
  204. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/core/utils/util.py +0 -0
  205. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/24x16/adc.yaml +0 -0
  206. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/24x16/binary_sensor.yaml +0 -0
  207. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/24x16/config.yaml +0 -0
  208. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/24x16/event.yaml +0 -0
  209. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/24x16/mqtt.yaml +0 -0
  210. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/24x16/output24x16A.yaml +0 -0
  211. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/32x10/adc.yaml +0 -0
  212. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/32x10/binary_sensor.yaml +0 -0
  213. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/32x10/config.yaml +0 -0
  214. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/32x10/event.yaml +0 -0
  215. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/32x10/mqtt.yaml +0 -0
  216. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/32x10/output32x10A.yaml +0 -0
  217. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/__init__.py +0 -0
  218. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/cover/adc.yaml +0 -0
  219. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/cover/binary_sensor.yaml +0 -0
  220. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/cover/config.yaml +0 -0
  221. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/cover/cover.yaml +0 -0
  222. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/cover/event.yaml +0 -0
  223. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/cover/mqtt.yaml +0 -0
  224. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/cover/outputCover.yaml +0 -0
  225. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/cover_mix/adc.yaml +0 -0
  226. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/cover_mix/binary_sensor.yaml +0 -0
  227. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/cover_mix/config.yaml +0 -0
  228. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/cover_mix/cover.yaml +0 -0
  229. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/cover_mix/event.yaml +0 -0
  230. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/cover_mix/mqtt.yaml +0 -0
  231. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/cover_mix/outputCoverMix.yaml +0 -0
  232. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/different_configs/adc.yaml +0 -0
  233. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/different_configs/all_binary_sensor.yaml +0 -0
  234. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/different_configs/binary_sensor.yaml +0 -0
  235. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/different_configs/binary_sensor_v_0_7.yaml +0 -0
  236. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/different_configs/config_24_16.yaml +0 -0
  237. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/different_configs/event_all.yaml +0 -0
  238. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/different_configs/event_v_0_7.yaml +0 -0
  239. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/different_configs/led32x4A.yaml +0 -0
  240. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/different_configs/output24x16A.yaml +0 -0
  241. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/different_configs/output24x16A_v0.3.yaml +0 -0
  242. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/different_configs/output32x10A.yaml +0 -0
  243. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/example_config/different_configs/output32x5A.yaml +0 -0
  244. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/exceptions.py +0 -0
  245. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/__init__.py +0 -0
  246. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/analog/__init__.py +0 -0
  247. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/analog/adc.py +0 -0
  248. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/display/__init__.py +0 -0
  249. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/display/fonts/danube__.ttf +0 -0
  250. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/display/oled.py +0 -0
  251. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/gpio/__init__.py +0 -0
  252. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/gpio/expanders/__init__.py +0 -0
  253. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/gpio/expanders/mcp23017.py +0 -0
  254. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/gpio/expanders/pca9685.py +0 -0
  255. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/gpio/expanders/pcf8575.py +0 -0
  256. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/gpio/input/__init__.py +0 -0
  257. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/gpio/input/base.py +0 -0
  258. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/gpio/input/manager.py +0 -0
  259. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/i2c/__init__.py +0 -0
  260. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/i2c/bus.py +0 -0
  261. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/i2c/ina219.py +0 -0
  262. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/i2c/ina219_driver.py +0 -0
  263. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/i2c/mcp9808.py +0 -0
  264. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/i2c/pct2075.py +0 -0
  265. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/onewire/__init__.py +0 -0
  266. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/onewire/bus.py +0 -0
  267. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/onewire/dallas.py +0 -0
  268. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/onewire/ds2482.py +0 -0
  269. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/sensor/__init__.py +0 -0
  270. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/sensor/temperature/__init__.py +0 -0
  271. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/sensor/temperature/base.py +0 -0
  272. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/sensor/temperature/mcp9808.py +0 -0
  273. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/hardware/sensor/temperature/pct2075.py +0 -0
  274. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/integration/__init__.py +0 -0
  275. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/integration/interlock.py +0 -0
  276. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/__init__.py +0 -0
  277. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/cli.py +0 -0
  278. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/client.py +0 -0
  279. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/__init__.py +0 -0
  280. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/energy_meters/le-03mw.json +0 -0
  281. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/energy_meters/le-03mwct.json +0 -0
  282. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/energy_meters/orno-or-we-517.json +0 -0
  283. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/energy_meters/sdm120.json +0 -0
  284. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/energy_meters/sdm630.json +0 -0
  285. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/hvac/fujitsu-ac.json +0 -0
  286. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/hvac/ventclear.json +0 -0
  287. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/sensors/dts1964_3f.json +0 -0
  288. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/sensors/gdfs.json +0 -0
  289. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/devices/sensors/gdfx.json +0 -0
  290. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/entities/__init__.py +0 -0
  291. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/entities/derived/__init__.py +0 -0
  292. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/entities/derived/numeric.py +0 -0
  293. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/entities/sensor/__init__.py +0 -0
  294. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/entities/sensor/numeric.py +0 -0
  295. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/entities/writeable/__init__.py +0 -0
  296. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/modbus/utils.py +0 -0
  297. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/models/__init__.py +0 -0
  298. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/models/actions.py +0 -0
  299. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/models/events.py +0 -0
  300. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/models/files.py +0 -0
  301. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/models/logs.py +0 -0
  302. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/models/mqtt.py +0 -0
  303. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/schema/actions.yaml +0 -0
  304. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/schema/actions_sensor.yaml +0 -0
  305. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/schema/actions_switch.yaml +0 -0
  306. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/schema/filters.yaml +0 -0
  307. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/schema/filters_adc.yaml +0 -0
  308. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/schema/id.yaml +0 -0
  309. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/schema/remote_devices.yaml +0 -0
  310. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/schema/temp_unit.yaml +0 -0
  311. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/schema/update_interval.yaml +0 -0
  312. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/abap-CRCWOmpq.js +0 -0
  313. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/apex-DnsZk_dE.js +0 -0
  314. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/azcli-1IWB1ccx.js +0 -0
  315. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/bat-DPkNLes8.js +0 -0
  316. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/bicep-Corcdgou.js +0 -0
  317. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/cameligo-CGrWLZr3.js +0 -0
  318. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/clojure-D9WOWImG.js +0 -0
  319. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/codicon-DCmgc-ay.ttf +0 -0
  320. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/coffee-B7EJu28W.js +0 -0
  321. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/cpp-SEyurbux.js +0 -0
  322. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/csharp-BoL64M5l.js +0 -0
  323. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/csp-C46ZqvIl.js +0 -0
  324. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/css-DQU6DXDx.js +0 -0
  325. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/cypher-D84EuPTj.js +0 -0
  326. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/dart-D8lhlL1r.js +0 -0
  327. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/dockerfile-DLk6rpji.js +0 -0
  328. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/ecl-BO6FnfXk.js +0 -0
  329. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/editor.worker-B4pQIWZD.js +0 -0
  330. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/elixir-BRjLKONM.js +0 -0
  331. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/flow9-Cac8vKd7.js +0 -0
  332. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/fsharp-fd1GTHhf.js +0 -0
  333. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/go-O9LJTZXk.js +0 -0
  334. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/graphql-LQdxqEYJ.js +0 -0
  335. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/hcl-DxDQ3s82.js +0 -0
  336. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/ini-BvajGCUy.js +0 -0
  337. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/java-SYsfObOQ.js +0 -0
  338. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/json.worker-aFakAbRR.js +0 -0
  339. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/julia-DQXNmw_w.js +0 -0
  340. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/kotlin-qQ0MG-9I.js +0 -0
  341. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/less-GGFNNJHn.js +0 -0
  342. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/lexon-Canl7DCW.js +0 -0
  343. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/lua-D28Ae8-K.js +0 -0
  344. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/m3-DPitgjJI.js +0 -0
  345. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/markdown-B811l8j2.js +0 -0
  346. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/mips-CdjsipkG.js +0 -0
  347. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/msdax-CYqgjx_P.js +0 -0
  348. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/mysql-BHd6q0vd.js +0 -0
  349. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/objective-c-B1aVtJYH.js +0 -0
  350. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/pascal-BhNW15KB.js +0 -0
  351. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/pascaligo-5jv8CcQD.js +0 -0
  352. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/perl-DlYyT36c.js +0 -0
  353. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/pgsql-Dy0bjov7.js +0 -0
  354. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/php-120yhfDK.js +0 -0
  355. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/pla-CjnFlu4u.js +0 -0
  356. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/postiats-CQpG440k.js +0 -0
  357. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/powerquery-DdJtto1Z.js +0 -0
  358. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/powershell-Bu_VLpJB.js +0 -0
  359. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/protobuf-IBS6jZEB.js +0 -0
  360. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/pug-kFxLfcjb.js +0 -0
  361. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/qsharp-q7JyzKFN.js +0 -0
  362. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/r-BIFz-_sK.js +0 -0
  363. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/redis-CHOsPHWR.js +0 -0
  364. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/redshift-CBifECDb.js +0 -0
  365. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/restructuredtext-CghPJEOS.js +0 -0
  366. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/ruby-CYWGW-b1.js +0 -0
  367. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/rust-DMDD0SHb.js +0 -0
  368. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/sb-BYAiYHFx.js +0 -0
  369. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/scala-Bqvq8jcR.js +0 -0
  370. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/scheme-Dhb-2j9p.js +0 -0
  371. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/scss-CTwUZ5N7.js +0 -0
  372. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/shell-CsDZo4DB.js +0 -0
  373. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/solidity-CME5AdoB.js +0 -0
  374. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/sophia-RYC1BQQz.js +0 -0
  375. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/sparql-KEyrF7De.js +0 -0
  376. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/sql-BdTr02Mf.js +0 -0
  377. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/st-C7iG7M4S.js +0 -0
  378. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/swift-D7IUmUK8.js +0 -0
  379. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/systemverilog-DgMryOEJ.js +0 -0
  380. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/tcl-PloMZuKG.js +0 -0
  381. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/twig-BfRIq3la.js +0 -0
  382. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/typespec-CzxlYoT_.js +0 -0
  383. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/vb-BwAE3J76.js +0 -0
  384. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/wgsl-B_1kOXbF.js +0 -0
  385. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/workbox-window.prod.es5-BIl4cyR9.js +0 -0
  386. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/assets/yaml.worker-DBeHcBRc.js +0 -0
  387. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/boneio-192.png +0 -0
  388. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/boneio-512.png +0 -0
  389. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/boneio.svg +0 -0
  390. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/boneio_fav.svg +0 -0
  391. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/adc.schema.json +0 -0
  392. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/areas.schema.json +0 -0
  393. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/binary_sensor.schema.json +0 -0
  394. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/cover.schema.json +0 -0
  395. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/dallas.schema.json +0 -0
  396. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/ds2482.schema.json +0 -0
  397. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/event.schema.json +0 -0
  398. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/ina219.schema.json +0 -0
  399. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/lm75.schema.json +0 -0
  400. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/logger.schema.json +0 -0
  401. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/mcp23017.schema.json +0 -0
  402. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/mcp9808.schema.json +0 -0
  403. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/modbus.schema.json +0 -0
  404. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/mqtt.schema.json +0 -0
  405. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/oled.schema.json +0 -0
  406. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/output.schema.json +0 -0
  407. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/output_group.schema.json +0 -0
  408. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/pca9685.schema.json +0 -0
  409. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/pcf8575.schema.json +0 -0
  410. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/remote_devices.schema.json +0 -0
  411. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/sensor.schema.json +0 -0
  412. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/template.schema.json +0 -0
  413. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/virtual_energy_sensor.schema.json +0 -0
  414. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/schema/web.schema.json +0 -0
  415. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/frontend-dist/workbox-226dbdbf.js +0 -0
  416. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/middleware/__init__.py +0 -0
  417. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/middleware/auth.py +0 -0
  418. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/routes/auth.py +0 -0
  419. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/routes/caddy.py +0 -0
  420. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/routes/covers.py +0 -0
  421. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/routes/outputs.py +0 -0
  422. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/routes/remote_devices.py +0 -0
  423. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/routes/sensors.py +0 -0
  424. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/routes/system.py +0 -0
  425. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/routes/templates.py +0 -0
  426. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/routes/tools.py +0 -0
  427. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/routes/update.py +0 -0
  428. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/adc.schema.json +0 -0
  429. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/areas.schema.json +0 -0
  430. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/binary_sensor.schema.json +0 -0
  431. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/cover.schema.json +0 -0
  432. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/dallas.schema.json +0 -0
  433. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/ds2482.schema.json +0 -0
  434. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/event.schema.json +0 -0
  435. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/ina219.schema.json +0 -0
  436. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/lm75.schema.json +0 -0
  437. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/logger.schema.json +0 -0
  438. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/mcp23017.schema.json +0 -0
  439. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/mcp9808.schema.json +0 -0
  440. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/modbus.schema.json +0 -0
  441. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/mqtt.schema.json +0 -0
  442. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/oled.schema.json +0 -0
  443. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/output.schema.json +0 -0
  444. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/output_group.schema.json +0 -0
  445. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/pca9685.schema.json +0 -0
  446. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/pcf8575.schema.json +0 -0
  447. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/remote_devices.schema.json +0 -0
  448. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/sensor.schema.json +0 -0
  449. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/template.schema.json +0 -0
  450. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/virtual_energy_sensor.schema.json +0 -0
  451. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/schema/web.schema.json +0 -0
  452. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/services/__init__.py +0 -0
  453. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/services/logs.py +0 -0
  454. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/web_server.py +0 -0
  455. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio/webui/websocket_manager.py +0 -0
  456. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio.egg-info/dependency_links.txt +0 -0
  457. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio.egg-info/entry_points.txt +0 -0
  458. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/boneio.egg-info/top_level.txt +0 -0
  459. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/setup.cfg +0 -0
  460. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/setup.py +0 -0
  461. {boneio-1.2.0.dev27 → boneio-1.3.0.dev1}/tests/test_py313_compatibility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boneio
3
- Version: 1.2.0.dev27
3
+ Version: 1.3.0.dev1
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
@@ -35,6 +35,7 @@ Requires-Dist: requests==2.32.5
35
35
  Requires-Dist: packaging==25.0
36
36
  Requires-Dist: aioesphomeapi>=29.0.0
37
37
  Requires-Dist: zeroconf>=0.148.0
38
+ Requires-Dist: canopen-asyncio>=2.3.0
38
39
  Dynamic: license-file
39
40
 
40
41
  Example usage:
@@ -40,6 +40,7 @@ NONE = "none"
40
40
  MODBUS = "modbus"
41
41
  MODBUS_SENSOR = "modbus_sensor"
42
42
  MODBUS_DEVICE = "modbus_device"
43
+ CAN = "can"
43
44
  UART = "uart"
44
45
  RX = "rx"
45
46
  TX = "tx"
@@ -50,6 +50,7 @@ class ConfigHelper:
50
50
  update_channel: str = "stable",
51
51
  cloud_registration: bool = False,
52
52
  pwa_name: str | None = None,
53
+ ha_child_devices: bool = False,
53
54
  ):
54
55
  self._name = name
55
56
 
@@ -81,6 +82,7 @@ class ConfigHelper:
81
82
  self._receive_boneio_autodiscovery = receive_boneio_autodiscovery
82
83
  self._update_channel = update_channel
83
84
  self._cloud_registration = cloud_registration
85
+ self._ha_child_devices = ha_child_devices
84
86
  self._device_type = device_type
85
87
  self._web_port = web_port
86
88
  self._proxy_port = proxy_port
@@ -225,6 +227,15 @@ class ConfigHelper:
225
227
  """Check if cloud registration (PWA) is enabled."""
226
228
  return self._cloud_registration
227
229
 
230
+ @property
231
+ def ha_child_devices(self) -> bool:
232
+ """Check if experimental HA child devices mode is enabled.
233
+
234
+ When enabled, each output/input/cover becomes its own child device
235
+ in Home Assistant instead of being grouped under one main device.
236
+ """
237
+ return self._ha_child_devices
238
+
228
239
  @property
229
240
  def device_type(self) -> str:
230
241
  return self._device_type
@@ -0,0 +1,552 @@
1
+ """CANopen manager for boneIO.
2
+
3
+ Manages CANopen network communication between boneIO devices.
4
+ Handles node discovery, heartbeat monitoring, and PDO exchange.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import asyncio
10
+ import logging
11
+ import os
12
+ import time
13
+ from typing import TYPE_CHECKING, Any, Callable
14
+
15
+ from boneio.hardware.can.client import CANopenClient, CANOPEN_AVAILABLE
16
+ from boneio.hardware.can.node import (
17
+ BoneIOCANNode,
18
+ NMTState,
19
+ OutputStateMessage,
20
+ )
21
+
22
+ if TYPE_CHECKING:
23
+ from boneio.core.manager import Manager
24
+
25
+ _LOGGER = logging.getLogger(__name__)
26
+
27
+ # Heartbeat interval in seconds
28
+ HEARTBEAT_INTERVAL = 1.0
29
+
30
+ # Node timeout in seconds (consider offline if no heartbeat)
31
+ NODE_TIMEOUT = 5.0
32
+
33
+
34
+ class CANopenManager:
35
+ """Manager for CANopen communication between boneIO devices.
36
+
37
+ Handles:
38
+ - Connection to CAN bus
39
+ - Periodic heartbeat transmission
40
+ - Discovery and monitoring of other nodes
41
+ - PDO exchange for output state synchronization
42
+
43
+ Args:
44
+ manager: Main boneIO manager instance
45
+ config: CANopen configuration dictionary
46
+ """
47
+
48
+ def __init__(
49
+ self,
50
+ manager: Manager | None = None,
51
+ config: dict[str, Any] | None = None,
52
+ ) -> None:
53
+ """Initialize CANopen manager.
54
+
55
+ Args:
56
+ manager: Main boneIO manager instance
57
+ config: CANopen configuration with keys:
58
+ - enabled: bool (default: False)
59
+ - channel: str (default: 'can0')
60
+ - bitrate: int (default: 125000)
61
+ - node_id: int (default: 1)
62
+ """
63
+ self._manager = manager
64
+ self._config = config or {}
65
+
66
+ self._enabled = self._config.get("enabled", False)
67
+ self._channel = self._config.get("channel", "can0")
68
+ self._bitrate = self._config.get("bitrate", 125000)
69
+ self._node_id: int | str = self._config.get("node_id", 1)
70
+ self._mode = self._config.get("mode", "master")
71
+ self._auto_setup = self._config.get("auto_setup", True)
72
+ self._restart_on_error = self._config.get("restart_on_error", True)
73
+
74
+ self._client: CANopenClient | None = None
75
+ self._nodes: dict[int, BoneIOCANNode] = {}
76
+ self._running = False
77
+
78
+ self._heartbeat_task: asyncio.Task | None = None
79
+ self._monitor_task: asyncio.Task | None = None
80
+ self._bridge = None # CANMQTTBridge, initialized in start() for master mode
81
+
82
+ # Callbacks for external handlers
83
+ self._output_state_callbacks: list[Callable[[int, int, int], None]] = []
84
+
85
+ @property
86
+ def is_enabled(self) -> bool:
87
+ """Check if CANopen is enabled in configuration."""
88
+ return self._enabled and CANOPEN_AVAILABLE
89
+
90
+ @property
91
+ def is_connected(self) -> bool:
92
+ """Check if connected to CAN bus."""
93
+ return self._client is not None and self._client.is_connected
94
+
95
+ @property
96
+ def node_id(self) -> int | str:
97
+ """Get local node ID (int after start, may be 'auto' before)."""
98
+ return self._node_id
99
+
100
+ @property
101
+ def nodes(self) -> dict[int, BoneIOCANNode]:
102
+ """Get dictionary of discovered nodes."""
103
+ return self._nodes
104
+
105
+ async def start(self) -> bool:
106
+ """Start CANopen manager.
107
+
108
+ Connects to CAN bus and starts heartbeat/monitoring tasks.
109
+
110
+ Returns:
111
+ True if started successfully.
112
+ """
113
+ if not self.is_enabled:
114
+ _LOGGER.info("CANopen is disabled or not available")
115
+ return False
116
+
117
+ if self._running:
118
+ _LOGGER.warning("CANopen manager already running")
119
+ return True
120
+
121
+ try:
122
+ # Resolve node_id if set to 'auto'
123
+ if self._node_id == "auto" or (isinstance(self._node_id, str) and self._node_id.lower() == "auto"):
124
+ from boneio.hardware.can.node_id import resolve_node_id
125
+ mac = ""
126
+ config_dir = ""
127
+ if self._manager is not None:
128
+ mac = self._manager.config_helper.network_info.get("mac", "")
129
+ config_dir = os.path.dirname(self._manager._config_file_path)
130
+ self._node_id = resolve_node_id(self._node_id, mac, config_dir)
131
+
132
+ # Auto-setup CAN interface if configured
133
+ if self._auto_setup:
134
+ from boneio.hardware.can.interface import setup_can_interface, interface_exists
135
+ if not interface_exists(self._channel):
136
+ _LOGGER.error("CAN interface %s does not exist in the system", self._channel)
137
+ return False
138
+ if not await setup_can_interface(self._channel, self._bitrate):
139
+ _LOGGER.error("Failed to auto-setup CAN interface %s", self._channel)
140
+ return False
141
+
142
+ # Create and connect client (node_id is guaranteed int after resolve)
143
+ self._client = CANopenClient(
144
+ channel=self._channel,
145
+ bitrate=self._bitrate,
146
+ node_id=int(self._node_id),
147
+ )
148
+
149
+ if not await self._client.connect():
150
+ _LOGGER.error("Failed to connect to CAN bus")
151
+ return False
152
+
153
+ # Register callbacks
154
+ self._client.add_heartbeat_callback(self._on_heartbeat)
155
+ self._client.add_pdo_callback(self._on_pdo)
156
+
157
+ # Check for node_id collision (listen 3s for heartbeats)
158
+ collision = await self._check_node_id_collision()
159
+ if collision:
160
+ _LOGGER.warning(
161
+ "Node ID %d collision detected, cannot start CANopen",
162
+ self._node_id,
163
+ )
164
+ await self._client.disconnect()
165
+ self._client = None
166
+ return False
167
+
168
+ # Start background tasks
169
+ self._running = True
170
+ self._heartbeat_task = asyncio.create_task(self._heartbeat_loop())
171
+ self._monitor_task = asyncio.create_task(self._monitor_loop())
172
+
173
+ # Start CAN-MQTT bridge in master mode
174
+ if self._mode == "master" and self._manager is not None:
175
+ from boneio.hardware.can.bridge import CANMQTTBridge
176
+ self._bridge = CANMQTTBridge(
177
+ manager=self._manager,
178
+ canopen_manager=self,
179
+ message_bus=self._manager.message_bus,
180
+ )
181
+ self._bridge.start()
182
+
183
+ _LOGGER.info(
184
+ "CANopen manager started: channel=%s, bitrate=%d, node_id=%d, mode=%s",
185
+ self._channel,
186
+ self._bitrate,
187
+ self._node_id,
188
+ self._mode,
189
+ )
190
+ return True
191
+
192
+ except Exception as e:
193
+ _LOGGER.error("Failed to start CANopen manager: %s", e)
194
+ self._running = False
195
+ return False
196
+
197
+ async def _check_node_id_collision(self, listen_seconds: float = 3.0) -> bool:
198
+ """Check if another node on the bus uses the same node_id.
199
+
200
+ Listens for heartbeat messages for `listen_seconds`. If a heartbeat
201
+ from our own node_id is received, a collision is detected.
202
+
203
+ Args:
204
+ listen_seconds: How long to listen for collisions.
205
+
206
+ Returns:
207
+ True if collision detected.
208
+ """
209
+ collision_detected = False
210
+ own_id = int(self._node_id)
211
+
212
+ def _collision_cb(node_id: int, state: str) -> None:
213
+ nonlocal collision_detected
214
+ if node_id == own_id:
215
+ collision_detected = True
216
+
217
+ # Temporarily register collision callback
218
+ if self._client is not None:
219
+ self._client.add_heartbeat_callback(_collision_cb)
220
+
221
+ _LOGGER.info(
222
+ "Checking for node_id %d collision (%0.1fs)...", own_id, listen_seconds
223
+ )
224
+ await asyncio.sleep(listen_seconds)
225
+
226
+ # Remove temporary callback
227
+ if self._client is not None and _collision_cb in self._client._heartbeat_callbacks:
228
+ self._client._heartbeat_callbacks.remove(_collision_cb)
229
+
230
+ if collision_detected:
231
+ _LOGGER.warning("Collision: another node is using node_id %d", own_id)
232
+ else:
233
+ _LOGGER.info("No node_id collision detected for %d", own_id)
234
+
235
+ return collision_detected
236
+
237
+ async def stop(self) -> None:
238
+ """Stop CANopen manager."""
239
+ if not self._running:
240
+ return
241
+
242
+ self._running = False
243
+
244
+ # Stop bridge
245
+ if self._bridge is not None:
246
+ self._bridge.stop()
247
+ self._bridge = None
248
+
249
+ # Cancel background tasks
250
+ if self._heartbeat_task:
251
+ self._heartbeat_task.cancel()
252
+ try:
253
+ await self._heartbeat_task
254
+ except asyncio.CancelledError:
255
+ pass
256
+ self._heartbeat_task = None
257
+
258
+ if self._monitor_task:
259
+ self._monitor_task.cancel()
260
+ try:
261
+ await self._monitor_task
262
+ except asyncio.CancelledError:
263
+ pass
264
+ self._monitor_task = None
265
+
266
+ # Disconnect client
267
+ if self._client:
268
+ await self._client.disconnect()
269
+ self._client = None
270
+
271
+ _LOGGER.info("CANopen manager stopped")
272
+
273
+ async def send_output_state(
274
+ self,
275
+ output_index: int,
276
+ state: int,
277
+ brightness: int = 0,
278
+ ) -> bool:
279
+ """Send output state change to CAN bus.
280
+
281
+ Other boneIO devices on the bus will receive this and can
282
+ react accordingly (e.g., for synchronized lighting).
283
+
284
+ Args:
285
+ output_index: Output index (0-47)
286
+ state: State (0=OFF, 1=ON)
287
+ brightness: Brightness for dimmers (0-255)
288
+
289
+ Returns:
290
+ True if sent successfully.
291
+ """
292
+ if not self.is_connected or self._client is None:
293
+ return False
294
+
295
+ return await self._client.send_output_state(output_index, state, brightness)
296
+
297
+ async def send_command_to_node(
298
+ self,
299
+ target_node_id: int,
300
+ output_index: int,
301
+ state: int,
302
+ brightness: int = 0,
303
+ ) -> bool:
304
+ """Send output command to a specific node via RPDO.
305
+
306
+ Args:
307
+ target_node_id: Target CAN node ID (1-127).
308
+ output_index: Output index on the target device (0-47).
309
+ state: Desired state (0=OFF, 1=ON).
310
+ brightness: Brightness level (0-255).
311
+
312
+ Returns:
313
+ True if sent successfully.
314
+ """
315
+ if not self.is_connected or self._client is None:
316
+ return False
317
+
318
+ return await self._client.send_command_to_node(
319
+ target_node_id, output_index, state, brightness
320
+ )
321
+
322
+ def add_output_state_callback(
323
+ self,
324
+ callback: Callable[[int, int, int], None],
325
+ ) -> None:
326
+ """Add callback for received output state changes.
327
+
328
+ Args:
329
+ callback: Function(node_id, output_index, state) called on reception.
330
+ """
331
+ self._output_state_callbacks.append(callback)
332
+
333
+ def get_node(self, node_id: int) -> BoneIOCANNode | None:
334
+ """Get node by ID.
335
+
336
+ Args:
337
+ node_id: Node ID to look up.
338
+
339
+ Returns:
340
+ BoneIOCANNode if found, None otherwise.
341
+ """
342
+ return self._nodes.get(node_id)
343
+
344
+ def get_online_nodes(self) -> list[BoneIOCANNode]:
345
+ """Get list of online nodes.
346
+
347
+ Returns:
348
+ List of nodes that have sent heartbeat recently.
349
+ """
350
+ return [node for node in self._nodes.values() if node.is_online]
351
+
352
+ async def _heartbeat_loop(self) -> None:
353
+ """Background task for sending periodic heartbeats."""
354
+ _LOGGER.debug("Heartbeat loop started")
355
+
356
+ while self._running:
357
+ try:
358
+ if self._client is None:
359
+ break
360
+ await self._client.send_heartbeat(NMTState.OPERATIONAL)
361
+ await asyncio.sleep(HEARTBEAT_INTERVAL)
362
+ except asyncio.CancelledError:
363
+ break
364
+ except Exception as e:
365
+ _LOGGER.error("Error in heartbeat loop: %s", e)
366
+ await asyncio.sleep(HEARTBEAT_INTERVAL)
367
+
368
+ _LOGGER.debug("Heartbeat loop stopped")
369
+
370
+ async def _monitor_loop(self) -> None:
371
+ """Background task for monitoring node timeouts and bus-off recovery."""
372
+ _LOGGER.debug("Monitor loop started")
373
+
374
+ while self._running:
375
+ try:
376
+ current_time = time.time()
377
+
378
+ # Check node timeouts
379
+ for node in list(self._nodes.values()):
380
+ if node.last_heartbeat is not None:
381
+ elapsed = current_time - node.last_heartbeat
382
+ if elapsed > NODE_TIMEOUT and node.is_online:
383
+ _LOGGER.warning(
384
+ "Node %d timed out (no heartbeat for %.1fs)",
385
+ node.node_id,
386
+ elapsed,
387
+ )
388
+ node.nmt_state = NMTState.PRE_OPERATIONAL
389
+
390
+ # Check for bus-off and auto-restart
391
+ if self._restart_on_error:
392
+ from boneio.hardware.can.interface import get_can_state
393
+ can_state = await get_can_state(self._channel)
394
+ if can_state == "BUS-OFF":
395
+ _LOGGER.warning("CAN bus-off detected on %s, restarting interface", self._channel)
396
+ from boneio.hardware.can.interface import restart_can_interface
397
+ if await restart_can_interface(self._channel, self._bitrate):
398
+ _LOGGER.info("CAN interface %s restarted successfully", self._channel)
399
+ else:
400
+ _LOGGER.error("Failed to restart CAN interface %s", self._channel)
401
+
402
+ await asyncio.sleep(1.0)
403
+ except asyncio.CancelledError:
404
+ break
405
+ except Exception as e:
406
+ _LOGGER.error("Error in monitor loop: %s", e)
407
+ await asyncio.sleep(1.0)
408
+
409
+ _LOGGER.debug("Monitor loop stopped")
410
+
411
+ def _on_heartbeat(self, node_id: int, state: str) -> None:
412
+ """Handle received heartbeat message.
413
+
414
+ Args:
415
+ node_id: Node ID of sender
416
+ state: NMT state string
417
+ """
418
+ if node_id == self._node_id:
419
+ return # Ignore own heartbeat
420
+
421
+ # Map state string to NMTState
422
+ state_map = {
423
+ "BOOT-UP": NMTState.BOOT_UP,
424
+ "STOPPED": NMTState.STOPPED,
425
+ "OPERATIONAL": NMTState.OPERATIONAL,
426
+ "PRE-OPERATIONAL": NMTState.PRE_OPERATIONAL,
427
+ }
428
+ nmt_state = state_map.get(state, NMTState.OPERATIONAL)
429
+
430
+ # Create or update node
431
+ if node_id not in self._nodes:
432
+ self._nodes[node_id] = BoneIOCANNode(node_id=node_id)
433
+ _LOGGER.info("Discovered new CANopen node: %d", node_id)
434
+
435
+ # Auto-register as CANRemoteDevice in Manager
436
+ if self._manager is not None:
437
+ from boneio.core.remote.can import CANRemoteDevice
438
+ can_device = CANRemoteDevice(
439
+ node=self._nodes[node_id],
440
+ canopen_manager=self,
441
+ )
442
+ self._manager.remote_devices.add_device(can_device)
443
+
444
+ self._nodes[node_id].update_heartbeat(time.time(), nmt_state)
445
+
446
+ def _on_pdo(self, cob_id: int, data: bytes) -> None:
447
+ """Handle received PDO message.
448
+
449
+ Handles two PDO types:
450
+ - TPDO1 (0x180 + node_id): output state broadcast from other nodes
451
+ - RPDO1 (0x200 + node_id): command addressed to us from master
452
+
453
+ Args:
454
+ cob_id: COB-ID of the message
455
+ data: PDO data
456
+ """
457
+ # RPDO1: 0x200 + our_node_id — command addressed to us (slave mode)
458
+ if cob_id == 0x200 + int(self._node_id) and len(data) >= 3:
459
+ output_index = data[0]
460
+ state = data[1] & 0x01
461
+ sender_id = data[3] if len(data) > 3 else 0
462
+ _LOGGER.info(
463
+ "Received command from node %d: output=%d, state=%d",
464
+ sender_id, output_index, state,
465
+ )
466
+ # Execute locally via Manager
467
+ if self._manager is not None:
468
+ asyncio.get_event_loop().create_task(
469
+ self._execute_local_output_command(output_index, state)
470
+ )
471
+ return
472
+
473
+ # TPDO1: 0x180 + node_id — output state broadcast from other nodes
474
+ if 0x181 <= cob_id <= 0x1FF:
475
+ node_id = cob_id - 0x180
476
+
477
+ if node_id == self._node_id:
478
+ return # Ignore own PDO
479
+
480
+ try:
481
+ msg = OutputStateMessage.from_bytes(data)
482
+ _LOGGER.debug(
483
+ "Received output state from node %d: output=%d, state=%d",
484
+ node_id,
485
+ msg.output_index,
486
+ msg.state,
487
+ )
488
+
489
+ # Update node state
490
+ if node_id in self._nodes:
491
+ self._nodes[node_id].update_output(msg.output_index, msg.state)
492
+
493
+ # Call registered callbacks
494
+ for callback in self._output_state_callbacks:
495
+ try:
496
+ callback(node_id, msg.output_index, msg.state)
497
+ except Exception as e:
498
+ _LOGGER.error("Error in output state callback: %s", e)
499
+
500
+ except Exception as e:
501
+ _LOGGER.error("Failed to parse PDO data: %s", e)
502
+
503
+ async def _execute_local_output_command(self, output_index: int, state: int) -> None:
504
+ """Execute output command locally (slave receiving RPDO from master).
505
+
506
+ Finds the output by index and toggles/sets it.
507
+
508
+ Args:
509
+ output_index: Output index (0-47).
510
+ state: Desired state (0=OFF, 1=ON).
511
+ """
512
+ if self._manager is None:
513
+ return
514
+
515
+ try:
516
+ outputs = self._manager.outputs
517
+ output_list = list(outputs.get_all_outputs().values())
518
+ if output_index >= len(output_list):
519
+ _LOGGER.warning(
520
+ "CAN command for output index %d but only %d outputs configured",
521
+ output_index, len(output_list),
522
+ )
523
+ return
524
+
525
+ output = output_list[output_index]
526
+ if state == 1:
527
+ await output.async_turn_on()
528
+ else:
529
+ await output.async_turn_off()
530
+ _LOGGER.info(
531
+ "Executed CAN command: output[%d]=%s -> %s",
532
+ output_index, output.name if hasattr(output, "name") else str(output_index),
533
+ "ON" if state else "OFF",
534
+ )
535
+ except Exception as e:
536
+ _LOGGER.error("Failed to execute local output command: %s", e)
537
+
538
+ def to_dict(self) -> dict[str, Any]:
539
+ """Get manager status as dictionary.
540
+
541
+ Returns:
542
+ Dictionary with manager status.
543
+ """
544
+ return {
545
+ "enabled": self._enabled,
546
+ "connected": self.is_connected,
547
+ "channel": self._channel,
548
+ "bitrate": self._bitrate,
549
+ "node_id": self._node_id,
550
+ "mode": self._mode,
551
+ "nodes": [node.to_dict() for node in self._nodes.values()],
552
+ }
@@ -15,8 +15,10 @@ from typing import TYPE_CHECKING, Any
15
15
 
16
16
  from boneio.const import (
17
17
  BUTTON,
18
+ CAN,
18
19
  COVER,
19
20
  COVER_OVER_MQTT,
21
+ ENABLED,
20
22
  MQTT,
21
23
  NONE,
22
24
  ONLINE,
@@ -116,6 +118,7 @@ class Manager:
116
118
  cover: list[dict] = [],
117
119
  template: list[dict] = [],
118
120
  remote_devices: list[dict] = [],
121
+ can: dict[str, Any] = {},
119
122
  web_active: bool = False,
120
123
  web_port: int = 8090,
121
124
  ) -> None:
@@ -219,6 +222,15 @@ class Manager:
219
222
  template_config=template,
220
223
  )
221
224
 
225
+ # 11. CANopenManager (optional - CAN bus communication)
226
+ self.canopen = None
227
+ if can.get(ENABLED, False):
228
+ from boneio.core.manager.canopen import CANopenManager
229
+ self.canopen = CANopenManager(
230
+ manager=self,
231
+ config=can,
232
+ )
233
+
222
234
  # Configure virtual energy sensors (must be after outputs are initialized)
223
235
  self.sensors.configure_virtual_energy_sensors()
224
236
 
@@ -227,15 +239,33 @@ class Manager:
227
239
 
228
240
  _LOGGER.info("Manager initialization complete")
229
241
 
242
+ async def start_canopen(self) -> None:
243
+ """Start CANopen manager if configured."""
244
+ if self.canopen is not None:
245
+ can_started = await self.canopen.start()
246
+ if can_started:
247
+ _LOGGER.info("CANopen manager started successfully")
248
+ else:
249
+ _LOGGER.warning("CANopen manager failed to start")
250
+ self.canopen = None
251
+
230
252
  async def stop(self) -> None:
231
253
  """Stop manager async tasks.
232
254
 
233
255
  This should be called during shutdown to cleanly stop:
256
+ - CANopen manager
234
257
  - ESPHome connections
235
258
  - Other async tasks
236
259
  """
237
260
  _LOGGER.info("Stopping manager async tasks")
238
261
 
262
+ # Stop CANopen manager
263
+ if self.canopen is not None:
264
+ try:
265
+ await self.canopen.stop()
266
+ except Exception as e:
267
+ _LOGGER.error("Error stopping CANopen manager: %s", e)
268
+
239
269
  # Stop ESPHome connections
240
270
  await self.remote_devices.stop_all_connections()
241
271
 
@@ -169,6 +169,7 @@ class ModbusManager:
169
169
  ),
170
170
  modbus=self._modbus,
171
171
  sensors_filters=device_config.get("sensors_filters", {}),
172
+ entity_labels=device_config.get("entity_labels", {}),
172
173
  additional_data=additional_data,
173
174
  area=area,
174
175
  has_custom_id=has_custom_id,