labpulse 0.3.6__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 (294) hide show
  1. labpulse-0.3.6/.dockerignore +4 -0
  2. labpulse-0.3.6/.gitattributes +3 -0
  3. labpulse-0.3.6/.github/workflows/release.yml +170 -0
  4. labpulse-0.3.6/.github/workflows/test.yml +32 -0
  5. labpulse-0.3.6/.gitignore +18 -0
  6. labpulse-0.3.6/.vscode/launch.json +7 -0
  7. labpulse-0.3.6/.vscode/settings.json +4 -0
  8. labpulse-0.3.6/.vscode/tasks.json +29 -0
  9. labpulse-0.3.6/CHANGELOG.md +100 -0
  10. labpulse-0.3.6/CITATION.cff +11 -0
  11. labpulse-0.3.6/CONTRIBUTING.md +108 -0
  12. labpulse-0.3.6/Dockerfile +23 -0
  13. labpulse-0.3.6/LICENSE +21 -0
  14. labpulse-0.3.6/PKG-INFO +228 -0
  15. labpulse-0.3.6/README.md +188 -0
  16. labpulse-0.3.6/ROADMAP.md +433 -0
  17. labpulse-0.3.6/SECURITY.md +40 -0
  18. labpulse-0.3.6/config.d/triton-01-measurements.yaml +14 -0
  19. labpulse-0.3.6/config.d/triton-02-measurements.yaml +14 -0
  20. labpulse-0.3.6/config.yaml +354 -0
  21. labpulse-0.3.6/deployment/README.md +49 -0
  22. labpulse-0.3.6/deployment/edit_config.sh +277 -0
  23. labpulse-0.3.6/deployment/generate_compose.sh +75 -0
  24. labpulse-0.3.6/deployment/generate_homeassistant_config.sh +106 -0
  25. labpulse-0.3.6/deployment/setup_container_fs.sh +345 -0
  26. labpulse-0.3.6/docs/ARCHITECTURE.md +607 -0
  27. labpulse-0.3.6/docs/CONFIGURATION.md +979 -0
  28. labpulse-0.3.6/docs/DEVELOPMENT.md +417 -0
  29. labpulse-0.3.6/docs/HARDWARE.md +75 -0
  30. labpulse-0.3.6/docs/INSTALLATION.md +772 -0
  31. labpulse-0.3.6/docs/Internship purchased items.xlsx +0 -0
  32. labpulse-0.3.6/docs/LabPulse Sensors.xlsx +0 -0
  33. labpulse-0.3.6/docs/Mini Shopping List.xlsx +0 -0
  34. labpulse-0.3.6/docs/OPERATIONS.md +64 -0
  35. labpulse-0.3.6/docs/README.md +72 -0
  36. labpulse-0.3.6/docs/TRITON_PUBLISHER.md +1187 -0
  37. labpulse-0.3.6/docs/TROUBLESHOOTING.md +95 -0
  38. labpulse-0.3.6/docs/USER_GUIDE.md +574 -0
  39. labpulse-0.3.6/docs/examples/calculated-measurement.yaml +43 -0
  40. labpulse-0.3.6/docs/examples/driver_template.py +79 -0
  41. labpulse-0.3.6/docs/examples/minimal-serial.yaml +20 -0
  42. labpulse-0.3.6/docs/examples/mqtt-input.yaml +27 -0
  43. labpulse-0.3.6/docs/images/labpulse-overview.png +0 -0
  44. labpulse-0.3.6/docs/~$Internship purchased items.xlsx +0 -0
  45. labpulse-0.3.6/firmware/README.md +345 -0
  46. labpulse-0.3.6/firmware/examples/pressure_monitor/pressure_monitor.cpp +40 -0
  47. labpulse-0.3.6/firmware/examples/pressure_monitor/pressure_monitor.h +58 -0
  48. labpulse-0.3.6/firmware/examples/pressure_monitor/pressure_monitor.ino +9 -0
  49. labpulse-0.3.6/firmware/examples/pump_room/pump_room.cpp +100 -0
  50. labpulse-0.3.6/firmware/examples/pump_room/pump_room.h +80 -0
  51. labpulse-0.3.6/firmware/examples/pump_room/pump_room.ino +9 -0
  52. labpulse-0.3.6/firmware/examples/turbo_pump/turbo_pump.cpp +82 -0
  53. labpulse-0.3.6/firmware/examples/turbo_pump/turbo_pump.h +50 -0
  54. labpulse-0.3.6/firmware/examples/turbo_pump/turbo_pump.ino +9 -0
  55. labpulse-0.3.6/firmware/library.properties +10 -0
  56. labpulse-0.3.6/firmware/run_triton_publisher.example.ps1 +28 -0
  57. labpulse-0.3.6/firmware/src/Dht11Sensor.cpp +36 -0
  58. labpulse-0.3.6/firmware/src/Dht11Sensor.h +39 -0
  59. labpulse-0.3.6/firmware/src/LinearPressureSensor.cpp +44 -0
  60. labpulse-0.3.6/firmware/src/LinearPressureSensor.h +38 -0
  61. labpulse-0.3.6/firmware/src/PinMeasurement.h +17 -0
  62. labpulse-0.3.6/firmware/src/PipeSampleWriter.cpp +56 -0
  63. labpulse-0.3.6/firmware/src/PipeSampleWriter.h +31 -0
  64. labpulse-0.3.6/firmware/src/PulseFlowSensor.cpp +57 -0
  65. labpulse-0.3.6/firmware/src/PulseFlowSensor.h +43 -0
  66. labpulse-0.3.6/firmware/src/Reading.h +13 -0
  67. labpulse-0.3.6/firmware/src/Sht40Sensor.cpp +56 -0
  68. labpulse-0.3.6/firmware/src/Sht40Sensor.h +38 -0
  69. labpulse-0.3.6/firmware/src/ThermistorSensor.cpp +45 -0
  70. labpulse-0.3.6/firmware/src/ThermistorSensor.h +37 -0
  71. labpulse-0.3.6/firmware/triton_logfile_publisher_production.py +381 -0
  72. labpulse-0.3.6/firmware/triton_logfile_publisher_setup.py +208 -0
  73. labpulse-0.3.6/hardware/3d_parts/README.txt +12 -0
  74. labpulse-0.3.6/hardware/3d_parts/RPi 4 cover holes.stl +0 -0
  75. labpulse-0.3.6/hardware/3d_parts/Tall boi With hole!.stl +1 -0
  76. labpulse-0.3.6/hardware/PCB_files/Gerber_PCB_Arduino-Hat_Final_prototype.zip +0 -0
  77. labpulse-0.3.6/hardware/PCB_files/Gerber_PCB_Arduino-Hat_prototype1.zip +0 -0
  78. labpulse-0.3.6/hardware/PCB_files/Gerber_PCB_Arduino-Hat_prototype2_2025-11-14.zip +0 -0
  79. labpulse-0.3.6/hardware/PCB_files/Gerber_PCB_Arduino-Hat_prototype3.zip +0 -0
  80. labpulse-0.3.6/hardware/PCB_files/PCBv6.zip +0 -0
  81. labpulse-0.3.6/legacy/Arduino/Compressed Air sensor/Arduino instructions for CA sensor.cpp +51 -0
  82. labpulse-0.3.6/legacy/Arduino/Compressed Air sensor/Calibration code for CA sensor.cpp +25 -0
  83. labpulse-0.3.6/legacy/Arduino/Compressed Air sensor/pressurepub.py +50 -0
  84. labpulse-0.3.6/legacy/Arduino/DHT sensor code/Arduino Instructions for TH sensor.cpp +32 -0
  85. labpulse-0.3.6/legacy/Arduino/DHT sensor code/TH_sensor_code.cpp +140 -0
  86. labpulse-0.3.6/legacy/Arduino/DHT sensor code/TH_sensor_code.h +48 -0
  87. labpulse-0.3.6/legacy/Arduino/Pressure_Arduino.cpp +20 -0
  88. labpulse-0.3.6/legacy/Arduino/Pump_Room_Arduino.cpp +125 -0
  89. labpulse-0.3.6/legacy/Arduino/Water Temp sensor code/Arduino Instructions for WT sensor.cpp +51 -0
  90. labpulse-0.3.6/legacy/Arduino/Water flow meter code/Arduino Instructions.cpp +118 -0
  91. labpulse-0.3.6/legacy/Arduino/Water flow meter code/Temporary flow reader.cpp +41 -0
  92. labpulse-0.3.6/legacy/Arduino/Water flow meter code/WT_and_WF_sensor_code_for_P_sensor.cpp +53 -0
  93. labpulse-0.3.6/legacy/Arduino/Water flow meter code/flowpub.py +55 -0
  94. labpulse-0.3.6/legacy/Arduino/full_water_sensor_code.cpp +155 -0
  95. labpulse-0.3.6/legacy/Arduino/pressure_monitor/README.md +6 -0
  96. labpulse-0.3.6/legacy/Arduino/pressure_monitor/pressure_monitor.cpp +30 -0
  97. labpulse-0.3.6/legacy/Arduino/pressure_monitor/pressure_monitor.h +40 -0
  98. labpulse-0.3.6/legacy/Arduino/pressure_monitor/pressure_monitor.ino +9 -0
  99. labpulse-0.3.6/legacy/Arduino code Water Temperature Sensor calibration.py +90 -0
  100. labpulse-0.3.6/legacy/Documentation/Internship purchased items.xlsx +0 -0
  101. labpulse-0.3.6/legacy/Documentation/LabPulse cartoon-03.png +0 -0
  102. labpulse-0.3.6/legacy/Documentation/PROJECT_REVIEW.md +99 -0
  103. labpulse-0.3.6/legacy/Documentation/Setup of a lab monitor on a raspberry pi.docx +0 -0
  104. labpulse-0.3.6/legacy/Future_work/README_FW.md +40 -0
  105. labpulse-0.3.6/legacy/Future_work/drivers/serial_driver.py +72 -0
  106. labpulse-0.3.6/legacy/Future_work/generalised_architecture.md +51 -0
  107. labpulse-0.3.6/legacy/Future_work/main.py +114 -0
  108. labpulse-0.3.6/legacy/Future_work/sensor_base.py +43 -0
  109. labpulse-0.3.6/legacy/Future_work/sensor_factory.py +50 -0
  110. labpulse-0.3.6/legacy/Future_work/update_config.py +88 -0
  111. labpulse-0.3.6/legacy/Future_work/update_config.yaml +61 -0
  112. labpulse-0.3.6/legacy/Installation/COMPATIBILITY.md +15 -0
  113. labpulse-0.3.6/legacy/Installation/QUICKSTART.md +25 -0
  114. labpulse-0.3.6/legacy/Installation/bootstap_pi.sh +29 -0
  115. labpulse-0.3.6/legacy/Installation/setup.sh +113 -0
  116. labpulse-0.3.6/legacy/LEGACY README.md +60 -0
  117. labpulse-0.3.6/legacy/Set_up_flowchart.pdf +0 -0
  118. labpulse-0.3.6/legacy/archive_v1_pi_code/Config files and scripts/Discoverycleaner.py +64 -0
  119. labpulse-0.3.6/legacy/archive_v1_pi_code/Config files and scripts/modem-watchdog.sh +28 -0
  120. labpulse-0.3.6/legacy/archive_v1_pi_code/Config files and scripts/phone_number_config.json +9 -0
  121. labpulse-0.3.6/legacy/archive_v1_pi_code/Config files and scripts/phone_number_edit.py +75 -0
  122. labpulse-0.3.6/legacy/archive_v1_pi_code/Config files and scripts/threshold_config_file.json +49 -0
  123. labpulse-0.3.6/legacy/archive_v1_pi_code/General error detection code/Multiple_sensor changes.py +21 -0
  124. labpulse-0.3.6/legacy/archive_v1_pi_code/General error detection code/Single_sensor_long_term_changes.py +35 -0
  125. labpulse-0.3.6/legacy/archive_v1_pi_code/General error detection code/Upper_lower_limits.py +13 -0
  126. labpulse-0.3.6/legacy/archive_v1_pi_code/General error detection code/WT and flow sensor error detection.py +20 -0
  127. labpulse-0.3.6/legacy/archive_v1_pi_code/Python publishing scripts/DHT_publishing_code.py +100 -0
  128. labpulse-0.3.6/legacy/archive_v1_pi_code/Python publishing scripts/UPS_Monitoring_code.py +360 -0
  129. labpulse-0.3.6/legacy/archive_v1_pi_code/Python publishing scripts/pressure_pub.py +266 -0
  130. labpulse-0.3.6/legacy/archive_v1_pi_code/Python publishing scripts/water_sensor.py +302 -0
  131. labpulse-0.3.6/legacy/archive_v1_pi_code/Service Scripts/dhtpub.service +15 -0
  132. labpulse-0.3.6/legacy/archive_v1_pi_code/Service Scripts/power_monitor.service +14 -0
  133. labpulse-0.3.6/legacy/archive_v1_pi_code/Service Scripts/pressure_monitor.service +14 -0
  134. labpulse-0.3.6/legacy/archive_v1_pi_code/Service Scripts/pump_room_monitor.service +14 -0
  135. labpulse-0.3.6/legacy/archive_v1_pi_code/Service Scripts/turbo_pump_monitor.service +14 -0
  136. labpulse-0.3.6/legacy/archive_v1_pi_code/setup_homeassistant_313.sh +65 -0
  137. labpulse-0.3.6/legacy/pi_scripts/config.yaml +49 -0
  138. labpulse-0.3.6/legacy/pi_scripts/dhtpub.py +104 -0
  139. labpulse-0.3.6/legacy/pi_scripts/labpulse_common/__init__.py +0 -0
  140. labpulse-0.3.6/legacy/pi_scripts/labpulse_common/config.py +101 -0
  141. labpulse-0.3.6/legacy/pi_scripts/labpulse_common/mqtt_health.py +39 -0
  142. labpulse-0.3.6/legacy/pi_scripts/labpulse_common/sms.py +96 -0
  143. labpulse-0.3.6/legacy/pi_scripts/labpulse_common/utils.py +6 -0
  144. labpulse-0.3.6/legacy/pi_scripts/powerpub.py +173 -0
  145. labpulse-0.3.6/legacy/pi_scripts/pressurepub.py +182 -0
  146. labpulse-0.3.6/legacy/pi_scripts/pumproompub.py +192 -0
  147. labpulse-0.3.6/legacy/pi_scripts/pyproject.toml +57 -0
  148. labpulse-0.3.6/legacy/pi_scripts/requirements.txt +22 -0
  149. labpulse-0.3.6/legacy/pi_scripts/setup.sh +137 -0
  150. labpulse-0.3.6/legacy/pi_scripts/smstest.py +76 -0
  151. labpulse-0.3.6/legacy/pi_scripts/thresholds.json +52 -0
  152. labpulse-0.3.6/legacy/pi_scripts/turbo_pump_monitor.py +188 -0
  153. labpulse-0.3.6/pyproject.toml +109 -0
  154. labpulse-0.3.6/requirements-host.txt +6 -0
  155. labpulse-0.3.6/setup.cfg +4 -0
  156. labpulse-0.3.6/setup_usb_devices.py +315 -0
  157. labpulse-0.3.6/simulate_serial.py +744 -0
  158. labpulse-0.3.6/src/labpulse/README.md +35 -0
  159. labpulse-0.3.6/src/labpulse/__init__.py +9 -0
  160. labpulse-0.3.6/src/labpulse/backup.py +524 -0
  161. labpulse-0.3.6/src/labpulse/common/README.md +32 -0
  162. labpulse-0.3.6/src/labpulse/common/__init__.py +1 -0
  163. labpulse-0.3.6/src/labpulse/common/config.py +620 -0
  164. labpulse-0.3.6/src/labpulse/common/fake_config.py +11 -0
  165. labpulse-0.3.6/src/labpulse/common/generated_files.py +27 -0
  166. labpulse-0.3.6/src/labpulse/common/identity.py +32 -0
  167. labpulse-0.3.6/src/labpulse/common/logging_config.py +58 -0
  168. labpulse-0.3.6/src/labpulse/common/measurement_config.py +330 -0
  169. labpulse-0.3.6/src/labpulse/common/mqtt_contracts.py +89 -0
  170. labpulse-0.3.6/src/labpulse/common/output_config.py +52 -0
  171. labpulse-0.3.6/src/labpulse/common/service_config.py +199 -0
  172. labpulse-0.3.6/src/labpulse/common/sms_templates.py +76 -0
  173. labpulse-0.3.6/src/labpulse/common/sms_templates.yaml +73 -0
  174. labpulse-0.3.6/src/labpulse/control.py +1007 -0
  175. labpulse-0.3.6/src/labpulse/deployment/README.md +24 -0
  176. labpulse-0.3.6/src/labpulse/deployment/__init__.py +1 -0
  177. labpulse-0.3.6/src/labpulse/deployment/__main__.py +7 -0
  178. labpulse-0.3.6/src/labpulse/deployment/compose.py +197 -0
  179. labpulse-0.3.6/src/labpulse/deployment/generate.py +225 -0
  180. labpulse-0.3.6/src/labpulse/deployment/mosquitto.py +60 -0
  181. labpulse-0.3.6/src/labpulse/doctor.py +635 -0
  182. labpulse-0.3.6/src/labpulse/hardware/README.md +31 -0
  183. labpulse-0.3.6/src/labpulse/hardware/__init__.py +1 -0
  184. labpulse-0.3.6/src/labpulse/hardware/__main__.py +93 -0
  185. labpulse-0.3.6/src/labpulse/hardware/_simulation.py +140 -0
  186. labpulse-0.3.6/src/labpulse/hardware/driver.py +166 -0
  187. labpulse-0.3.6/src/labpulse/hardware/drivers/README.md +38 -0
  188. labpulse-0.3.6/src/labpulse/hardware/drivers/__init__.py +1 -0
  189. labpulse-0.3.6/src/labpulse/hardware/drivers/_gpio.py +44 -0
  190. labpulse-0.3.6/src/labpulse/hardware/drivers/dht11.py +118 -0
  191. labpulse-0.3.6/src/labpulse/hardware/drivers/gpio_input.py +118 -0
  192. labpulse-0.3.6/src/labpulse/hardware/drivers/gpio_output.py +163 -0
  193. labpulse-0.3.6/src/labpulse/hardware/drivers/mqtt_json.py +404 -0
  194. labpulse-0.3.6/src/labpulse/hardware/drivers/serial_pipe.py +145 -0
  195. labpulse-0.3.6/src/labpulse/hardware/drivers/sht40.py +170 -0
  196. labpulse-0.3.6/src/labpulse/hardware/drivers/x1200.py +180 -0
  197. labpulse-0.3.6/src/labpulse/hardware/homeassistant_publisher.py +224 -0
  198. labpulse-0.3.6/src/labpulse/hardware/registry.py +40 -0
  199. labpulse-0.3.6/src/labpulse/hardware/runner.py +338 -0
  200. labpulse-0.3.6/src/labpulse/homeassistant/README.md +30 -0
  201. labpulse-0.3.6/src/labpulse/homeassistant/__init__.py +1 -0
  202. labpulse-0.3.6/src/labpulse/homeassistant/__main__.py +7 -0
  203. labpulse-0.3.6/src/labpulse/homeassistant/alarm.py +653 -0
  204. labpulse-0.3.6/src/labpulse/homeassistant/generator.py +143 -0
  205. labpulse-0.3.6/src/labpulse/homeassistant/templates/README.md +32 -0
  206. labpulse-0.3.6/src/labpulse/homeassistant/templates/alarm/alarm_package.yaml.j2 +15 -0
  207. labpulse-0.3.6/src/labpulse/homeassistant/templates/alarm/automations/installation.yaml.j2 +31 -0
  208. labpulse-0.3.6/src/labpulse/homeassistant/templates/alarm/automations/measurement.yaml.j2 +4 -0
  209. labpulse-0.3.6/src/labpulse/homeassistant/templates/alarm/automations/measurement_missing_reading.yaml.j2 +148 -0
  210. labpulse-0.3.6/src/labpulse/homeassistant/templates/alarm/automations/measurement_state.yaml.j2 +167 -0
  211. labpulse-0.3.6/src/labpulse/homeassistant/templates/alarm/automations/power.yaml.j2 +6 -0
  212. labpulse-0.3.6/src/labpulse/homeassistant/templates/alarm/automations/power_state.yaml.j2 +142 -0
  213. labpulse-0.3.6/src/labpulse/homeassistant/templates/alarm/automations/service_health.yaml.j2 +134 -0
  214. labpulse-0.3.6/src/labpulse/homeassistant/templates/alarm/derived_entities.yaml.j2 +191 -0
  215. labpulse-0.3.6/src/labpulse/homeassistant/templates/alarm/helpers.yaml.j2 +236 -0
  216. labpulse-0.3.6/src/labpulse/homeassistant/templates/alarm/scripts.yaml.j2 +263 -0
  217. labpulse-0.3.6/src/labpulse/homeassistant/templates/configuration.yaml.j2 +54 -0
  218. labpulse-0.3.6/src/labpulse/homeassistant/templates/dashboard/alarm_setup/bulk_editor.yaml.j2 +204 -0
  219. labpulse-0.3.6/src/labpulse/homeassistant/templates/dashboard/alarm_setup/notification_controls.yaml.j2 +30 -0
  220. labpulse-0.3.6/src/labpulse/homeassistant/templates/dashboard/alarm_setup/targets.yaml.j2 +102 -0
  221. labpulse-0.3.6/src/labpulse/homeassistant/templates/dashboard/alarm_setup.yaml.j2 +11 -0
  222. labpulse-0.3.6/src/labpulse/homeassistant/templates/dashboard/custom_dashboards.yaml.j2 +18 -0
  223. labpulse-0.3.6/src/labpulse/homeassistant/templates/dashboard/monitor.yaml.j2 +83 -0
  224. labpulse-0.3.6/src/labpulse/homeassistant/templates/dashboard/monitor_status.yaml.j2 +135 -0
  225. labpulse-0.3.6/src/labpulse/homeassistant/templates/dashboard/power_subviews.yaml.j2 +40 -0
  226. labpulse-0.3.6/src/labpulse/homeassistant/templates/dashboard/setup_measurements.yaml.j2 +38 -0
  227. labpulse-0.3.6/src/labpulse/homeassistant/templates/dashboard/setup_subviews/measurement_cards.yaml.j2 +329 -0
  228. labpulse-0.3.6/src/labpulse/homeassistant/templates/dashboard/setup_subviews/setup_header.yaml.j2 +73 -0
  229. labpulse-0.3.6/src/labpulse/homeassistant/templates/dashboard/setup_subviews.yaml.j2 +14 -0
  230. labpulse-0.3.6/src/labpulse/homeassistant/templates/dashboard/system_status.yaml.j2 +151 -0
  231. labpulse-0.3.6/src/labpulse/homeassistant/templates/dashboard.yaml.j2 +12 -0
  232. labpulse-0.3.6/src/labpulse/installer.py +71 -0
  233. labpulse-0.3.6/src/labpulse/output/README.md +24 -0
  234. labpulse-0.3.6/src/labpulse/output/__init__.py +1 -0
  235. labpulse-0.3.6/src/labpulse/output/__main__.py +80 -0
  236. labpulse-0.3.6/src/labpulse/output/service.py +323 -0
  237. labpulse-0.3.6/src/labpulse/sms/README.md +28 -0
  238. labpulse-0.3.6/src/labpulse/sms/__init__.py +1 -0
  239. labpulse-0.3.6/src/labpulse/sms/__main__.py +76 -0
  240. labpulse-0.3.6/src/labpulse/sms/sender.py +545 -0
  241. labpulse-0.3.6/src/labpulse/sms/subscriber.py +295 -0
  242. labpulse-0.3.6/src/labpulse.egg-info/PKG-INFO +228 -0
  243. labpulse-0.3.6/src/labpulse.egg-info/SOURCES.txt +292 -0
  244. labpulse-0.3.6/src/labpulse.egg-info/dependency_links.txt +1 -0
  245. labpulse-0.3.6/src/labpulse.egg-info/entry_points.txt +10 -0
  246. labpulse-0.3.6/src/labpulse.egg-info/requires.txt +22 -0
  247. labpulse-0.3.6/src/labpulse.egg-info/scm_file_list.json +288 -0
  248. labpulse-0.3.6/src/labpulse.egg-info/scm_version.json +8 -0
  249. labpulse-0.3.6/src/labpulse.egg-info/top_level.txt +1 -0
  250. labpulse-0.3.6/testing/README.md +33 -0
  251. labpulse-0.3.6/testing/conftest.py +29 -0
  252. labpulse-0.3.6/testing/real_hardware/README.md +17 -0
  253. labpulse-0.3.6/testing/real_hardware/hardware_fault_common.sh +121 -0
  254. labpulse-0.3.6/testing/real_hardware/test_dht11_fault.sh +143 -0
  255. labpulse-0.3.6/testing/real_hardware/test_x1200_faults.sh +161 -0
  256. labpulse-0.3.6/testing/test_backup_restore.py +377 -0
  257. labpulse-0.3.6/testing/test_common_contracts.py +280 -0
  258. labpulse-0.3.6/testing/test_config_editor_bundle.py +250 -0
  259. labpulse-0.3.6/testing/test_config_pipeline.py +216 -0
  260. labpulse-0.3.6/testing/test_container_release.py +64 -0
  261. labpulse-0.3.6/testing/test_control_cli.py +857 -0
  262. labpulse-0.3.6/testing/test_custom_measurements.py +216 -0
  263. labpulse-0.3.6/testing/test_deployment_generation.py +602 -0
  264. labpulse-0.3.6/testing/test_dht11_driver.py +192 -0
  265. labpulse-0.3.6/testing/test_doctor.py +309 -0
  266. labpulse-0.3.6/testing/test_documentation.py +140 -0
  267. labpulse-0.3.6/testing/test_fake_hardware.py +69 -0
  268. labpulse-0.3.6/testing/test_firmware_layout.py +139 -0
  269. labpulse-0.3.6/testing/test_gpio_input_driver.py +131 -0
  270. labpulse-0.3.6/testing/test_gpio_output_driver.py +200 -0
  271. labpulse-0.3.6/testing/test_hardware_factory.py +274 -0
  272. labpulse-0.3.6/testing/test_hardware_runner.py +419 -0
  273. labpulse-0.3.6/testing/test_homeassistant_entities.py +83 -0
  274. labpulse-0.3.6/testing/test_homeassistant_generator.py +521 -0
  275. labpulse-0.3.6/testing/test_homeassistant_publisher.py +449 -0
  276. labpulse-0.3.6/testing/test_logging_config.py +61 -0
  277. labpulse-0.3.6/testing/test_measurement_files.py +320 -0
  278. labpulse-0.3.6/testing/test_mqtt_json_driver.py +546 -0
  279. labpulse-0.3.6/testing/test_notification_context.py +266 -0
  280. labpulse-0.3.6/testing/test_output_mqtt_service.py +509 -0
  281. labpulse-0.3.6/testing/test_packaging.py +108 -0
  282. labpulse-0.3.6/testing/test_power_monitor.py +300 -0
  283. labpulse-0.3.6/testing/test_serial_driver.py +161 -0
  284. labpulse-0.3.6/testing/test_serial_parser.py +68 -0
  285. labpulse-0.3.6/testing/test_setup_grouping.py +285 -0
  286. labpulse-0.3.6/testing/test_sht40_driver.py +253 -0
  287. labpulse-0.3.6/testing/test_simulate_serial.py +227 -0
  288. labpulse-0.3.6/testing/test_sms_container.py +776 -0
  289. labpulse-0.3.6/testing/test_triton_logfile_decoder.py +330 -0
  290. labpulse-0.3.6/testing/test_unified_generation.py +125 -0
  291. labpulse-0.3.6/testing/test_usb_setup.py +236 -0
  292. labpulse-0.3.6/testing/test_x1200_ups_driver.py +199 -0
  293. labpulse-0.3.6/testing/test_yaml_dashboard.py +639 -0
  294. labpulse-0.3.6/testing/ups_test_pi_config.yaml +43 -0
