Skip to content

Instantly share code, notes, and snippets.

@coman3
Last active November 16, 2023 07:09
Show Gist options
  • Save coman3/437adfbeff4089064656e1f988bb5eb6 to your computer and use it in GitHub Desktop.
Save coman3/437adfbeff4089064656e1f988bb5eb6 to your computer and use it in GitHub Desktop.
Klipper module that turns on relays that isolate AC heating elements when heat is requested.
# Heater/sensor verification code
#
# Copyright (C) 2023 Lachlan van der Velden <lachlan@velden.au>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import logging
PIN_MIN_TIME = 0.100
RESEND_HOST_TIME = 0.300 + PIN_MIN_TIME
MAX_SCHEDULE_TIME = 5.0
class HeaterIsolator:
def __init__(self, config):
self.printer = config.get_printer()
self.printer.register_event_handler("klippy:connect",
self.handle_connect)
self.printer.register_event_handler("klippy:shutdown",
self.handle_shutdown)
ppins = self.printer.lookup_object('pins')
pin_names = config.get("pins").split(',')
self.mcu_pins = []
max_mcu_duration = config.getfloat('maximum_mcu_duration', 0.,
minval=0.500,
maxval=MAX_SCHEDULE_TIME)
for pin in pin_names:
pin = ppins.setup_pin('digital_out', pin)
self.mcu_pins.append(pin)
pin.setup_max_duration(max_mcu_duration)
pin.setup_start_value(0., 0.)
if max_mcu_duration:
self.resend_interval = max_mcu_duration - RESEND_HOST_TIME
self.heater_name = config.get_name().split()[1]
self.heater = None
self.check_timer = None
self.last_value = 0.
self.last_print_time = 0.
self.reactor = self.printer.get_reactor()
self.resend_timer = None
self.resend_interval = 0.
gcode = self.printer.lookup_object('gcode')
gcode.register_mux_command("TOGGLE_ISOLATION", "ISOLATOR", config.get_name().split()[1],
self.cmd_TOGGLE_ISOLATION,
desc="Test toggle isolation")
def handle_connect(self):
pheaters = self.printer.lookup_object('heaters')
self.heater = pheaters.lookup_heater(self.heater_name)
logging.info("Starting heater isolator checks for %s", self.heater_name)
reactor = self.printer.get_reactor()
self.check_timer = reactor.register_timer(self.check_event, reactor.NOW)
def handle_shutdown(self):
if self.check_timer is not None:
reactor = self.printer.get_reactor()
reactor.update_timer(self.check_timer, reactor.NEVER)
def cmd_TOGGLE_ISOLATION(self, gcmd):
toolhead = self.printer.lookup_object('toolhead')
toolhead.register_lookahead_callback(
lambda print_time: self._update_all(print_time, not self.last_value))
def _resend_current_val(self, eventtime):
if self.last_value == 0:
self.reactor.unregister_timer(self.resend_timer)
self.resend_timer = None
return self.reactor.NEVER
systime = self.reactor.monotonic()
print_time = self.mcu_pins[0].get_mcu().estimated_print_time(systime)
time_diff = (self.last_print_time + self.resend_interval) - print_time
if time_diff > 0.:
# Reschedule for resend time
return systime + time_diff
self._update_all(print_time + PIN_MIN_TIME, self.last_value, True)
return systime + self.resend_interval
def _update_all(self, print_time, value, is_resend=False):
if value == self.last_value:
if not is_resend:
return
print_time = max(print_time, self.last_print_time + PIN_MIN_TIME)
for pin in self.mcu_pins:
pin.set_digital(print_time, value)
self.last_value = value
self.last_print_time = print_time
if self.resend_interval and self.resend_timer is None:
self.resend_timer = self.reactor.register_timer(
self._resend_current_val, self.reactor.NOW)
def check_event(self, eventtime):
temp, target = self.heater.get_temp(eventtime)
if(target > 0. and self.last_value <= 0.):
logging.info("Intergrating heater `%s` with pins: %s:", self.heater_name, self.mcu_pins)
toolhead = self.printer.lookup_object('toolhead')
toolhead.register_lookahead_callback(
lambda print_time: self._update_all(print_time, 1))
elif (target <= 0. and self.last_value > 0):
logging.info("Isolating heater: %s", self.heater_name)
toolhead = self.printer.lookup_object('toolhead')
toolhead.register_lookahead_callback(
lambda print_time: self._update_all(print_time, 0))
return eventtime + 1.
def load_config_prefix(config):
return HeaterIsolator(config)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment