I have just come back from being away and upgraded to 0.80.3 (from 0.79.x I think).
I am now getting the error shown below many tens of times after a re-start which I wasn’t getting before I went away. I don’t know if this is related to the upgrade but I have not made any changes to the relevant bits of my config for many months.
The errors all relate to sensors of the form sensor.zoneX_time_today which are all templated on sensor.zoneX_time. (X is a number from one to five)
They appear precisely once each in my config as shown.
Any help greatly appreciated.
sensor:
- platform: template
sensors:
zone5_time_today:
friendly_name: Zone 5 total watering time today
value_template: >
{% set duration = states('sensor.zone5_time') %}
{{ (float(duration) * 60) | round }}
unit_of_measurement: minutes
icon_template: mdi:water
Log Details (ERROR)
Wed Oct 24 2018 11:58:45 GMT+0100 (British Summer Time)
Error doing job: Task exception was never retrieved
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/homeassistant/helpers/entity.py", line 310, in async_update_ha_state
self.entity_id, state, attr, self.force_update, self._context)
File "/usr/local/lib/python3.6/site-packages/homeassistant/core.py", line 903, in async_set
context)
File "/usr/local/lib/python3.6/site-packages/homeassistant/core.py", line 673, in __init__
"State max length is 255 characters.").format(entity_id))
homeassistant.exceptions.InvalidStateError: Invalid state encountered for entity id: sensor.zone5_time_today. State max length is 255 characters.
Apparently the float() function, if given a string that does not represent a valid number, will simply return the input string. And when you “multiply” a string by a number, the result is the string replicated that many times. And the round filter will also just pass through an invalid number (such as a string.) The end result is, if the state of sensor.zone5_time is ‘unknown’, the template will output a string which contains ‘unknown’ sixty times, which is longer than the maximum allowed state string length of 255.
I don’t know why the state of sensor.zone5_time is different than it was, but I would at least recommend changing the second part of your template sensor’s value_template to:
{{ duration|float|multiply(60)|round }}
The float filter (as opposed to the float function) will output 0.0 if the input cannot be properly converted to a float.
The real difference is using float(x) vs x|float. As I mentioned, if x cannot be properly converted to float, the former will return x, whereas the latter will return 0.0.
I changed from using the operator * to the filter multiply() only for stylistic reasons. This should also work:
@pnbruckner thank you very much. I found the reasons behind my issues and why i’m not seeing any history stats.
One other question though and i’d really appreciate some help on this. I’m trying to change the input select from using “Daily” to selecting days of the week instead. Klogg wrote something really nice and appreciate the great share.
Below are just some information on his other post with the rest of the code:
Please format the code correctly. I can’t provide feedback if I can’t read it properly. Also, are you just looking for general comments, or are you having some specific issue with the code, and if so, what?
@pnbruckner Thank you very much. I’m just looking for some advice to change the “Daily” to days of the week. I really appreciate you willing to take a look. This is quite a bit of code so i’ll have to post it in 3 seperate posts. All three files have been saved in packages and has been included in my config.yaml file. I haven’t had time to take out some of the code that relate to the weather and irrigation information. I’m only interested in Cycle1 and to be able to select a day of the week.
#=================
# === Automations
#=================
automation:
#=====================================================================
#=== Adjust weather durations if:
#=== the baseline duration is changed
#=== the temperature threshold or rainfall baseline are changed
#=== use weather adjustment is turn on
#=====================================================================
- alias: Duration changed in cycle1
initial_state: 'on'
trigger:
- platform: state
entity_id:
- input_number.cycle1_zone1_duration
- input_number.cycle1_zone2_duration
- input_number.cycle1_zone3_duration
- input_number.cycle1_zone4_duration
action:
- service: script.adjust_cycle1_durations
- alias: Duration changed in cycle2
initial_state: 'on'
trigger:
- platform: state
entity_id:
- input_number.cycle2_zone1_duration
- input_number.cycle2_zone2_duration
- input_number.cycle2_zone3_duration
- input_number.cycle2_zone4_duration
action:
- service: script.adjust_cycle2_durations
- alias: Change in rain baseline or temp baseline
initial_state: 'on'
trigger:
- platform: state
entity_id:
- input_number.temperature_baseline
- input_number.rainfall_threshold
action:
- service: script.adjust_cycle1_durations
- service: script.adjust_cycle2_durations
- alias: Use weather adjustment turned on
initial_state: 'on'
trigger:
- platform: state
entity_id:
- input_boolean.cycle1_use_weather_adjustment
- input_boolean.cycle2_use_weather_adjustment
to: 'on'
action:
- service: script.adjust_cycle1_durations
- service: script.adjust_cycle2_durations
#===============================================
#=== Cycle historic weather data in the history
#===============================================
- alias: Collect weather data
initial_state: 'on'
trigger:
- platform: time
at: '23:55:00'
action:
# Cycle the temperature figures
- service: input_number.set_value
data_template:
entity_id: input_number.temp_minus5
value: >
{{ states('input_number.temp_minus4') }}
- service: input_number.set_value
data_template:
entity_id: input_number.temp_minus4
value: >
{{ states('input_number.temp_minus3') }}
- service: input_number.set_value
data_template:
entity_id: input_number.temp_minus3
value: >
{{ states('input_number.temp_minus2') }}
- service: input_number.set_value
data_template:
entity_id: input_number.temp_minus2
value: >
{{ states('input_number.temp_minus1') }}
- service: input_number.set_value
data_template:
entity_id: input_number.temp_minus1
value: >
{{ states('input_number.temp_minus0') }}
# Reset todays temp to low - the average weather calculations happen every
# 30 mins and will only update todays temperature if it goes up.
# This is because the DarkSky max temperature appears to change during
# the day to reflect max temperature for the remainder of the day.
- service: input_number.set_value
data_template:
entity_id: input_number.temp_minus0
value: '0'
# Cycle the rainfall figures
- service: input_number.set_value
data_template:
entity_id: input_number.rain_minus3
value: >
{{ states('input_number.rain_minus2') }}
- service: input_number.set_value
data_template:
entity_id: input_number.rain_minus2
value: >
{{ states('input_number.rain_minus1') }}
- service: input_number.set_value
data_template:
entity_id: input_number.rain_minus1
value: >
{{ states('input_number.rain_minus0') }}
# Set today's forecast rain
# DarkSky rain is measured in mm/h so multiply by 24 then multiply by the probibility of rain.
# This is done here so that it is only done once a day after midnight.
# The forcast figues go up and down all day so the the best we can do for history
# is take the whole day forecast once only.
# We do NOT want to do it every time a re-calculation of the averages is performed.
- wait_template: "{{ states.sensor.time.state == '00:10' }}"
- service: input_number.set_value
data_template:
entity_id: input_number.rain_minus0
value: >
{{ float(states.sensor.dark_sky_precip_intensity.state) * 24 *
(float(states.sensor.dark_sky_precip_probability.state) / 100) }}
# Calculate temperature and rainfall averages
- service: script.calculate_average_weather_conditions
- wait_template: "{{ is_state('script.calculate_average_weather_conditions', 'off') }}"
# Adjust Cycle 1 durations
- service: script.adjust_cycle1_durations
- wait_template: "{{ is_state('script.adjust_cycle1_durations', 'off') }}"
# Adjust Cycle 2 durations
- service: script.adjust_cycle2_durations
- wait_template: "{{ is_state('script.adjust_cycle2_durations', 'off') }}"
#=================================================
#=== Recalculate average weather conditions every
#=== 30 minutes to account for todays weather
#=================================================
- alias: Update average weather every 30 mins
initial_state: 'on'
trigger:
- platform: time
minutes: '/30'
seconds: 00
action:
- service: script.calculate_average_weather_conditions
#============
#=== Scripts
#============
script:
#=========================================
#=== Calculate average weather conditions
#=========================================
calculate_average_weather_conditions:
sequence:
# Set today's forecast high temperature
# but only if it has gone up
# temp_minus0 is set to low evry night at 23:50 when the weather
# information is cycled
- service: input_number.set_value
data_template:
entity_id: input_number.temp_minus0
value: >
{% if states.input_number.temp_minus0.state | float < states.sensor.dark_sky_daily_high_temperature.state | float %}
{{ states('sensor.dark_sky_daily_high_temperature') }}
{% else %}
{{ states('input_number.temp_minus0') }}
{% endif %}
# Calculate average high temp for the today and yesterday
- service: input_number.set_value
data_template:
entity_id: input_number.temp_high_2days
value: >
{{ ((float(states.input_number.temp_minus0.state) +
float(states.input_number.temp_minus1.state)) / 2 ) | round }}
# Calculate average high temp for the today and yesterday and previous 3 days
- service: input_number.set_value
data_template:
entity_id: input_number.temp_high_5days
value: >
{{ ((float(states.input_number.temp_minus0.state) +
float(states.input_number.temp_minus1.state) +
float(states.input_number.temp_minus2.state) +
float(states.input_number.temp_minus3.state) +
float(states.input_number.temp_minus4.state)) / 5) | round }}
# Adjust the total amount of rain depending on how many days ago it was.
# If 3 days ago take 20% of the rain.
# If 2 days ago take 50% of the rain.
# If yesterday take 80% of the rain.
- service: input_number.set_value
data_template:
entity_id: input_number.rain_3days_ratio
value: >
{{ (float(states.input_number.rain_minus1.state) * 0.8) +
(float(states.input_number.rain_minus2.state) * 0.5) +
(float(states.input_number.rain_minus3.state) * 0.2) }}
# Add in todays forecast rain
- service: input_number.set_value
data_template:
entity_id: input_number.rain_3days_ratio
value: >
{{ float(states.input_number.rain_3days_ratio.state) +
(float(states.input_number.rain_minus0.state)) }}
# Convert into a ratio (maximum 1.00) used to reduce irrigation time or stop it altogether:
# Rain needed in last 3 days to stop grass irrigation is set in RainfallThreshold
# Rain levels less than this amount will be used to reduce irrigation run times proportionally
- service: input_number.set_value
data_template:
entity_id: input_number.rain_3days_ratio
value: >
{{ states.input_number.rain_3days_ratio.state | float / states.input_number.rainfall_threshold.state | float }}
- service: input_number.set_value
data_template:
entity_id: input_number.rain_3days_ratio
value: >
{% if states.input_number.rain_3days_ratio.state | float > 1 %}
1
{% else %}
{{ states.input_number.rain_3days_ratio.state }}
{% endif %}
#=========================================
#=== Adjust duration for zones in cycle 1
#=========================================
adjust_cycle1_durations:
sequence:
- service: script.calculate_adjusted_zone_durations
data:
cycle: '1'
zone: '1'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
- service: script.calculate_adjusted_zone_durations
data:
cycle: '1'
zone: '2'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
- service: script.calculate_adjusted_zone_durations
data:
cycle: '1'
zone: '3'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
- service: script.calculate_adjusted_zone_durations
data:
cycle: '1'
zone: '4'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
#=========================================
#=== Adjust duration for zones in cycle 2
#=========================================
adjust_cycle2_durations:
sequence:
- service: script.calculate_adjusted_zone_durations
data:
cycle: '2'
zone: '1'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
- service: script.calculate_adjusted_zone_durations
data:
cycle: '2'
zone: '2'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
- service: script.calculate_adjusted_zone_durations
data:
cycle: '2'
zone: '3'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
- service: script.calculate_adjusted_zone_durations
data:
cycle: '2'
zone: '4'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
#========================================================
#=== Adjust zone duration for average weather conditions
#=== is passed:
#=== {{ cycle }}
#=== {{ zone }}
#========================================================
calculate_adjusted_zone_durations:
sequence:
# Adjust for average daily temperature
# Calculate any change in run time based on daily average temperature.
# The default run time will occur at TemperatureBaseline degrees.
# As the daily average temperature increases above this the run time will
# also increase.
# As the average temp drops below TemperatureBaseline the run time decreases.
# The forumla used ‐ based on a 20 degree TemperatureBaseline would be:
# (((TwoDayHighAverageTemp ‐ 20) / 20) +1) * BaseLineDuration
# So: the percentage change in duration is the same as the percentage
# difference between the actual temperature and the baseline temperature
# i.e. a 10% increase in duration when the baseline temperataure
# is 20 degrees and the actual temperature is 22 degrees
- service: input_number.set_value
data_template:
entity_id: input_number.adjusted_cycle{{ cycle }}_zone{{ zone }}_duration
value: >
{% set duration = states('input_number.cycle' + cycle + '_zone' + zone + '_duration') %}
{{ (((float(states.input_number.temp_high_2days.state) - float(states.input_number.temperature_baseline.state)) / float(states.input_number.temperature_baseline.state)) + 1) * float(duration) }}
# Adjust for average daily rainfall
- service: input_number.set_value
data_template:
entity_id: input_number.adjusted_cycle{{ cycle }}_zone{{ zone }}_duration
value: >
{% set duration = states('input_number.cycle' + cycle + '_zone' + zone + '_duration') %}
{% set adj_duration = states('input_number.adjusted_cycle' + cycle + '_zone' + zone + '_duration') %}
{{ float(adj_duration) - (float(duration) * float(states.input_number.rain_3days_ratio.state)) }}
# Make sure new duration is not less than zero
- service: input_number.set_value
data_template:
entity_id: input_number.adjusted_cycle{{ cycle }}_zone{{ zone }}_duration
value: >
{% if states('input_number.adjusted_cycle' + cycle + '_zone' + zone + '_duration') | float < 0 %}
0
{% elif states('input_number.adjusted_cycle' + cycle + '_zone' + zone + '_duration') | float > 30 %}
30
{% else %}
{{ states('input_number.adjusted_cycle' + cycle + '_zone' + zone + '_duration') }}
{% endif %}
So I browsed through the code, and although I could probably fairly easily modify it to allow for selecting which days of the week to run the cycles, it’s clearly a bit involved. A bit more than I’d like to take on, especially since I’m not using it myself. And even suggesting what to do is a bit involved (and would require even a deeper understanding on my part.) So, sorry, I’m not going to be able to help with this one. Good luck!