classGreeter:def__init__(self,config):self.printer=config.get_printer()self.reactor=self.printer.get_reactor()self.gcode=self.printer.lookup_object('gcode')self.message=config.get('message','Welcome to Klipper!')self.gcode.register_command('GREET',self.cmd_GREET,desc=self.cmd_GREET_help)self.printer.register_event_handler('klippy:ready',self._ready_handler)def_ready_handler(self):waketime=self.reactor.monotonic()+1self.reactor.register_timer(self._greet,waketime)def_greet(self,eventtime=None):self.gcode.respond_info(self.message)returnself.reactor.NEVERcmd_GREET_help="Greet the user"defcmd_GREET(self,gcmd):self._greet()defload_config(config):returnGreeter(config)
Goals
For the BetterGreeter, we want the following features:
Ability to have multiple different greetings
Allow the user to choose if they want their greeting to display after Klipper starts, and if so, to set the delay
classGreeting:def__init__(self,config):self.printer=config.get_printer()self.reactor=self.printer.get_reactor()self.gcode=self.printer.lookup_object('gcode')self.name=config.get_name().split()[1]self.message=config.get('message','Welcome to Klipper!')self.delay=config.getint('delay',0)
Quiz
If there was a configuration option (int) named repeats, how would you get it in the initializer?
config.getint('repeats')
Here, the printer, reactor, gcode, and message variables are the same as in the previous Klippy extra. However, in this case, there are a couple new variables:
classGreeting:def__init__(self,config):self.printer=config.get_printer()self.reactor=self.printer.get_reactor()self.gcode=self.printer.lookup_object('gcode')self.name=config.get_name().split()[1]self.message=config.get('message','Welcome to Klipper!')self.delay=config.getint('delay',0)#(1)!self.gcode.register_mux_command('GREETING','NAME',self.name,self.cmd_GREETING,desc=self.cmd_GREETING_help)ifself.delay>0:self.printer.register_event_handler('klippy:ready',self._ready_handler)
register_mux_command is used here because there are multiplegreeting configuration sections, and each should be called separately.
Here, a few parts are similar to the example in Structure, but not identical. Let's start with the GCode command.
In the Structure example, the GCode command was registered with:
The difference here is that there can be multiplegreeting configuration sections, and as a result, multiple Greeting objects. To call each one separately, register_mux_command is used, passing the following parameters:
Macro name: "GREETING"
Parameter name: "NAME"
Parameter value: self.name
Function: self.cmd_GREETING
Description self.cmd_GREETING_help
Next, the register_event_handler is nearly identical to the Structure example, except in this case, it is run only ifself.delay>0.
Functions
The next part to creating this Klippy extra is the functions.
There are three functions in the Greeting class:
ready_handler
_greet
cmd_GREETING
Flowchart
graph TD
A[klippy:ready] --> B[_ready_handler]
B --> C[Wait self.delay seconds]
C --> D[_greet]
D --> E[Display self.message]
F[cmd_GREETING] --> E
classGreeting:def__init__(self,config):self.printer=config.get_printer()self.reactor=self.printer.get_reactor()self.gcode=self.printer.lookup_object('gcode')self.name=config.get_name().split()[1]self.message=config.get('message','Welcome to Klipper!')self.delay=config.getint('delay',0)self.gcode.register_mux_command('GREETING','NAME',self.name,self.cmd_GREETING,desc=self.cmd_GREETING_help)ifself.delay>0:self.printer.register_event_handler('klippy:ready',self._ready_handler)def_ready_handler(self):waketime=self.reactor.monotonic()+self.delayself.reactor.register_timer(self._greet,waketime)
This function takes no parameters, and runs when Klippy reports "klippy:ready".
Inside, the waketime variable is declared as self.reactor.monotonic()+self.delay. Let's break this declaration down:
self.reactor.monotonic() This is the current Klippy time
+self.delay This adds self.delay to the current time.
The result is that waketime contains the Klippy time for self.delay seconds in the future. Finally, we use self.reactor.register_timer to register this time, telling it to run self._greet() when the time occurs.
classGreeting:def__init__(self,config):self.printer=config.get_printer()self.reactor=self.printer.get_reactor()self.gcode=self.printer.lookup_object('gcode')self.name=config.get_name().split()[1]self.message=config.get('message','Welcome to Klipper!')self.delay=config.getint('delay',0)self.gcode.register_mux_command('GREETING','NAME',self.name,self.cmd_GREETING,desc=self.cmd_GREETING_help)ifself.delay>0:self.printer.register_event_handler('klippy:ready',self._ready_handler)def_ready_handler(self):waketime=self.reactor.monotonic()+self.delayself.reactor.register_timer(self._greet,waketime)def_greet(self,eventtime=None):self.gcode.respond_info(self.message)returnself.reactor.NEVER
This function takes an optional eventtime parameter (unused) (1), and prints out self.message to the Klipper console, using self.gcode.respond_info.
This is passed by Klippy when it calls _greet() after the timer occurs.
Tip
If you want the timer function to repeat, you can return the provided eventtime plus any number of seconds in the future, and it will repeat.
The final function in this class is the cmd_GREETING function:
classGreeting:def__init__(self,config):self.printer=config.get_printer()self.reactor=self.printer.get_reactor()self.gcode=self.printer.lookup_object('gcode')self.name=config.get_name().split()[1]self.message=config.get('message','Welcome to Klipper!')self.delay=config.getint('delay',0)self.gcode.register_mux_command('GREETING','NAME',self.name,self.cmd_GREETING,desc=self.cmd_GREETING_help)ifself.delay>0:self.printer.register_event_handler('klippy:ready',self._ready_handler)def_ready_handler(self):waketime=self.reactor.monotonic()+self.delayself.reactor.register_timer(self._greet,waketime)def_greet(self,eventtime=None):self.gcode.respond_info(self.message)returnself.reactor.NEVERcmd_GREETING_help="Greet the user"defcmd_GREETING(self,gcmd):self._greet()
This function simply calls self._greet(), which displays self.message to the Klipper terminal.
classGreeting:def__init__(self,config):self.printer=config.get_printer()self.reactor=self.printer.get_reactor()self.gcode=self.printer.lookup_object('gcode')self.name=config.get_name().split()[1]self.message=config.get('message','Welcome to Klipper!')self.delay=config.getint('delay',0)self.gcode.register_mux_command('GREETING','NAME',self.name,self.cmd_GREETING,desc=self.cmd_GREETING_help)ifself.delay>0:self.printer.register_event_handler('klippy:ready',self._ready_handler)def_ready_handler(self):waketime=self.reactor.monotonic()+self.delayself.reactor.register_timer(self._greet,waketime)def_greet(self,eventtime=None):self.gcode.respond_info(self.message)returnself.reactor.NEVERcmd_GREETING_help="Greet the user"defcmd_GREETING(self,gcmd):self._greet()defload_config_prefix(config):returnGreeting(config)
You can install it following these instructions, replacing greeter.py with greeting.py.