TypeError: can't multiply sequence by non-int of type 'float'

My automation code below is generating a rather unhelpful cryptic error and no clue as to where , what line or why. I was always taught at college to make errors meaningful and certainly not like “Error 1234” - as per the lunar lander in 60s - which is meaningless without the decipher book !

So with that in mind, what on earth might be causing the error do we think?

Error:

2025-03-15 21:30:00.222 ERROR (MainThread) [homeassistant.components.automation.heating_pid_controller] Heating PID Controller: Error executing script. Error rendering template for variables at pos 1: TypeError: can't multiply sequence by non-int of type 'float'
2025-03-15 21:30:00.224 ERROR (MainThread) [homeassistant.components.automation.heating_pid_controller] Error while executing automation automation.heating_pid_controller: TypeError: can't multiply sequence by non-int of type 'float

Code: (package file pump_pid.yaml)

pump_pid:

  # Input Select for Current Temperature Sensor
  input_select:
    current_temperature_sensor:
      name: Current Temperature Sensor
      options:
        - sensor.meter_plus_da53_lounge
        - sensor.meter_plus_88d5_kitchen
        # Add more sensors as needed
      initial: sensor.meter_plus_da53_lounge

  # Input Number for Target Temperature and PID Gains
  input_number:
    pid_target_temperature:
      name: PID Target Temperature
      min: 10  # Minimum temperature allowed
      max: 30  # Maximum temperature allowed
      step: 0.1  # Step increment/decrement
      initial: 20.5  # Default target temperature
      mode: slider  # Slider input for easier adjustment

    pid_high_temperature_threshold:
      name: PID High Temperature Threshold
      min: 0
      max: 50
      step: 0.1
      initial: 25

    pid_low_temperature_threshold:
      name: PID Low Temperature Threshold
      min: 0
      max: 50
      step: 0.1
      initial: 15

    pid_proportional_gain:
      name: PID Proportional Gain
      min: 0
      max: 10
      step: 0.1
      initial: 1.0

    pid_integral_gain:
      name: PID Integral Gain
      min: 0
      max: 10
      step: 0.1
      initial: 1.0

    pid_derivative_gain:
      name: PID Derivative Gain
      min: 0
      max: 10
      step: 0.1
      initial: 1.0

    pid_previous_error:
      name: PID Previous Error
      min: -100
      max: 100
      step: 0.1
      initial: 0

    pid_integral:
      name: PID Integral
      min: -100
      max: 100
      step: 0.1
      initial: 0

    pid_current_offset:
      name: PID Current Offset
      min: -10
      max: 10
      step: 0.5
      initial: 0


  # Automation for PID Control
  automation:
    - alias: Heating PID Initialize
      trigger:
        platform: homeassistant
        event: start
      action:
        - service: input_number.set_value
          target:
            entity_id: input_number.pid_previous_error
          data:
            value: 0
        - service: input_number.set_value
          target:
            entity_id: input_number.pid_integral
          data:
            value: 0
        - service: input_number.set_value
          target:
            entity_id: input_number.pid_current_offset
          data:
            value: 0

    - alias: Heating PID on off
      triggers:
        - trigger: numeric_state
          entity_id:
            - sensor.meter_plus_da53_lounge
          above: input_number.pid_high_temperature_threshold
          id: pid-above-setpoint-day
          enabled: true
        - trigger: numeric_state
          entity_id:
            - sensor.meter_plus_da53_lounge
          below: input_number.pid_low_temperature_threshold
          id: pid-below-setpoint-day
          enabled: true
      conditions: []
      actions:
        - alias: PID daytime heating off
          continue_on_error: true
          if:
            - condition: trigger
              id:
                - pid-above-setpoint-day
          then:
            - action: input_boolean.turn_off
              data: {}
              target:
                entity_id: input_boolean.heating_demand
        - alias: PID daytime heating on
          continue_on_error: true
          if:
            - condition: trigger
              id:
                - pid-below-setpoint-day
          then:
            - action: input_boolean.turn_on
              data: {}
              target:
                entity_id: input_boolean.heating_demand

    - alias: Heating PID Controller
      trigger:
        - platform: time_pattern
          minutes: '/10'  # every 10 minutes
        - platform: homeassistant
          event: start
      action:
        - variables:
            pid_target_temp: "{{ states('input_number.pid_target_temperature') | float }}"  # Get target temperature from input_number
            pid_current_sensor: "{{ states('sensor.meter_plus_da53_lounge') | float }}"
            pid_current_temp: "{{ pid_current_sensor | float }}"
            pid_high_threshold: "{{ states('input_number.pid_high_temperature_threshold') | float }}"
            pid_low_threshold: "{{ states('input_number.pid_low_temperature_threshold') | float }}"
            pid_previous_error: "{{ states('input_number.pid_previous_error') | float }}"
            pid_integral_orig: "{{ states('input_number.pid_integral') | float }}"
            pid_dt: 10.0  # time difference in minutes for actual sensor update period
            pid_proportional_gain: "{{ states('input_number.pid_proportional_gain') | float }}"
            pid_integral_gain: "{{ states('input_number.pid_integral_gain') | float }}"
            pid_derivative_gain: "{{ states('input_number.pid_derivative_gain') | float }}"

            # Calculate the error
            pid_error: "{{ (pid_target_temp - pid_current_temp) | float }}"

            # Adjust the integral to reduce overshooting
            pid_integral: >
              {% if pid_error | abs < 0.5 %}
                {{ pid_integral_orig | float}}  # Reduce the integral if close to target
              {% else %}
                {{ (pid_integral_orig + pid_error) | float  * pid_dt }}  # Regular accumulation
              {% endif %}

            pid_derivative: "{{ (pid_error - pid_previous_error) | float / pid_dt }}"

            # Calculate PID output (scaled to range of -10 to +10)
            pid_output: >
              {{ (
                 (pid_proportional_gain | float * pid_error | float) + 
                 (pid_integral_gain | float * pid_integral | float) + 
                 (pid_derivative_gain | float * pid_derivative | float)
                 ) | float * (10.0 / pid_target_temp | float) | float }}

            # Limit PID output changes to avoid rapid spikes
            pid_new_offset_raw: "{{ states('input_number.pid_current_offset') | float + pid_output }}"
            pid_current_offset: "{{ states('input_number.pid_current_offset') | float }}"
            pid_new_offset: >
              {% if (pid_new_offset_raw - pid_current_offset) > 1 %}
                {{ pid_current_offset + 1 }}  # Limit increase
              {% elif (pid_new_offset_raw - pid_current_offset) < -1 %}
                {{ pid_current_offset - 1 }}  # Limit decrease
              {% else %}
                {{ pid_new_offset_raw }}  # Allow normal adjustment
              {% endif %}

            # Self-tuning logic
            pid_adjustment_factor: >
              {% if pid_error | abs > 1 %}
                0.1  # Increase gains if error is large
              {% elif pid_error | abs < 0.5 %}
                -0.05  # Decrease gains if close to target
              {% else %}
                0  # No change
              {% endif %}
            
            pid_new_proportional_gain: "{{ (pid_proportional_gain + pid_adjustment_factor) | max(0) | min(10) }}"
            pid_new_integral_gain: "{{ (pid_integral_gain + pid_adjustment_factor) | max(0) | min(10) }}"
            pid_new_derivative_gain: "{{ (pid_derivative_gain + pid_adjustment_factor) | max(0) | min(10) }}"

        # Log all important values
        - service: logger.log
          data:
            message: >
              Target Temp: {{ pid_target_temp }} | 
              Current Temp: {{ pid_current_temp }} | 
              Error: {{ pid_error }} | 
              PID Output: {{ pid_output }} | 
              Proportional Gain: {{ pid_proportional_gain }} | 
              Integral Gain: {{ pid_integral_gain }} | 
              Derivative Gain: {{ pid_derivative_gain }} | 
              Updated Proportional Gain: {{ pid_new_proportional_gain }} | 
              Updated Integral Gain: {{ pid_new_integral_gain }} | 
              Updated Derivative Gain: {{ pid_new_derivative_gain }} | 
              Current Offset: {{ pid_current_offset }} | 
              New Offset: {{ pid_new_offset }} | 
              Integral: {{ pid_integral }}
 
        # Only update the temperature offset if it has changed
        - choose:
            - conditions:
                - condition: template
                  value_template: "{{ pid_new_offset != pid_current_offset }}"
              sequence:
                - service: input_number.set_value
                  target:
                    entity_id: input_number.pid_current_offset
                  data:
                    value: "{{ pid_new_offset }}"
                - action: climate.set_temperature
                  metadata: {}
                  data:
                    temperature: >-
                      {{ pid_new_offset }}
                  target:
                    entity_id: climate.heating_leaving_water_offset

        - service: input_number.set_value
          target:
            entity_id: input_number.pid_previous_error
          data:
            value: "{{ pid_error }}"

        - service: input_number.set_value
          target:
            entity_id: input_number.pid_integral
          data:
            value: "{{ pid_integral }}"

        # Update PID gains for self-tuning
        - service: input_number.set_value
          target:
            entity_id: input_number.pid_proportional_gain
          data:
            value: "{{ pid_new_proportional_gain }}"

        - service: input_number.set_value
          target:
            entity_id: input_number.pid_integral_gain
          data:
            value: "{{ pid_new_integral_gain }}"

        - service: input_number.set_value
          target:
            entity_id: input_number.pid_derivative_gain
          data:
            value: "{{ pid_new_derivative_gain }}"

That is not how you use comments inside templates. This is:

{{ pid_current_offset + 1 }} {# Limit increase #}

You need to fix this in multiple places.

it’s not complaining about those comments is it? is that the reason?

aside for information the code was generated by Deep AI … about 90% of it in involving a grueling session of about two hours going back and forth to get it to modify as I wanted. It put the comments in, and not me … but it also got a few other things wrong that didn’t execute without error and I fixed them.

Yes. It’s one of the reasons, you have strings in your template where they are not expected. The other reason is:

Stop using that stupid thing. LLMs outright make up bullshit and if you don’t know what you are doing you won’t recognise when it is doing that. Wasting your time and ours.

Sorry but I am not prepared to fix LLM garbage for you. Try reading the documentation, attempting to configure things yourself and asking questions here to help you learn instead of using that hopelessly broken crutch.

And do not ever use an LLM to help others on this forum or you will be banned: Want to help others? Leave your AI at the door - Home Assistant

2 Likes

I haven’t had much look with creating my automation so turned to AI. It has provided a lot of the lifting for me , about 60% which I then used to read a multitude of home assistant articles to acquire further knowledge and deep learning. However it’s not without error as you refer to although I wouldn’t quite describe it using your vernacula. I do feel it’s a assistive starting place to scaffold the framework that then requires expert knowledge to complete it … that’s my personal view and opinion which are freely entitled to express in a respectful and logical and constructive manner. definitely a place for AI for me at the moment however it is confined to providing a basic platform scaffold skeleton onto which substance needs to be applied , the latter sourced from experience competence knowledge and skill , not a chatbot.:call_me_hand:

in terms of using it to help others that’s almost laughable if it wasn’t serious demand… I’m absolutely in no position in no way to start helping anybody in HA system anytime soon, far too much learning and error to engage in.

incidentally I remove the offending comments and it’s made no difference to the error reporting so thank you for that suggestion and assertion however I do have to feedback , that was not the root cause. I’m just modifying the code iteratively to identify which lines are causing the problem… HA error reporting is certainly go for improvement , to be able to identify lines in complex script causing offence rather than glib cryptic messages which perhaps only the experts understand but even then not identify the root cause :laughing:

EDIT
gave up, it’s not operating as I need … and now 3 screens of code … so going back to basics and googling :roll_eyes::grinning: