diff --git a/lib/tesla_api/stream.ex b/lib/tesla_api/stream.ex index f73aa55b..6d9fbd9c 100644 --- a/lib/tesla_api/stream.ex +++ b/lib/tesla_api/stream.ex @@ -152,7 +152,15 @@ defmodule TeslaApi.Stream do {:ok, %{"msg_type" => "data:error", "tag" => ^tag, "error_type" => "vehicle_error", "value" => v}} -> - Logger.error("Vehicle Error: #{v}") + case v do + "Vehicle is offline" -> + Logger.info("Streaming API: Vehicle offline") + state.receiver.(:vehicle_offline) + + _ -> + Logger.error("Vehicle Error: #{v}") + end + {:ok, state} {:ok, %{"msg_type" => "data:error", "tag" => ^tag, "error_type" => "client_error"} = msg} -> diff --git a/lib/teslamate/vehicles/vehicle.ex b/lib/teslamate/vehicles/vehicle.ex index 5957ece6..a8a4a015 100644 --- a/lib/teslamate/vehicles/vehicle.ex +++ b/lib/teslamate/vehicles/vehicle.ex @@ -526,6 +526,14 @@ defmodule TeslaMate.Vehicles.Vehicle do {:keep_state, %Data{data | stream_pid: pid}} end + def handle_event(:info, {:stream, msg}, _state, data) + when msg in [:vehicle_offline] do + Logger.info("Stream reports vehicle as offline … ", car_id: data.car.id) + + {:next_state, :start, data, + [broadcast_fetch(false), {:next_event, :internal, {:update, {:offline, data.last_response}}}]} + end + def handle_event(:info, {:stream, stream_data}, _state, data) do Logger.info("Received stream data: #{inspect(stream_data)}", car_id: data.car.id) :keep_state_and_data diff --git a/test/teslamate/vehicles/vehicle/streaming_test.exs b/test/teslamate/vehicles/vehicle/streaming_test.exs index 9befa38d..25226048 100644 --- a/test/teslamate/vehicles/vehicle/streaming_test.exs +++ b/test/teslamate/vehicles/vehicle/streaming_test.exs @@ -556,4 +556,47 @@ defmodule TeslaMate.Vehicles.Vehicle.StreamingTest do refute_receive _ end end + + describe "offline" do + test "go offline when stream get :vehicle_offline", %{test: name} do + me = self() + + events = [ + {:ok, online_event()}, + {:ok, online_event()}, + {:ok, online_event()}, + fn -> + send(me, :continue?) + + receive do + :continue -> {:ok, %TeslaApi.Vehicle{state: "offline"}} + after + 5_000 -> raise "No :continue after 5s" + end + end, + fn -> Process.sleep(10_000) end + ] + + :ok = + start_vehicle(name, events, + settings: %{use_streaming_api: true, suspend_min: 999_999_999} + ) + + assert_receive {:start_state, car, :online, date: _} + assert_receive {:insert_position, ^car, %{}} + assert_receive {ApiMock, {:stream, _eid, func}} when is_function(func) + assert_receive {:pubsub, {:broadcast, _, _, %Summary{state: :online}}} + + send(name, {:stream, :vehicle_offline}) + + assert_receive :continue? + send(:"api_#{name}", :continue) + + assert_receive {:start_state, _, :offline, _} + assert_receive {:"$websockex_cast", :disconnect} + assert_receive {:pubsub, {:broadcast, _, _, %Summary{state: :offline}}} + + refute_receive _ + end + end end