dsf-python 3.5.0.1rc2__tar.gz → 3.5.1rc1__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 (192) hide show
  1. {dsf-python-3.5.0.1rc2/src/dsf_python.egg-info → dsf_python-3.5.1rc1}/PKG-INFO +1 -1
  2. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/setup.py +1 -1
  3. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/code_interception.py +2 -2
  4. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/code_parameter.py +0 -1
  5. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/generic.py +2 -2
  6. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/connections/base_connection.py +5 -10
  7. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/connections/exceptions.py +0 -7
  8. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/connections/init_messages/client_init_messages.py +6 -1
  9. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/connections/intercept_connection.py +12 -2
  10. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/boards/accelerometer.py +13 -0
  11. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/boards/boards.py +33 -19
  12. dsf_python-3.5.1rc1/src/dsf/object_model/boards/inductive_sensor.py +9 -0
  13. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/directories/directories.py +7 -7
  14. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/fans/fan_thermostatic_control.py +5 -5
  15. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/fans/fans.py +12 -1
  16. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/heat/heat.py +4 -4
  17. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/heat/heater.py +2 -2
  18. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/heat/heater_model.py +1 -3
  19. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/heat/heater_model_pid.py +2 -2
  20. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/heat/heater_monitor.py +4 -5
  21. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/inputs/input_channel.py +13 -17
  22. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/job/build.py +4 -4
  23. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/job/build_object.py +10 -10
  24. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/job/gcode_fileinfo.py +16 -17
  25. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/job/job.py +20 -16
  26. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/job/layer.py +3 -3
  27. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/job/thumbnail_info.py +5 -6
  28. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/job/times_left.py +7 -7
  29. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/limits/limits.py +49 -49
  30. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/messages/messages.py +6 -9
  31. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/model_collection.py +1 -3
  32. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/model_dictionary.py +2 -4
  33. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/model_object.py +3 -3
  34. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/axis.py +31 -12
  35. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/current_move.py +5 -5
  36. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/driver_id.py +2 -3
  37. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/extruder.py +6 -6
  38. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/input_shaping.py +5 -6
  39. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/kinematics/delta_kinematics.py +2 -2
  40. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/kinematics/hangprinter_kinematics.py +2 -2
  41. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/kinematics/kinematics.py +4 -4
  42. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/kinematics/tilt_correction.py +4 -4
  43. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/microstepping.py +1 -1
  44. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/move.py +6 -6
  45. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/move_compensation.py +10 -9
  46. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/move_rotation.py +2 -2
  47. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/move_segmentation.py +4 -4
  48. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/probe_grid.py +5 -5
  49. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/skew.py +1 -1
  50. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/network/network.py +8 -8
  51. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/network/network_interface.py +31 -29
  52. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/object_model.py +6 -6
  53. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/plugins/plugin_manifest.py +34 -26
  54. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/plugins/plugins.py +4 -4
  55. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sbc/dsf/dsf.py +10 -0
  56. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sbc/dsf/http_endpoint.py +3 -4
  57. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sbc/dsf/user_sessions/user_sessions.py +10 -15
  58. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/analog_sensor.py +27 -6
  59. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/endstop.py +5 -6
  60. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/filament_monitors/filament_monitor.py +9 -9
  61. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/filament_monitors/laser_filament_monitor.py +4 -4
  62. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/probe.py +25 -15
  63. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/sensors.py +6 -6
  64. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/spindles/spindles.py +6 -5
  65. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/state/message_box.py +7 -6
  66. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/state/restore_point.py +6 -6
  67. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/state/state.py +31 -34
  68. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/tools/tools.py +15 -14
  69. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/utils.py +2 -2
  70. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/volumes/volumes.py +16 -16
  71. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1/src/dsf_python.egg-info}/PKG-INFO +1 -1
  72. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf_python.egg-info/SOURCES.txt +1 -0
  73. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/LICENSE +0 -0
  74. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/MANIFEST.in +0 -0
  75. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/README.md +0 -0
  76. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/pyproject.toml +0 -0
  77. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/setup.cfg +0 -0
  78. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/__init__.py +0 -0
  79. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/__init__.py +0 -0
  80. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/base_command.py +0 -0
  81. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/code.py +0 -0
  82. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/code_channel.py +0 -0
  83. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/code_flags.py +0 -0
  84. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/code_type.py +0 -0
  85. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/condition_type.py +0 -0
  86. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/files.py +0 -0
  87. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/http_endpoints.py +0 -0
  88. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/model_subscription.py +0 -0
  89. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/object_model.py +0 -0
  90. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/packages.py +0 -0
  91. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/plugins.py +0 -0
  92. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/responses.py +0 -0
  93. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/commands/user_sessions.py +0 -0
  94. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/connections/__init__.py +0 -0
  95. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/connections/base_command_connection.py +0 -0
  96. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/connections/command_connection.py +0 -0
  97. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/connections/init_messages/__init__.py +0 -0
  98. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/connections/init_messages/server_init_message.py +0 -0
  99. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/connections/subscribe_connection.py +0 -0
  100. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/exceptions.py +0 -0
  101. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/http.py +0 -0
  102. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/__init__.py +0 -0
  103. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/boards/__init__.py +0 -0
  104. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/boards/board_closed_loop.py +0 -0
  105. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/boards/direct_display/__init__.py +0 -0
  106. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/boards/direct_display/direct_display.py +0 -0
  107. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/boards/direct_display/direct_display_controller.py +0 -0
  108. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/boards/direct_display/direct_display_encoder.py +0 -0
  109. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/boards/direct_display/direct_display_screen.py +0 -0
  110. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/boards/direct_display/direct_display_screen_st7567.py +0 -0
  111. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/boards/driver.py +0 -0
  112. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/boards/driver_closed_loop.py +0 -0
  113. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/boards/min_max_current.py +0 -0
  114. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/directories/__init__.py +0 -0
  115. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/fans/__init__.py +0 -0
  116. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/heat/__init__.py +0 -0
  117. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/inputs/__init__.py +0 -0
  118. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/inputs/compatibility.py +0 -0
  119. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/inputs/distance_unit.py +0 -0
  120. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/inputs/input_channel_state.py +0 -0
  121. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/inputs/inputs.py +0 -0
  122. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/job/__init__.py +0 -0
  123. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/led_strips/__init__.py +0 -0
  124. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/led_strips/led_strip.py +0 -0
  125. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/limits/__init__.py +0 -0
  126. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/messages/__init__.py +0 -0
  127. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/__init__.py +0 -0
  128. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/extruder_non_linear.py +0 -0
  129. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/keepout_zone.py +0 -0
  130. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/kinematics/__init__.py +0 -0
  131. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/kinematics/core_kinematics.py +0 -0
  132. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/kinematics/delta_tower.py +0 -0
  133. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/kinematics/kinematics_name.py +0 -0
  134. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/kinematics/polar_kinematics.py +0 -0
  135. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/kinematics/scara_kinematics.py +0 -0
  136. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/kinematics/zleadscrew_kinematics.py +0 -0
  137. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/motors_idle_control.py +0 -0
  138. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/move_calibration.py +0 -0
  139. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/move_deviations.py +0 -0
  140. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/move/move_queue_item.py +0 -0
  141. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/network/__init__.py +0 -0
  142. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/network/network_interface_type.py +0 -0
  143. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/network/network_protocol.py +0 -0
  144. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/network/network_state.py +0 -0
  145. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/plugins/__init__.py +0 -0
  146. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/plugins/sbc_permissions.py +0 -0
  147. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sbc/__init__.py +0 -0
  148. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sbc/cpu.py +0 -0
  149. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sbc/dsf/__init__.py +0 -0
  150. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sbc/dsf/http_endpoint_type.py +0 -0
  151. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sbc/dsf/user_sessions/__init__.py +0 -0
  152. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sbc/dsf/user_sessions/access_level.py +0 -0
  153. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sbc/dsf/user_sessions/session_type.py +0 -0
  154. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sbc/memory.py +0 -0
  155. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sbc/sbc.py +0 -0
  156. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/__init__.py +0 -0
  157. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/analog_sensor_type.py +0 -0
  158. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/endstop_type.py +0 -0
  159. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/filament_monitors/Duet3DFilamentMonitor.py +0 -0
  160. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/filament_monitors/__init__.py +0 -0
  161. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/filament_monitors/filament_monitor_enable_type.py +0 -0
  162. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/filament_monitors/filament_monitor_status.py +0 -0
  163. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/filament_monitors/filament_monitor_type.py +0 -0
  164. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/filament_monitors/pulsed_filament_monitor.py +0 -0
  165. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/filament_monitors/rotating_magnet_filament_monitor.py +0 -0
  166. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/gp_input_port.py +0 -0
  167. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/probe_type.py +0 -0
  168. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/sensors/temperature_error.py +0 -0
  169. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/spindles/__init__.py +0 -0
  170. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/spindles/spindle_state.py +0 -0
  171. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/state/__init__.py +0 -0
  172. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/state/beep_request.py +0 -0
  173. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/state/gp_output_port.py +0 -0
  174. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/state/log_level.py +0 -0
  175. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/state/machine_mode.py +0 -0
  176. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/state/machine_status.py +0 -0
  177. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/state/startup_error.py +0 -0
  178. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/tools/__init__.py +0 -0
  179. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/tools/tool_retraction.py +0 -0
  180. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/tools/tool_state.py +0 -0
  181. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/object_model/volumes/__init__.py +0 -0
  182. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/utility/__init__.py +0 -0
  183. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf/utils.py +0 -0
  184. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf_python.egg-info/dependency_links.txt +0 -0
  185. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf_python.egg-info/requires.txt +0 -0
  186. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/src/dsf_python.egg-info/top_level.txt +0 -0
  187. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/tests/test_code.py +0 -0
  188. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/tests/test_custom_http_endpoint.py +0 -0
  189. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/tests/test_custom_m_codes.py +0 -0
  190. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/tests/test_object_model.py +0 -0
  191. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/tests/test_send_simple_code.py +0 -0
  192. {dsf-python-3.5.0.1rc2 → dsf_python-3.5.1rc1}/tests/test_subscribe_object_model.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dsf-python
