jhansche / ha-teslafi

Home Assistant integration for TeslaFi-monitored vehicles
MIT License
12 stars 0 forks source link

Climate reports as Off for a few minutes after being activated in HA #21

Closed LampyDave closed 7 months ago

LampyDave commented 8 months ago

I think I might have found the thing to change to adjust this, but am not sure - and you have been so generous with knowledge in the past that I thought I'd start here.

In the cold weather I am turning the car climate on from HA (both manually and via automations) by the following process: Press 'Wake Up' button in HA; Wait some time - normally about 30s; Press 'Auto' button (in HVAC modes) on Climate entity.

If the car hasn't Woken Up before the 'Auto' button is pressed then an error is displayed "...vehicle unavailable" so I know it hasn't worked. Once it has worked the Climate entity turns green and the car is warming up.

However, on occasion (I don't think it's every time - it happens quite often) shortly after that the Climate entity will go back to grey and show as Off. That is despite the car HVAC actually being active.

Having looked at the TeslaFi API history it seems that the 'auto_conditioning_start' is sent, then 30 seconds after that a 'lastGood' is sent - I don't know for sure what this is but it seems to be a status check. Usually with my setup that seems to be too little time for the car to have turned the HVAC on, reported that fact to TeslaFi and therefore that to be reported to HA. The response from that 'lastGood' is therefore that the climate is not on, so HA shows it as off. The next status check isn't for another 3 minutes, when TeslaFi shows climate as being in Auto, and so the Climate entity in HA goes back to Green & showing Auto.

Sequence of events in HA: firefox_GAOmfXxLSl

API calls as reported by TeslaFi: ACDSeeQVUltimate13_olx1XHw72P

It seems that the delay times are set in const.py, and this one specifically on line 18. If I change that from 30 to (say) 45 on my system with Studio Code Server will that do what I'm after (waiting 45 seconds after sending the command before the next status call)? Will I need to re-start to make the change take effect or will it 'just work'?

Many thanks, Dave

jhansche commented 8 months ago

I think your understanding(s) are, more or less, accurate. The code in question is: https://github.com/jhansche/ha-teslafi/blob/6480a6a52ea75a07a24bd3238eeef401e3d34014/custom_components/teslafi/climate.py#L135-L153

So, when the car was sleeping before you set the mode, it will wait DELAY_WAKEUP which is 30 seconds.

We do have a more deterministic "wait" in the locks and alarm_control_panel platforms. Those platforms will start the action, and then keep re-checking status periodically until the desired state comes back from TeslaFi. The climate platform doesn't do that re-scheduling polling behavior.

It would be relatively straight forward to add that:

The reason we skip writing state when current state doesn't match pending state, is because writing the state back to HA is what causes it to switch to the "current" state as seen by TeslaFi. If we don't write that state, then HA will show the optimistic state change (off -> auto) and then it won't persist any other changes until we do write state. That's how the lock entity and alarm (sentry) entity are able to show the "Locking..." state and "Arming..." state, for as long as it takes until TeslaFi reports the success state. In the above links to lock and alarm code, you'll see that the "else" conditions do not call into the super class and therefore will not write the current state, until after the pending condition is met:

        if target is None:
            LOGGER.debug("Not waiting for a lock change, using state %s", newest)
            ...
            # write the state
            super()._handle_coordinator_update()
        elif target == newest:
            # It succeeded
            LOGGER.debug(
                "Waiting for %s complete, state=%s", self._pending_action, newest
            )
            ...
            # write the state
            super()._handle_coordinator_update()
        else:
            # Still waiting...
            LOGGER.debug("Still waiting for %s", self._pending_action)
            self.coordinator.schedule_refresh_in(DELAY_WAKEUP)

I'm not sure why I didn't add the same "pending" polling for climate, like I did for locks and sentry - probably just to get a MVP in place. 🤷‍♂️ There's also a question of whether we have to do the same kind of wait for every kind of change; e.g. do we also need to wait for the defrost action, or changing the target temperature, or so on? That becomes tedious to keep track of, and increased complexity also increases the chances of introducing bugs.


TeslaFi -> API -> Commands tab (https://teslafi.com/api.php#skeletabsPanel5) shows that we can tell the API to wake up automatically and insert a delay before sending the command:

Adding &wake=X after a command will send a wake command and then pause for X seconds before sending the command if the vehicle is sleeping. Usually 10-15 seconds is enough time for the vehicle to wake up. Maximum time is 60 seconds.

So that is one option - but I don't think this would be any more useful than what we already have in the other entities.


In the meantime, you could also work around this yourself by using a wait-for-trigger in your automations (or a script when you want to set it manually). Something like:

action:
  - service: button.press
    target:
      entity_id: button.car_name_wake_up
  - wait_for_trigger:
      - platform: state
        entity_id:
          - sensor.car_name_car_state
        from: sleeping

If we put that into a script, we can also make the script do this sequence only if the current car_state = sleeping. And then when you want to perform the climate hvac mode, you can just call that script right before setting the climate state.

But long term, I would actually prefer that the service call actually wait around until the re-polling indicates that it succeeded, and not even do the schedule_refresh_in() hack.

LampyDave commented 8 months ago

This is fascinating - thanks so much for writing it up. I will do more reading...

jhansche commented 8 months ago

If I have some time this weekend, I'll see if I can work on 2 things:

  1. reusable "wait for wakeup": if currently awake, do nothing; else if currently sleeping, send a wakeup request and wait until TeslaFi reports awake.
  2. reusable "send and wait for state change": basically what lock and alarm panel do - send the command and then poll on a shorter interval until TeslaFi reflects that the desired change has been made.

I'll also do some testing to see if there's a measurable distinction between a coroutine (suspending) function waiting around for the state to change before proceeding; vs scheduling another coordinator update.