Plate config file error after update to 0.7.6 custom component
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'
I get the same TypeError: 'NoneType' object is not iterable
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
Here are the two main issues that cause those errors in the logs, along with ways to fix or at least silence them:
- “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.
- ”’/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.