3
- Version: 3.5.0.1rc2
3
+ Version: 3.5.1rc1
4
4
  Summary: Python interface to access DuetSoftwareFramework
5
5
  Home-page: https://github.com/Duet3D/dsf-python
6
6
  Author: Duet3D Ltd.
@@ -6,7 +6,7 @@ long_description = open("README.md", encoding="utf-8").read()
6
6
 
7
7
  setuptools.setup(
8
8
  name="dsf-python",
9
- version="3.5.0.1rc2",
9
+ version="3.5.1rc1",
10
10
  description="Python interface to access DuetSoftwareFramework",
11
11
  long_description=long_description,
12
12
  long_description_content_type="text/markdown",
@@ -1,4 +1,4 @@
1
- from __future__ import annotations
1
+ from typing import Optional
2
2
 
3
3
  from .base_command import BaseCommand
4
4
  from ..object_model.messages import MessageType
@@ -17,7 +17,7 @@ def ignore():
17
17
  return BaseCommand("Ignore")
18
18
 
19
19
 
20
- def resolve_code(rtype: MessageType, content: str | None = None):
20
+ def resolve_code(rtype: MessageType, content: Optional[str]):
21
21
  """
22
22
  Resolve the code to intercept and return the given message details for its completion.
23
23
  This command is only permitted in ConnectionMode.Intercept mode.
@@ -1,7 +1,6 @@
1
1
  """
2
2
  codeparameter contains all classes and methods dealing with deserialized code parameters.
3
3
  """
4
- from __future__ import annotations
5
4
  import json
6
5
 
7
6
  from ..exceptions import CodeParserException
@@ -1,4 +1,4 @@
1
- from __future__ import annotations
1
+ from typing import Optional
2
2
 
3
3
  from .base_command import BaseCommand
4
4
  from .code_channel import CodeChannel
@@ -108,7 +108,7 @@ def write_message(
108
108
  message_type: MessageType,
109
109
  content: str,
110
110
  output_message: bool = True,
111
- log_level: LogLevel | None = None,
111
+ log_level: Optional[LogLevel] = None,
112
112
  ):
113
113
  """
114
114
  Write an arbitrary generic message
@@ -1,9 +1,8 @@
1
- from __future__ import annotations
2
1
  import json
3
2
  import socket
3
+ from typing import Optional
4
4
 
5
- from .exceptions import (IncompatibleVersionException, InternalServerException, IPCSocketBrokenException,
6
- TaskCanceledException)
5
+ from .exceptions import IncompatibleVersionException, InternalServerException, TaskCanceledException
7
6
  from .init_messages import client_init_messages, server_init_message
8
7
  from ..commands import responses
9
8
 
@@ -12,16 +11,12 @@ class BaseConnection:
12
11
  """
13
12
  Base class for connections that access the control server via the Duet API
14
13
  using a UNIX socket
15
-
16
- Constructor arguments:
17
- :param debug: Whether to print debug information or not
18
- :param timeout: Set a timeout value on blocking socket operations or None to set the socket in non-blocking mode
19
14
  """
20
15
 
21
- def __init__(self, debug: bool = False, timeout: int = None):
16
+ def __init__(self, debug: bool = False, timeout: int = 3):
22
17
  self.debug = debug
23
18
  self.timeout = timeout
24
- self.socket: socket.socket | None = None
19
+ self.socket: Optional[socket.socket] = None
25
20
  self.id = None
26
21
  self.input = ""
27
22
 
@@ -30,7 +25,7 @@ class BaseConnection:
30
25
 
31
26
  self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
32
27
  self.socket.connect(socket_file)
33
- self.socket.settimeout(self.timeout)
28
+ self.socket.setblocking(True)
34
29
  server_init_msg = server_init_message.ServerInitMessage.from_json(
35
30
  json.loads(self.socket.recv(50).decode("utf8"))
36
31
  )
@@ -14,10 +14,3 @@ class InternalServerException(Exception):
14
14
 
15
15
  class TaskCanceledException(Exception):
16
16
  """Exception returned by the server if the task has been cancelled remotely"""
17
-
18
-
19
- class IPCSocketBrokenException(Exception):
20
- """Exception raised if the IPC connection has been closed on the remote server"""
21
-
22
- def __init__(self):
23
- super().__init__("IPC socket connection broken")
@@ -41,7 +41,8 @@ def intercept_init_message(
41
41
  channels: List[CodeChannel],
42
42
  filters: List[str],
43
43
  priority_codes: bool,
44
- auto_flush: bool = True):
44
+ auto_flush: bool = True,
45
+ auto_evaluate_expression: bool = True):
45
46
  """
46
47
  Enter interception mode
47
48
  Whenever a code is received, the connection must respond with one of
@@ -62,6 +63,9 @@ def intercept_init_message(
62
63
  is specified.
63
64
  This option makes extra Flush calls in the interceptor implementation obsolete.
64
65
  It is highly recommended to enable this in order to avoid potential deadlocks when dealing with macros!
66
+ :param auto_evaluate_expression: Automatically evaluate expression parameters to their final values
67
+ before sending it over to the client.
68
+ This requires auto_flush to be True and happens when the remaining codes have been processed.
65
69
  """
