How to catch a service call error and retry (inside a script)

Hi,

I have I have a Tapo c220 which does not remember its current position. That’s OK.

However, every so often, I get an error that my preset “does not exist”. This occasionally happens when turning the camera on after it has been off for a while. Is there a way to catch the error and retry? I have a script to perform the select.move_to_preset and would like to handle the error inside the script.

script:
  tapo_move_to_door:
    alias: "Tapo: Point camera at door"
    icon: mdi:door
    mode: queued
    sequence:
      - if:
          - condition: state
            entity_id: switch.tapo_door_camera
            state: 'on'
        then:
          # move to preset
          - service: input_select.select_option
            target:
              entity_id: input_select.tapo_move_to
            data:
              option: door
          # wait for move to complete
          - delay: 5
          # send message with camera snapshot
          - service: script.tapo_notify_snapshot
        else:
          # notify
          - service: script.notify_james
            data:
              message: "Unable to move to door - camera is off."

The errors in the logs are:

logs
2024-03-26 10:59:56.941 ERROR (MainThread) [homeassistant.components.script.tapo_move_to_door] Tapo: Point camera at door: If at step 1: Error executing script. Error for call_service at pos 2: Option door is not valid for select.tapo_c220_move_to_preset
2024-03-26 10:59:56.941 ERROR (MainThread) [homeassistant.components.script.tapo_move_to_door] Tapo: Point camera at door: Error executing script. Error for if at pos 1: Option door is not valid for select.tapo_c220_move_to_preset
2024-03-26 10:59:56.943 ERROR (MainThread) [homeassistant.components.automation.tapo_auto_on_off] Tapo: Camera control: Choose at step 1: choice 3: Repeat at step 1: If at step 3: Error executing script. Error for call_service at pos 2: Option door is not valid for select.tapo_c220_move_to_preset
2024-03-26 10:59:56.944 ERROR (MainThread) [homeassistant.components.automation.tapo_auto_on_off] Tapo: Camera control: Choose at step 1: choice 3: Repeat at step 1: Error executing script. Error for if at pos 3: Option door is not valid for select.tapo_c220_move_to_preset
2024-03-26 10:59:56.945 ERROR (MainThread) [homeassistant.components.automation.tapo_auto_on_off] Tapo: Camera control: Choose at step 1: choice 3: Error executing script. Error for repeat at pos 1: Option door is not valid for select.tapo_c220_move_to_preset
2024-03-26 10:59:56.945 ERROR (MainThread) [homeassistant.components.automation.tapo_auto_on_off] Tapo: Camera control: Error executing script. Error for choose at pos 1: Option door is not valid for select.tapo_c220_move_to_preset
2024-03-26 10:59:57.003 ERROR (MainThread) [homeassistant.components.automation.tapo_auto_on_off] Error while executing automation automation.tapo_auto_on_off: Option door is not valid for select.tapo_c220_move_to_preset

Any ideas?

I have also asked this question in the Tapo Camera control discord channel, but I think it’s a useful general question as well.

I appreciate the continue_on_error: true option, but I am also interested in a some logic that is “if previous service call errored out, then…”.

Use a wait template after turning your camera on. Wait for the option to exist.

Also are you sure it is an input_select and not just a select entity?

That’s a great idea - I’ll give that a shot - thanks.

Screenshot 2024-03-27 at 08.16.45

Yeah that is not an input select and you have the entity id incorrect. That is why you are having issues. Change your automation to:

        then:
          # move to preset
          - service: select.select_option # change here
            target:
              entity_id: select.tapo_c220_move_to_preset # and here
            data:
              option: door

Thanks and well spotted but I mis-pasted and do have it correct in my version

  tapo_move_to_door:
    alias: "Tapo: Point camera at door"
    icon: mdi:door
    mode: queued
    sequence:
      - if:
          - condition: state
            entity_id: switch.tapo_door_camera
            state: 'on'
        then:
          # remember move
          - service: input_select.select_option
            target:
              entity_id: input_select.tapo_move_to
            data:
              option: door
          # move to preset
          - service: select.select_option
            continue_on_error: true
            target:
              entity_id: select.tapo_c220_move_to_preset
            data:
              option: door
          # wait
          - delay: 5
          # notify
          - service: script.tapo_notify_snapshot
        else:
          # notify
          - service: script.notify_james
            data:
              message: "Unable to move to door - camera is off."

I tried to cut the input_select.select_option to avoid confusion as I only use it to remember which of the several scripts (this is one) that I last used. However I cut the select.select_option by accident instead.


Edit: I should make it clear that I did not release my copy/paste mistake until you pointed it out so thanks and apologies for the mislead it caused.

OK, I am going to try this (unedited full script!)

  tapo_move_to_door:
    alias: "Tapo: Point camera at door"
    icon: mdi:door
    mode: queued
    sequence:
      - if:
          - condition: state
            entity_id: switch.tapo_door_camera
            state: 'on'
        then:
          - alias: "Wait until preset is available"
            wait_template: "{{ is_state('select.tapo_c220_move_to_preset', 'unknown') }}"
            timeout: "00:00:30"
            continue_on_timeout: true
          - if:
              - "{{ wait.completed }}"
            then:
              # remember move
              - service: input_select.select_option
                target:
                  entity_id: input_select.tapo_move_to
                data:
                  option: door
              # move to preset
              - service: select.select_option
                continue_on_error: true
                target:
                  entity_id: select.tapo_c220_move_to_preset
                data:
                  option: door
              # wait
              - delay: 5
              # notify
              - service: script.tapo_notify_snapshot
            else:
              # notify
              - service: script.notify_james_loud
                data:
                  message: "Unable to move to door - 'select' not availabe"
        else:
          # notify
          - service: script.notify_james
            data:
              message: "Unable to move to door - camera is off."

Thanks, @tom_l

Change this:

 wait_template: "{{ is_state('select.tapo_c220_move_to_preset', 'unknown') }}"

It is waiting for the state to become unknown. You want the opposite. Try

 wait_template: "{{ has_value('select.tapo_c220_move_to_preset') }}"

I appreciate your suggestion but the camera never knows where it is (it’s a great camera, but this is its one problem for me).

The state of select.tapo_c220_move_to_preset is always either unknown (when the camera is on) or unavailable (when the camera is off). This is why I got stuck working out what to do. I’m therefore waiting for it to be unknown (meaning it does exist) per your suggestion. I’ve just tried it and it works :slight_smile:

It’s not an elegant script right now. Once I can confirm it works when select. select.tapo_c220_move_to_preset is unavailable (may take a couple of days) I’ll replace the nested if/then with choose.

1 Like