led: Support setting display_template parameters via SET_LED_TEMPLATE

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2022-03-25 11:46:45 -04:00
parent 1ab3ac39e4
commit e6bfc4c9aa
3 changed files with 35 additions and 16 deletions

View File

@ -716,7 +716,7 @@ idle timeout.
#### SET_LED_TEMPLATE #### SET_LED_TEMPLATE
`SET_LED_TEMPLATE LED=<led_name> TEMPLATE=<template_name> `SET_LED_TEMPLATE LED=<led_name> TEMPLATE=<template_name>
[INDEX=<index>]`: Assign a [<param_x>=<literal>] [INDEX=<index>]`: Assign a
[display_template](Config_Reference.md#display_template) to a given [display_template](Config_Reference.md#display_template) to a given
[LED](Config_Reference.md#leds). For example, if one defined a [LED](Config_Reference.md#leds). For example, if one defined a
`[display_template my_led_template]` config section then one could `[display_template my_led_template]` config section then one could
@ -724,12 +724,14 @@ assign `TEMPLATE=my_led_template` here. The display_template should
produce a comma separated string containing four floating point produce a comma separated string containing four floating point
numbers corresponding to red, green, blue, and white color settings. numbers corresponding to red, green, blue, and white color settings.
The template will be continuously evaluated and the LED will be The template will be continuously evaluated and the LED will be
automatically set to the resulting colors. If INDEX is not specified automatically set to the resulting colors. One may set
then all chips in the LED's daisy-chain will be set to the template, display_template parameters to use during template evaluation
otherwise only the chip with the given index will be updated. If (parameters will be parsed as Python literals). If INDEX is not
TEMPLATE is an empty string then this command will clear any previous specified then all chips in the LED's daisy-chain will be set to the
template assigned to the LED (one can then use `SET_LED` commands to template, otherwise only the chip with the given index will be
manage the LED's color settings). updated. If TEMPLATE is an empty string then this command will clear
any previous template assigned to the LED (one can then use `SET_LED`
commands to manage the LED's color settings).
### [output_pin] ### [output_pin]

View File

@ -39,6 +39,8 @@ class DisplayTemplate:
option, config.get_name())) option, config.get_name()))
gcode_macro = self.printer.load_object(config, 'gcode_macro') gcode_macro = self.printer.load_object(config, 'gcode_macro')
self.template = gcode_macro.load_template(config, 'text') self.template = gcode_macro.load_template(config, 'text')
def get_params(self):
return self.params
def render(self, context, **kwargs): def render(self, context, **kwargs):
params = dict(self.params) params = dict(self.params)
params.update(**kwargs) params.update(**kwargs)

View File

@ -3,7 +3,7 @@
# Copyright (C) 2019-2022 Kevin O'Connor <kevin@koconnor.net> # Copyright (C) 2019-2022 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 logging import logging, ast
from .display import display from .display import display
# Time between each led template update # Time between each led template update
@ -92,10 +92,11 @@ class PrinterLED:
return return
reactor = self.printer.get_reactor() reactor = self.printer.get_reactor()
self.render_timer = reactor.register_timer(self._render, reactor.NOW) self.render_timer = reactor.register_timer(self._render, reactor.NOW)
def _activate_template(self, led_helper, index, template): def _activate_template(self, led_helper, index, template, lparams):
key = (led_helper, index) key = (led_helper, index)
if template is not None: if template is not None:
self.active_templates[key] = template uid = (template,) + tuple(sorted(lparams.items()))
self.active_templates[key] = (uid, template, lparams)
return return
if key in self.active_templates: if key in self.active_templates:
del self.active_templates[key] del self.active_templates[key]
@ -114,11 +115,12 @@ class PrinterLED:
# Render all templates # Render all templates
need_transmit = {} need_transmit = {}
rendered = {} rendered = {}
for (led_helper, index), template in self.active_templates.items(): template_info = self.active_templates.items()
color = rendered.get(template) for (led_helper, index), (uid, template, lparams) in template_info:
color = rendered.get(uid)
if color is None: if color is None:
try: try:
text = template.render(context) text = template.render(context, **lparams)
parts = [max(0., min(1., float(f))) parts = [max(0., min(1., float(f)))
for f in text.split(',', 4)] for f in text.split(',', 4)]
except Exception as e: except Exception as e:
@ -126,7 +128,7 @@ class PrinterLED:
parts = [] parts = []
if len(parts) < 4: if len(parts) < 4:
parts += [0.] * (4 - len(parts)) parts += [0.] * (4 - len(parts))
rendered[template] = color = tuple(parts) rendered[uid] = color = tuple(parts)
prev_color = led_helper.led_state[index-1] prev_color = led_helper.led_state[index-1]
if color != prev_color: if color != prev_color:
if led_helper not in need_transmit: if led_helper not in need_transmit:
@ -150,16 +152,29 @@ class PrinterLED:
led_count = led_helper.led_count led_count = led_helper.led_count
index = gcmd.get_int("INDEX", None, minval=1, maxval=led_count) index = gcmd.get_int("INDEX", None, minval=1, maxval=led_count)
template = None template = None
lparams = {}
tpl_name = gcmd.get("TEMPLATE") tpl_name = gcmd.get("TEMPLATE")
if tpl_name: if tpl_name:
template = self.templates.get(tpl_name) template = self.templates.get(tpl_name)
if template is None: if template is None:
raise gcmd.error("Unknown display_template '%s'" % (tpl_name,)) raise gcmd.error("Unknown display_template '%s'" % (tpl_name,))
tparams = template.get_params()
for p, v in gcmd.get_command_parameters().items():
if not p.startswith("PARAM_"):
continue
p = p.lower()
if p not in tparams:
raise gcmd.error("Invalid display_template parameter: %s"
% (p,))
try:
lparams[p] = ast.literal_eval(v)
except ValueError as e:
raise gcmd.error("Unable to parse '%s' as a literal" % (v,))
if index is not None: if index is not None:
self._activate_template(led_helper, index, template) self._activate_template(led_helper, index, template, lparams)
else: else:
for i in range(led_count): for i in range(led_count):
self._activate_template(led_helper, i+1, template) self._activate_template(led_helper, i+1, template, lparams)
self._activate_timer() self._activate_timer()
PIN_MIN_TIME = 0.100 PIN_MIN_TIME = 0.100