mirror of
https://github.com/Klipper3d/klipper.git
synced 2025-07-10 00:07:54 -06:00

Allows a limited number of DS18B20 read failures before stopping the printer. This is designed to tolerate spurious read errors, while still stopping for serious issues. The printer will stop when the sensor fails to report a value five times in a row. Implementation works as follows: The MCU reports any read errors using a new "fault" parameter in its answers. The Python code tracks the number of errors and triggers the shutdown. This paves the way for more sophisticated error handling in the future, as well as an example for other sensors to follow. Signed-off-by: Lorenzo Pfeifer <Lorenzo.Pfeifer+github@googlemail.com>
81 lines
3 KiB
Python
81 lines
3 KiB
Python
# Support for 1-wire based temperature sensors
|
|
#
|
|
# Copyright (C) 2020 Alan Lord <alanslists@gmail.com>
|
|
#
|
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
|
import logging
|
|
import mcu
|
|
|
|
DS18_REPORT_TIME = 3.0
|
|
# Temperature can be sampled at any time but conversion time is ~750ms, so
|
|
# setting the time too low will not make the reports come faster.
|
|
DS18_MIN_REPORT_TIME = 1.0
|
|
DS18_MAX_CONSECUTIVE_ERRORS = 4
|
|
|
|
class DS18B20:
|
|
def __init__(self, config):
|
|
self.printer = config.get_printer()
|
|
self.name = config.get_name().split()[-1]
|
|
self.sensor_id = bytearray(config.get("serial_no").encode())
|
|
self.temp = self.min_temp = self.max_temp = 0.0
|
|
self._report_clock = 0
|
|
self.report_time = config.getfloat(
|
|
'ds18_report_time',
|
|
DS18_REPORT_TIME,
|
|
minval=DS18_MIN_REPORT_TIME
|
|
)
|
|
self._mcu = mcu.get_printer_mcu(self.printer, config.get('sensor_mcu'))
|
|
self.oid = self._mcu.create_oid()
|
|
self._mcu.register_response(self._handle_ds18b20_response,
|
|
"ds18b20_result", self.oid)
|
|
self._mcu.register_config_callback(self._build_config)
|
|
|
|
def _build_config(self):
|
|
sid = "".join(["%02x" % (x,) for x in self.sensor_id])
|
|
self._mcu.add_config_cmd("config_ds18b20 oid=%d serial=%s"
|
|
% (self.oid, sid, DS18_MAX_CONSECUTIVE_ERRORS))
|
|
|
|
clock = self._mcu.get_query_slot(self.oid)
|
|
self._report_clock = self._mcu.seconds_to_clock(self.report_time)
|
|
self._mcu.add_config_cmd("query_ds18b20 oid=%d clock=%u rest_ticks=%u"
|
|
" min_value=%d max_value=%d" % (
|
|
self.oid, clock, self._report_clock,
|
|
self.min_temp * 1000, self.max_temp * 1000), is_init=True)
|
|
|
|
def _handle_ds18b20_response(self, params):
|
|
temp = params['value'] / 1000.0
|
|
|
|
if params["fault"] != 0:
|
|
temp = 0 # read error! report 0C and don't check temp range
|
|
elif temp < self.min_temp or temp > self.max_temp:
|
|
self.printer.invoke_shutdown(
|
|
"DS18B20 temperature %0.1f outside range of %0.1f:%.01f"
|
|
% (temp, self.min_temp, self.max_temp))
|
|
|
|
next_clock = self._mcu.clock32_to_clock64(params['next_clock'])
|
|
last_read_clock = next_clock - self._report_clock
|
|
last_read_time = self._mcu.clock_to_print_time(last_read_clock)
|
|
self._callback(last_read_time, temp)
|
|
|
|
def setup_minmax(self, min_temp, max_temp):
|
|
self.min_temp = min_temp
|
|
self.max_temp = max_temp
|
|
|
|
def fault(self, msg):
|
|
self.printer.invoke_async_shutdown(msg)
|
|
|
|
def get_report_time_delta(self):
|
|
return self.report_time
|
|
|
|
def setup_callback(self, cb):
|
|
self._callback = cb
|
|
|
|
def get_status(self, eventtime):
|
|
return {
|
|
'temperature': round(self.temp, 2),
|
|
}
|
|
|
|
def load_config(config):
|
|
# Register sensor
|
|
pheaters = config.get_printer().load_object(config, "heaters")
|
|
pheaters.add_sensor_factory("DS18B20", DS18B20)
|