|
|
|
@@ -1,6 +1,6 @@
|
|
|
|
# Tracking of PWM controlled heaters and their temperature control
|
|
|
|
# Tracking of PWM controlled heaters and their temperature control
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# Copyright (C) 2016-2020 Kevin O'Connor <kevin@koconnor.net>
|
|
|
|
# Copyright (C) 2016-2024 Kevin O'Connor <kevin@koconnor.net>
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
|
|
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
|
|
|
import os, logging, threading
|
|
|
|
import os, logging, threading
|
|
|
|
@@ -38,6 +38,7 @@ class Heater:
|
|
|
|
self.smooth_time = config.getfloat('smooth_time', 1., above=0.)
|
|
|
|
self.smooth_time = config.getfloat('smooth_time', 1., above=0.)
|
|
|
|
self.inv_smooth_time = 1. / self.smooth_time
|
|
|
|
self.inv_smooth_time = 1. / self.smooth_time
|
|
|
|
self.is_shutdown = False
|
|
|
|
self.is_shutdown = False
|
|
|
|
|
|
|
|
self.set_temp_count = 0
|
|
|
|
self.lock = threading.Lock()
|
|
|
|
self.lock = threading.Lock()
|
|
|
|
self.last_temp = self.smoothed_temp = self.target_temp = 0.
|
|
|
|
self.last_temp = self.smoothed_temp = self.target_temp = 0.
|
|
|
|
self.last_temp_time = 0.
|
|
|
|
self.last_temp_time = 0.
|
|
|
|
@@ -63,6 +64,9 @@ class Heater:
|
|
|
|
gcode.register_mux_command("SET_HEATER_TEMPERATURE", "HEATER",
|
|
|
|
gcode.register_mux_command("SET_HEATER_TEMPERATURE", "HEATER",
|
|
|
|
short_name, self.cmd_SET_HEATER_TEMPERATURE,
|
|
|
|
short_name, self.cmd_SET_HEATER_TEMPERATURE,
|
|
|
|
desc=self.cmd_SET_HEATER_TEMPERATURE_help)
|
|
|
|
desc=self.cmd_SET_HEATER_TEMPERATURE_help)
|
|
|
|
|
|
|
|
wh = self.printer.lookup_object('webhooks')
|
|
|
|
|
|
|
|
wh.register_mux_endpoint("heaters/set_target_temperature", "heater",
|
|
|
|
|
|
|
|
self.name, self._api_set_target_temperature)
|
|
|
|
self.printer.register_event_handler("klippy:shutdown",
|
|
|
|
self.printer.register_event_handler("klippy:shutdown",
|
|
|
|
self._handle_shutdown)
|
|
|
|
self._handle_shutdown)
|
|
|
|
def set_pwm(self, read_time, value):
|
|
|
|
def set_pwm(self, read_time, value):
|
|
|
|
@@ -106,6 +110,7 @@ class Heater:
|
|
|
|
raise self.printer.command_error(
|
|
|
|
raise self.printer.command_error(
|
|
|
|
"Requested temperature (%.1f) out of range (%.1f:%.1f)"
|
|
|
|
"Requested temperature (%.1f) out of range (%.1f:%.1f)"
|
|
|
|
% (degrees, self.min_temp, self.max_temp))
|
|
|
|
% (degrees, self.min_temp, self.max_temp))
|
|
|
|
|
|
|
|
self.set_temp_count += 1
|
|
|
|
with self.lock:
|
|
|
|
with self.lock:
|
|
|
|
self.target_temp = degrees
|
|
|
|
self.target_temp = degrees
|
|
|
|
def get_temp(self, eventtime):
|
|
|
|
def get_temp(self, eventtime):
|
|
|
|
@@ -143,11 +148,17 @@ class Heater:
|
|
|
|
last_pwm_value = self.last_pwm_value
|
|
|
|
last_pwm_value = self.last_pwm_value
|
|
|
|
return {'temperature': round(smoothed_temp, 2), 'target': target_temp,
|
|
|
|
return {'temperature': round(smoothed_temp, 2), 'target': target_temp,
|
|
|
|
'power': last_pwm_value}
|
|
|
|
'power': last_pwm_value}
|
|
|
|
|
|
|
|
def get_set_temp_count(self):
|
|
|
|
|
|
|
|
return self.set_temp_count
|
|
|
|
cmd_SET_HEATER_TEMPERATURE_help = "Sets a heater temperature"
|
|
|
|
cmd_SET_HEATER_TEMPERATURE_help = "Sets a heater temperature"
|
|
|
|
def cmd_SET_HEATER_TEMPERATURE(self, gcmd):
|
|
|
|
def cmd_SET_HEATER_TEMPERATURE(self, gcmd):
|
|
|
|
temp = gcmd.get_float('TARGET', 0.)
|
|
|
|
temp = gcmd.get_float('TARGET', 0.)
|
|
|
|
pheaters = self.printer.lookup_object('heaters')
|
|
|
|
pheaters = self.printer.lookup_object('heaters')
|
|
|
|
pheaters.set_temperature(self, temp)
|
|
|
|
pheaters.set_temperature(self, temp)
|
|
|
|
|
|
|
|
def _api_set_target_temperature(self, web_request):
|
|
|
|
|
|
|
|
temp = web_request.get_float('target')
|
|
|
|
|
|
|
|
pheaters = self.printer.lookup_object('heaters')
|
|
|
|
|
|
|
|
pheaters.set_temperature(self, temp)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
######################################################################
|
|
|
|
######################################################################
|
|
|
|
@@ -239,6 +250,7 @@ class PrinterHeaters:
|
|
|
|
self.available_heaters = []
|
|
|
|
self.available_heaters = []
|
|
|
|
self.available_sensors = []
|
|
|
|
self.available_sensors = []
|
|
|
|
self.available_monitors = []
|
|
|
|
self.available_monitors = []
|
|
|
|
|
|
|
|
self.in_temperature_wait = None
|
|
|
|
self.has_started = self.have_load_sensors = False
|
|
|
|
self.has_started = self.have_load_sensors = False
|
|
|
|
self.printer.register_event_handler("klippy:ready", self._handle_ready)
|
|
|
|
self.printer.register_event_handler("klippy:ready", self._handle_ready)
|
|
|
|
self.printer.register_event_handler("gcode:request_restart",
|
|
|
|
self.printer.register_event_handler("gcode:request_restart",
|
|
|
|
@@ -305,7 +317,8 @@ class PrinterHeaters:
|
|
|
|
def get_status(self, eventtime):
|
|
|
|
def get_status(self, eventtime):
|
|
|
|
return {'available_heaters': self.available_heaters,
|
|
|
|
return {'available_heaters': self.available_heaters,
|
|
|
|
'available_sensors': self.available_sensors,
|
|
|
|
'available_sensors': self.available_sensors,
|
|
|
|
'available_monitors': self.available_monitors}
|
|
|
|
'available_monitors': self.available_monitors,
|
|
|
|
|
|
|
|
'temperature_wait': self.in_temperature_wait}
|
|
|
|
def turn_off_all_heaters(self, print_time=0.):
|
|
|
|
def turn_off_all_heaters(self, print_time=0.):
|
|
|
|
for heater in self.heaters.values():
|
|
|
|
for heater in self.heaters.values():
|
|
|
|
heater.set_temp(0.)
|
|
|
|
heater.set_temp(0.)
|
|
|
|
@@ -336,14 +349,23 @@ class PrinterHeaters:
|
|
|
|
# Helper to wait on heater.check_busy() and report M105 temperatures
|
|
|
|
# Helper to wait on heater.check_busy() and report M105 temperatures
|
|
|
|
if self.printer.get_start_args().get('debugoutput') is not None:
|
|
|
|
if self.printer.get_start_args().get('debugoutput') is not None:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
full_name = heater.get_name()
|
|
|
|
|
|
|
|
set_temp_count = heater.get_set_temp_count()
|
|
|
|
toolhead = self.printer.lookup_object("toolhead")
|
|
|
|
toolhead = self.printer.lookup_object("toolhead")
|
|
|
|
gcode = self.printer.lookup_object("gcode")
|
|
|
|
gcode = self.printer.lookup_object("gcode")
|
|
|
|
reactor = self.printer.get_reactor()
|
|
|
|
reactor = self.printer.get_reactor()
|
|
|
|
eventtime = reactor.monotonic()
|
|
|
|
eventtime = reactor.monotonic()
|
|
|
|
while not self.printer.is_shutdown() and heater.check_busy(eventtime):
|
|
|
|
while not self.printer.is_shutdown() and heater.check_busy(eventtime):
|
|
|
|
|
|
|
|
self.in_temperature_wait = full_name
|
|
|
|
print_time = toolhead.get_last_move_time()
|
|
|
|
print_time = toolhead.get_last_move_time()
|
|
|
|
gcode.respond_raw(self._get_temp(eventtime))
|
|
|
|
gcode.respond_raw(self._get_temp(eventtime))
|
|
|
|
eventtime = reactor.pause(eventtime + 1.)
|
|
|
|
eventtime = reactor.pause(eventtime + 1.)
|
|
|
|
|
|
|
|
if heater.get_set_temp_count() != set_temp_count:
|
|
|
|
|
|
|
|
self.in_temperature_wait = None
|
|
|
|
|
|
|
|
raise self.printer.command_error(
|
|
|
|
|
|
|
|
"Heater '%s' target temperature changed during wait"
|
|
|
|
|
|
|
|
% (full_name,))
|
|
|
|
|
|
|
|
self.in_temperature_wait = None
|
|
|
|
def set_temperature(self, heater, temp, wait=False):
|
|
|
|
def set_temperature(self, heater, temp, wait=False):
|
|
|
|
toolhead = self.printer.lookup_object('toolhead')
|
|
|
|
toolhead = self.printer.lookup_object('toolhead')
|
|
|
|
toolhead.register_lookahead_callback((lambda pt: None))
|
|
|
|
toolhead.register_lookahead_callback((lambda pt: None))
|
|
|
|
@@ -362,8 +384,12 @@ class PrinterHeaters:
|
|
|
|
"Error on 'TEMPERATURE_WAIT': missing MINIMUM or MAXIMUM.")
|
|
|
|
"Error on 'TEMPERATURE_WAIT': missing MINIMUM or MAXIMUM.")
|
|
|
|
if self.printer.get_start_args().get('debugoutput') is not None:
|
|
|
|
if self.printer.get_start_args().get('debugoutput') is not None:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
full_name = sensor_name
|
|
|
|
|
|
|
|
set_temp_count = None
|
|
|
|
if sensor_name in self.heaters:
|
|
|
|
if sensor_name in self.heaters:
|
|
|
|
sensor = self.heaters[sensor_name]
|
|
|
|
sensor = self.heaters[sensor_name]
|
|
|
|
|
|
|
|
full_name = sensor.get_name()
|
|
|
|
|
|
|
|
set_temp_count = sensor.get_set_temp_count()
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
sensor = self.printer.lookup_object(sensor_name)
|
|
|
|
sensor = self.printer.lookup_object(sensor_name)
|
|
|
|
toolhead = self.printer.lookup_object("toolhead")
|
|
|
|
toolhead = self.printer.lookup_object("toolhead")
|
|
|
|
@@ -372,10 +398,18 @@ class PrinterHeaters:
|
|
|
|
while not self.printer.is_shutdown():
|
|
|
|
while not self.printer.is_shutdown():
|
|
|
|
temp, target = sensor.get_temp(eventtime)
|
|
|
|
temp, target = sensor.get_temp(eventtime)
|
|
|
|
if temp >= min_temp and temp <= max_temp:
|
|
|
|
if temp >= min_temp and temp <= max_temp:
|
|
|
|
return
|
|
|
|
break
|
|
|
|
|
|
|
|
self.in_temperature_wait = full_name
|
|
|
|
print_time = toolhead.get_last_move_time()
|
|
|
|
print_time = toolhead.get_last_move_time()
|
|
|
|
gcmd.respond_raw(self._get_temp(eventtime))
|
|
|
|
gcmd.respond_raw(self._get_temp(eventtime))
|
|
|
|
eventtime = reactor.pause(eventtime + 1.)
|
|
|
|
eventtime = reactor.pause(eventtime + 1.)
|
|
|
|
|
|
|
|
if (set_temp_count is not None
|
|
|
|
|
|
|
|
and sensor.get_set_temp_count() != set_temp_count):
|
|
|
|
|
|
|
|
self.in_temperature_wait = None
|
|
|
|
|
|
|
|
raise self.printer.command_error(
|
|
|
|
|
|
|
|
"Heater '%s' target temperature changed during wait"
|
|
|
|
|
|
|
|
% (full_name,))
|
|
|
|
|
|
|
|
self.in_temperature_wait = None
|
|
|
|
|
|
|
|
|
|
|
|
def load_config(config):
|
|
|
|
def load_config(config):
|
|
|
|
return PrinterHeaters(config)
|
|
|
|
return PrinterHeaters(config)
|
|
|
|
|