@@ -0,0 +1,4 @@
1
+ *
2
+ !Dockerfile
3
+ !dist/
4
+ !dist/labpulse-*.whl
@@ -0,0 +1,3 @@
1
+ # Keep Raspberry Pi shell scripts executable by /usr/bin/env.
2
+ *.sh text eol=lf
3
+ *.py text eol=lf
@@ -0,0 +1,170 @@
1
+ name: Release LabPulse
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ validate:
9
+ name: Validate release artifacts
10
+ runs-on: ubuntu-latest
11
+ outputs:
12
+ version: ${{ steps.version.outputs.version }}
13
+ steps:
14
+ - name: Check out source
15
+ uses: actions/checkout@v6
16
+ with:
17
+ fetch-depth: 0
18
+ ref: ${{ github.event.release.tag_name }}
19
+
20
+ - name: Set up Python
21
+ uses: actions/setup-python@v6
22
+ with:
23
+ python-version: "3.12"
24
+ cache: pip
25
+
26
+ - name: Install build tools
27
+ run: python -m pip install --upgrade pip build twine setuptools-scm
28
+
29
+ - name: Resolve release version from tag
30
+ id: version
31
+ env:
32
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
33
+ run: |
34
+ version="${RELEASE_TAG#v}"
35
+ scm_version="$(python -m setuptools_scm)"
36
+ if [ "$scm_version" != "$version" ]; then
37
+ echo "Release tag $RELEASE_TAG produced package version $scm_version, expected $version" >&2
38
+ exit 1
39
+ fi
40
+ echo "Release tag determines package version $scm_version"
41
+ echo "version=$version" >> "$GITHUB_OUTPUT"
42
+
43
+ - name: Install LabPulse
44
+ run: python -m pip install --editable ".[dev]"
45
+
46
+ - name: Run hardware-free tests
47
+ run: python -m pytest
48
+
49
+ - name: Build and check distributions
50
+ run: |
51
+ python -m build
52
+ python -m twine check dist/*
53
+
54
+ - name: Smoke-test installed wheel and source distribution
55
+ run: |
56
+ python -m venv "$RUNNER_TEMP/wheel-smoke"
57
+ "$RUNNER_TEMP/wheel-smoke/bin/python" -m pip install dist/*.whl
58
+ "$RUNNER_TEMP/wheel-smoke/bin/labpulse" help
59
+ "$RUNNER_TEMP/wheel-smoke/bin/python" -c "from labpulse.installer import find_install_assets; print(find_install_assets())"
60
+ "$RUNNER_TEMP/wheel-smoke/bin/labpulse" \
61
+ --live-dir "$RUNNER_TEMP/labpulse-live" setup --fake-hardware
62
+ "$RUNNER_TEMP/wheel-smoke/bin/python" -c "import sys, yaml; data = yaml.safe_load(open(sys.argv[1])); images = {service.get('image') for name, service in data['services'].items() if name.startswith('labpulse-')}; expected = {'ghcr.io/lairdgrouplancaster/labpulse:${{ steps.version.outputs.version }}'}; assert images == expected, (images, expected)" "$RUNNER_TEMP/labpulse-live/compose.yaml"
63
+ test ! -d "$RUNNER_TEMP/labpulse-live/labpulse-python"
64
+ python -m venv "$RUNNER_TEMP/sdist-smoke"
65
+ "$RUNNER_TEMP/sdist-smoke/bin/python" -m pip install dist/*.tar.gz
66
+ "$RUNNER_TEMP/sdist-smoke/bin/labpulse" help
67
+
68
+ - name: Smoke-test container
69
+ run: |
70
+ docker build \
71
+ --build-arg "LABPULSE_VERSION=${{ steps.version.outputs.version }}" \
72
+ --tag labpulse-release-smoke \
73
+ .
74
+ docker run --rm labpulse-release-smoke \
75
+ python -c "from importlib.metadata import version; assert version('labpulse') == '${{ steps.version.outputs.version }}'"
76
+ docker run --rm labpulse-release-smoke python -m labpulse.hardware --help
77
+ docker run --rm labpulse-release-smoke python -m labpulse.sms --help
78
+
79
+ - name: Upload distributions
80
+ uses: actions/upload-artifact@v7
81
+ with:
82
+ name: python-distributions
83
+ path: dist/
84
+ if-no-files-found: error
85
+ retention-days: 7
86
+
87
+ publish-python:
88
+ name: Publish Python distributions to PyPI
89
+ needs: validate
90
+ runs-on: ubuntu-latest
91
+ environment:
92
+ name: pypi
93
+ url: https://pypi.org/project/labpulse/${{ needs.validate.outputs.version }}/
94
+ permissions:
95
+ id-token: write
96
+ steps:
97
+ - name: Download distributions
98
+ uses: actions/download-artifact@v8
99
+ with:
100
+ name: python-distributions
101
+ path: dist/
102
+
103
+ - name: Publish to PyPI
104
+ uses: pypa/gh-action-pypi-publish@release/v1
105
+
106
+ publish-container:
107
+ name: Publish multi-platform container
108
+ needs: validate
109
+ runs-on: ubuntu-latest
110
+ permissions:
111
+ contents: read
112
+ packages: write
113
+ attestations: write
114
+ id-token: write
115
+ steps:
116
+ - name: Check out source
117
+ uses: actions/checkout@v6
118
+
119
+ - name: Download distributions
120
+ uses: actions/download-artifact@v8
121
+ with:
122
+ name: python-distributions
123
+ path: dist/
124
+
125
+ - name: Set up QEMU
126
+ uses: docker/setup-qemu-action@v3
127
+
128
+ - name: Set up Docker Buildx
129
+ uses: docker/setup-buildx-action@v3
130
+
131
+ - name: Log in to GHCR
132
+ uses: docker/login-action@v3
133
+ with:
134
+ registry: ghcr.io
135
+ username: ${{ github.actor }}
136
+ password: ${{ secrets.GITHUB_TOKEN }}
137
+
138
+ - name: Generate image metadata
139
+ id: metadata
140
+ uses: docker/metadata-action@v5
141
+ with:
142
+ images: ghcr.io/lairdgrouplancaster/labpulse
143
+ tags: |
144
+ type=semver,pattern={{version}},value=${{ github.event.release.tag_name }}
145
+ type=semver,pattern={{major}}.{{minor}},value=${{ github.event.release.tag_name }}
146
+ labels: |
147
+ org.opencontainers.image.title=LabPulse
148
+ org.opencontainers.image.description=Raspberry Pi laboratory infrastructure monitoring
149
+
150
+ - name: Build and push image
151
+ id: image
152
+ uses: docker/build-push-action@v6
153
+ with:
154
+ context: .
155
+ file: ./Dockerfile
156
+ platforms: linux/amd64,linux/arm64
157
+ push: true
158
+ build-args: |
159
+ LABPULSE_VERSION=${{ needs.validate.outputs.version }}
160
+ tags: ${{ steps.metadata.outputs.tags }}
161
+ labels: ${{ steps.metadata.outputs.labels }}
162
+ provenance: mode=max
163
+ sbom: true
164
+
165
+ - name: Attest image provenance
166
+ uses: actions/attest@v4
167
+ with:
168
+ subject-name: ghcr.io/lairdgrouplancaster/labpulse
169
+ subject-digest: ${{ steps.image.outputs.digest }}
170
+ push-to-registry: true
@@ -0,0 +1,32 @@
1
+ name: Test LabPulse
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ pytest:
9
+ name: Python ${{ matrix.python-version }}
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ python-version: ["3.11", "3.12"]
15
+
16
+ steps:
17
+ - name: Check out source
18
+ uses: actions/checkout@v6
19
+ with:
20
+ fetch-depth: 0
21
+
22
+ - name: Set up Python
23
+ uses: actions/setup-python@v6
24
+ with:
25
+ python-version: ${{ matrix.python-version }}
26
+ cache: pip
27
+
28
+ - name: Install LabPulse and test dependencies
29
+ run: python -m pip install --editable ".[dev]"
30
+
31
+ - name: Run hardware-free tests
32
+ run: python -m pytest
@@ -0,0 +1,18 @@
1
+ waterenv/
2
+ .venv/
3
+ build/
4
+ dist/
5
+ *.egg-info/
6
+ __pycache__/
7
+ .pytest_cache/
8
+ /logs/
9
+ **/__pycache__/
10
+
11
+ # Generated Home Assistant smoke-test outputs
12
+ tmp_ha_*/
13
+ tmp_ha_*-check.py
14
+ /testing/tmp/
15
+
16
+ # Codex local workspace/artifact files
17
+ .codex/
18
+ .agents/
@@ -0,0 +1,7 @@
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": []
7
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "python-envs.defaultEnvManager": "ms-python.python:system",
3
+ "python-envs.defaultPackageManager": "ms-python.python:pip"
4
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "tasks": [
3
+ {
4
+ "type": "cppbuild",
5
+ "label": "C/C++: clang build active file",
6
+ "command": "/usr/bin/clang",
7
+ "args": [
8
+ "-fcolor-diagnostics",
9
+ "-fansi-escape-codes",
10
+ "-g",
11
+ "${file}",
12
+ "-o",
13
+ "${fileDirname}/${fileBasenameNoExtension}"
14
+ ],
15
+ "options": {
16
+ "cwd": "${fileDirname}"
17
+ },
18
+ "problemMatcher": [
19
+ "$gcc"
20
+ ],
21
+ "group": {
22
+ "kind": "build",
23
+ "isDefault": true
24
+ },
25
+ "detail": "Task generated by Debugger."
26
+ }
27
+ ],
28
+ "version": "2.0.0"
29
+ }
@@ -0,0 +1,100 @@
1
+ # Changelog
2
+
3
+ All notable user-visible changes will be recorded here. The earlier prototype
4
+ history was not maintained as formal releases.
5
+
6
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
7
+ Versioning follows [Semantic Versioning](https://semver.org/).
8
+
9
+ ## Unreleased
10
+
11
+ ### Added
12
+
13
+ - Independent Triton control-PC publisher heartbeats and availability, with
14
+ fridge service alerts driven by script health instead of logfile activity.
15
+ - A per-service `notify_on_service_failure` setting, enabled by default, to
16
+ silence known unreliable or intentionally disconnected hubs without hiding
17
+ their status.
18
+
19
+ - Repository-wide MIT licensing for software, firmware, documentation, and
20
+ hardware design files.
21
+ - A reference Raspberry Pi deployment matrix and explicit pre-1.0 support,
22
+ compatibility, safety, and experimental-feature boundaries.
23
+ - An explicit product boundary defining LabPulse as monitoring and best-effort
24
+ alerting rather than safety-critical equipment control.
25
+ - A pipx-installable `labpulse` package and unified operator command.
26
+ - Setup, lifecycle, logs, configuration, browser, firmware-help, and diagnostic
27
+ commands.
28
+ - Version reporting through `labpulse version` and runtime-image matching in
29
+ `labpulse doctor`.
30
+ - Tag-derived package, runtime, and container versions through `setuptools-scm`.
31
+ - One-container-per-service hardware execution with a central lifecycle runner.
32
+ - Self-contained serial, DHT11, and X1200 drivers with declarative resources.
33
+ - A self-contained Sensirion SHT40 I2C temperature/humidity driver with
34
+ CRC-validated measurements and least-privilege device access.
35
+ - Compressed-air Arduino firmware that publishes pressure plus SHT40
36
+ temperature/humidity through the standard serial pipe, with the superseded
37
+ pressure-only sketch retained under `legacy/Arduino/pressure_monitor/`.
38
+ - Complete fake-hardware deployments which preserve the configured dashboard
39
+ and container layout while simulating every sensor and output in memory.
40
+ - Generated Home Assistant MQTT entities, alarm package, and native YAML
41
+ dashboard.
42
+ - Dry-run, test-mode, and modem-backed SMS delivery with subscription controls.
43
+ - Checksummed, consistent state archives and guarded blank-host reconstruction
44
+ through `labpulse backup` and `labpulse restore`.
45
+ - A release workflow that validates wheel, source distribution, and container
46
+ artifacts, publishes through PyPI Trusted Publishing, and publishes
47
+ attested AMD64/ARM64 images to GHCR.
48
+
49
+ ### Changed
50
+
51
+ - Home Assistant now receives the validated IANA timezone selected in
52
+ `config.yaml` instead of a hard-coded `Europe/London` timezone.
53
+ - Service measurement configuration now supports typed shared defaults,
54
+ infers labels from stable IDs when omitted, and keeps MQTT JSON source names
55
+ beside their measurements instead of duplicating IDs under driver options.
56
+ - Optional hardware dependencies are grouped by the `serial`, `i2c`, and
57
+ `gpio` connection types instead of individual driver names.
58
+ - The installed deployment directory is `~/labpulse-live`.
59
+ - The guarded configuration command is `labpulse config`.
60
+ - Deployment shell scripts are maintained under `deployment/`.
61
+ - Measurement units are published exactly as configured while icons are
62
+ derived independently.
63
+ - Real-Pi reliability acceptance now records two weeks of continuous operation,
64
+ real and injected hardware faults, UPS and abrupt-power recovery, restart
65
+ alarm reconciliation, SMS delivery, and the built-in watchdog decision.
66
+ - `labpulse config` now preserves an active fake-hardware deployment and validates
67
+ and regenerates its derived runtime configuration transactionally.
68
+ - Hardware lifecycle logs now include stable service/driver/target context,
69
+ status transitions, and the age of the last valid reading.
70
+ - `labpulse doctor` now reports the active runtime mode and gives corrective
71
+ commands or checks for common deployment, container, hardware, MQTT, and
72
+ Home Assistant failures.
73
+ - `labpulse down` and `labpulse restart` accept individual Compose service
74
+ names.
75
+ - Generated deployments use the GHCR image matching the installed package
76
+ version instead of copying source and rebuilding containers on each Pi.
77
+ - Guarded configuration now uses the same configurable Docker command as every
78
+ other lifecycle operation.
79
+ - Doctor now checks Docker daemon access and versions, host timezone/NTP state,
80
+ and systemd hardware-watchdog activation.
81
+ - Installation now includes ordered Home Assistant/MQTT onboarding, a
82
+ first-install acceptance checklist, host-time validation, and a non-editable
83
+ production update command.
84
+ - Power-loss and restoration notifications are explicitly separate: loss is
85
+ reported promptly, while recovery closes the lifecycle with outage duration.
86
+ - Persistent Python worker logs now rotate daily and retain seven previous
87
+ daily files instead of growing without a bound.
88
+ - The deployed USB assignment helper now reliably switches from the system
89
+ Python to LabPulse's managed environment before importing the package.
90
+ - Measurement configuration now uses the optional strict boolean `required`
91
+ field, defaulting to `true`, with plainly named missing/recovery timers.
92
+ - The generated Diagnostics view is now a human-readable System Status view
93
+ with Working, Needs attention, and Offline service states.
94
+
95
+ ### Removed
96
+
97
+ - Prototype package layouts and earlier Pi implementations from the active
98
+ runtime. They remain under `legacy/` for reference only.
99
+ - The redundant per-reading availability sensor and the old
100
+ `availability: required|optional` measurement configuration.
@@ -0,0 +1,11 @@
1
+ cff-version: 1.2.0
2
+ message: >-
3
+ If you use LabPulse in published research, please cite the software and
4
+ record the exact release and local configuration used.
5
+ title: LabPulse
6
+ type: software
7
+ authors:
8
+ - name: LabPulse contributors
9
+ repository-code: https://github.com/lairdgrouplancaster/LabPulse
10
+ url: https://github.com/lairdgrouplancaster/LabPulse
11
+ license: MIT
@@ -0,0 +1,108 @@
1
+ # Contributing to LabPulse
2
+
3
+ Thank you for helping improve LabPulse. Changes to public commands,
4
+ configuration or extension interfaces need migration notes and normal semantic
5
+ versioning so existing installations are not surprised.
6
+
7
+ ## Before starting
8
+
9
+ For a small correction, open a focused pull request. For a new feature,
10
+ configuration change, public interface, or hardware driver, open an issue first
11
+ so the intended behavior and test boundary can be agreed.
12
+
13
+ Read:
14
+
15
+ 1. [User guide and safety boundary](docs/USER_GUIDE.md)
16
+ 2. [Architecture](docs/ARCHITECTURE.md)
17
+ 3. [Development](docs/DEVELOPMENT.md)
18
+ 4. [Hardware driver package guide](src/labpulse/hardware/drivers/README.md)
19
+ when adding direct hardware support
20
+ 5. [Firmware guide](firmware/README.md) when changing Arduino firmware or
21
+ serial output
22
+
23
+ ## Development principles
24
+
25
+ - Preserve `~/labpulse-live/config.yaml` as the installed source of truth.
26
+ - Keep sensor acquisition in Python and alarm decisions in Home Assistant.
27
+ - Keep equipment control and safety functions outside the measurement driver
28
+ contract; discuss any actuation proposal before implementation.
29
+ - Prefer the standard serial protocol when firmware can normalize a device.
30
+ - Keep optional hardware libraries lazy so unrelated drivers and host-side
31
+ generation do not require them.
32
+ - Make important behavior testable without Raspberry Pi hardware.
33
+ - Add compatibility or migration logic only for a concrete published-release
34
+ requirement.
35
+ - Do not commit phone numbers, credentials, Home Assistant state, logs, or
36
+ locally generated deployment files.
37
+
38
+ ## Making a change
39
+
40
+ 1. Create a branch from the current main branch.
41
+ 2. Install the project in editable mode as described in
42
+ [Development](docs/DEVELOPMENT.md).
43
+ 3. Make the smallest coherent change.
44
+ 4. Add or update automated tests.
45
+ 5. Update the authoritative documentation for changed behavior.
46
+ 6. Run the complete hardware-free suite with `python -m pytest`.
47
+ 7. Describe any real-Pi checks that are still required.
48
+
49
+ By submitting a contribution, you agree that it may be distributed under the
50
+ [MIT License](LICENSE) used by this project.
51
+
52
+ Do not hand-edit generated `compose.yaml`,
53
+ `homeassistant/config/packages/labpulse_generated.yaml`, or
54
+ `homeassistant/config/labpulse-dashboard.yaml` as source changes. Update their
55
+ generators, models, templates, or source configuration.
56
+
57
+ ## Pull requests
58
+
59
+ A pull request should explain:
60
+
61
+ - the problem and intended behavior;
62
+ - the components changed;
63
+ - automated tests run;
64
+ - real hardware tested, if any;
65
+ - configuration or generated-output changes;
66
+ - documentation updated;
67
+ - remaining risks or follow-up work.
68
+
69
+ Keep unrelated formatting and refactors out of functional changes. Preserve
70
+ user changes already present in the branch.
71
+
72
+ ## Hardware contributions
73
+
74
+ First decide whether the device can emit the unit-free pipe-delimited serial
75
+ protocol. If it can, add firmware, configuration, simulator coverage, and
76
+ documentation without creating a Python driver.
77
+
78
+ A direct-hardware driver must include:
79
+
80
+ - a stable driver ID and strict options model;
81
+ - `connect`, `read`, and idempotent `close` behavior;
82
+ - normalized numeric readings and classified failures;
83
+ - declarative container resources;
84
+ - lazy optional dependency imports;
85
+ - hardware-free tests for configuration, reading, failure, and cleanup;
86
+ - fake or injectable hardware where practical;
87
+ - example configuration and documentation;
88
+ - a recorded real-device smoke test before release.
89
+
90
+ See the [hardware driver package guide](src/labpulse/hardware/drivers/README.md).
91
+
92
+ ## Documentation style
93
+
94
+ Write current facts rather than implementation history. Put operator tasks in
95
+ operator guides, cross-component contracts in architecture references, and
96
+ code-local details in docstrings. Avoid creating one-off implementation-plan
97
+ documents for completed features.
98
+
99
+ Use relative links inside the repository. Examples must distinguish the
100
+ repository starter `config.yaml` from the installed
101
+ `~/labpulse-live/config.yaml`.
102
+
103
+ ## Participation
104
+
105
+ Be respectful, constructive, and professional when opening issues, reviewing
106
+ changes, or discussing the project. Do not publish credentials, phone numbers,
107
+ private network details, or other sensitive information in issues or pull
108
+ requests.
@@ -0,0 +1,23 @@
1
+ FROM python:3.12-slim
2
+
3
+ ARG LABPULSE_VERSION
4
+
5
+ LABEL org.opencontainers.image.source="https://github.com/lairdgrouplancaster/LabPulse"
6
+ LABEL org.opencontainers.image.licenses="MIT"
7
+ LABEL org.opencontainers.image.version="${LABPULSE_VERSION}"
8
+
9
+ WORKDIR /app
10
+
11
+ RUN apt-get update \
12
+ && apt-get install -y --no-install-recommends \
13
+ gpiod \
14
+ modemmanager \
15
+ && rm -rf /var/lib/apt/lists/*
16
+
17
+ COPY dist/labpulse-${LABPULSE_VERSION}-py3-none-any.whl /tmp/
18
+
19
+ RUN python -m pip install --no-cache-dir \
20
+ "labpulse[serial,i2c,gpio] @ file:///tmp/labpulse-${LABPULSE_VERSION}-py3-none-any.whl" \
21
+ && rm "/tmp/labpulse-${LABPULSE_VERSION}-py3-none-any.whl"
22
+
23
+ CMD ["python", "-m", "labpulse.hardware", "--help"]
labpulse-0.3.6/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LabPulse contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.