Interacting with REST-API, write response like tokens to helpers

Hello,

I’m having problems communicating with a REST API.
I’ve defined a POST, a PATCH, and a GET command, which I then use in the corresponding automations.

The idea is to log in to the API with credentials and then receive a beacon token including a refresh token.
The beacon thus obtained should be used to retrieve values ​​via GET.

All values, including tokens, are written to or read from helpers.

Through debugging, I’ve seen that my automation for retrieving a token works, and the API also returns the corresponding tokens.

However, I can’t get the returned values ​​into the helpers.
Apparently, there are problems in HomeAssistant precisely here, as values ​​can’t be written to helpers due to a timing issue in HA.
Is there any truth to this?
rest_command.yaml:

fronius_get_jwt:
  url: "https://api.solarweb.com/swqapi/iam/jwt?scope={{ scope }}"
  method: POST
  headers:
    accesskeyid: "{{ accesskeyid }}"
    accesskeyvalue: "{{ accesskeyvalue }}"
    content-type: "application/json; charset=UTF-8"
    accept-encoding: "gzip"
    user-agent: "okhttp/4.12.0"
  payload: '{"userId": "{{ userid }}", "password": "{{ password }}"}'
  content_type: "application/json; charset=UTF-8"
  verify_ssl: true

fronius_refresh_jwt:
  url: "https://api.solarweb.com/swqapi/iam/jwt/{{ refresh_token }}?scope={{ scope }}"
  method: PATCH
  headers:
    accesskeyid: "{{ accesskeyid }}"
    accesskeyvalue: "{{ accesskeyvalue }}"
    content-type: "application/json; charset=UTF-8"
    authorization: "Bearer {{ jwt_token }}"
    accept-encoding: "gzip"
    user-agent: "okhttp/4.12.0"
  payload: "{}"
  content_type: "application/json; charset=UTF-8"
  verify_ssl: true

fronius_get_energy_forecast:
  url: "https://api.solarweb.com/swqapi/pvsystems/{{ pvsystemid }}/weather/energyforecast?fromTime={{ fromtime }}&toTime={{ totime }}"
  method: GET
  headers:
    accesskeyid: "{{ accesskeyid }}"
    accesskeyvalue: "{{ accesskeyvalue }}"
    authorization: "Bearer {{ jwt_token }}"
    accept-encoding: "gzip"
    user-agent: "okhttp/4.12.0"
  content_type: "application/json; charset=UTF-8"
  verify_ssl: true

Automations:

- id: 'fronius_init'
  alias: "Fronius: Initialwerte setzen"
  trigger:
    - platform: homeassistant
      event: start
    - platform: time
      at: '04:55:00'
    - platform: event
      event_type: fronius_start_flow
  action:
    - service: input_text.set_value
      target:
        entity_id: input_text.fronius_userid
      data:
        value: !secret fronius_userid
    - service: input_text.set_value
      target:
        entity_id: input_text.fronius_password
      data:
        value: !secret fronius_password
    - service: input_text.set_value
      target:
        entity_id: input_text.fronius_scope
      data:
        value: !secret fronius_scope
    - service: input_text.set_value
      target:
        entity_id: input_text.fronius_accesskeyid
      data:
        value: !secret fronius_accesskeyid
    - service: input_text.set_value
      target:
        entity_id: input_text.fronius_accesskeyvalue
      data:
        value: !secret fronius_accesskeyvalue
    - service: input_text.set_value
      target:
        entity_id: input_text.fronius_pvsystemid
      data:
        value: !secret fronius_pvsystemid
    - service: input_text.set_value
      target:
        entity_id: input_text.fronius_fromtime
      data:
        value: "050000"
    - service: input_text.set_value
      target:
        entity_id: input_text.fronius_totime
      data:
        value: "220000"

    - service: input_text.set_value
      target:
        entity_id: input_text.fronius_jwt_token
      data:
        value: "jwt-init"
    - service: input_text.set_value
      target:
        entity_id: input_text.fronius_refresh_token
      data:
        value: "refreshtoken-init"
    - service: input_text.set_value
      target:
        entity_id: input_text.fronius_jwt_token_expiration
      data:
        value: "expiration-init"
    - event: fronius_jwt_request


