Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save nledenyi/c2ab349b506955efc9baa7320d1ffae8 to your computer and use it in GitHub Desktop.

Select an option

Save nledenyi/c2ab349b506955efc9baa7320d1ffae8 to your computer and use it in GitHub Desktop.
Toyota EU integration - test the ha_toyota fork that fixes the refresh-status 500 auto-disable bug + entity staleness (companion to ha_toyota#293)

Toyota EU integration - test ha_toyota fork (refresh-status 500 resilience)

A work-in-progress fork of the Toyota EU community integration that fixes the smart status-refresh strategy on vehicles whose gateway returns persistent HTTP 500 on POST /v1/global/remote/refresh-status. Targets ha_toyota#293 (the gateway-rejects-the-wake-POST bucket of #291).

What changes vs stock ha_toyota 2.3.0:

  • The wake POST is wrapped in try/except. A 5xx exception now correctly advances the auto-disable counter and lets the rest of the cycle's bookkeeping run (instead of propagating past it and freezing entities at last-good).
  • A bare GET fallback fires when the POST fails, so /status entities still refresh this cycle even before auto-disable kicks in.
  • The "Refresh vehicle status" service / button now bypasses both auto-disable AND user-disable. If the gateway recovers (or you want a fully manual schedule), pressing the button forces a POST through.
  • A successful POST automatically clears auto_disabled_status_refresh, so recovery from auto-disable is a single button press instead of the options-flow toggle dance.

Once ha_toyota#293 is merged and a release is cut, none of this will be needed - HACS will pull the fix normally.

Read this first

You will run terminal commands inside your Home Assistant container. If that sentence is unfamiliar, the rest of this document might be too. Set aside 10 minutes, follow each step exactly, and don't worry if something breaks - there's a rollback section at the bottom.

This guide does not modify pytoyoda. Stock pytoyoda 5.1.0 (which ha_toyota 2.3.0 already pins) is what stays installed.

Step 0 - figure out which Home Assistant install you have

Install type How to recognise it What you'll do
Home Assistant OS (HAOS) Settings -> System -> About shows "Operating system: Home Assistant OS X.Y" SSH into the host, then docker exec into the container
HA Container / Supervised You run HA via docker compose or docker run directly docker exec straight from your Docker host
HA Core in a venv You manage the Python venv yourself Skip the docker exec parts, edit /config/custom_components/toyota/ directly

For HAOS, install the Advanced SSH & Web Terminal add-on by frenck, set Protection Mode: off, restart the add-on, and SSH in. The official "Terminal & SSH" core add-on has no docker command and won't work.

You're in the right shell when docker --version returns a version number.

Step 1 - get a ROOT shell inside the Home Assistant container

docker exec -u 0 -it homeassistant bash

You should now see a # prompt.

Step 2 - swap ha_toyota for the fix branch

# 2a. Move the stock integration OUT of custom_components/ entirely.
#     Putting backups inside custom_components/ confuses HA's loader and
#     can crash setup with "No module named 'custom_components.toyota.bak'".
cd /config/custom_components
rm -rf /config/_toyota_stock_backup
[ -d toyota ] && mv toyota /config/_toyota_stock_backup

# 2b. Clone the fork branch and move it into place.
git clone -b fix/wake-post-500-auto-disable --depth 1 \
  https://github.com/nledenyi/ha_toyota.git /tmp/ha_toyota_fork
mv /tmp/ha_toyota_fork/custom_components/toyota toyota
rm -rf /tmp/ha_toyota_fork

After this, /config/custom_components/toyota/ contains the fork code and /config/_toyota_stock_backup/ contains the stock backup outside the integrations folder.

Verify the swap took

Quick check that the fork code is in place:

grep -c "status_after_post_fail" /config/custom_components/toyota/__init__.py

Expected: 1. If 0, the swap didn't take - the toyota directory is still stock 2.3.0; re-run Step 2.

Step 3 - restart HA

Exit the container shell:

exit

Then restart HA Core. From your host shell:

ha core restart

Wait 1-3 minutes for HA to come back up.

Step 4 - how to know it worked

The behaviour change is visible in two places:

(a) Status sensor flips to hard_disabled_auto after ~12 minutes

If your gateway 500s persistently, the fork will:

  • Cycle 1 (within first 6 minutes): POST fails -> consecutive_post_rejections = 1, bare GET fallback runs.
  • Cycle 2 (~12 minutes after restart): POST fails again -> counter hits threshold -> auto_disabled_status_refresh = True is persisted, integration reloads, strategy goes to HARD_DISABLED_AUTO.

In Home Assistant, find sensor.<alias>_status_refresh_state (under your vehicle's diagnostic entities). After ~12 minutes it should report hard_disabled_auto. On stock 2.3.0 this sensor stayed active forever even with the same persistent 500s - that's the exact bug this PR fixes.

(b) Entities now update every cycle

On stock 2.3.0, when the wake POST 500'd, /status-derived entities (parking location, lock state, door states) froze at last-good. With the fork, the bare GET fallback runs on Layer 1 failure, so those entities refresh on every coordinator cycle as long as Toyota's gateway serves stale-cache data.

Check device_tracker.<alias>_parking_location and binary_sensor.<alias>_*_lock for state changes after ~12 minutes (or after a real-world event - e.g. someone takes the car for a drive, parks elsewhere; the location entity should pick that up after the next coordinator cycle once the legacy GET fires).

(c) Optional - press the refresh button to test recovery

After the integration auto-disables, find the Refresh vehicle status button entity for your car and press it. Expected behaviour:

  • The fork bypasses HARD_DISABLED_AUTO for service-call invocations.
  • A POST is attempted.
  • If the POST succeeds (return_code == "000000"), the fork auto-clears auto_disabled_status_refresh and the strategy returns to ACTIVE on the next cycle.
  • If the POST fails again (your gateway is still 500ing), the counter increments and re-trips auto-disable on the next failure.

In Settings -> System -> Logs, filter for toyota. After a successful service-call POST you should see:

INFO ... Toyota auto-disable cleared for vin=...XXXXXX after successful POST

That message is the recovery signal.

What should NOT happen

On stock 2.3.0 you saw an endless retry loop in the logs every cycle:

WARNING ... pytoyoda.controller:request_raw - Toyota API 500 on /v1/global/remote/refresh-status; retrying in 2s (attempt 2 of 4)
WARNING ... pytoyoda.controller:request_raw - Toyota API 500 on /v1/global/remote/refresh-status; retrying in 4s (attempt 3 of 4)
WARNING ... pytoyoda.controller:request_raw - Toyota API 500 on /v1/global/remote/refresh-status; retrying in 8s (attempt 4 of 4)

repeating forever. With the fork, you should see this pattern at most twice (cycles 1 and 2) before auto-disable kicks in and silences it.

Rollback

If anything goes wrong, revert ha_toyota to stock 2.3.0:

docker exec -u 0 -it homeassistant bash
rm -rf /config/custom_components/toyota
mv /config/_toyota_stock_backup /config/custom_components/toyota
exit
ha core restart

After the restart, your integration is back on stock 2.3.0 and your manual workaround (disabling "Refresh vehicle status remotely permanently" in the integration's options) continues to work.

What to report back

If you can post the following on issue #293, that's the most useful:

  1. Did the integration set up successfully after the swap?
  2. After ~12 minutes, did sensor.<alias>_status_refresh_state flip from active to hard_disabled_auto?
  3. After auto-disable, are your /status-derived entities (parking location, lock state) updating again? (They should be served by the legacy bare GET path now.)
  4. Bonus: try the refresh button while in hard_disabled_auto. Does it (a) attempt a POST, and (b) flip the state back to active if the POST succeeds?

Thanks for testing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment