MQTT payload template based on input select?

So I’m trying to integrate my brewpiless into hass, it’s a small software running on a esp that takes care of a fridge dedicated for fermentation.
The software supports mqtt control (BrewPiLess/doc/MQTT.md at 690eb0edcefc2d700dd84755dd2a4b74d770dff7 · vitotai/BrewPiLess · GitHub) and I’ve made the input sliders for temperatures but I want to be able to set the mode:

Mode

The values can be 0,1,2,3 or o,f,b,p for ‘Off’, ‘Fridge Constant’, ‘Beer Constant’, and ‘Beer Profile’. If the mode is changed to ‘Beer Profile’, the current profile will be used and the profile starting time will be set to current time. That is, you should edit the profile beforehand, and expect the profile to be execute starting from the time it is set.

So I’ve made a input select like this:

input_select:
  fridge_mode:
    name: Fridge mode
    options:
      - 'Off'
      - 'Fridge constant'
      - 'Beer constant'
      - 'Beer profile'
    icon: mdi:beer

And then an automation with a payload template:

  - alias: Set fridge mode
    trigger:
      platform: state
      entity_id: input_select.fridge_mode
    action:
      - service: mqtt.publish
        data_template:
          topic: "/brewing/modeSet"
          payload_template: >-
            {% if states('input_select.fridge_mode', 'off') %}
              o      
            {% elif states('input_select.fridge_mode', 'Fridge constant') %}
              f 
            {% elif states('input_select.fridge_mode', 'Beer constant') %}
              b 
            {% elif states('input_select.fridge_mode', 'Beer profile') %}
              p 
            {% else %}
              b
            {% endif %}

but I just keep getting the following error:

Error while executing automation automation.set_fridge_mode. Unknown error for call_service at pos 1: 
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/automation/__init__.py", line 397, in async_trigger
    await self.action_script.async_run(variables, trigger_context)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 247, in async_run
    await self._handle_action(action, variables, context)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 331, in _handle_action
    await self._actions[_determine_action(action)](action, variables, context)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 413, in _async_call_service
    context=context,
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 86, in async_call_from_config
    template.render_complex(config[CONF_SERVICE_DATA_TEMPLATE], variables)
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 70, in render_complex
    return {key: render_complex(item, variables) for key, item in value.items()}
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 70, in <dictcomp>
    return {key: render_complex(item, variables) for key, item in value.items()}
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 72, in render_complex
    return value.async_render(variables)
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 221, in async_render
    return compiled.render(kwargs).strip()
  File "/usr/local/lib/python3.7/site-packages/jinja2/environment.py", line 1090, in render
    self.environment.handle_exception()
  File "/usr/local/lib/python3.7/site-packages/jinja2/environment.py", line 832, in handle_exception
    reraise(*rewrite_traceback_stack(source=source))
  File "/usr/local/lib/python3.7/site-packages/jinja2/_compat.py", line 28, in reraise
    raise value.with_traceback(tb)
  File "<template>", line 1, in top-level template code
  File "/usr/local/lib/python3.7/site-packages/jinja2/sandbox.py", line 462, in call
    return __context.call(__obj, *args, **kwargs)
TypeError: __call__() takes 2 positional arguments but 3 were given
1 Like

After some trial and error I found the solution, leaving it here if someone else wants to do the same!

  - alias: Set fridge mode
    trigger:
      platform: state
      entity_id: input_select.fridge_mode
    action:
    - service: mqtt.publish
      data:
        payload_template: >-
          {% if is_state("input_select.fridge_mode", "Off") %}
            o          
          {% elif is_state("input_select.fridge_mode", "Fridge constant") %}
            f
          {% elif is_state("input_select.fridge_mode", "Beer constant") %}
            b
          {% elif is_state("input_select.fridge_mode", "Beer profile") %}
            p
          {% endif %}
        topic: "/brewing/modeSet"
1 Like

Here’s another way to construct the template:

  - alias: 'Set fridge mode'
    trigger:
      platform: state
      entity_id: input_select.fridge_mode
    action:
      service: mqtt.publish
      data_template:
        topic: "/brewing/modeSet"
        payload: >-
          {% set options = {'Off':'o', 'Fridge constant':'f', 'Beer constant':'b', 'Beer profile':'p'} %}
          {{ options[trigger.to_state.state] if trigger.to_state_state in options.keys() else 'error' }}

In your first example, it tested for off instead of Off. It means if the trigger value is Off, the payload_template fails to produce a value. In other words, the template fails to report a default value if it encounters an unknown fridge mode.

In addition, if you specify data_template then you would use payload, not payload_template.

In the example I posted, if the received value of fridge_mode is not found in the options dictionary, the template will report a default value (error). This ensures the service call (mqtt.publish) works even if the fridge mode is unknown and also helps you to debug the problem when you see the topic brewing/modeSet contains a payload of error.

NOTE:

  • The first line of payload: defines a dictionary (key-value pairs) called options.
  • The second line uses the supplied fridge mode (trigger.to_state.state) to find its matching value within the options dictionary but only if the fridge mode exists as a key within the dictionary. If it does not exist, the template reports error.
3 Likes