- id: 'fronius_jwt_request'
  alias: "Fronius: JWT anfordern"
  description: Authentifizierung bei Fronius Solarweb API
  trigger:
    - platform: event
      event_type: fronius_jwt_request
  condition:
    - condition: template
      value_template: >-
        {{
          states('input_text.fronius_userid') not in ['', 'unknown'] and
          states('input_text.fronius_password') not in ['', 'unknown'] and
          states('input_text.fronius_scope') not in ['', 'unknown'] and
          states('input_text.fronius_accesskeyid') not in ['', 'unknown'] and
          states('input_text.fronius_accesskeyvalue') not in ['', 'unknown']
        }}
  action:
    - service: rest_command.fronius_get_jwt
      data:
        userid: "{{ states('input_text.fronius_userid') }}"
        password: "{{ states('input_text.fronius_password') }}"
        scope: "{{ states('input_text.fronius_scope') }}"
        accesskeyid: "{{ states('input_text.fronius_accesskeyid') }}"
        accesskeyvalue: "{{ states('input_text.fronius_accesskeyvalue') }}"
      response_variable: jwt_response

    - service: system_log.write
      data:
        message: "JWT Response Raw: {{ jwt_response }}"
        level: info

    - choose:
        # Erfolgsfall (200 OK)
        - conditions: "{{ jwt_response.status == 200 }}"
          sequence:
            - service: input_text.set_value
              target:
                entity_id: input_text.fronius_jwt_token
              data:
                value: >-
                  {% if jwt_response.content is string %}
                    {{ (jwt_response.content | from_json).get('jwtToken', '') }}
                  {% else %}
                    {{ jwt_response.content.get('jwtToken', '') }}
                  {% endif %}

            - service: input_text.set_value
              target:
                entity_id: input_text.fronius_refresh_token
              data:
                value: >-
                  {% if jwt_response.content is string %}
                    {{ (jwt_response.content | from_json).get('refreshToken', '') }}
                  {% else %}
                    {{ jwt_response.content.get('refreshToken', '') }}
                  {% endif %}

            - service: input_number.set_value
              target:
                entity_id: input_number.fronius_retry_count
              data:
                value: 0

            - service: system_log.write
              data:
                message: "Token erfolgreich gespeichert: {{ now() }}"
                level: info

            - delay: "00:00:10"
            
            - condition: template
              value_template: "{{ states('input_text.fronius_jwt_token') not in [None, '', 'unavailable'] }}"
            
            - event: fronius_energy_forecast_request

        # Fehlerfall (401 Unauthorized)
        - conditions: "{{ jwt_response.status == 401 }}"
          sequence:
            - service: input_number.increment
              target:
                entity_id: input_number.fronius_retry_count
            
            - delay: "00:01:00"
            
            - choose:
                - conditions: "{{ states('input_number.fronius_retry_count') | int <= 3 }}"
                  sequence:
                    - delay: "00:01:00"
                    - event: fronius_jwt_request
                    - service: system_log.write
                      data:
                        message: "Erneuter Authentifizierungsversuch: {{ now() }}"
                        level: warning
                
                - conditions: "{{ states('input_number.fronius_retry_count') | int > 3 }}"
                  sequence:
                    - service: input_number.set_value
                      target:
                        entity_id: input_number.fronius_retry_count
                      data:
                        value: 0
                    - service: system_log.write
                      data:
                        message: "Authentifizierung fehlgeschlagen, Initialisierung erforderlich: {{ now() }}"
                        level: error
                    - event: fronius_init


- id: 'fronius_energy_forecast'
  alias: "Fronius: Energieprognose abrufen"
  trigger:
    - platform: event
      event_type: fronius_energy_forecast_request
  action:
    - service: rest_command.fronius_get_energy_forecast
      data:
        jwt_token: "{{ states('input_text.fronius_jwt_token') }}"
        accesskeyid: "{{ states('input_text.fronius_accesskeyid') }}"
        accesskeyvalue: "{{ states('input_text.fronius_accesskeyvalue') }}"
        pvsystemid: "{{ states('input_text.fronius_pvsystemid') }}"
        fromtime: "{{ states('input_text.fronius_fromtime') }}"
        totime: "{{ states('input_text.fronius_totime') }}"
      response_variable: forecast_response
    - choose:
        - conditions: "{{ forecast_response.status == 200 }}"
          sequence:
            - service: input_number.set_value
              target:
                entity_id: input_number.fronius_energy_forecast
              data:
                value: "{{ ((forecast_response.content | from_json | default({}) | get('data', []) | map(attribute='channels') | map('first') | map(attribute='value') | map('float') | list) | sum / 1000 | round(2) if (forecast_response.content | from_json | default({}) | get('data', []) | count > 0) else '0.0') | string }}"
            - service: system_log.write
              data:
                message: "getting forecast and writing in Entitäten ok: {{ now() }}"
                level: info    
        - conditions: "{{ forecast_response.status == 401 or 'JWT expired.' in forecast_response.content }}"
          sequence:
            - service: system_log.write
              data:
                message: "forecast request failed, 401 or 'JWT expired: {{ now() }} "
                level: warning
            - delay: "00:01:00"
            - event: fronius_jwt_request

