-
Notifications
You must be signed in to change notification settings - Fork 766
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
feat: handle sleep behavior of MCU2 upgraded cars #4453
base: master
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 site 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
end I 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
end i.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])
end So 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
end This 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? |
There are a lot of references to Wonder if with these changes we have triggered a new code path that invokes one of these that wasn't previously used. |
I think bottom line is our tests are far too brittle. I had hoped we already did something sensible with date times, but apparently not. I created a hacked commit that will isolate calls to https://github.com/teslamate-org/teslamate/commits/push-ktmmkymmrnny/ But somehow Now the test fails with a different error:
Which is kind of odd, somehow the vehicle got a state of driving. |
Thank you for digging into this!
Unfortunately, I have to agree. At least in the past, they gave us enough confidence to release new versions.
I have stumbled over this in the past and wondered why more realistic dates are not used to cover the case where a date is not correctly initialized. |
6c7f0d8
to
8d4da30
Compare
power > 0 is when e.g. the climate is on which could be scheduled preconditioning or starting preheat from the app. The code parts you showed will make sure it doesn't enter 'trying to sleep' (the internal state suspended) It would make sense to split it out, since its not really related to MCU2 upgraded cars. Might also need some added tests (like as far as I remember is for 'Charging detected') And on that note I also added some optimizations for that in line 616-630 where it only goes to Charging when the car is plugged in (power < 0) and its not preconditioning or in dog mode.
There should have been an enumeration, but my noob-ness in elixir told me to do it later :) I hope it kind of covers your other comments, which in general seems to make sense :) Regarding the test fails and time. I actually don't think they fail because of the time. If the test succeeds I still think it makes those stale fetch logs, but you just don't see them.
I think it makes sense, the test you tried is this one:
The online_event is settting shift_state to N and this is feed into start_vehicle. start_vehicle is creating a Vehicle and executing the array of events. But e.g. will Sorry for the huge comment :D |
Thanks for your comprehensive response. Will be considering what you said in detail. One thing I was missing is that you need to connect to the stream to get the power level. I guess that is the only way to do so without risking waking up the car. |
8d4da30
to
ab333fb
Compare
ab333fb
to
33a76ed
Compare
33a76ed
to
cd6be38
Compare
This PR is gradually becoming simpler now. I need to re-examine it when I have time I think. The additional code at 341-417 is still a bit of a pain. Possibly this is most this PR can be broken up. Refactoring still possible, but not sure it will make the PR any easier to understand. |
Exactly. To be honest, its a nasty workaround but it was the only difference I found between fake and real online (back in the investigation days of #3084)
Thanks for helping splitting it up. I also think its sized down to the bare minimum now. Still complex and I would hope there was another simpler way to detect it. Now the app for iphone and android can be opened without waking up the car. |
changes from @micves from #3262, fixes #3084