Ending charge if value met as part of the action (condition)

At the moment I am using a set of input_datetime to charge my house battery bank between set times.

I want to be able to turn off charge if it reaches 98% as part of the action.
Will the following work as expected?

# Automation to start forcetime 1 based on time.
  - alias: Start Force Time 1
    trigger:
      - platform: template
        value_template: "{{ states('sensor.time') == (states.input_datetime.start_forcetime_1_time.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"
    condition:
      condition: state
      entity_id: input_boolean.timed_forcetime1
      state: 'on'
    action:
      - service: homeassistant.turn_on
        entity_id: input_boolean.solax_forcetime
      - service_template: "{{ 'homeassistant.turn_off' if states.sensor.solax_battery_capacity.state == '98' }}"
        entity_id: input_boolean.solax_forcetime

If the battery bank hasn’t fully charged I still have a second action to turn it off.

# Automation to stop forcetime 1 based on time.
  - alias: Stop Force Time 1
    trigger:
      - platform: template
        value_template: "{{ states('sensor.time') == (states.input_datetime.stop_forcetime_1_time.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"
    condition:
      condition: state
      entity_id: input_boolean.timed_forcetime1
      state: 'on'
    action:
      - service: homeassistant.turn_off
        entity_id: input_boolean.solax_forcetime
      - service: homeassistant.turn_off
        entity_id: input_boolean.timed_forcetime1

Configuration validation isn’t showing any errors and normally I would just leave to run it.
But Solar has been rubbish today so I need to charge it while at the cheapest rate during the night to get me through to tomorrow.

The automation runs without the service_template part, but I want to know if that addition will work as intended.

Did you know you can use that input datetime directly in a time trigger as of v0.115?

  - alias: Start Force Time 1
    trigger:
      - platform: time
        at: input_datetime.start_forcetime_1_time

You need an else case so the service is never empty here:

service_template: "{{ 'homeassistant.turn_off' if states.sensor.solax_battery_capacity.state == '98' }}"

Something like this would probably do:

service_template: "{{ 'homeassistant.turn_off' if states('sensor.solax_battery_capacity')|float >= '98' else 'homeassistant.turn_on' }}"

I also changed the sensor template to the preferred format that does not generate errors if the sensor is not ready and changed it to a number so you can do numerical comparisons. It was a string the way you had it, which was ok for simple digit comparisons but sill not a great habit to get into. It definitely would not work for a “grater than or equal to” test. I did that in case the value skips over 98.

1 Like

Thanks for the tips and pointers.
So now it all becomes

# Automation to start forcetime 1 based on time.
  - alias: Start Force Time 1
    trigger:
      - platform: time
        at: input_datetime.start_forcetime_1_time
    condition:
      condition: state
      entity_id: input_boolean.timed_forcetime1
      state: 'on'
    action:
      - service: homeassistant.turn_on
        entity_id: input_boolean.solax_forcetime
      - service_template: "{{ 'homeassistant.turn_off' if states('sensor.solax_battery_capacity')|float >= '98' else 'homeassistant.turn_on' }}"
        entity_id: input_boolean.solax_forcetime

I wrote the original automation a while back, so didn’t really spot the change in platform: time instead of platform: template and all the mess of a value_template.

1 Like

If you’re interested, this single automation should do the same thing:

- alias: 'Control Force Time 1'
  trigger:
    platform: time
    at:
      - input_datetime.start_forcetime_1_time
      - input_datetime.stop_forcetime_1_time
  condition: "{{ is_state('input_boolean.timed_forcetime1', 'on') }}"
  action:
    choose:
      - conditions: >
          {{ (trigger.now.time()|string)[:5] == states('input_datetime.start_forcetime_1_time')[:5] and 
             states('sensor.solax_battery_capacity') | int < 98 }}
        sequence:
          - service: input_boolean.turn_on
            entity_id: input_boolean.solax_forcetime
      - conditions: >
          {{ (trigger.now.time()|string)[:5] == states('input_datetime.stop_forcetime_1_time')[:5] }}
        sequence:
          - service: input_boolean.turn_off
            entity_id: input_boolean.solax_forcetime, input_boolean.timed_forcetime1

EDIT

Correction. Moved ) to the correct position within the condition template.

1 Like

Thanks @123 the info you and @tom_l are sharing it’s very useful in helping me to understand these new features better!

I was wondering if I could use a condition to effectively end the automation like my second automation did. Makes for a lot cleaner and compact automation’s without having a start automation and a stop automation!

I take it that the [:5] refers to the time set in my input_datetime say for example 06:00 (_time)

I also didn’t realise you could stack entity_id: like
entity_id: input_boolean.solax_forcetime, input_boolean.timed_forcetime1

I actually have two of these automations with two set of times (There isn’t always a solid block of cheap electric where I can fully charge the bank in one go, so I have to split it sometimes)

input_datetime.start_forcetime_1_time
input_datetime.stop_forcetime_1_time
input_datetime.start_forcetime_2_time
input_datetime.stop_forcetime_2_time

I know in automation’s you can tell what triggered the automation ie input_datetime.start_forcetime_1_time but can you then get it to react only to input_datetime.stop_forcetime_1_time and somehow not to input_datetime.start_forcetime_2_time based on using say [:4] in there?
Like check contents of [:4] (1 or 2) of what triggered the start and react to a stop_forcetime that matches the same start number?

I read your comment’s last paragraph several times and, unfortunately, I don’t understand what you are attempting to do.

Is your goal to create a single automation that is triggered by the start/stop times for forcetime_1 and forcetime_2?

Yes, it doesn’t matter if it’s not possible but I was wondering if a single automation could handle multiple time slots.

I am just curious how much you can compact automation’s / code.

So for example I set the following times.

input_datetime.start_forcetime_1_time 00:30
input_datetime.stop_forcetime_1_time 02:00
input_datetime.start_forcetime_2_time 03:00
input_datetime.stop_forcetime_2_time 04:30

I’ve made some assumptions about the entities you have so this might need modification:

- alias: 'Control Force Time 1 and 2'
  trigger:
    platform: time
    at:
      - input_datetime.start_forcetime_1_time
      - input_datetime.stop_forcetime_1_time
      - input_datetime.start_forcetime_2_time
      - input_datetime.stop_forcetime_2_time
  condition: "{{ is_state('input_boolean.timed_forcetime1', 'on') or is_state('input_boolean.timed_forcetime2', 'on')}}"
  action:
    choose:
      - conditions: >
          {% set t = (trigger.now.time()|string)[:5] %}
          {{ (t == states('input_datetime.start_forcetime_1_time')[:5] or
              t == states('input_datetime.start_forcetime_2_time')[:5]) and 
              states('sensor.solax_battery_capacity') | int < 98 }}
        sequence:
          - service: input_boolean.turn_on
            entity_id: input_boolean.solax_forcetime
      - conditions: >
          {{ (trigger.now.time()|string)[:5] == states('input_datetime.stop_forcetime_1_time')[:5] }}
        sequence:
          - service: input_boolean.turn_off
            entity_id: input_boolean.solax_forcetime, input_boolean.timed_forcetime1
      - conditions: >
          {{ (trigger.now.time()|string)[:5] == states('input_datetime.stop_forcetime_2_time')[:5] }}
        sequence:
          - service: input_boolean.turn_off
            entity_id: input_boolean.solax_forcetime, input_boolean.timed_forcetime2

EDIT

Correction. Copy/paste error. Added missing ( in front of trigger.now.time in three places.

I take it that {% set t = trigger.now.time()|string)[:5] %} is setting t as the variable?

I thought you could only set variables as per https://www.home-assistant.io/blog/2020/09/17/release-115/#variables so far. (Although the description in the blog makes it a little hard to understand! (Hard day at work I guess))

Yes. That’s a variable defined within the template. That ability has been available for a very long time.

The new variables feature introduced in 0.115 is a separate concept and shouldn’t be confused with what you see in my template.

Unfortunately when I left it to run @tom_l example from the second post it failed during the night.

service_template: "{{ 'homeassistant.turn_off' if states('sensor.solax_battery_capacity')|float >= '98' else 'homeassistant.turn_on' }}"

Start Force Time 1: Error executing script. Unexpected error for call_service at pos 2: ‘>=’ not supported between instances of ‘float’ and ‘str’
While executing automation automation.start_force_time_1

I should have quickly tried it before going to bed.

Just quickly tested @123 post 4 and it started ok! But electric is expensive at the moment so I didn’t let it run it’s full course.

I’ll have a proper look at your second method later, as when I tried it earlier it gave
Invalid config for [automation]: Expected a dictionary @ data['action'][0]['choose'][0]['conditions'][0]. Got None. (See ?, line ?).

So probably just need the formatting correcting somewhere?
I’ll take a look when electric is cheaper.

Yes. I made a copy/paste error. There are three instances of trigger.now.time that are missing a leading ( character.

I have corrected the example (above) and it now passes “Check Configuration”.

1 Like

Yeah, remove the quotes from around '98'. The quotes make it a string not a number.

service_template: "{{ 'homeassistant.turn_off' if states('sensor.solax_battery_capacity')|float >= 98 else 'homeassistant.turn_on' }}"

My bad. Sorry.

Ahh yes, now that you point it out I can see the difference!

I have noticed bit of a strange problem with your examples @123

Say for example it’s 08:00 and I set the input_datetime’s to 09:00 and 10:00 and turn the input_boolean on.
The automation works as expected, it turns the battery on at 09:00 and off at 10:00

But say it’s 22:00 I am about to go to bed, I set the two input_datetime’s to 03:00 and 04:00 and turn the input_boolean on.
But I wake in the morning, the battery has not charge and the input_boolean.time_forcetime1 is still showing as on. So it never got triggered.

Is the automation getting confused by (trigger.now.time()|string) as the time I turn on the input_boolean is the day before I want the times to trigger?

So I set the times on Thurs 15th Oct and turn the input_boolean on.
But I am expecting the times to trigger early hours of 16th Oct, but it doesn’t as the date stamp for the times being set is the 15th?

trigger.now is the time when the automation is triggered. It is a datetime object but the template uses the object’s time() method to return just the time.