openHASP-custom-component icon indicating copy to clipboard operation
openHASP-custom-component copied to clipboard

Plate config file error after update to 0.7.6 custom component

Open Taffy9325 opened this issue 1 year ago • 3 comments

Version of the custom_component

0.7.6

Configuration


plate1: #Bedroom
  objects:
    - obj: "p0b1" # temperature label on all pages
      properties:
        "text": '{{ states("sensor.bedroom_temperature_temperature_2") }}°C'
    - obj: "p0b6" # time
      properties:
        "text": "{{ states('sensor.time') }}"
    - obj: "p1b2" # light-switch toggle button
      properties:
        "val": '{{ 1 if states("light.bedroom_light") == "on" else 0 }}'
        "text": '{{ "\uE6E8 Light" if is_state("light.bedroom_light", "on") else "\uE335 Light" | e }}'
      event:
        "up":
          - service: homeassistant.toggle
            entity_id: "light.bedroom_light"

    - obj: "p1b5" # toggle button for ON/OFF switching of light I.
      properties:
        "val": '{{ 1 if is_state("light.rhys_shelly_lamp", "on") else 0 }}'
      event:
        "down":
          - service: homeassistant.toggle
            entity_id: "light.rhys_shelly_lamp"

    - obj: "p1b6" # toggle button for ON/OFF switching of light II.
      properties:
        "val": '{{ 1 if is_state("light.jess_shelly_lamp", "on") else 0 }}'
      event:
        "down":
          - service: homeassistant.toggle
            entity_id: "light.jess_shelly_lamp"

    - obj: "p2b20" # arc slider
      properties:
        "val": >
          {% if state_attr('climate.bedroom_thermostat','temperature') is not none %}
          {{ state_attr('climate.bedroom_thermostat','temperature') | int * 10 }}
          {%- endif %}
        "min": >
          {% if state_attr('climate.bedroom_thermostat','min_temp') is not none %}
          {{ state_attr('climate.bedroom_thermostat','min_temp') | int * 10 }}
          {%- endif %}
        "max": >
          {% if state_attr('climate.bedroom_thermostat','max_temp') is not none %}
          {{ state_attr('climate.bedroom_thermostat','max_temp') | int * 10 }}
          {%- endif %}
        "opacity": "{{ 60 if (is_state('climate.bedroom_thermostat','unavailable') or is_state('climate.bedroom_thermostat','unknown')) else 255 }}"
        "click": "{{ 'false' if (is_state('climate.bedroom_thermostat','unavailable') or is_state('climate.bedroom_thermostat','unknown')) else 'true' }}"
        "line_color1": >
          {% if is_state('climate.bedroom_thermostat', 'cool') %}
          {{ "#346beb" }}
          {%-elif is_state('climate.bedroom_thermostat', 'heat_cool') %}
          {{ "#34bdeb" }}
          {%-elif is_state('climate.bedroom_thermostat', 'heat') %}
          {{ "#eb3434" }}
          {%-elif is_state('climate.bedroom_thermostat', 'dry') %}
          {{ "#ebeb34" }}
          {%-elif is_state('climate.bedroom_thermostat', 'fan_only') %}
          {{ "#34eb77" }}
          {%-else %}
          {{ "#9f96b0" }}
          {% endif %}
      event:
        "changed":
          - service: climate.set_temperature
            target:
              entity_id: climate.bedroom_thermostat
            data:
              temperature: "{{ val | int / 10 }}"
        "up":
          - service: climate.set_temperature
            target:
              entity_id: climate.bedroom_thermostat
            data:
              temperature: "{{ val | int / 10 }}"

    - obj: "p2b21" # gauge current temp
      properties:
        "val": >
          {% if not (is_state('sensor.bedroom_temperature_temperature_2','unavailable') or is_state('sensor.bedroom_temperature_temperature_2','unknown')) %}
          {{ states('sensor.bedroom_temperature_temperature_2') | float (default=0) * 10 }}
          {%- endif %}
        "min": >
          {% if state_attr('climate.bedroom_thermostat','min_temp') is not none %}
          {{ state_attr('climate.bedroom_thermostat','min_temp') | int * 10 }}
          {%- endif %}
        "max": >
          {% if state_attr('climate.bedroom_thermostat','max_temp') is not none %}
          {{ state_attr('climate.bedroom_thermostat','max_temp') | int * 10 }}
          {%- endif %}
        "critical_value": >
          {% if state_attr('climate.bedroom_thermostat','max_temp') is not none %}
          {{ state_attr('climate.bedroom_thermostat','max_temp') | int * 10 + 1 }}
          {%- endif %}
        "label_count": >
          {% if state_attr('climate.bedroom_thermostat','max_temp') is not none %}
          {{ state_attr('climate.bedroom_thermostat','max_temp') | int - state_attr('climate.bedroom_thermostat','min_temp') | int + 1 }}
          {%- endif %}
        "line_count": >
          {% if state_attr('climate.bedroom_thermostat','max_temp') is not none %}
          {{ (state_attr('climate.bedroom_thermostat','max_temp') | int - state_attr('climate.bedroom_thermostat','min_temp') | int) * 2 + 1 }}
          {%- endif %}
        "opacity": "{{ 60 if (is_state('climate.bedroom_thermostat','unavailable') or is_state('climate.bedroom_thermostat','unknown')) else 255 }}"

    - obj: "p2b23" # label current temp (and +/- with short/long touch)
      properties:
        "text": >
          {% if (is_state('sensor.bedroom_temperature_temperature_2','unavailable') or is_state('sensor.bedroom_temperature_temperature_2','unknown')) %}
          {{ "--.-" }}
          {%-else %}
          {{ states('sensor.bedroom_temperature_temperature_2') | round(1,default=0) }}
          {%- endif %}
        "click": "{{ 'false' if (is_state('climate.bedroom_thermostat','unavailable') or is_state('climate.bedroom_thermostat','unknown')) else 'true' }}"
        "opacity": "{{ 60 if (is_state('climate.bedroom_thermostat','unavailable') or is_state('climate.bedroom_thermostat','unknown')) else 255 }}"
      event:
        "up":
          - service: climate.set_temperature
            target:
              entity_id: climate.bedroom_thermostat
            data:
              temperature: "{{ state_attr('climate.bedroom_thermostat','temperature') + state_attr('climate.bedroom_thermostat','target_temp_step') | float(default=1)}}"
        "long":
          - service: climate.set_temperature
            target:
              entity_id: climate.bedroom_thermostat
            data:
              temperature: "{{ state_attr('climate.bedroom_thermostat','temperature') - state_attr('climate.bedroom_thermostat','target_temp_step') | float(default=1)}}"

    - obj: "p2b25" # label target temp
      properties:
        "text": >
          {% if state_attr('climate.bedroom_thermostat','temperature') is not none %}
          {{ state_attr('climate.bedroom_thermostat','temperature') }}
          {%- endif %}
        "opacity": "{{ 60 if (is_state('climate.bedroom_thermostat','unavailable') or is_state('climate.bedroom_thermostat','unknown')) else 255 }}"

    - obj: "p2b41" # on/off switch
      properties:
        "val": "{{ 0 if (is_state('climate.bedroom_thermostat', 'off') or is_state('climate.bedroom_thermostat', 'unavailable')) else 1 }}"
        "click": "{{ 'false' if (is_state('climate.bedroom_thermostat','unavailable') or is_state('climate.bedroom_thermostat','unknown')) else 'true' }}"
        "opacity": "{{ 60 if (is_state('climate.bedroom_thermostat','unavailable') or is_state('climate.bedroom_thermostat','unknown')) else 255 }}"
      event:
        "down":
          - service_template: >
              {% if val == 0 -%}
              climate.turn_on
              {% else -%}
              climate.turn_off
              {% endif -%}
            entity_id: "climate.bedroom_thermostat"

    - obj: "p2b30" # tab dots
      event:
        "changed":
          - service: openhasp.command
            target:
              entity_id: openhasp.your_plate
            data:
              keyword: p3b26.text
              parameters: >
                {% if val == 0 %}
                {{ "#000000 \u2022# #909090 \u2022# #909090 \u2022#" | e }}
                {%-elif val == 1 %}
                {{ "#909090 \u2022# #000000 \u2022# #909090 \u2022#" | e }}
                {%-elif val == 2 %}
                {{ "#909090 \u2022# #909090 \u2022# #000000 \u2022#" | e }}
                {% endif %}

    - obj: "p2b42" # dropdown with fan_modes
      properties:
        "options": >
          {% if state_attr('climate.bedroom_thermostat','fan_modes') is not none %}{%for mode in state_attr('climate.bedroom_thermostat','fan_modes')%}
          {%- if mode == 'auto' -%}
          Automatic{{"\n"|e}}
          {%- elif mode == 'low' -%}
          Low{{"\n"|e}}
          {%- elif mode == 'medium' -%}
          Medium{{"\n"|e}}
          {%- elif mode == 'high' -%}
          High{{"\n"|e}}
          {%- elif mode == 'turbo' -%}
          Turbo{{"\n"|e}}
          {%- endif -%}
          {%-if not loop.last%}{%-endif%}{%-endfor%}{% endif %}
        "click": "{{ 'false' if (is_state('climate.bedroom_thermostat','unavailable') or is_state('climate.bedroom_thermostat','unknown')) else 'true' }}"
        "val": >
          {% if not (is_state('climate.bedroom_thermostat','unavailable')) %}{%for mode in state_attr('climate.bedroom_thermostat','fan_modes')%}
          {{loop.index -1 if mode == state_attr('climate.bedroom_thermostat','fan_mode') }}
          {%-endfor%}{% endif %}
      event:
        "changed":
          - service: climate.set_fan_mode
            target:
              entity_id: climate.bedroom_thermostat
            data:
              fan_mode: >
                {% if text == "Automatic" -%}
                auto
                {% elif text == 'Low' -%}
                low
                {% elif text == 'Medium' -%}
                medium
                {% elif text == 'High' -%}
                high
                {% elif text == 'Turbo' -%}
                turbo
                {% endif -%}

    - obj: "p2b43" # dropdown with hvac_modes
      properties:
        "options": >
          {% if state_attr('climate.bedroom_thermostat','hvac_modes') is not none %}{%for mode in state_attr('climate.bedroom_thermostat','hvac_modes')%}
          {%- if mode == 'off' -%}
          Off{{"\n"|e}}
          {%- elif mode == 'heat' -%}
          Heating{{"\n"|e}}
          {%- elif mode == 'cool' -%}
          Cooling{{"\n"|e}}
          {%- elif mode == 'heat_cool' -%}
          Heat/Cool{{"\n"|e}}
          {%- elif mode == 'dry' -%}
          Drying{{"\n"|e}}
          {%- elif mode == 'fan_only' -%}
          Fan only{{"\n"|e}}
          {%- else -%}
          On{{"\n"|e}}
          {%- endif -%}
          {%-if not loop.last%}{%-endif%}{%-endfor%}{% endif %}
        "click": "{{ 'false' if (is_state('climate.bedroom_thermostat','unavailable') or is_state('climate.bedroom_thermostat','unknown')) else 'true' }}"
        "val": >
          {% if not (is_state('climate.bedroom_thermostat','unavailable')) %}{%for mode in state_attr('climate.bedroom_thermostat','hvac_modes')%}
          {{loop.index -1 if mode == states('climate.bedroom_thermostat') }}
          {%-endfor%}{% endif %}
      event:
        "changed":
          - service: climate.set_hvac_mode
            target:
              entity_id: climate.bedroom_thermostat
            data:
              hvac_mode: >
                {% if text == "Off" -%}
                off
                {% elif text == 'Heating' -%}
                heat
                {% elif text == 'Cooling' -%}
                cool
                {% elif text == 'Heat/Cool' -%}
                heat_cool
                {% elif text == 'Drying' -%}
                dry
                {% elif text == 'Fan only' -%}
                fan_only
                {% endif -%}

    - obj: "p3b10" # bed heater-switch toggle button
      properties:
        "val": '{{ 1 if states("switch.bed_heater_shelly_7") == "on" else 0 }}'
        "text": '{{ "\uE438 Bed Heater" if is_state("switch.bed_heater_shelly_7", "on") else "\uEAD7 Bed Heater" | e }}'
      event:
        "up":
          - service: homeassistant.toggle
            entity_id: "switch.bed_heater_shelly_7"

    - obj: "p3b12" # Movie night button
      event:
        "down":
          - service: input_button.press
            entity_id: "input_button.movie_night"

    - obj: "p3b13" # Romance night button
      event:
        "down":
          - service: input_button.press
            entity_id: "input_button.romance_night"

    - obj: "p3b14" # Game night button
      event:
        "down":
          - service: input_button.press
            entity_id: "input_button.gaming_bedroom"

Describe the bug

Upgraded to 0.7.6. Error log states page file is no longer valid. Screen showing page layouts buttons and switches but no data being sent. IE temp sensor showing blank

Debug log

Logger: custom_components.openhasp
Source: custom_components/openhasp/__init__.py:638
integration: openHASP ([documentation](https://www.openhasp.com/), [issues](https://github.com/HASwitchPlate/openHASP-custom-component/issues))
First occurred: 10:17:55 AM (4 occurrences)
Last logged: 11:09:28 AM

'/config/openhaspconfig/bedroomtouchscreen.jsonl' is not an allowed directory

Logger: homeassistant.helpers.event
Source: helpers/template.py:621
First occurred: 10:17:55 AM (4 occurrences)
Last logged: 11:09:28 AM

Error while processing template: Template<template=({% if not (is_state('climate.bedroom_thermostat','unavailable')) %}{%for mode in state_attr('climate.bedroom_thermostat','fan_modes')%} {{loop.index -1 if mode == state_attr('climate.bedroom_thermostat','fan_mode') }} {%-endfor%}{% endif %}) renders=2>
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 619, in async_render
    render_result = _render_with_context(self.template, compiled, **kwargs)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 2654, in _render_with_context
    return template.render(**kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/jinja2/environment.py", line 1304, in render
    self.environment.handle_exception()
  File "/usr/local/lib/python3.12/site-packages/jinja2/environment.py", line 939, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "<template>", line 1, in top-level template code
  File "/usr/local/lib/python3.12/site-packages/jinja2/runtime.py", line 422, in __init__
    self._iterator = self._to_iterator(iterable)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/jinja2/runtime.py", line 430, in _to_iterator
    return iter(iterable)
           ^^^^^^^^^^^^^^
TypeError: 'NoneType' object is not iterable

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 731, in async_render_to_info
    render_info._result = self.async_render(  # noqa: SLF001
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 621, in async_render
    raise TemplateError(err) from err
homeassistant.exceptions.TemplateError: TypeError: 'NoneType' object is not iterable

Logger: custom_components.openhasp
Source: custom_components/openhasp/__init__.py:753
integration: openHASP ([documentation](https://www.openhasp.com/), [issues](https://github.com/HASwitchPlate/openHASP-custom-component/issues))
First occurred: 10:17:55 AM (4 occurrences)
Last logged: 11:09:28 AM

TemplateError('TypeError: 'NoneType' object is not iterable') while processing template 'Template<template=({% if not (is_state('climate.bedroom_thermostat','unavailable')) %}{%for mode in state_attr('climate.bedroom_thermostat','fan_modes')%} {{loop.index -1 if mode == state_attr('climate.bedroom_thermostat','fan_mode') }} {%-endfor%}{% endif %}) renders=4>' in entity 'None'


Taffy9325 avatar Sep 12 '24 10:09 Taffy9325

I get the same TypeError: 'NoneType' object is not iterable

pvtex avatar Sep 27 '24 08:09 pvtex

I get the same TypeError: 'NoneType' object is not iterable

Strangely enough though it hasn’t affected the functionality. I’ve upgraded to latest version of home assistant which is 2024.9.3 and it’s fine just a throws the error up. I think it’s got something to do with the thermostat entity’s

Taffy9325 avatar Sep 27 '24 08:09 Taffy9325

Here are the two main issues that cause those errors in the logs, along with ways to fix or at least silence them:

  1. “NoneType object is not iterable”

This error happens because your template is trying to loop over state_attr('climate.bedroom_thermostat','fan_modes'), but sometimes fan_modes is None (no data) instead of a list.

How to fix it

Before iterating over fan_modes or hvac_modes, wrap it in a conditional that checks if it actually has a value. For example, replace:

{% if state_attr('climate.bedroom_thermostat','fan_modes') is not none %}
{% for mode in state_attr('climate.bedroom_thermostat','fan_modes') %}
    ...
{% endfor %}
{% endif %}

And do the same for hvac_modes as well. That stops the error when your climate device temporarily does not expose those attributes.

  1. ”’/config/openhaspconfig/bedroomtouchscreen.jsonl’ is not an allowed directory”

As of version 0.7.6, openHASP’s custom component enforces stricter checks on which directories it can read from. If you’ve saved your plate config file in a folder that’s not in the integration’s internal allowlist, Home Assistant logs that “not an allowed directory” error.

Ways to fix it

• Move the file into a directory the integration does allow. Double-check the openHASP documentation (or the GitHub issues) to see where they recommend putting .jsonl files.

• Or, if the integration supports it, add your /config/openhaspconfig path to Home Assistant’s allowlist_external_dirs in configuration.yaml. That might look like:

homeassistant:
  allowlist_external_dirs:
    - /config/openhaspconfig

However, that depends on whether the custom component actually respects the global allowlist_external_dirs setting. If it doesn’t, you need to follow the openHASP docs for placing or referencing config files.

Once you correct those two items—(1) add a conditional check around the fan_modes and hvac_modes loops, and (2) relocate or allowlist the .jsonl file—those error messages should go away. Even if the thermostat doesn’t always provide the modes and you see occasional null data, the new conditionals will keep the template from erroring out.

wjnelson78 avatar Mar 11 '25 04:03 wjnelson78