66
70
  return ClientInitMessage(
67
71
  ConnectionMode.INTERCEPT,
@@ -69,6 +73,7 @@ def intercept_init_message(
69
73
  "InterceptionMode": intercept_mode,
70
74
  "Channels": channels,
71
75
  "AutoFlush": auto_flush,
76
+ "AutoEvaluateExpressions": auto_evaluate_expression,
72
77
  "Filters": filters,
73
78
  "PriorityCodes": priority_codes,
74
79
  },
@@ -21,6 +21,9 @@ class InterceptConnection(BaseCommandConnection):
21
21
  in case a code filter is specified.
22
22
  This option makes extra Flush calls in the interceptor implementation obsolete.
23
23
  It is highly recommended to enable this in order to avoid potential deadlocks when dealing with macros!
24
+ :param auto_evaluate_expression: Automatically evaluate expression parameters to their final values
25
+ before sending it over to the client.
26
+ This requires auto_flush to be True and happens when the remaining codes have been processed.
24
27
  :param priority_codes: Defines if priority codes may be intercepted (e.g. M122 or M999)
25
28
  :param debug: Whether debugging output is turned on for this connection
26
29
  """
@@ -31,6 +34,7 @@ class InterceptConnection(BaseCommandConnection):
31
34
  channels: List[CodeChannel] = None,
32
35
  filters: List[str] = None,
33
36
  auto_flush: bool = True,
37
+ auto_evaluate_expression: bool = True,
34
38
  priority_codes: bool = False,
35
39
  debug: bool = False,
36
40
  ):
@@ -39,12 +43,18 @@ class InterceptConnection(BaseCommandConnection):
39
43
  self.channels = channels if channels is not None else CodeChannel.list()
40
44
  self.filters = filters
41
45
  self.auto_flush = auto_flush
46
+ self.auto_evaluate_expression = auto_evaluate_expression
42
47
  self.priority_codes = priority_codes
43
48
 
44
49
  def connect(self, socket_file: str = SOCKET_FILE): # noqa
45
50
  """Establishes a connection to the given UNIX socket file"""
46
51
  iim = client_init_messages.intercept_init_message(
47
- self.interception_mode, self.channels, self.filters, self.priority_codes, self.auto_flush
52
+ self.interception_mode,
53
+ self.channels,
54
+ self.filters,
55
+ self.priority_codes,
56
+ self.auto_flush,
57
+ self.auto_evaluate_expression
48
58
  )
49
59
  return super().connect(iim, socket_file)
50
60
 
@@ -60,7 +70,7 @@ class InterceptConnection(BaseCommandConnection):
60
70
  """Instruct the control server to ignore the last received code (in intercepting mode)"""
61
71
  self.send(commands.code_interception.ignore())
62
72
 
63
- def resolve_code(self, rtype: MessageType = MessageType.Success, content: str | None = None):
73
+ def resolve_code(self, rtype: MessageType = MessageType.Success, content: Optional[str] = None):
64
74
  """
65
75
  Instruct the control server to resolve the last received code with the given
66
76
  message details (in intercepting mode)
@@ -5,11 +5,24 @@ class Accelerometer(ModelObject):
5
5
  """This represents an accelerometer"""
6
6
  def __init__(self):
7
7
  super(Accelerometer, self).__init__()
8
+ # Orientation of the accelerometer
9
+ # See https://docs.duet3d.com/en/Duet3D_hardware/Accessories/Duet3D_Accelerometer#orientation for a list of orientations
10
+ self._orientation = 20
8
11
  # Number of collected data points in the last run or 0 if it failed
9
12
  self._points = 0
10
13
  # Number of completed sampling runs
11
14
  self._runs = 0
12
15
 
16
+ @property
17
+ def orientation(self) -> int:
18
+ """Orientation of the accelerometer
19
+ See https://docs.duet3d.com/en/Duet3D_hardware/Accessories/Duet3D_Accelerometer#orientation for a list of orientations"""
20
+ return self._orientation
21
+
22
+ @orientation.setter
23
+ def orientation(self, value):
24
+ self._orientation = int(value)
25
+
13
26
  @property
14
27
  def points(self) -> int:
15
28
  """Number of collected data points in the last run or 0 if it failed"""
@@ -1,11 +1,11 @@
1
- from __future__ import annotations
2
1
  from enum import Enum
3
- from typing import List, Union
2
+ from typing import List, Optional
4
3
 
5
4
  from .accelerometer import Accelerometer
6
5
  from .board_closed_loop import BoardClosedLoop
7
6
  from .direct_display import DirectDisplay
8
7
  from .driver import Driver
8
+ from .inductive_sensor import InductiveSensor
9
9
  from .min_max_current import MinMaxCurrent
10
10
  from ..model_collection import ModelCollection
11
11
  from ..model_object import ModelObject
@@ -43,6 +43,8 @@ class Board(ModelObject):
43
43
  closed_loop = wrap_model_property('closed_loop', BoardClosedLoop)
44
44
  # Details about a connected display or None if none is connected
45
45
  direct_display = wrap_model_property('direct_display', DirectDisplay)
46
+ # Information about an inductive sensor or None if not present
47
+ inductive_sensor = wrap_model_property('inductive_sensor', InductiveSensor)
46
48
  # Minimum, maximum, and current temperatures of the MCU or None if unknown
47
49
  mcu_temp = wrap_model_property('mcu_temp', MinMaxCurrent)
48
50
  # Minimum, maximum, and current voltages on the 12V rail or None if unknown
@@ -73,11 +75,15 @@ class Board(ModelObject):
73
75
  self._firmware_name = ""
74
76
  # Version of the firmware build
75
77
  self._firmware_version = ""
78
+ # Amount of free RAM on this board (in bytes or null if unknown)
79
+ self._free_ram = None
76
80
  # Filename of the IAP binary that is used for updates from the SBC or None if unsupported
77
81
  self._iap_file_name_SBC = None
78
82
  # Filename of the IAP binary that is used for updates from the SD card or None if unsupported
79
83
  # This is only available for the mainboard (first board item)
80
84
  self._iap_file_name_SD = None
85
+ # Information about an inductive sensor or None if not present
86
+ self._inductive_sensor = None
81
87
  # Maximum number of heaters this board can control
82
88
  self._max_heaters = 0
83
89
  # Maximum number of motors this board can drive
@@ -105,25 +111,25 @@ class Board(ModelObject):
105
111
  self._wifi_firmware_file_name = None
106
112
 
107
113
  @property
108
- def bootloader_file_name(self) -> Union[str, None]:
114
+ def bootloader_file_name(self) -> Optional[str]:
109
115
  """Filename of the bootloader binary or None if unknown"""
110
116
  return self._bootloader_file_name
111
117
 
112
118
  @bootloader_file_name.setter
113
- def bootloader_file_name(self, value: str | None = None):
119
+ def bootloader_file_name(self, value):
114
120
  self._bootloader_file_name = str(value) if value is not None else None
115
121
 
116
122
  @property
117
- def can_address(self) -> Union[int, None]:
123
+ def can_address(self) -> Optional[int]:
118
124
  """CAN address of this board or None if not applicable"""
119
125
  return self._can_address
120
126
 
121
127
  @can_address.setter
122
- def can_address(self, value: int | None = None):
128
+ def can_address(self, value):
123
129
  self._can_address = int(value) if value is not None else None
124
130
 
125
131
  @property
126
- def drivers(self) -> Union[List[Driver], None]:
132
+ def drivers(self) -> Optional[List[Driver]]:
127
133
  """Drivers of this board"""
128
134
  return self._drivers
129
135
 
@@ -168,22 +174,31 @@ class Board(ModelObject):
168
174
  self._firmware_version = str(value)
169
175
 
170
176
  @property
171
- def iap_file_name_SBC(self) -> Union[str, None]:
177
+ def free_ram(self) -> Optional[int]:
178
+ """Amount of free RAM on this board (in bytes or null if unknown)"""
179
+ return self._free_ram
180
+
181
+ @free_ram.setter
182
+ def free_ram(self, value):
183
+ self._free_ram = None if value is None else int(value)
184
+
185
+ @property
186
+ def iap_file_name_SBC(self) -> Optional[str]:
172
187
  """Filename of the IAP binary that is used for updates from the SBC or None if unsupported"""
173
188
  return self._iap_file_name_SBC
174
189
 
175
190
  @iap_file_name_SBC.setter
176
- def iap_file_name_SBC(self, value: str | None = None):
191
+ def iap_file_name_SBC(self, value):
177
192
  self._iap_file_name_SBC = str(value) if value is not None else None
178
193
 
179
194
  @property
180
- def iap_file_name_SD(self) -> Union[str, None]:
195
+ def iap_file_name_SD(self) -> Optional[str]:
181
196
  """Filename of the IAP binary that is used for updates from the SD card or None if unsupported
182
197
  This is only available for the mainboard (first board item)"""
183
198
  return self._iap_file_name_SD
184
199
 
185
200
  @iap_file_name_SD.setter
186
- def iap_file_name_SD(self, value: str | None = None):
201
+ def iap_file_name_SD(self, value):
187
202
  self._iap_file_name_SD = str(value) if value is not None else None
188
203
 
189
204
  @property
@@ -228,14 +243,13 @@ class Board(ModelObject):
228
243
  return self._state
229
244
 
230
245
  @state.setter
231
- def state(self, value: BoardState):
232
- if isinstance(value, BoardState):
246
+ def state(self, value):
247
+ if value is None or isinstance(value, BoardState):
233
248
  self._state = value
234
249
  elif isinstance(value, str):
235
250
  self._state = BoardState(value)
236
251
  else:
237
- raise TypeError(f"{__name__}.state must be of type BoardState."
238
- f" Got {type(value)}: {value}")
252
+ raise TypeError(f"{__name__}.state must be of type BoardState or None. Got {type(value)}: {value}")
239
253
 
240
254
  @property
241
255
  @deprecated(f"Use {__name__}.supports_direct_display instead")
@@ -245,7 +259,7 @@ class Board(ModelObject):
245
259
  return self._supports_12864
246
260
 
247
261
  @supports_12864.setter
248
- def supports_12864(self, value: bool):
262
+ def supports_12864(self, value):
249
263
  self._supports_12864 = bool(value)
250
264
 
251
265
  @property
@@ -254,16 +268,16 @@ class Board(ModelObject):
254
268
  return self._supports_direct_display
255
269
 
256
270
  @supports_direct_display.setter
257
- def supports_direct_display(self, value: bool):
271
+ def supports_direct_display(self, value):
258
272
  self._supports_direct_display = bool(value)
259
273
 
260
274
  @property
261
- def unique_id(self) -> Union[str, None]:
275
+ def unique_id(self) -> Optional[str]:
262
276
  """Unique identifier of the board or None if unknown"""
263
277
  return self._unique_id
264
278
 
265
279
  @unique_id.setter
266
- def unique_id(self, value: str | None = None):
280
+ def unique_id(self, value):
267
281
  self._unique_id = str(value) if value is not None else None
268
282
 
269
283
  @property
@@ -0,0 +1,9 @@
1
+ from ..model_object import ModelObject
2
+
3
+
4
+ class InductiveSensor(ModelObject):
5
+ """"""
6
+
7
+ def __init__(self):
8
+ super(InductiveSensor, self).__init__()
9
+ # still empty
@@ -27,7 +27,7 @@ class Directories(ModelObject):
27
27
  return self._filaments
28
28
 
29
29
  @filaments.setter
30
- def filaments(self, value: str):
30
+ def filaments(self, value):
31
31
  self._filaments = str(value)
32
32
 
33
33
  @property
@@ -36,7 +36,7 @@ class Directories(ModelObject):
36
36
  return self._firmware
37
37
 
38
38
  @firmware.setter
39
- def firmware(self, value: str):
39
+ def firmware(self, value):
40
40
  self._firmware = str(value)
41
41
 
42
42
  @property
@@ -45,7 +45,7 @@ class Directories(ModelObject):
45
45
  return self._g_codes
46
46
 
47
47
  @g_codes.setter
48
- def g_codes(self, value: str):
48
+ def g_codes(self, value):
49
49
  self._g_codes = str(value)
50
50
 
51
51
  @property
@@ -54,7 +54,7 @@ class Directories(ModelObject):
54
54
  return self._macros
55
55
 
56
56
  @macros.setter
57
- def macros(self, value: str):
57
+ def macros(self, value):
58
58
  self._macros = str(value)
59
59
 
60
60
  @property
@@ -64,7 +64,7 @@ class Directories(ModelObject):
64
64
  return self._menu
65
65
 
66
66
  @menu.setter
67
- def menu(self, value: str):
67
+ def menu(self, value):
68
68
  self._menu = str(value)
69
69
 
70
70
  @property
@@ -73,7 +73,7 @@ class Directories(ModelObject):
73
73
  return self._system
74
74
 
75
75
  @system.setter
76
- def system(self, value: str):
76
+ def system(self, value):
77
77
  self._system = str(value)
78
78
 
79
79
  @property
@@ -82,5 +82,5 @@ class Directories(ModelObject):
82
82
  return self._web
83
83
 
84
84
  @web.setter
85
- def web(self, value: str):
85
+ def web(self, value):
86
86
  self._web = str(value)
@@ -1,4 +1,4 @@
1
- from __future__ import annotations
1
+ from typing import List, Union
2
2
  from ..model_object import ModelObject
3
3
  from ...utils import deprecated
4
4
 
@@ -24,21 +24,21 @@ class FanThermostaticControl(ModelObject):
24
24
  return self._heaters
25
25
 
26
26
  @property
27
- def high_temperature(self) -> float | None:
27
+ def high_temperature(self) -> Union[float, None]:
28
28
  """Upper temperature range required to turn on the fan (in C)"""
29
29
  return self._high_temperature
30
30
 
31
31
  @high_temperature.setter
32
- def high_temperature(self, value: float | None = None):
32
+ def high_temperature(self, value):
33
33
  self._high_temperature = float(value) if value is not None else None
34
34
 
35
35
  @property
36
- def low_temperature(self) -> float | None:
36
+ def low_temperature(self) -> Union[float, None]:
37
37
  """Lower temperature range required to turn on the fan (in C)"""
38
38
  return self._low_temperature
39
39
 
40
40
  @low_temperature.setter
41
- def low_temperature(self, value: float | None = None):
41
+ def low_temperature(self, value):
42
42
  self._low_temperature = float(value) if value is not None else None
43
43
 
44
44
  @property
@@ -23,6 +23,8 @@ class Fan(ModelObject):
23
23
  self._requested_value = 0
24
24
  # Current RPM of this fan or -1 if unknown/unset
25
25
  self._rpm = -1
26
+ # Pulses per tacho revolution
27
+ self._tacho_ppr = 2.0
26
28
  # Thermostatic control parameters
27
29
  self._thermostatic = FanThermostaticControl()
28
30
 
@@ -78,7 +80,7 @@ class Fan(ModelObject):
78
80
  return self._name
79
81
 
80
82
  @name.setter
81
- def name(self, value: str):
83
+ def name(self, value):
82
84
  self._name = str(value)
83
85
 
84
86
  @property
@@ -99,6 +101,15 @@ class Fan(ModelObject):
99
101
  def rpm(self, value):
100
102
  self._rpm = int(value)
101
103
 
104
+ @property
105
+ def tacho_ppr(self) -> float:
106
+ """Pulses per tacho revolution"""
107
+ return self._tacho_ppr
108
+
109
+ @tacho_ppr.setter
110
+ def tacho_ppr(self, value):
111
+ self._tacho_ppr = float(value)
112
+
102
113
  @property
103
114
  def thermostatic(self) -> FanThermostaticControl:
104
115
  """Thermostatic control parameters"""
@@ -1,4 +1,4 @@
1
- from __future__ import annotations
1
+ from typing import List
2
2
 
3
3
  from .heater import Heater
4
4
  from ..model_collection import ModelCollection
@@ -22,13 +22,13 @@ class Heat(ModelObject):
22
22
  self._heaters = ModelCollection(Heater)
23
23
 
24
24
  @property
25
- def bed_heaters(self) -> list[int]:
25
+ def bed_heaters(self) -> List[int]:
26
26
  """List of configured bed heaters (indices)
27
27
  Items may be -1 if unconfigured"""
28
28
  return self._bed_heaters
29
29
 
30
30
  @property
31
- def chamber_heaters(self) -> list[int]:
31
+ def chamber_heaters(self) -> List[int]:
32
32
  """List of configured chamber heaters (indices)
33
33
  Items may be -1 if unconfigured"""
34
34
  return self._chamber_heaters
@@ -52,6 +52,6 @@ class Heat(ModelObject):
52
52
  self._cold_retract_temperature = float(value)
53
53
 
54
54
  @property
55
- def heaters(self) -> list[Heater]:
55
+ def heaters(self) -> List[Heater]:
56
56
  """List of configured heaters"""
57
57
  return self._heaters
@@ -1,5 +1,5 @@
1
- from __future__ import annotations
2
1
  from enum import Enum
2
+ from typing import List
3
3
 
4
4
  from .heater_model import HeaterModel
5
5
  from .heater_monitor import HeaterMonitor
@@ -142,7 +142,7 @@ class Heater(ModelObject):
142
142
  return self._model
143
143
 
144
144
  @property
145
- def monitors(self) -> list[HeaterMonitor]:
145
+ def monitors(self) -> List[HeaterMonitor]:
146
146
  """Monitors of this heater"""
147
147
  return self._monitors
148
148
 
@@ -1,5 +1,3 @@
1
- from __future__ import annotations
2
-
3
1
  from ..model_object import ModelObject
4
2
  from .heater_model_pid import HeaterModelPID
5
3
 
@@ -108,7 +106,7 @@ class HeaterModel(ModelObject):
108
106
  return self._pid
109
107
 
110
108
  @property
111
- def standard_voltage(self) -> float | None:
109
+ def standard_voltage(self) -> float:
112
110
  """Standard voltage or null if unknown"""
113
111
  return self._standard_voltage
114
112
 
@@ -41,7 +41,7 @@ class HeaterModelPID(ModelObject):
41
41
  return self._overridden
42
42
 
43
43
  @overridden.setter
44
- def overridden(self, value: bool):
44
+ def overridden(self, value):
45
45
  self._overridden = bool(value)
46
46
 
47
47
  @property
@@ -59,5 +59,5 @@ class HeaterModelPID(ModelObject):
59
59
  return self._used
60
60
 
61
61
  @used.setter
62
- def used(self, value: bool):
62
+ def used(self, value):
63
63
  self._used = bool(value)
@@ -1,4 +1,3 @@
1
- from __future__ import annotations
2
1
  from enum import Enum, IntEnum
3
2
  from typing import Union
4
3
 
@@ -61,7 +60,7 @@ class HeaterMonitor(ModelObject):
61
60
  self._action = HeaterMonitorAction(value)
62
61
  else:
63
62
  raise TypeError(f"{__name__}.action must be of type HeaterMonitorAction or None."
64
- f" Got {type(value)}: {value}")
63
+ f"Got {type(value)}: {value}")
65
64
 
66
65
  @property
67
66
  def condition(self):
@@ -70,16 +69,16 @@ class HeaterMonitor(ModelObject):
70
69
 
71
70
  @condition.setter
72
71
  def condition(self, value: HeaterMonitorCondition = HeaterMonitorCondition.disabled):
73
- if isinstance(value, HeaterMonitorCondition):
72
+ if value is None or isinstance(value, HeaterMonitorCondition):
74
73
  self._condition = value
75
74
  elif isinstance(value, str):
76
75
  self._condition = HeaterMonitorCondition(value)
77
76
  else:
78
77
  raise TypeError(f"{__name__}.condition must be of type HeaterMonitorCondition or None."
79
- f" Got {type(value)}: {value}")
78
+ f"Got {type(value)}: {value}")
80
79
 
81
80
  @property
82
- def limit(self) -> float | None:
81
+ def limit(self) -> float:
83
82
  """Limit threshold for this heater monitor"""
84
83
  return self._limit
85
84