- id: 'fronius_token_refresh'
  alias: "Fronius: JWT Refresh"
  trigger:
    - platform: time_pattern
      minutes: "/55"
  action:
    - choose:
        # Prüfe, ob beide Tokens vorhanden sind
        - conditions: >
            {{ 
              states('input_text.fronius_jwt_token') not in ['', 'unknown', 'unavailable'] and
              states('input_text.fronius_refresh_token') not in ['', 'unknown', 'unavailable'] 
            }}
          sequence:
            - service: rest_command.fronius_refresh_jwt
              data:
                refresh_token: "{{ states('input_text.fronius_refresh_token') }}"
                accesskeyid: "{{ states('input_text.fronius_accesskeyid') }}"
                accesskeyvalue: "{{ states('input_text.fronius_accesskeyvalue') }}"
                scope: "{{ states('input_text.fronius_scope') }}"
                jwt_token: "{{ states('input_text.fronius_jwt_token') }}"
                response_variable: refresh_response

            - choose:
                # Erfolgsfall: Tokens speichern und Prognose abrufen
                - conditions: "{{ (refresh_response.status | default(0)) == 200 }}"
                  sequence:
                    - service: input_text.set_value
                      target:
                        entity_id: input_text.fronius_jwt_token
                      data:
                        value: "{{ (refresh_response.content | from_json).get('jwtToken', '') | string }}"
                    - service: input_text.set_value
                      target:
                        entity_id: input_text.fronius_refresh_token
                      data:
                        value: "{{ (refresh_response.content | from_json).get('refreshToken', '') | string }}"
                    - delay: "00:01:00"
                    - condition: template
                      value_template: "{{ states('input_text.fronius_jwt_token') not in [None, '', 'unavailable'] }}"
                    - service: system_log.write
                      data:
                        message: "Token Refresh ok: {{ now() }}, starting forecast request"
                        level: info
                    - event: fronius_energy_forecast_request
                # Fehlerfall: Token abgelaufen oder ungültig, neuen JWT anfordern
                - conditions: "{{ (refresh_response.status | default(0)) == 401 or (refresh_response.content is defined and 'JWT expired.' in refresh_response.content) }}"
                  sequence:
                    - delay: "00:00:10"
                    - event: fronius_jwt_request
                    - service: system_log.write
                      data:
                        message: "Token abgelaufen oder ungültig, neuen JWT anfordern: {{ now() }}"
                        level: info
                # Fehlerfall: refresh_response ist undefined (z.B. REST-Fehler)
                - conditions: "{{ refresh_response is undefined }}"
                  sequence:
                    - service: system_log.write
                      data:
                        message: "Keine Antwort vom Refresh-Endpoint. Starte Neuauthentifizierung: {{ now() }}"
                        level: error
                    - event: fronius_jwt_request
        # Falls ein Token fehlt: direkt neuen JWT anfordern
        - conditions: >
            {{ 
              states('input_text.fronius_jwt_token') in ['', 'unknown', 'unavailable'] or
              states('input_text.fronius_refresh_token') in ['', 'unknown', 'unavailable'] 
            }}
          sequence:
            - service: system_log.write
              data:
                message: "Token Refresh übersprungen, da Token fehlt: {{ now() }}"
                level: warning
            - event: fronius_jwt_request

input_text.yaml:

fronius_userid:
  name: User ID
fronius_password:
  name: Passwort
  mode: password
fronius_scope:
  name: Scope
fronius_accesskeyid:
  name: Access Key ID
fronius_accesskeyvalue:
  name: Access Key Value
fronius_pvsystemid:
  name: PV System ID
fronius_jwt_token:
  name: JWT Token
fronius_refresh_token:
  name: Refresh Token
fronius_jwt_token_expiration:
  name: JWT Token Expiration
fronius_fromtime:
  name: Fronius From Time
fronius_totime:
  name: Fronius To Time

Try:

  action:
    - service: rest_command.fronius_get_jwt
      data:
        userid: "{{ states('input_text.fronius_userid') }}"
        password: "{{ states('input_text.fronius_password') }}"
        scope: "{{ states('input_text.fronius_scope') }}"
        accesskeyid: "{{ states('input_text.fronius_accesskeyid') }}"
        accesskeyvalue: "{{ states('input_text.fronius_accesskeyvalue') }}"
      response_variable: jwt_response

    - wait_template: "{{ jwt_response is defined }}"
      timeout: 10 # seconds
          
    - service: system_log.write
      data:
        message: "JWT Response Raw: {{ jwt_response }}"
        level: etc...

This will wait for the response before continuing. Or timeout after 10 seconds (adjust as necessary). You can also capture the timeout event to deal with it. See: https://www.home-assistant.io/docs/scripts#wait-variable