Closed nicolasbuch closed 2 months ago
Sorry for the delay..
We have been trying to account for that here, and handling it by sending the wake command: https://github.com/jhansche/ha-teslafi/blob/647972209af37bfb99e1c17cec84b830a6e4d9bd/custom_components/teslafi/client.py#L68
But it looks like the TeslaFi response has changed:
Error reading as json: FleetApi::auto_conditioning_start - 500 From Tesla:: {"response":null,"error":"vehicle unavailable: vehicle is offline or asleep","error_description":""}
This means the json data is not returned properly, and instead TeslaFi is reporting the error with plain text prepended, and that plaintext string has changed. Looks like we can fix this by changing the startwith check to a contains/substring check.
Ultimately TeslaFi is wrong to return non-json here 🤦♂️ they should instead be encapsulating the upstream error and embedding that into the json error response.
Just adding a +1 to this, I'm seeing the same error when attempting to start a charge while the car is asleep.
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/components/automation/__init__.py", line 755, in async_trigger
return await self.action_script.async_run(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1799, in async_run
return await asyncio.shield(create_eager_task(run.async_run()))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 463, in async_run
await self._async_step(log_exceptions=False)
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 527, in _async_step
self._handle_exception(
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 557, in _handle_exception
raise exception
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 525, in _async_step
await getattr(self, handler)()
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1075, in _async_if_step
await self._async_run_script(if_data["if_then"])
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1269, in _async_run_script
result = await self._async_run_long_action(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 727, in _async_run_long_action
return await long_task
^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1799, in async_run
return await asyncio.shield(create_eager_task(run.async_run()))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 463, in async_run
await self._async_step(log_exceptions=False)
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 527, in _async_step
self._handle_exception(
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 557, in _handle_exception
raise exception
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 525, in _async_step
await getattr(self, handler)()
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 764, in _async_call_service_step
response_data = await self._async_run_long_action(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 727, in _async_run_long_action
return await long_task
^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/core.py", line 2763, in async_call
response_data = await coro
^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/core.py", line 2806, in _execute_service
return await target(service_call)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 999, in entity_service_call
single_response = await _handle_entity_call(
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 1071, in _handle_entity_call
result = await task
^^^^^^^^^^
File "/config/custom_components/teslafi/switch.py", line 51, in async_turn_on
await self.entity_description.cmd(self.coordinator, True)
File "/config/custom_components/teslafi/coordinator.py", line 51, in execute_command
return await self._client.command(cmd, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/config/custom_components/teslafi/client.py", line 44, in command
return await self._request(cmd, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/config/custom_components/teslafi/client.py", line 74, in _request
raise exc
File "/config/custom_components/teslafi/client.py", line 67, in _request
data = response.json()
^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/httpx/_models.py", line 764, in json
return jsonlib.loads(self.content, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/json/__init__.py", line 346, in loads
return _default_decoder.decode(s)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/json/decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
I have a workaround that's functional: The automation checks for the sleep state, wakes the car if needed, then begin the charge once it's confirmed as awake
...
action:
- if:
- condition: state
entity_id: binary_sensor.octopus_energy_target_car_charging_cheap
state: "on"
then:
- if:
- condition: state
entity_id: sensor.tesla_car_state
state: sleeping
then:
- device_id: 0ed14f92e3ab3e1ddd296384ba04857a // button.tesla_wake_up
domain: button
entity_id: 5fb1417e4027b186d67ca8e783622d05
type: press
- wait_for_trigger:
- platform: state
entity_id:
- sensor.tesla_car_state
from: sleeping
to: null
- action: switch.turn_on
metadata: {}
data: {}
target:
entity_id: switch.tesla_charging
else:
- action: switch.turn_on
metadata: {}
data: {}
target:
entity_id: switch.tesla_charging
Unfortunately, wait_for_trigger
seems to fire around 10 minutes after the wake press, so it misses the start window by 10 mins every time, but at least it works.
It seems that polling takes quite a while to update the state. Is there a way to increase the polling frequency? Or perhaps trigger a poll manually within the automation?
Sorry for the delay..
We have been trying to account for that here, and handling it by sending the wake command:
But it looks like the TeslaFi response has changed:
Error reading as json: FleetApi::auto_conditioning_start - 500 From Tesla:: {"response":null,"error":"vehicle unavailable: vehicle is offline or asleep","error_description":""}
This means the json data is not returned properly, and instead TeslaFi is reporting the error with plain text prepended, and that plaintext string has changed. Looks like we can fix this by changing the startwith check to a contains/substring check.
Ultimately TeslaFi is wrong to return non-json here 🤦♂️ they should instead be encapsulating the upstream error and embedding that into the json error response.
@jhansche I spend some time looking into your suggestion and changed the startswith to contains, but it still does not work.
I'm not a python developer, but as far as I can tell this check just throws a VehicleNotReadyError
which is not caught anywhere. I might be wrong, but this does not seem like the right place to fix it.
Do you have the time to take a look or point me in the right direction here? I might find some time to look into it again if you help me understand the problem.
You're right - that would only surface the error in a more user-friendly way.
In coordinator.execute_command(), we are automatically adding wake=10
to the command parameters, if the car is currently sleeping. That is a TeslaFi API feature, and it should be enough to cause the car to wake up:
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.
Can you tell if the error is raised immediately, or does it hang for 10 seconds before the error?
If you don't do anything -- that is, you try the command, get the "offline or asleep" error -- does the car eventually perform the requested action? Like, maybe after a minute or two? If not, does it at least wake up on its own?
If the car eventually responds to the command despite the TeslaFi API error, then we might just need to suppress the error while we wait for the car to wake up.
If the car does not respond, and the request waits for those ~10 seconds before responding with an error, then maybe the DELAY_CMD_WAKE
delay is too conservative and we might need to increase that delay.
Can you tell if the error is raised immediately, or does it hang for 10 seconds before the error?
When toggling charge / setting charge target with the car asleep, the error is returned immediately.
The car does wake from sleep, but the intended action doesn't ever run.
I've noticed that the wake time can vary quite a bit - everything from a couple of seconds to well beyond 1 minute. Setting a timeout feels a bit fragile with that in mind, might be better to wake the car, wait for confirmation, then set the desired actions.
Right, that should be the intent behind TeslaFi's wake=
parameter. But clearly that is not working correctly currently.
We could work around it in the integration, but I wonder if this should be a bug report to TeslaFi instead... Possibly even a feature request to replace the wake-delay parameter with a simple "wake if needed and send the command whenever it wakes up", so that we don't have to guess how long a typical wake should take. Even if the TeslaFi wake parameter worked correctly, it sounds like it would impose the requested delay regardless of how long it actually takes for it to wake up
@jhansche I looked into the "api documentation" over at teslafi.com and it does indeed seem like the wake command is currently broken.
Sending a &command=auto_conditioning_start&wake=10
returns the same 500 error as we see here in the logs after just a few seconds. It does wake the vehicle as @avhm pointed out - but the original command is never executed.
I think that this is a TeslaFi issue. Will try to contact them and see what they say. I'll keep you posted here.
It was indeed a problem over at teslafi and it seems like they fixed it now. It's working as intended for me at least.
Response from James:
Hi,
That should be corrected now. The only exception is if a users firmware reports the car as offline instead of asleep it won't trigger the time to wait. These users will need to enable show offline as asleep in sleet settings for it to work as expected. Sleep Sessions No Longer Showing
As he points out there might be a case where some firmware versions report the vehicle as offline instead of asleep. In this case the command will not be able to wake the car. Might be something we should handle somewhere or at the very least document.
What's your view on this @jhansche?
Awesome, thanks for checking on that.
My view is we shouldn't go out of our way to work around issues with TeslaFi or Fleet API or specific car models and versions.
If there is some intricacy with how Home Assistant works with certain scenarios, then I can make a case for handling that in the integration -- example being how we need to wait for TeslaFi to reflect the new status for an unlock command or climate command. In those cases, I schedule a refresh after a short delay, and try to suppress the state flapping in the meantime. Without that, you would send the unlock command, it would show unlocked, and then a few seconds later switch back to locked again because TeslaFi hasn't updated its status yet, and then a minute or two later switch to unlocked once it is reflected.
So, with that in mind, I don't think we should work around the exception that James described.
That makes sense. Well, seems like we can close this one.
Thanks for the assistance 😄
Unfortunately, this issue seems to have returned, and the API is responding with vehicle unavailable: vehicle is offline or asleep
again.
Still works fine on my end. Could be your vehicle reporting as offline rather than asleep depending on model/firmware. Try to enable "show offline as asleep" in the teslafi sleep settings and see if it fixes the problem.
Interesting that it's still working for you, I already had the offline / sleep toggle enabled. It's been failing for roughly 5 days (looking at the logs when the automations began failing)
I haven't changed anything in the setup during this time.
This seems to be the case for every change requested (set charge level etc) while the car is asleep.
Try to call the API manually to see what response you get.
This error caused the API to return a 500 response when we tried to wake the vehicle with the request &command=auto_conditioning_start&wake=10
. The problem was faulty endpoint behaviour from teslafi.
Since I can still wake my vehicle with this command i guess the problem you are experiencing is different.
Thought I'd update here - this started working again not long after my last post, and hasn't happened since then, so I can only assume it was an issue on TeslaFi's side, or perhaps a timeout issue (e.g 10s wasn't long enough) - As the car is on cellular, this might be more variable in my situation.
If it does happen again, I'll try the manual API call again with a longer timeout and see if this fixes the issue.
I'm having issues with turning on the climate when the vehicle is asleep. HA shows an error and usually I can just wait a few seconds (until the vehicle wakes up) and try it again successfully.
Expected behaviour should be to wake up the vehicle when it is asleep and then send the auto_conditioning_start command. It seems like we get a 500 error back with the message: "vehicle is offline or asleep".
Have you encountered this problem before?
Se attached log below: