diff --git a/lib/tesla_mate/log.ex b/lib/tesla_mate/log.ex index 9fe8a4e5..e33ab0ed 100644 --- a/lib/tesla_mate/log.ex +++ b/lib/tesla_mate/log.ex @@ -8,7 +8,7 @@ defmodule TeslaMate.Log do alias TeslaMate.Log.Position - def insert_position(attrs \\ %{}) do + def insert_position(attrs) do %Position{} |> Position.changeset(attrs) |> Repo.insert() @@ -119,7 +119,7 @@ defmodule TeslaMate.Log do |> update(set: [end_date: ^end_date, end_position_id: ^last_position_id]) |> Repo.update_all([]) |> case do - {0, nil} -> {:erorr, :no_state_to_be_closed} + {0, nil} -> {:erorr, :no_drive_state_to_be_closed} {1, nil} -> :ok {n, nil} -> {:error, {:closed_multiple_states, n}} end @@ -181,4 +181,70 @@ defmodule TeslaMate.Log do |> DriveState.changeset(attrs) |> Repo.update() end + + alias TeslaMate.Log.{ChargingState, Charge} + + def insert_charge(attrs) do + %Charge{} + |> Charge.changeset(attrs) + |> Repo.insert() + end + + def get_last_charge_id! do + Charge + |> select([p], max(p.id)) + |> Repo.one!() + end + + def start_charging_state do + # TODO combine with insert_charge && insert_position + + last_position_id = get_last_position_id!() + last_charge_id = get_last_charge_id!() + + attrs = %{ + start_date: DateTime.utc_now(), + position: last_position_id, + charge_start_id: last_charge_id + } + + with {:ok, _} <- create_charging_state(attrs) do + :ok + end + end + + def close_charging_state do + last_charge_id = get_last_charge_id!() + end_date = DateTime.utc_now() + + result = + ChargingState + |> where([c], is_nil(c.end_date)) + |> update(set: [end_date: ^end_date, charge_end_id: ^last_charge_id]) + |> Repo.update_all([]) + + case result do + {0, nil} -> {:erorr, :no_charging_state_to_be_closed} + {1, nil} -> :ok + {n, nil} -> {:error, {:closed_multiple_charging_states, n}} + end + end + + defp create_charging_state(attrs \\ %{}) do + %ChargingState{} + |> ChargingState.changeset(attrs) + |> Repo.insert() + end + + defp update_charging_state(%ChargingState{} = charging_state, attrs) do + charging_state + |> ChargingState.changeset(attrs) + |> Repo.update() + end + + defp update_charge(%Charge{} = charge, attrs) do + charge + |> Charge.changeset(attrs) + |> Repo.update() + end end diff --git a/lib/tesla_mate/log/charge.ex b/lib/tesla_mate/log/charge.ex new file mode 100644 index 00000000..302bbd58 --- /dev/null +++ b/lib/tesla_mate/log/charge.ex @@ -0,0 +1,39 @@ +defmodule TeslaMate.Log.Charge do + use Ecto.Schema + import Ecto.Changeset + + schema "charges" do + field :battery_level, :float + field :charge_energy_added, :float + field :charger_actual_current, :integer + field :charger_phases, :integer, default: 1 + field :charger_power, :float + field :charger_voltage, :integer + field :date, :utc_datetime + field :ideal_battery_range, :float + field :outside_temp, :float + end + + @doc false + def changeset(charge, attrs) do + charge + |> cast(attrs, [ + :battery_level, + :charge_energy_added, + :charger_power, + :date, + :ideal_battery_range, + :charger_voltage, + :charger_phases, + :charger_actual_current, + :outside_temp + ]) + |> validate_required([ + :battery_level, + :charge_energy_added, + :charger_power, + :date, + :ideal_battery_range + ]) + end +end diff --git a/lib/tesla_mate/log/charging_state.ex b/lib/tesla_mate/log/charging_state.ex new file mode 100644 index 00000000..d04800ce --- /dev/null +++ b/lib/tesla_mate/log/charging_state.ex @@ -0,0 +1,35 @@ +defmodule TeslaMate.Log.ChargingState do + use Ecto.Schema + import Ecto.Changeset + + alias TeslaMate.Log.Charge + + schema "charging_states" do + field :start_date, :utc_datetime + field :end_date, :utc_datetime + field :unplug_date, :utc_datetime + field :charge_energy_added, :float + + belongs_to(:position, Position, foreign_key: :position_id) + belongs_to(:charge_start, Charge, foreign_key: :charge_start_id) + belongs_to(:charge_end, Charge, foreign_key: :charge_end_id) + end + + @doc false + def changeset(charging_state, attrs) do + charging_state + |> cast(attrs, [ + :start_date, + :end_date, + :unplug_date, + :charge_energy_added, + :position_id, + :charge_start_id, + :charge_end_id + ]) + |> validate_required([:start_date]) + |> foreign_key_constraint(:position_id) + |> foreign_key_constraint(:charge_start_id) + |> foreign_key_constraint(:charge_end_id) + end +end diff --git a/priv/repo/migrations/20190331184331_create_charges.exs b/priv/repo/migrations/20190331184331_create_charges.exs new file mode 100644 index 00000000..4fa7b3b4 --- /dev/null +++ b/priv/repo/migrations/20190331184331_create_charges.exs @@ -0,0 +1,17 @@ +defmodule TeslaMate.Repo.Migrations.CreateCharges do + use Ecto.Migration + + def change do + create table(:charges) do + add(:date, :utc_datetime, null: false) + add(:ideal_battery_range, :float, null: false) + add(:battery_level, :float, null: false) + add(:charge_energy_added, :float, null: false) + add(:charger_power, :float, null: false) + add(:charger_voltage, :integer) + add(:charger_phases, :integer) + add(:charger_actual_current, :integer) + add(:outside_temp, :float) + end + end +end diff --git a/priv/repo/migrations/20190331185127_create_charging_states.exs b/priv/repo/migrations/20190331185127_create_charging_states.exs new file mode 100644 index 00000000..c9b80599 --- /dev/null +++ b/priv/repo/migrations/20190331185127_create_charging_states.exs @@ -0,0 +1,17 @@ +defmodule TeslaMate.Repo.Migrations.CreateChargingStates do + use Ecto.Migration + + def change do + create table(:charging_states) do + add(:start_date, :utc_datetime, nul: false) + add(:end_date, :utc_datetime) + + add(:unplug_date, :utc_datetime) + add(:charge_energy_added, :float) + + add(:position_id, references(:positions)) + add(:charge_start_id, references(:charges)) + add(:charge_end_id, references(:charges)) + end + end +end diff --git a/test/tesla_mate/log/log_test.exs b/test/tesla_mate/log/log_test.exs index 08f786ea..e08d572a 100644 --- a/test/tesla_mate/log/log_test.exs +++ b/test/tesla_mate/log/log_test.exs @@ -193,4 +193,140 @@ defmodule TeslaMate.LogTest do assert %Ecto.Changeset{} = Log.change_drive_state(drive_state) end end + + describe "charging_states" do + alias TeslaMate.Log.ChargingState + + @valid_attrs %{end_date: "2010-04-17T14:00:00Z", start_date: "2010-04-17T14:00:00Z"} + @update_attrs %{end_date: "2011-05-18T15:01:01Z", start_date: "2011-05-18T15:01:01Z"} + @invalid_attrs %{end_date: nil, start_date: nil} + + def charging_state_fixture(attrs \\ %{}) do + {:ok, charging_state} = + attrs + |> Enum.into(@valid_attrs) + |> Log.create_charging_state() + + charging_state + end + + test "list_charging_states/0 returns all charging_states" do + charging_state = charging_state_fixture() + assert Log.list_charging_states() == [charging_state] + end + + test "get_charging_state!/1 returns the charging_state with given id" do + charging_state = charging_state_fixture() + assert Log.get_charging_state!(charging_state.id) == charging_state + end + + test "create_charging_state/1 with valid data creates a charging_state" do + assert {:ok, %ChargingState{} = charging_state} = Log.create_charging_state(@valid_attrs) + assert charging_state.end_date == DateTime.from_naive!(~N[2010-04-17T14:00:00Z], "Etc/UTC") + assert charging_state.start_date == DateTime.from_naive!(~N[2010-04-17T14:00:00Z], "Etc/UTC") + end + + test "create_charging_state/1 with invalid data returns error changeset" do + assert {:error, %Ecto.Changeset{}} = Log.create_charging_state(@invalid_attrs) + end + + test "update_charging_state/2 with valid data updates the charging_state" do + charging_state = charging_state_fixture() + assert {:ok, %ChargingState{} = charging_state} = Log.update_charging_state(charging_state, @update_attrs) + assert charging_state.end_date == DateTime.from_naive!(~N[2011-05-18T15:01:01Z], "Etc/UTC") + assert charging_state.start_date == DateTime.from_naive!(~N[2011-05-18T15:01:01Z], "Etc/UTC") + end + + test "update_charging_state/2 with invalid data returns error changeset" do + charging_state = charging_state_fixture() + assert {:error, %Ecto.Changeset{}} = Log.update_charging_state(charging_state, @invalid_attrs) + assert charging_state == Log.get_charging_state!(charging_state.id) + end + + test "delete_charging_state/1 deletes the charging_state" do + charging_state = charging_state_fixture() + assert {:ok, %ChargingState{}} = Log.delete_charging_state(charging_state) + assert_raise Ecto.NoResultsError, fn -> Log.get_charging_state!(charging_state.id) end + end + + test "change_charging_state/1 returns a charging_state changeset" do + charging_state = charging_state_fixture() + assert %Ecto.Changeset{} = Log.change_charging_state(charging_state) + end + end + + describe "charges" do + alias TeslaMate.Log.Charge + + @valid_attrs %{battery_level: 120.5, charge_energy_added: 120.5, charger_actual_current: 42, charger_phases: 42, charger_power: 120.5, charger_voltage: 42, date: "2010-04-17T14:00:00Z", ideal_battery_range: 120.5, outside_temp: 120.5} + @update_attrs %{battery_level: 456.7, charge_energy_added: 456.7, charger_actual_current: 43, charger_phases: 43, charger_power: 456.7, charger_voltage: 43, date: "2011-05-18T15:01:01Z", ideal_battery_range: 456.7, outside_temp: 456.7} + @invalid_attrs %{battery_level: nil, charge_energy_added: nil, charger_actual_current: nil, charger_phases: nil, charger_power: nil, charger_voltage: nil, date: nil, ideal_battery_range: nil, outside_temp: nil} + + def charge_fixture(attrs \\ %{}) do + {:ok, charge} = + attrs + |> Enum.into(@valid_attrs) + |> Log.create_charge() + + charge + end + + test "list_charges/0 returns all charges" do + charge = charge_fixture() + assert Log.list_charges() == [charge] + end + + test "get_charge!/1 returns the charge with given id" do + charge = charge_fixture() + assert Log.get_charge!(charge.id) == charge + end + + test "create_charge/1 with valid data creates a charge" do + assert {:ok, %Charge{} = charge} = Log.create_charge(@valid_attrs) + assert charge.battery_level == 120.5 + assert charge.charge_energy_added == 120.5 + assert charge.charger_actual_current == 42 + assert charge.charger_phases == 42 + assert charge.charger_power == 120.5 + assert charge.charger_voltage == 42 + assert charge.date == DateTime.from_naive!(~N[2010-04-17T14:00:00Z], "Etc/UTC") + assert charge.ideal_battery_range == 120.5 + assert charge.outside_temp == 120.5 + end + + test "create_charge/1 with invalid data returns error changeset" do + assert {:error, %Ecto.Changeset{}} = Log.create_charge(@invalid_attrs) + end + + test "update_charge/2 with valid data updates the charge" do + charge = charge_fixture() + assert {:ok, %Charge{} = charge} = Log.update_charge(charge, @update_attrs) + assert charge.battery_level == 456.7 + assert charge.charge_energy_added == 456.7 + assert charge.charger_actual_current == 43 + assert charge.charger_phases == 43 + assert charge.charger_power == 456.7 + assert charge.charger_voltage == 43 + assert charge.date == DateTime.from_naive!(~N[2011-05-18T15:01:01Z], "Etc/UTC") + assert charge.ideal_battery_range == 456.7 + assert charge.outside_temp == 456.7 + end + + test "update_charge/2 with invalid data returns error changeset" do + charge = charge_fixture() + assert {:error, %Ecto.Changeset{}} = Log.update_charge(charge, @invalid_attrs) + assert charge == Log.get_charge!(charge.id) + end + + test "delete_charge/1 deletes the charge" do + charge = charge_fixture() + assert {:ok, %Charge{}} = Log.delete_charge(charge) + assert_raise Ecto.NoResultsError, fn -> Log.get_charge!(charge.id) end + end + + test "change_charge/1 returns a charge changeset" do + charge = charge_fixture() + assert %Ecto.Changeset{} = Log.change_charge(charge) + end + end end