-
Notifications
You must be signed in to change notification settings - Fork 878
feat: handle sleep behavior of MCU2 upgraded cars #4453
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
✅ Deploy Preview for teslamate ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
I am having trouble making sense of this PR. It started off simple (with the original first two commits from the first PR) and has become rather complicated, and IMHO hard to understand. And I am wondering if this complexity is really required. Then there are some changes when in this PR that don't belong here; for example the changes to delete the "models2" entries. I think this might have been included in error. There are some changes though that would be easy to apply separately, for example improvements to the log messages. |
|
Agree, I do have trouble reviewing. The comments helped a bit. |
850eb3f to
dee7726
Compare
d2999d2 to
f951d44
Compare
|
Not sure where the model2 changes are coming from. They are not in the original https://github.com/teslamate-org/teslamate/pull/3262/files Maybe it wasn't synced when this PR was made? The commit history of the old #3262 is long and a bit messed up. Might be easier to only look at the end result. Which again as you mention is a bit complex :( The shortest way to sum it up, might actually just be the description I made on fake_online_state variable: The complexity comes in because online all of a sudden might not be online. This means that the entire online state handling and stream is re-done, and the tests (or as I see it, the API mock used for tests) does not support the fact that a Stream is required. The ultimate solution would be that the car or Tesla servers would hide the fake online. |
|
I guess next step is to double check this is still required. Which might be the case, but I think we do need to check to be sure. |
|
I just checked my logs and it seems to still be an issue: It has the hourly sequence with 'Fake online: power is nil' lasting 2-3 minutes @brianmay, I think I read somewhere that you also have an MCU2 upgraded car? |
|
Sample of my logs of 2017 MCU2 upgraded Model S. On 2024.26.7 and TeslaMate on 1.31.2-dev from pr-3262. 200s are from uptime Kuma, so unrelated. |
|
I can confirm that I have MCU2 upgraded car, am using this branch, and am seeing similar log messages. So yes, does seem like this PR is still required. |
f951d44 to
b15924e
Compare
|
Looking at the simplest piece of the PR here: diff --git a/lib/teslamate/vehicles/vehicle.ex b/lib/teslamate/vehicles/vehicle.ex
index d32098b9a8..e30020392b 100644
--- a/lib/teslamate/vehicles/vehicle.ex
+++ b/lib/teslamate/vehicles/vehicle.ex
@@ -1433,6 +1645,12 @@
{:keep_state, %Data{data | last_used: DateTime.utc_now()},
[broadcast_summary(), schedule_fetch(default_interval() * i, data)]}
+ {:error, :power_usage} ->
+ if suspend?, do: Logger.warning("Power usage ...", car_id: car.id)
+
+ {:keep_state, %Data{data | last_used: DateTime.utc_now()},
+ [broadcast_summary(), schedule_fetch(default_interval() * i, data)]}
+
{:error, :unlocked} ->
if suspend?, do: Logger.warning("Unlocked ...", car_id: car.id)
@@ -1501,6 +1719,10 @@
%CarSettings{req_not_unlocked: true}} ->
{:error, :unlocked}
+ {%Vehicle{drive_state: %Drive{power: power}}, _}
+ when is_number(power) and power > 0 ->
+ {:error, :power_usage}
+
{%Vehicle{}, %CarSettings{}} ->
:ok
endI believe this means Teslamate will never enter "trying to sleep" if power > 0. What is the rationale here? Does power > 0 suggest that the tesla itself is not trying to sleep, and as a result there is no point entering "trying to sleep" ourselves? Would it make sense to split this patch out and apply it first? |
|
There appear to be 4 different values for |
|
The model2 changes don't appear in the original PR: |
|
The model2 changes are not in the original PR; am going to delete them. diff --git a/lib/teslamate/vehicles/vehicle.ex b/lib/teslamate/vehicles/vehicle.ex
index d32098b9a8..e30020392b 100644
--- a/lib/teslamate/vehicles/vehicle.ex
+++ b/lib/teslamate/vehicles/vehicle.ex
@@ -65,7 +70,6 @@
with str when is_binary(str) <- type do
case String.downcase(str) do
"models" <> _ -> "S"
- "models2" <> _ -> "S"
"model3" <> _ -> "3"
"modelx" <> _ -> "X"
"modely" <> _ -> "Y"
@@ -79,7 +83,6 @@
case {model, trim_badging, type} do
{"S", "100D", "lychee"} -> "LR"
{"S", "P100D", "lychee"} -> "Plaid"
- {"S", "100D", "models2"} -> "LR+"
{"3", "P74D", _} -> "LR AWD Performance"
{"3", "74D", _} -> "LR AWD"
{"3", "74", _} -> "LR" |
f910970 to
6c7f0d8
Compare
|
Testing my understanding of the code here. Please correct any errors!
|
|
Am wondering about the changes to the fetch function. What we have is: defp fetch(%Data{car: car, deps: deps}, expected_state: expected_state) do
reachable? =
case expected_state do
:online -> true
{:driving, _, _} -> true
{:updating, _} -> true
{:charging, _} -> true
:start -> false
{:offline, _} -> false
{:asleep, _} -> false
{:suspended, _} -> false
end
if reachable? do
fetch_with_reachable_assumption(car.eid, deps)
else
fetch_with_unreachable_assumption(car.eid, deps)
end
end
defp fetch_with_reachable_assumption(id, deps) do
with {:error, :vehicle_unavailable} <- call(deps.api, :get_vehicle_with_state, [id]) do
call(deps.api, :get_vehicle, [id])
end
end
defp fetch_with_unreachable_assumption(id, deps) do
with {:ok, %Vehicle{state: "online"}} <- call(deps.api, :get_vehicle, [id]) do
call(deps.api, :get_vehicle_with_state, [id])
end
endi.e. we try to guess if car is reachable or not, then we check if this assumption is correct or not, and then we try to get the data. But after this PR we do things differently but only if the streaming api is enabled in the config. allow_vehicle_data? =
case expected_state do
# will not go to real state :online unless a stream is received
# with power not nil in state :offline/:asleep or if use_streaming api is turned off
:online ->
true
{:driving, _, _} ->
true
{:updating, _} ->
true
{:charging, _} ->
true
:start ->
false
{state, _} when state in [:asleep, :offline] ->
case data do
%Data{fake_online_state: 3} -> true
%Data{} -> false
end
{:suspended, _} ->
false
end
if allow_vehicle_data? do
call(deps.api, :get_vehicle_with_state, [car.eid])
else
call(deps.api, :get_vehicle, [car.eid])
endSo now if But now instead of carefully making calls to |
|
To half answer my own question, we can't trust this logic anymore: defp fetch_with_unreachable_assumption(id, deps) do
with {:ok, %Vehicle{state: "online"}} <- call(deps.api, :get_vehicle, [id]) do
call(deps.api, :get_vehicle_with_state, [id])
end
endThis would result in calling And the logic to upgrade a car that is asleep to awake does seem to be dependent on creating streaming. Hence we have to fall back to But I still do wonder why we can't use And contrary to the comment at the top, the logic seems to be more along the lines of "Is car awake? Can we receive streaming data?" as opposed to looking a the power level (except for the logic that inhibits sleeping when the power level is non-zero). |
|
Taking a different approach. Take a random failing test, for example: It looks like there is confusion in the date/time happening. As in the test wants to use 1970-01-01 but we are getting present day date and times. This in turn means any incoming data is discarded because it is 2025-1970 = 55 years too late: Note the timestamp of the incoming data is 0, the other timestamp is 1735967380670 which I assume was the current date time when I ran the test. Similarly the test is expecting 1970-01-01 to be in the data, but it gets 2025-01-04 instead: But oddly enough I don't think anything in this PR deals with date/time? |
Those regular hourly wake-ups are exactly what this branch should fix (it does for me), by detecting that the car isn't really awake and then not polling for data that will properly wake up the car. Whenever the car wakes up, e.g. you check on it in the app (not just opening the app these days, but actually going to the location map, or checking climate for example) or you physically access the car (e.g. open the trunk / door and then close it again), then it always takes 13 minutes to fall back to sleep - that's normal, but TeslaMate here is causing these extra wake-ups unnecessarily by data polling during a "fake wake". Those longer online periods of two hours might be something else - if it's in your garage and plugged in then it might be some charge scheduling thing? |
Gotcha, so this fix or a varient of it is not out in their flagship release yet(the 2.0.0 I am on rn). Hope it gets out there. I can test this branch myself too to see if it changes the pattern then. |
|
Actually, those 2 hours wakes seem to happen at regular 8 hour intervals. Curious. |
No, they've chosen to keep it as a separate branch - as per discussion above. |
Sucks when things get so complicated we end up with all kinda one off builds to support things in a tool hah, I do see the workaround is basically: In a docker compose to grab the github CI build image they pump out. Testing it out now. |
Obviously yes, not sure what the benefit of posting in a PR is, when not using the dedicated pr version. If you have issues, please use issues. If you have additions to a PR use PR comments. If you are happy, as TeslaMate supports MCU2 upgraded cars, great, please share. And yes, we are confident this PR solves issues only MCU2 upgraded cars have, much of confirmation in the issue, the previous PR and this PR. |
Probably not related to TeslaMate, but on the subject of sleep behaviour, I've since noticed that whenever my car is sleeping whilst connected to wifi it also wakes up on exactly 8 hour intervals, though in my case it falls asleep again in the usual 13 minutes rather than 2 hours (you can actually see that in my data above, but I've since found many more examples). If the car is sleeping without a wifi connection it can sleep for much longer than 8 hours without waking. Random wakes still occur occasionally. I would love to know why exactly. |
Turn off the polling in the HA App (or set the time to more than 60 minutes aka 3600 seconds). Note Polling will turn back on whenever HA restarts |
@MadManDK, That looks normal |
|
This branch will get v2.1.0 changes later today or tomorrow |
fd0d26c to
06be505
Compare
Done, this is latest 2.1.0 for MCU2 upgraded cars |
06be505 to
87beb3f
Compare
|
Updated to v2.1.1, this is latest v2.1.1 for MCU2 upgraded cars |
|
Nice work guys, it's great to get this long-standing MCU2 upgrade sleep issue fixed. Is there any prospect that this will be merged? Or should I switch to this PR fork for good? |
|
This code is "proof of concept" only. It is somewhat ugly. Problem is that the Vehicle state machine (GenServer) is already overly complicated and unmaintainable (IMHO), and this just makes it so much worse. Ideally the code needs a refactor to implement this properly. I have some vague ideas on how to do this. Problem is though with Tesla threatening to shut off the unofficial API, nobody wants to dedicate their time on a refactor that may eventually become useless. |
|
Fair enough, I've just switched to this PR and my Model S has finally slept for more than 50 min since getting the MCU2 upgrade a year ago! Nice work It wasn't too difficult to switch to this PR, upgrading to V2 was more involved! |
|
I think this is somewhat typical. The legacy API is somewhat terrible, and sometimes we might miss events. In theory we should be able to detect the car is waking up, IIRC through streaming and polling the tesla endpoint (as in the endpoint that doesn't wake the car). In practice, I have occasionally seen times it misses trips also. This PR is somewhat complicated, it is possible there is some edge cases we don't deal with correctly. Alternatively it is possible we are getting bad/cached data from Tesla API. Need to investigate. But can't investigate without a reproducible test case. |
For more details see: https://docs.teslamate.org/docs/faq#why-am-i-missing-data-when-not-using-the-streaming-api I personally make sure, TeslaMate is not in falling asleep state before every start (using secure connection to my instance and, open webpage and if in trying to fall asleep I hit the button. This way I never lost a single meter). |
I recall reading that some time ago, I'm just surprised it never picked up on my 30 min drive home, like after 8 min. (10 min stop and 8 min of the drive would cover the the 3 + 15 min "timeout").
Thanks, I'll look at setting something like this up - probably via home assistant. |
There is an put api endpoint for this as well (not really documented: #91). As I do not want to miss anything, I do not trust the automation like mobile has Bluetooth connection to car -> call wake-up), as sometime Bluetooth in Tesla hangs. |
87beb3f to
1bfb9c7
Compare
|
Updated to v2.2.0, this is latest v2.2.0 for MCU2 upgraded cars |




changes from @micves from #3262, fixes #3084
to use this just follow https://docs.teslamate.org/docs/development#testing-with-our-ci-which-builds-the-docker-images-automatically-per-pr with
pr-4453