Last active
November 16, 2023 07:09
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Heater/sensor verification code | |
# | |
# Copyright (C) 2023 Lachlan van der Velden <[email protected]> | |
# | |
# 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