dsf-python 3.6.0rc3__tar.gz → 3.7.0b1__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.
- dsf_python-3.7.0b1/PKG-INFO +303 -0
- dsf_python-3.7.0b1/README.md +261 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/setup.cfg +1 -1
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/setup.py +4 -7
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/__init__.py +2 -2
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/base_command.py +4 -2
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/code.py +34 -24
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/code_channel.py +7 -1
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/code_interception.py +0 -4
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/code_parameter.py +106 -62
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/files.py +7 -5
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/generic.py +4 -28
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/http_endpoints.py +0 -14
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/object_model.py +0 -12
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/packages.py +4 -4
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/plugins.py +15 -15
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/responses.py +27 -14
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/user_sessions.py +2 -8
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/connections/base_command_connection.py +11 -4
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/connections/base_connection.py +27 -8
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/connections/command_connection.py +2 -2
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/connections/exceptions.py +3 -1
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/connections/init_messages/client_init_messages.py +19 -7
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/connections/init_messages/server_init_message.py +9 -3
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/connections/intercept_connection.py +3 -3
- dsf_python-3.7.0b1/src/dsf/connections/subscribe_connection.py +219 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/http.py +33 -16
- dsf_python-3.7.0b1/src/dsf/object_model/boards/accelerometer.py +19 -0
- dsf_python-3.7.0b1/src/dsf/object_model/boards/board_closed_loop.py +15 -0
- dsf_python-3.7.0b1/src/dsf/object_model/boards/boards.py +112 -0
- dsf_python-3.7.0b1/src/dsf/object_model/boards/direct_display/direct_display.py +18 -0
- dsf_python-3.7.0b1/src/dsf/object_model/boards/direct_display/direct_display_encoder.py +12 -0
- dsf_python-3.7.0b1/src/dsf/object_model/boards/direct_display/direct_display_screen.py +54 -0
- dsf_python-3.7.0b1/src/dsf/object_model/boards/direct_display/direct_display_screen_st7567.py +14 -0
- dsf_python-3.7.0b1/src/dsf/object_model/boards/driver.py +20 -0
- dsf_python-3.7.0b1/src/dsf/object_model/boards/driver_closed_loop.py +41 -0
- dsf_python-3.7.0b1/src/dsf/object_model/boards/driver_config.py +16 -0
- dsf_python-3.7.0b1/src/dsf/object_model/boards/driver_mode.py +23 -0
- dsf_python-3.7.0b1/src/dsf/object_model/boards/min_max_current.py +18 -0
- dsf_python-3.7.0b1/src/dsf/object_model/directories/directories.py +32 -0
- dsf_python-3.7.0b1/src/dsf/object_model/fans/fan_thermostatic_control.py +19 -0
- dsf_python-3.7.0b1/src/dsf/object_model/fans/fans.py +40 -0
- dsf_python-3.7.0b1/src/dsf/object_model/heat/heat.py +36 -0
- dsf_python-3.7.0b1/src/dsf/object_model/heat/heater.py +81 -0
- dsf_python-3.7.0b1/src/dsf/object_model/heat/heater_model.py +40 -0
- dsf_python-3.7.0b1/src/dsf/object_model/heat/heater_model_pid.py +21 -0
- dsf_python-3.7.0b1/src/dsf/object_model/heat/heater_monitor.py +52 -0
- dsf_python-3.7.0b1/src/dsf/object_model/inputs/input_channel.py +65 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/inputs/input_channel_state.py +3 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/inputs/inputs.py +1 -1
- dsf_python-3.7.0b1/src/dsf/object_model/job/build.py +25 -0
- dsf_python-3.7.0b1/src/dsf/object_model/job/build_object.py +24 -0
- dsf_python-3.7.0b1/src/dsf/object_model/job/gcode_fileinfo.py +51 -0
- dsf_python-3.7.0b1/src/dsf/object_model/job/job.py +51 -0
- dsf_python-3.7.0b1/src/dsf/object_model/job/layer.py +27 -0
- dsf_python-3.7.0b1/src/dsf/object_model/job/thumbnail_info.py +41 -0
- dsf_python-3.7.0b1/src/dsf/object_model/job/times_left.py +23 -0
- dsf_python-3.7.0b1/src/dsf/object_model/led_strips/led_strip.py +44 -0
- dsf_python-3.7.0b1/src/dsf/object_model/led_strips/led_strip_color_order.py +22 -0
- dsf_python-3.7.0b1/src/dsf/object_model/limits/limits.py +93 -0
- dsf_python-3.7.0b1/src/dsf/object_model/messages/messages.py +51 -0
- dsf_python-3.7.0b1/src/dsf/object_model/model_collection.py +156 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/model_dictionary.py +22 -7
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/model_object.py +27 -19
- dsf_python-3.7.0b1/src/dsf/object_model/model_type.py +21 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/axis.py +132 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/current_move.py +41 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/move/driver_id.py +10 -4
- dsf_python-3.7.0b1/src/dsf/object_model/move/extruder.py +67 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/extruder_non_linear.py +17 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/extruder_pressure_advance.py +18 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/input_shaping.py +63 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/keepout_zone.py +31 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/move/kinematics/core_kinematics.py +7 -13
- dsf_python-3.7.0b1/src/dsf/object_model/move/kinematics/delta_kinematics.py +32 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/kinematics/delta_tower.py +29 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/kinematics/hangprinter_kinematics.py +22 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/move/kinematics/kinematics.py +14 -30
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/move/kinematics/kinematics_name.py +8 -8
- dsf_python-3.7.0b1/src/dsf/object_model/move/kinematics/polar_kinematics.py +29 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/kinematics/scara_kinematics.py +38 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/kinematics/tilt_correction.py +30 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/move/kinematics/zleadscrew_kinematics.py +5 -7
- dsf_python-3.7.0b1/src/dsf/object_model/move/microstepping.py +15 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/motion_system.py +52 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/motors_idle_control.py +15 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/move.py +95 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/move_calibration.py +19 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/move_compensation.py +46 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/move_deviations.py +15 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/move_queue_item.py +15 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/move_rotation.py +16 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/move_segmentation.py +12 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/probe_grid.py +25 -0
- dsf_python-3.7.0b1/src/dsf/object_model/move/skew.py +21 -0
- dsf_python-3.7.0b1/src/dsf/object_model/network/network.py +30 -0
- dsf_python-3.7.0b1/src/dsf/object_model/network/network_interface.py +57 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/network/network_interface_type.py +1 -1
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/network/network_state.py +3 -0
- dsf_python-3.7.0b1/src/dsf/object_model/object_model.py +62 -0
- dsf_python-3.7.0b1/src/dsf/object_model/plugins/plugin_manifest.py +98 -0
- dsf_python-3.7.0b1/src/dsf/object_model/plugins/plugins.py +25 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/plugins/sbc_permissions.py +2 -2
- dsf_python-3.7.0b1/src/dsf/object_model/sbc/cpu.py +15 -0
- dsf_python-3.7.0b1/src/dsf/object_model/sbc/dsf/communication_method.py +11 -0
- dsf_python-3.7.0b1/src/dsf/object_model/sbc/dsf/dsf.py +25 -0
- dsf_python-3.7.0b1/src/dsf/object_model/sbc/dsf/http_endpoint.py +28 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/sbc/dsf/http_endpoint_type.py +2 -2
- dsf_python-3.7.0b1/src/dsf/object_model/sbc/dsf/user_sessions/user_sessions.py +26 -0
- dsf_python-3.7.0b1/src/dsf/object_model/sbc/memory.py +12 -0
- dsf_python-3.7.0b1/src/dsf/object_model/sbc/sbc.py +24 -0
- dsf_python-3.7.0b1/src/dsf/object_model/sensors/analog_sensor.py +27 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/sensors/analog_sensor_type.py +22 -4
- dsf_python-3.7.0b1/src/dsf/object_model/sensors/endstop.py +22 -0
- dsf_python-3.7.0b1/src/dsf/object_model/sensors/filament_monitors/Duet3DFilamentMonitor.py +28 -0
- dsf_python-3.7.0b1/src/dsf/object_model/sensors/filament_monitors/filament_monitor.py +52 -0
- dsf_python-3.7.0b1/src/dsf/object_model/sensors/filament_monitors/laser_filament_monitor.py +58 -0
- dsf_python-3.7.0b1/src/dsf/object_model/sensors/filament_monitors/pulsed_filament_monitor.py +58 -0
- dsf_python-3.7.0b1/src/dsf/object_model/sensors/filament_monitors/rotating_magnet_filament_monitor.py +58 -0
- dsf_python-3.7.0b1/src/dsf/object_model/sensors/gp_input_port.py +12 -0
- dsf_python-3.7.0b1/src/dsf/object_model/sensors/probe.py +33 -0
- dsf_python-3.7.0b1/src/dsf/object_model/sensors/probe_touch_mode.py +14 -0
- dsf_python-3.7.0b1/src/dsf/object_model/sensors/sensors.py +32 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/sensors/temperature_error.py +12 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/spindles/spindle_type.py +0 -3
- dsf_python-3.7.0b1/src/dsf/object_model/spindles/spindles.py +44 -0
- dsf_python-3.7.0b1/src/dsf/object_model/state/beep_request.py +12 -0
- dsf_python-3.7.0b1/src/dsf/object_model/state/gp_output_port.py +15 -0
- dsf_python-3.7.0b1/src/dsf/object_model/state/message_box.py +52 -0
- dsf_python-3.7.0b1/src/dsf/object_model/state/restore_point.py +23 -0
- dsf_python-3.7.0b1/src/dsf/object_model/state/startup_error.py +20 -0
- dsf_python-3.7.0b1/src/dsf/object_model/state/state.py +47 -0
- dsf_python-3.7.0b1/src/dsf/object_model/tools/tool_retraction.py +24 -0
- dsf_python-3.7.0b1/src/dsf/object_model/tools/tools.py +36 -0
- dsf_python-3.7.0b1/src/dsf/object_model/utils.py +154 -0
- dsf_python-3.7.0b1/src/dsf/object_model/volumes/volumes.py +33 -0
- dsf_python-3.7.0b1/src/dsf/utils.py +132 -0
- dsf_python-3.7.0b1/src/dsf_python.egg-info/PKG-INFO +303 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf_python.egg-info/SOURCES.txt +9 -0
- dsf_python-3.7.0b1/tests/test_base_connection.py +34 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/tests/test_custom_http_endpoint.py +10 -10
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/tests/test_custom_m_codes.py +1 -1
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/tests/test_object_model.py +336 -3
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/tests/test_send_simple_code.py +1 -1
- dsf_python-3.7.0b1/tests/test_subscribe_object_model.py +268 -0
- dsf_python-3.6.0rc3/PKG-INFO +0 -60
- dsf_python-3.6.0rc3/README.md +0 -15
- dsf_python-3.6.0rc3/src/dsf/connections/subscribe_connection.py +0 -65
- dsf_python-3.6.0rc3/src/dsf/object_model/boards/accelerometer.py +0 -42
- dsf_python-3.6.0rc3/src/dsf/object_model/boards/board_closed_loop.py +0 -29
- dsf_python-3.6.0rc3/src/dsf/object_model/boards/boards.py +0 -290
- dsf_python-3.6.0rc3/src/dsf/object_model/boards/direct_display/direct_display.py +0 -23
- dsf_python-3.6.0rc3/src/dsf/object_model/boards/direct_display/direct_display_encoder.py +0 -19
- dsf_python-3.6.0rc3/src/dsf/object_model/boards/direct_display/direct_display_screen.py +0 -101
- dsf_python-3.6.0rc3/src/dsf/object_model/boards/direct_display/direct_display_screen_st7567.py +0 -31
- dsf_python-3.6.0rc3/src/dsf/object_model/boards/driver.py +0 -29
- dsf_python-3.6.0rc3/src/dsf/object_model/boards/driver_closed_loop.py +0 -77
- dsf_python-3.6.0rc3/src/dsf/object_model/boards/min_max_current.py +0 -41
- dsf_python-3.6.0rc3/src/dsf/object_model/directories/directories.py +0 -86
- dsf_python-3.6.0rc3/src/dsf/object_model/fans/fan_thermostatic_control.py +0 -47
- dsf_python-3.6.0rc3/src/dsf/object_model/fans/fans.py +0 -116
- dsf_python-3.6.0rc3/src/dsf/object_model/heat/heat.py +0 -57
- dsf_python-3.6.0rc3/src/dsf/object_model/heat/heater.py +0 -201
- dsf_python-3.6.0rc3/src/dsf/object_model/heat/heater_model.py +0 -115
- dsf_python-3.6.0rc3/src/dsf/object_model/heat/heater_model_pid.py +0 -63
- dsf_python-3.6.0rc3/src/dsf/object_model/heat/heater_monitor.py +0 -96
- dsf_python-3.6.0rc3/src/dsf/object_model/inputs/input_channel.py +0 -212
- dsf_python-3.6.0rc3/src/dsf/object_model/job/build.py +0 -55
- dsf_python-3.6.0rc3/src/dsf/object_model/job/build_object.py +0 -46
- dsf_python-3.6.0rc3/src/dsf/object_model/job/gcode_fileinfo.py +0 -126
- dsf_python-3.6.0rc3/src/dsf/object_model/job/job.py +0 -188
- dsf_python-3.6.0rc3/src/dsf/object_model/job/layer.py +0 -57
- dsf_python-3.6.0rc3/src/dsf/object_model/job/thumbnail_info.py +0 -96
- dsf_python-3.6.0rc3/src/dsf/object_model/job/times_left.py +0 -54
- dsf_python-3.6.0rc3/src/dsf/object_model/led_strips/led_strip.py +0 -74
- dsf_python-3.6.0rc3/src/dsf/object_model/limits/limits.py +0 -307
- dsf_python-3.6.0rc3/src/dsf/object_model/messages/messages.py +0 -84
- dsf_python-3.6.0rc3/src/dsf/object_model/model_collection.py +0 -66
- dsf_python-3.6.0rc3/src/dsf/object_model/move/axis.py +0 -305
- dsf_python-3.6.0rc3/src/dsf/object_model/move/current_move.py +0 -75
- dsf_python-3.6.0rc3/src/dsf/object_model/move/extruder.py +0 -187
- dsf_python-3.6.0rc3/src/dsf/object_model/move/extruder_non_linear.py +0 -39
- dsf_python-3.6.0rc3/src/dsf/object_model/move/input_shaping.py +0 -90
- dsf_python-3.6.0rc3/src/dsf/object_model/move/keepout_zone.py +0 -58
- dsf_python-3.6.0rc3/src/dsf/object_model/move/kinematics/delta_kinematics.py +0 -74
- dsf_python-3.6.0rc3/src/dsf/object_model/move/kinematics/delta_tower.py +0 -62
- dsf_python-3.6.0rc3/src/dsf/object_model/move/kinematics/hangprinter_kinematics.py +0 -33
- dsf_python-3.6.0rc3/src/dsf/object_model/move/kinematics/polar_kinematics.py +0 -13
- dsf_python-3.6.0rc3/src/dsf/object_model/move/kinematics/scara_kinematics.py +0 -12
- dsf_python-3.6.0rc3/src/dsf/object_model/move/kinematics/tilt_correction.py +0 -63
- dsf_python-3.6.0rc3/src/dsf/object_model/move/microstepping.py +0 -29
- dsf_python-3.6.0rc3/src/dsf/object_model/move/motors_idle_control.py +0 -29
- dsf_python-3.6.0rc3/src/dsf/object_model/move/move.py +0 -188
- dsf_python-3.6.0rc3/src/dsf/object_model/move/move_calibration.py +0 -33
- dsf_python-3.6.0rc3/src/dsf/object_model/move/move_compensation.py +0 -88
- dsf_python-3.6.0rc3/src/dsf/object_model/move/move_deviations.py +0 -29
- dsf_python-3.6.0rc3/src/dsf/object_model/move/move_queue_item.py +0 -29
- dsf_python-3.6.0rc3/src/dsf/object_model/move/move_rotation.py +0 -27
- dsf_python-3.6.0rc3/src/dsf/object_model/move/move_segmentation.py +0 -27
- dsf_python-3.6.0rc3/src/dsf/object_model/move/probe_grid.py +0 -48
- dsf_python-3.6.0rc3/src/dsf/object_model/move/skew.py +0 -52
- dsf_python-3.6.0rc3/src/dsf/object_model/network/network.py +0 -59
- dsf_python-3.6.0rc3/src/dsf/object_model/network/network_interface.py +0 -202
- dsf_python-3.6.0rc3/src/dsf/object_model/object_model.py +0 -165
- dsf_python-3.6.0rc3/src/dsf/object_model/plugins/plugin_manifest.py +0 -264
- dsf_python-3.6.0rc3/src/dsf/object_model/plugins/plugins.py +0 -38
- dsf_python-3.6.0rc3/src/dsf/object_model/sbc/cpu.py +0 -50
- dsf_python-3.6.0rc3/src/dsf/object_model/sbc/dsf/dsf.py +0 -76
- dsf_python-3.6.0rc3/src/dsf/object_model/sbc/dsf/http_endpoint.py +0 -73
- dsf_python-3.6.0rc3/src/dsf/object_model/sbc/dsf/user_sessions/user_sessions.py +0 -74
- dsf_python-3.6.0rc3/src/dsf/object_model/sbc/memory.py +0 -30
- dsf_python-3.6.0rc3/src/dsf/object_model/sbc/sbc.py +0 -100
- dsf_python-3.6.0rc3/src/dsf/object_model/sensors/analog_sensor.py +0 -154
- dsf_python-3.6.0rc3/src/dsf/object_model/sensors/endstop.py +0 -56
- dsf_python-3.6.0rc3/src/dsf/object_model/sensors/filament_monitors/Duet3DFilamentMonitor.py +0 -77
- dsf_python-3.6.0rc3/src/dsf/object_model/sensors/filament_monitors/filament_monitor.py +0 -95
- dsf_python-3.6.0rc3/src/dsf/object_model/sensors/filament_monitors/laser_filament_monitor.py +0 -138
- dsf_python-3.6.0rc3/src/dsf/object_model/sensors/filament_monitors/pulsed_filament_monitor.py +0 -126
- dsf_python-3.6.0rc3/src/dsf/object_model/sensors/filament_monitors/rotating_magnet_filament_monitor.py +0 -126
- dsf_python-3.6.0rc3/src/dsf/object_model/sensors/gp_input_port.py +0 -18
- dsf_python-3.6.0rc3/src/dsf/object_model/sensors/probe.py +0 -234
- dsf_python-3.6.0rc3/src/dsf/object_model/sensors/sensors.py +0 -46
- dsf_python-3.6.0rc3/src/dsf/object_model/spindles/spindles.py +0 -147
- dsf_python-3.6.0rc3/src/dsf/object_model/state/beep_request.py +0 -27
- dsf_python-3.6.0rc3/src/dsf/object_model/state/gp_output_port.py +0 -30
- dsf_python-3.6.0rc3/src/dsf/object_model/state/message_box.py +0 -168
- dsf_python-3.6.0rc3/src/dsf/object_model/state/restore_point.py +0 -85
- dsf_python-3.6.0rc3/src/dsf/object_model/state/startup_error.py +0 -43
- dsf_python-3.6.0rc3/src/dsf/object_model/state/state.py +0 -261
- dsf_python-3.6.0rc3/src/dsf/object_model/tools/tool_retraction.py +0 -63
- dsf_python-3.6.0rc3/src/dsf/object_model/tools/tools.py +0 -208
- dsf_python-3.6.0rc3/src/dsf/object_model/utils.py +0 -49
- dsf_python-3.6.0rc3/src/dsf/object_model/volumes/volumes.py +0 -98
- dsf_python-3.6.0rc3/src/dsf/utils.py +0 -55
- dsf_python-3.6.0rc3/src/dsf_python.egg-info/PKG-INFO +0 -60
- dsf_python-3.6.0rc3/tests/test_subscribe_object_model.py +0 -136
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/LICENSE +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/MANIFEST.in +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/pyproject.toml +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/code_flags.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/code_type.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/condition_type.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/commands/model_subscription.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/connections/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/connections/init_messages/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/exceptions.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/boards/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/boards/direct_display/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/boards/direct_display/direct_display_controller.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/boards/inductive_sensor.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/directories/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/fans/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/heat/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/inputs/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/inputs/compatibility.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/inputs/distance_unit.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/job/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/led_strips/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/limits/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/messages/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/move/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/move/kinematics/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/network/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/network/network_protocol.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/plugins/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/sbc/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/sbc/dsf/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/sbc/dsf/user_sessions/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/sbc/dsf/user_sessions/access_level.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/sbc/dsf/user_sessions/session_type.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/sensors/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/sensors/endstop_type.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/sensors/filament_monitors/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/sensors/filament_monitors/filament_monitor_enable_type.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/sensors/filament_monitors/filament_monitor_status.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/sensors/filament_monitors/filament_monitor_type.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/sensors/probe_type.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/spindles/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/spindles/spindle_state.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/state/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/state/log_level.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/state/machine_mode.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/state/machine_status.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/tools/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/tools/tool_state.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/object_model/volumes/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf/utility/__init__.py +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf_python.egg-info/dependency_links.txt +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf_python.egg-info/requires.txt +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/src/dsf_python.egg-info/top_level.txt +0 -0
- {dsf_python-3.6.0rc3 → dsf_python-3.7.0b1}/tests/test_code.py +0 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dsf-python
|
|
3
|
+
Version: 3.7.0b1
|
|
4
|
+
Summary: Python interface to access DuetSoftwareFramework
|
|
5
|
+
Home-page: https://github.com/Duet3D/dsf-python
|
|
6
|
+
Author: Duet3D Ltd.
|
|
7
|
+
Author-email: pkg@duet3d.com
|
|
8
|
+
Project-URL: Duet3D Support, https://forum.duet3d.com/
|
|
9
|
+
Project-URL: Bug Reports, https://github.com/Duet3D/dsf-python/issues
|
|
10
|
+
Project-URL: Source, https://github.com/Duet3D/dsf-python/
|
|
11
|
+
Keywords: Duet3D,DuetSoftwareFramework,DSF,dsf-python
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
15
|
+
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
|
+
Requires-Python: >=3.11, <4
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: python-dateutil
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: sphinx; extra == "dev"
|
|
28
|
+
Requires-Dist: tox; extra == "dev"
|
|
29
|
+
Dynamic: author
|
|
30
|
+
Dynamic: author-email
|
|
31
|
+
Dynamic: classifier
|
|
32
|
+
Dynamic: description
|
|
33
|
+
Dynamic: description-content-type
|
|
34
|
+
Dynamic: home-page
|
|
35
|
+
Dynamic: keywords
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
Dynamic: project-url
|
|
38
|
+
Dynamic: provides-extra
|
|
39
|
+
Dynamic: requires-dist
|
|
40
|
+
Dynamic: requires-python
|
|
41
|
+
Dynamic: summary
|
|
42
|
+
|
|
43
|
+
# Duet Software Framework Python Bindings
|
|
44
|
+
|
|
45
|
+
`dsf-python` provides Python bindings for the Duet Software Framework control server.
|
|
46
|
+
It exposes the DSF socket protocol as Python connection classes, typed object model
|
|
47
|
+
classes, command builders, and helpers for custom HTTP endpoints.
|
|
48
|
+
|
|
49
|
+
This project is also published on [PyPI](https://pypi.org/project/dsf-python/).
|
|
50
|
+
|
|
51
|
+
Useful links:
|
|
52
|
+
|
|
53
|
+
- [Duet Software Framework](https://github.com/Duet3D/DuetSoftwareFramework)
|
|
54
|
+
- [dsf-python examples](https://github.com/Duet3D/dsf-python/tree/main/examples)
|
|
55
|
+
- [Duet Software Framework forum](https://forum.duet3d.com/category/31/dsf-development)
|
|
56
|
+
|
|
57
|
+
## What The Library Contains
|
|
58
|
+
|
|
59
|
+
The top-level package is organised around the main DSF workflows.
|
|
60
|
+
|
|
61
|
+
- `dsf.connections`: socket-based client connections for commands, subscriptions, and code interception
|
|
62
|
+
- `dsf.commands`: request payload builders for low-level DSF commands
|
|
63
|
+
- `dsf.object_model`: the typed DSF object model and related enums
|
|
64
|
+
- `dsf.http`: helpers for custom HTTP and WebSocket endpoints exposed through DSF
|
|
65
|
+
- `dsf.exceptions`: shared exception types raised by connection classes
|
|
66
|
+
|
|
67
|
+
## Installation
|
|
68
|
+
|
|
69
|
+
The package can be installed from source:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
python3 setup.py install
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Or with `pip`:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
python3 -m pip install dsf-python
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Most code using this library must run on a system with Duet Software Framework
|
|
82
|
+
installed and with permission to access the DSF UNIX socket.
|
|
83
|
+
|
|
84
|
+
## Quick Start
|
|
85
|
+
|
|
86
|
+
### Run A Simple Command
|
|
87
|
+
|
|
88
|
+
Use `CommandConnection` to send general-purpose commands such as G-code or to
|
|
89
|
+
request the full object model on demand.
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from dsf.connections import CommandConnection
|
|
93
|
+
|
|
94
|
+
connection = CommandConnection()
|
|
95
|
+
connection.connect()
|
|
96
|
+
|
|
97
|
+
response = connection.perform_simple_code("M115")
|
|
98
|
+
print(response.result)
|
|
99
|
+
|
|
100
|
+
connection.close()
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Read The Object Model Once
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from dsf.connections import CommandConnection
|
|
107
|
+
|
|
108
|
+
connection = CommandConnection()
|
|
109
|
+
connection.connect()
|
|
110
|
+
|
|
111
|
+
object_model = connection.get_object_model()
|
|
112
|
+
print(object_model.state.status)
|
|
113
|
+
print(object_model.move.axes[0].letter)
|
|
114
|
+
|
|
115
|
+
connection.close()
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Subscribe To Object Model Updates
|
|
119
|
+
|
|
120
|
+
Use `SubscribeConnection` when you want DSF to push object model updates over a
|
|
121
|
+
subscription socket.
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from dsf.connections import SubscribeConnection, SubscriptionMode
|
|
125
|
+
|
|
126
|
+
subscription = SubscribeConnection(SubscriptionMode.PATCH)
|
|
127
|
+
subscription.connect()
|
|
128
|
+
|
|
129
|
+
object_model = subscription.get_object_model()
|
|
130
|
+
|
|
131
|
+
while True:
|
|
132
|
+
object_model = subscription.get_object_model()
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
In `SubscriptionMode.PATCH`, the first `get_object_model()` call reads the full
|
|
136
|
+
model. Later calls reuse an internal cached model and apply one queued patch if
|
|
137
|
+
available.
|
|
138
|
+
|
|
139
|
+
## Connections
|
|
140
|
+
|
|
141
|
+
### CommandConnection
|
|
142
|
+
|
|
143
|
+
`CommandConnection` is the general-purpose connection type. It is used for:
|
|
144
|
+
|
|
145
|
+
- sending simple G-code
|
|
146
|
+
- requesting the full object model
|
|
147
|
+
- working with files, packages, plugins, and user sessions through DSF commands
|
|
148
|
+
- issuing lower-level requests through the command helpers in `dsf.commands`
|
|
149
|
+
|
|
150
|
+
Choose this connection when you want request-response behaviour and do not need
|
|
151
|
+
streamed updates.
|
|
152
|
+
|
|
153
|
+
### SubscribeConnection
|
|
154
|
+
|
|
155
|
+
`SubscribeConnection` receives streamed object model updates from DSF. It supports:
|
|
156
|
+
|
|
157
|
+
- `SubscriptionMode.FULL`: every update is a full object model
|
|
158
|
+
- `SubscriptionMode.PATCH`: every update is a partial JSON fragment
|
|
159
|
+
|
|
160
|
+
#### Key-Based Callbacks
|
|
161
|
+
|
|
162
|
+
`SubscribeConnection.subscribe_to_keys()` can run callbacks synchronously when
|
|
163
|
+
selected object model paths appear in a patch update processed by `get_object_model()`.
|
|
164
|
+
|
|
165
|
+
Key paths use dot notation and can include list indexes:
|
|
166
|
+
|
|
167
|
+
- `state.upTime`
|
|
168
|
+
- `heat.heaters.0.current`
|
|
169
|
+
- `move.axes.2.userPosition`
|
|
170
|
+
|
|
171
|
+
Use `^` in a list position to match any changed index:
|
|
172
|
+
|
|
173
|
+
- `heat.heaters.^.current`
|
|
174
|
+
- `tools.^.state`
|
|
175
|
+
|
|
176
|
+
Callbacks always receive keyword arguments:
|
|
177
|
+
|
|
178
|
+
- `key`: the subscribed key path that matched
|
|
179
|
+
- `data`: the changed value found at that path
|
|
180
|
+
- `indices`: a tuple of matched wildcard indexes, or `None` when the key does not use `^`
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
from dsf.connections import SubscribeConnection, SubscriptionMode
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def handle_change(*, key, data, indices):
|
|
187
|
+
print(key, data, indices)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
subscription = SubscribeConnection(SubscriptionMode.PATCH)
|
|
191
|
+
subscription.connect()
|
|
192
|
+
subscription.get_object_model()
|
|
193
|
+
|
|
194
|
+
unsubscribe = subscription.subscribe_to_keys(
|
|
195
|
+
["heat.heaters.0.current", "state.upTime"],
|
|
196
|
+
handle_change,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
while True:
|
|
200
|
+
object_model = subscription.get_object_model()
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Wildcard example:
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
def handle_any_heater(*, key, data, indices):
|
|
207
|
+
print(key, indices, data)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
subscription.subscribe_to_keys(
|
|
211
|
+
["heat.heaters.^.current"],
|
|
212
|
+
handle_any_heater,
|
|
213
|
+
)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### InterceptConnection
|
|
217
|
+
|
|
218
|
+
`InterceptConnection` is used for custom code handling and code interception. Use it
|
|
219
|
+
when a plugin needs to receive G/M/T-code events before or after the firmware handles them.
|
|
220
|
+
|
|
221
|
+
Typical use cases include:
|
|
222
|
+
|
|
223
|
+
- implementing custom M-codes
|
|
224
|
+
- inspecting or rewriting commands
|
|
225
|
+
- reacting to executed code notifications
|
|
226
|
+
|
|
227
|
+
See `examples/custom_m_codes.py` for a complete example.
|
|
228
|
+
|
|
229
|
+
## Object Model
|
|
230
|
+
|
|
231
|
+
The `dsf.object_model` package mirrors the DSF object model in typed Python classes.
|
|
232
|
+
It lets you work with structured properties instead of manually traversing raw JSON.
|
|
233
|
+
|
|
234
|
+
Examples:
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
print(object_model.boards[0].name)
|
|
238
|
+
print(object_model.state.up_time)
|
|
239
|
+
print(object_model.move.axes[0].letter)
|
|
240
|
+
print(object_model.tools[0].state)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Object model instances support JSON-driven updates:
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
object_model.update_from_json({"state": {"upTime": 1234}})
|
|
247
|
+
print(object_model.state.up_time)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
This is the mechanism used internally when patch subscriptions are applied.
|
|
251
|
+
|
|
252
|
+
## Commands
|
|
253
|
+
|
|
254
|
+
The `dsf.commands` package contains low-level command builders for code execution,
|
|
255
|
+
file access, plugins, packages, object model manipulation, and other DSF protocol
|
|
256
|
+
requests.
|
|
257
|
+
|
|
258
|
+
Most users should start with the higher-level methods on `CommandConnection` or
|
|
259
|
+
`BaseCommandConnection`. Reach for `dsf.commands` directly when you need explicit
|
|
260
|
+
control over the payload sent to DSF.
|
|
261
|
+
|
|
262
|
+
## Custom HTTP Endpoints
|
|
263
|
+
|
|
264
|
+
The `dsf.http` module contains helpers for custom HTTP and WebSocket endpoints.
|
|
265
|
+
This is useful when a DSF plugin needs to expose an HTTP route that is handled by
|
|
266
|
+
Python code.
|
|
267
|
+
|
|
268
|
+
Key types include:
|
|
269
|
+
|
|
270
|
+
- `HttpEndpointUnixSocket`
|
|
271
|
+
- `HttpEndpointConnection`
|
|
272
|
+
- `ReceivedHttpRequest`
|
|
273
|
+
- `HttpResponseType`
|
|
274
|
+
|
|
275
|
+
See `examples/custom_http_endpoint.py` for a practical example.
|
|
276
|
+
|
|
277
|
+
## Included Examples
|
|
278
|
+
|
|
279
|
+
The `examples/` directory demonstrates the main workflows supported by the library.
|
|
280
|
+
|
|
281
|
+
- `send_simple_code.py`: send G-code over a command connection
|
|
282
|
+
- `subscribe_object_model.py`: subscribe to object model updates
|
|
283
|
+
- `custom_m_codes.py`: intercept and implement custom M-codes
|
|
284
|
+
- `custom_http_endpoint.py`: serve a custom HTTP endpoint through DSF
|
|
285
|
+
|
|
286
|
+
## API Reference
|
|
287
|
+
|
|
288
|
+
The Sphinx docs expose the package API for the major public modules:
|
|
289
|
+
|
|
290
|
+
- `dsf`
|
|
291
|
+
- `dsf.connections`
|
|
292
|
+
- `dsf.commands`
|
|
293
|
+
- `dsf.object_model`
|
|
294
|
+
- `dsf.http`
|
|
295
|
+
|
|
296
|
+
## Development Notes
|
|
297
|
+
|
|
298
|
+
The library talks to DSF using the configured UNIX socket path. By default this is
|
|
299
|
+
resolved from the DSF config and falls back to `/run/dsf/dcs.sock`.
|
|
300
|
+
|
|
301
|
+
If you are extending the library itself, the test suite under `tests/` contains
|
|
302
|
+
mock socket servers and object model fixtures that are useful for validating new
|
|
303
|
+
connection behaviour.
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# Duet Software Framework Python Bindings
|
|
2
|
+
|
|
3
|
+
`dsf-python` provides Python bindings for the Duet Software Framework control server.
|
|
4
|
+
It exposes the DSF socket protocol as Python connection classes, typed object model
|
|
5
|
+
classes, command builders, and helpers for custom HTTP endpoints.
|
|
6
|
+
|
|
7
|
+
This project is also published on [PyPI](https://pypi.org/project/dsf-python/).
|
|
8
|
+
|
|
9
|
+
Useful links:
|
|
10
|
+
|
|
11
|
+
- [Duet Software Framework](https://github.com/Duet3D/DuetSoftwareFramework)
|
|
12
|
+
- [dsf-python examples](https://github.com/Duet3D/dsf-python/tree/main/examples)
|
|
13
|
+
- [Duet Software Framework forum](https://forum.duet3d.com/category/31/dsf-development)
|
|
14
|
+
|
|
15
|
+
## What The Library Contains
|
|
16
|
+
|
|
17
|
+
The top-level package is organised around the main DSF workflows.
|
|
18
|
+
|
|
19
|
+
- `dsf.connections`: socket-based client connections for commands, subscriptions, and code interception
|
|
20
|
+
- `dsf.commands`: request payload builders for low-level DSF commands
|
|
21
|
+
- `dsf.object_model`: the typed DSF object model and related enums
|
|
22
|
+
- `dsf.http`: helpers for custom HTTP and WebSocket endpoints exposed through DSF
|
|
23
|
+
- `dsf.exceptions`: shared exception types raised by connection classes
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
The package can be installed from source:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
python3 setup.py install
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or with `pip`:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
python3 -m pip install dsf-python
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Most code using this library must run on a system with Duet Software Framework
|
|
40
|
+
installed and with permission to access the DSF UNIX socket.
|
|
41
|
+
|
|
42
|
+
## Quick Start
|
|
43
|
+
|
|
44
|
+
### Run A Simple Command
|
|
45
|
+
|
|
46
|
+
Use `CommandConnection` to send general-purpose commands such as G-code or to
|
|
47
|
+
request the full object model on demand.
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from dsf.connections import CommandConnection
|
|
51
|
+
|
|
52
|
+
connection = CommandConnection()
|
|
53
|
+
connection.connect()
|
|
54
|
+
|
|
55
|
+
response = connection.perform_simple_code("M115")
|
|
56
|
+
print(response.result)
|
|
57
|
+
|
|
58
|
+
connection.close()
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Read The Object Model Once
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from dsf.connections import CommandConnection
|
|
65
|
+
|
|
66
|
+
connection = CommandConnection()
|
|
67
|
+
connection.connect()
|
|
68
|
+
|
|
69
|
+
object_model = connection.get_object_model()
|
|
70
|
+
print(object_model.state.status)
|
|
71
|
+
print(object_model.move.axes[0].letter)
|
|
72
|
+
|
|
73
|
+
connection.close()
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Subscribe To Object Model Updates
|
|
77
|
+
|
|
78
|
+
Use `SubscribeConnection` when you want DSF to push object model updates over a
|
|
79
|
+
subscription socket.
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from dsf.connections import SubscribeConnection, SubscriptionMode
|
|
83
|
+
|
|
84
|
+
subscription = SubscribeConnection(SubscriptionMode.PATCH)
|
|
85
|
+
subscription.connect()
|
|
86
|
+
|
|
87
|
+
object_model = subscription.get_object_model()
|
|
88
|
+
|
|
89
|
+
while True:
|
|
90
|
+
object_model = subscription.get_object_model()
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
In `SubscriptionMode.PATCH`, the first `get_object_model()` call reads the full
|
|
94
|
+
model. Later calls reuse an internal cached model and apply one queued patch if
|
|
95
|
+
available.
|
|
96
|
+
|
|
97
|
+
## Connections
|
|
98
|
+
|
|
99
|
+
### CommandConnection
|
|
100
|
+
|
|
101
|
+
`CommandConnection` is the general-purpose connection type. It is used for:
|
|
102
|
+
|
|
103
|
+
- sending simple G-code
|
|
104
|
+
- requesting the full object model
|
|
105
|
+
- working with files, packages, plugins, and user sessions through DSF commands
|
|
106
|
+
- issuing lower-level requests through the command helpers in `dsf.commands`
|
|
107
|
+
|
|
108
|
+
Choose this connection when you want request-response behaviour and do not need
|
|
109
|
+
streamed updates.
|
|
110
|
+
|
|
111
|
+
### SubscribeConnection
|
|
112
|
+
|
|
113
|
+
`SubscribeConnection` receives streamed object model updates from DSF. It supports:
|
|
114
|
+
|
|
115
|
+
- `SubscriptionMode.FULL`: every update is a full object model
|
|
116
|
+
- `SubscriptionMode.PATCH`: every update is a partial JSON fragment
|
|
117
|
+
|
|
118
|
+
#### Key-Based Callbacks
|
|
119
|
+
|
|
120
|
+
`SubscribeConnection.subscribe_to_keys()` can run callbacks synchronously when
|
|
121
|
+
selected object model paths appear in a patch update processed by `get_object_model()`.
|
|
122
|
+
|
|
123
|
+
Key paths use dot notation and can include list indexes:
|
|
124
|
+
|
|
125
|
+
- `state.upTime`
|
|
126
|
+
- `heat.heaters.0.current`
|
|
127
|
+
- `move.axes.2.userPosition`
|
|
128
|
+
|
|
129
|
+
Use `^` in a list position to match any changed index:
|
|
130
|
+
|
|
131
|
+
- `heat.heaters.^.current`
|
|
132
|
+
- `tools.^.state`
|
|
133
|
+
|
|
134
|
+
Callbacks always receive keyword arguments:
|
|
135
|
+
|
|
136
|
+
- `key`: the subscribed key path that matched
|
|
137
|
+
- `data`: the changed value found at that path
|
|
138
|
+
- `indices`: a tuple of matched wildcard indexes, or `None` when the key does not use `^`
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from dsf.connections import SubscribeConnection, SubscriptionMode
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def handle_change(*, key, data, indices):
|
|
145
|
+
print(key, data, indices)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
subscription = SubscribeConnection(SubscriptionMode.PATCH)
|
|
149
|
+
subscription.connect()
|
|
150
|
+
subscription.get_object_model()
|
|
151
|
+
|
|
152
|
+
unsubscribe = subscription.subscribe_to_keys(
|
|
153
|
+
["heat.heaters.0.current", "state.upTime"],
|
|
154
|
+
handle_change,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
while True:
|
|
158
|
+
object_model = subscription.get_object_model()
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Wildcard example:
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
def handle_any_heater(*, key, data, indices):
|
|
165
|
+
print(key, indices, data)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
subscription.subscribe_to_keys(
|
|
169
|
+
["heat.heaters.^.current"],
|
|
170
|
+
handle_any_heater,
|
|
171
|
+
)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### InterceptConnection
|
|
175
|
+
|
|
176
|
+
`InterceptConnection` is used for custom code handling and code interception. Use it
|
|
177
|
+
when a plugin needs to receive G/M/T-code events before or after the firmware handles them.
|
|
178
|
+
|
|
179
|
+
Typical use cases include:
|
|
180
|
+
|
|
181
|
+
- implementing custom M-codes
|
|
182
|
+
- inspecting or rewriting commands
|
|
183
|
+
- reacting to executed code notifications
|
|
184
|
+
|
|
185
|
+
See `examples/custom_m_codes.py` for a complete example.
|
|
186
|
+
|
|
187
|
+
## Object Model
|
|
188
|
+
|
|
189
|
+
The `dsf.object_model` package mirrors the DSF object model in typed Python classes.
|
|
190
|
+
It lets you work with structured properties instead of manually traversing raw JSON.
|
|
191
|
+
|
|
192
|
+
Examples:
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
print(object_model.boards[0].name)
|
|
196
|
+
print(object_model.state.up_time)
|
|
197
|
+
print(object_model.move.axes[0].letter)
|
|
198
|
+
print(object_model.tools[0].state)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Object model instances support JSON-driven updates:
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
object_model.update_from_json({"state": {"upTime": 1234}})
|
|
205
|
+
print(object_model.state.up_time)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
This is the mechanism used internally when patch subscriptions are applied.
|
|
209
|
+
|
|
210
|
+
## Commands
|
|
211
|
+
|
|
212
|
+
The `dsf.commands` package contains low-level command builders for code execution,
|
|
213
|
+
file access, plugins, packages, object model manipulation, and other DSF protocol
|
|
214
|
+
requests.
|
|
215
|
+
|
|
216
|
+
Most users should start with the higher-level methods on `CommandConnection` or
|
|
217
|
+
`BaseCommandConnection`. Reach for `dsf.commands` directly when you need explicit
|
|
218
|
+
control over the payload sent to DSF.
|
|
219
|
+
|
|
220
|
+
## Custom HTTP Endpoints
|
|
221
|
+
|
|
222
|
+
The `dsf.http` module contains helpers for custom HTTP and WebSocket endpoints.
|
|
223
|
+
This is useful when a DSF plugin needs to expose an HTTP route that is handled by
|
|
224
|
+
Python code.
|
|
225
|
+
|
|
226
|
+
Key types include:
|
|
227
|
+
|
|
228
|
+
- `HttpEndpointUnixSocket`
|
|
229
|
+
- `HttpEndpointConnection`
|
|
230
|
+
- `ReceivedHttpRequest`
|
|
231
|
+
- `HttpResponseType`
|
|
232
|
+
|
|
233
|
+
See `examples/custom_http_endpoint.py` for a practical example.
|
|
234
|
+
|
|
235
|
+
## Included Examples
|
|
236
|
+
|
|
237
|
+
The `examples/` directory demonstrates the main workflows supported by the library.
|
|
238
|
+
|
|
239
|
+
- `send_simple_code.py`: send G-code over a command connection
|
|
240
|
+
- `subscribe_object_model.py`: subscribe to object model updates
|
|
241
|
+
- `custom_m_codes.py`: intercept and implement custom M-codes
|
|
242
|
+
- `custom_http_endpoint.py`: serve a custom HTTP endpoint through DSF
|
|
243
|
+
|
|
244
|
+
## API Reference
|
|
245
|
+
|
|
246
|
+
The Sphinx docs expose the package API for the major public modules:
|
|
247
|
+
|
|
248
|
+
- `dsf`
|
|
249
|
+
- `dsf.connections`
|
|
250
|
+
- `dsf.commands`
|
|
251
|
+
- `dsf.object_model`
|
|
252
|
+
- `dsf.http`
|
|
253
|
+
|
|
254
|
+
## Development Notes
|
|
255
|
+
|
|
256
|
+
The library talks to DSF using the configured UNIX socket path. By default this is
|
|
257
|
+
resolved from the DSF config and falls back to `/run/dsf/dcs.sock`.
|
|
258
|
+
|
|
259
|
+
If you are extending the library itself, the test suite under `tests/` contains
|
|
260
|
+
mock socket servers and object model fixtures that are useful for validating new
|
|
261
|
+
connection behaviour.
|
|
@@ -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.
|
|
9
|
+
version="3.7.0-beta.1",
|
|
10
10
|
description="Python interface to access DuetSoftwareFramework",
|
|
11
11
|
long_description=long_description,
|
|
12
12
|
long_description_content_type="text/markdown",
|
|
@@ -19,22 +19,19 @@ setuptools.setup(
|
|
|
19
19
|
"Topic :: Software Development :: Libraries",
|
|
20
20
|
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
|
|
21
21
|
"Programming Language :: Python :: 3",
|
|
22
|
-
"Programming Language :: Python :: 3.7",
|
|
23
|
-
"Programming Language :: Python :: 3.8",
|
|
24
|
-
"Programming Language :: Python :: 3.9",
|
|
25
|
-
"Programming Language :: Python :: 3.10",
|
|
26
22
|
"Programming Language :: Python :: 3.11",
|
|
27
23
|
"Programming Language :: Python :: 3.12",
|
|
28
24
|
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Programming Language :: Python :: 3.14",
|
|
29
26
|
"Programming Language :: Python :: 3 :: Only",
|
|
30
27
|
],
|
|
31
28
|
install_requires=[
|
|
32
|
-
'python-dateutil'
|
|
29
|
+
'python-dateutil',
|
|
33
30
|
],
|
|
34
31
|
keywords="Duet3D, DuetSoftwareFramework, DSF, dsf-python",
|
|
35
32
|
package_dir={"": "src"},
|
|
36
33
|
packages=setuptools.find_packages(where="src"),
|
|
37
|
-
python_requires=">=3.
|
|
34
|
+
python_requires=">=3.11, <4",
|
|
38
35
|
extras_require={
|
|
39
36
|
"dev": [
|
|
40
37
|
"sphinx",
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
__version__ = "3.
|
|
1
|
+
__version__ = "3.7.0-beta.1"
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
5
|
|
|
6
6
|
# Default socket file path
|
|
7
|
-
SOCKET_FILE = "/run/dsf/dcs.sock"
|
|
7
|
+
SOCKET_FILE: str = "/run/dsf/dcs.sock"
|
|
8
8
|
|
|
9
9
|
# Try to read socket file path from config
|
|
10
10
|
config_path = "/opt/dsf/conf/config.json"
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
1
3
|
class BaseCommand:
|
|
2
4
|
"""Base class of a command."""
|
|
3
5
|
|
|
4
6
|
@classmethod
|
|
5
|
-
def from_json(cls, data):
|
|
7
|
+
def from_json(cls, data: Any):
|
|
6
8
|
"""Deserialize an instance of this class from a JSON deserialized dictionary"""
|
|
7
9
|
return cls(**data)
|
|
8
10
|
|
|
9
|
-
def __init__(self, command: str, **kwargs):
|
|
11
|
+
def __init__(self, command: str, **kwargs: Any):
|
|
10
12
|
self.command = command
|
|
11
13
|
for key, value in kwargs.items():
|
|
12
14
|
self.__dict__[key] = value
|