Implement Regimens again, add tests and test support
* This also includes changes to all Farmbot API Assets adding a `monitor: :boolean` field. This allows tests to be run causing minimal side effects on the rest of the systems.pull/974/head
parent
a4c1eac2d2
commit
6e2a018598
|
@ -12,3 +12,5 @@ alias Farmbot.Asset.{
|
||||||
PersistentRegimen,
|
PersistentRegimen,
|
||||||
Sequence
|
Sequence
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alias Farmbot.TestSupport.AssetFixtures
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use Mix.Config
|
use Mix.Config
|
||||||
|
|
||||||
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.FarmEvent, checkup_time_ms: 10_000
|
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.FarmEvent, checkup_time_ms: 10_000
|
||||||
|
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.PersistentRegimen, checkup_time_ms: 10_000
|
||||||
|
|
||||||
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.FarmwareInstallation,
|
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.FarmwareInstallation,
|
||||||
error_retry_time_ms: 30_000,
|
error_retry_time_ms: 30_000,
|
||||||
|
|
|
@ -4,6 +4,7 @@ config :farmbot_core, :behaviour,
|
||||||
celery_script_io_layer: Farmbot.TestSupport.CeleryScript.TestIOLayer
|
celery_script_io_layer: Farmbot.TestSupport.CeleryScript.TestIOLayer
|
||||||
|
|
||||||
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.FarmEvent, checkup_time_ms: 1000
|
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.FarmEvent, checkup_time_ms: 1000
|
||||||
|
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.PersistentRegimen, checkup_time_ms: 1000
|
||||||
|
|
||||||
# must be lower than other timers
|
# must be lower than other timers
|
||||||
# To ensure other timers have time to timeout
|
# To ensure other timers have time to timeout
|
||||||
|
|
|
@ -65,7 +65,7 @@ defmodule Farmbot.Asset do
|
||||||
|
|
||||||
## Begin PersistentRegimen
|
## Begin PersistentRegimen
|
||||||
|
|
||||||
def upsert_persistent_regimen(%Regimen{} = regimen, %FarmEvent{} = farm_event, params \\ %{}) do
|
def upsert_persistent_regimen!(%Regimen{} = regimen, %FarmEvent{} = farm_event, params \\ %{}) do
|
||||||
q =
|
q =
|
||||||
from(pr in PersistentRegimen,
|
from(pr in PersistentRegimen,
|
||||||
where: pr.regimen_id == ^regimen.local_id and pr.farm_event_id == ^farm_event.local_id
|
where: pr.regimen_id == ^regimen.local_id and pr.farm_event_id == ^farm_event.local_id
|
||||||
|
@ -78,7 +78,13 @@ defmodule Farmbot.Asset do
|
||||||
|> PersistentRegimen.changeset(params)
|
|> PersistentRegimen.changeset(params)
|
||||||
|> Ecto.Changeset.put_assoc(:regimen, regimen)
|
|> Ecto.Changeset.put_assoc(:regimen, regimen)
|
||||||
|> Ecto.Changeset.put_assoc(:farm_event, farm_event)
|
|> Ecto.Changeset.put_assoc(:farm_event, farm_event)
|
||||||
|> Repo.insert_or_update()
|
|> Repo.insert_or_update!()
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_persistent_regimen!(%PersistentRegimen{} = pr, params \\ %{}) do
|
||||||
|
pr
|
||||||
|
|> PersistentRegimen.changeset(params)
|
||||||
|
|> Repo.update!()
|
||||||
end
|
end
|
||||||
|
|
||||||
## End PersistentRegimen
|
## End PersistentRegimen
|
||||||
|
|
|
@ -17,6 +17,7 @@ defmodule Farmbot.Asset.Device do
|
||||||
|
|
||||||
field(:name, :string)
|
field(:name, :string)
|
||||||
field(:timezone, :string)
|
field(:timezone, :string)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ defmodule Farmbot.Asset.Device do
|
||||||
|
|
||||||
def changeset(device, params \\ %{}) do
|
def changeset(device, params \\ %{}) do
|
||||||
device
|
device
|
||||||
|> cast(params, [:id, :name, :timezone, :created_at, :updated_at])
|
|> cast(params, [:id, :name, :timezone, :monitor, :created_at, :updated_at])
|
||||||
|> validate_required([])
|
|> validate_required([])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,6 +20,7 @@ defmodule Elixir.Farmbot.Asset.DiagnosticDump do
|
||||||
field(:firmware_state, :string)
|
field(:firmware_state, :string)
|
||||||
field(:network_interface, :string)
|
field(:network_interface, :string)
|
||||||
field(:fbos_dmesg_dump, :string)
|
field(:fbos_dmesg_dump, :string)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -47,6 +48,7 @@ defmodule Elixir.Farmbot.Asset.DiagnosticDump do
|
||||||
:firmware_state,
|
:firmware_state,
|
||||||
:network_interface,
|
:network_interface,
|
||||||
:fbos_dmesg_dump,
|
:fbos_dmesg_dump,
|
||||||
|
:monitor,
|
||||||
:created_at,
|
:created_at,
|
||||||
:updated_at
|
:updated_at
|
||||||
])
|
])
|
||||||
|
|
|
@ -22,6 +22,7 @@ defmodule Elixir.Farmbot.Asset.FarmEvent do
|
||||||
|
|
||||||
# Private
|
# Private
|
||||||
field(:last_executed, :utc_datetime)
|
field(:last_executed, :utc_datetime)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
|
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
@ -49,6 +50,7 @@ defmodule Elixir.Farmbot.Asset.FarmEvent do
|
||||||
:start_time,
|
:start_time,
|
||||||
:time_unit,
|
:time_unit,
|
||||||
:last_executed,
|
:last_executed,
|
||||||
|
:monitor,
|
||||||
:created_at,
|
:created_at,
|
||||||
:updated_at
|
:updated_at
|
||||||
])
|
])
|
||||||
|
|
|
@ -15,6 +15,7 @@ defmodule Elixir.Farmbot.Asset.FarmwareEnv do
|
||||||
|
|
||||||
field(:key, :string)
|
field(:key, :string)
|
||||||
field(:value, :string)
|
field(:value, :string)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ defmodule Elixir.Farmbot.Asset.FarmwareEnv do
|
||||||
|
|
||||||
def changeset(farmware_env, params \\ %{}) do
|
def changeset(farmware_env, params \\ %{}) do
|
||||||
farmware_env
|
farmware_env
|
||||||
|> cast(params, [:id, :key, :value, :created_at, :updated_at])
|
|> cast(params, [:id, :key, :value, :monitor, :created_at, :updated_at])
|
||||||
|> validate_required([])
|
|> validate_required([])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,6 +18,7 @@ defmodule Farmbot.Asset.FarmwareInstallation do
|
||||||
field(:url, :string)
|
field(:url, :string)
|
||||||
|
|
||||||
embeds_one(:manifest, Manifest, on_replace: :update)
|
embeds_one(:manifest, Manifest, on_replace: :update)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ defmodule Farmbot.Asset.FarmwareInstallation do
|
||||||
|
|
||||||
def changeset(farmware_installation, params \\ %{}) do
|
def changeset(farmware_installation, params \\ %{}) do
|
||||||
farmware_installation
|
farmware_installation
|
||||||
|> cast(params, [:id, :url, :created_at, :updated_at])
|
|> cast(params, [:id, :url, :monitor, :created_at, :updated_at])
|
||||||
|> cast_embed(:manifest)
|
|> cast_embed(:manifest)
|
||||||
|> validate_required([])
|
|> validate_required([])
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,6 +27,7 @@ defmodule Elixir.Farmbot.Asset.FbosConfig do
|
||||||
field(:sequence_body_log, :boolean)
|
field(:sequence_body_log, :boolean)
|
||||||
field(:sequence_complete_log, :boolean)
|
field(:sequence_complete_log, :boolean)
|
||||||
field(:sequence_init_log, :boolean)
|
field(:sequence_init_log, :boolean)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -68,6 +69,7 @@ defmodule Elixir.Farmbot.Asset.FbosConfig do
|
||||||
:sequence_body_log,
|
:sequence_body_log,
|
||||||
:sequence_complete_log,
|
:sequence_complete_log,
|
||||||
:sequence_init_log,
|
:sequence_init_log,
|
||||||
|
:monitor,
|
||||||
:created_at,
|
:created_at,
|
||||||
:updated_at
|
:updated_at
|
||||||
])
|
])
|
||||||
|
|
|
@ -101,6 +101,7 @@ defmodule Elixir.Farmbot.Asset.FirmwareConfig do
|
||||||
field(:encoder_invert_x, :float)
|
field(:encoder_invert_x, :float)
|
||||||
field(:encoder_missed_steps_max_x, :float)
|
field(:encoder_missed_steps_max_x, :float)
|
||||||
field(:movement_invert_motor_y, :float)
|
field(:movement_invert_motor_y, :float)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -290,6 +291,7 @@ defmodule Elixir.Farmbot.Asset.FirmwareConfig do
|
||||||
:encoder_invert_x,
|
:encoder_invert_x,
|
||||||
:encoder_missed_steps_max_x,
|
:encoder_missed_steps_max_x,
|
||||||
:movement_invert_motor_y,
|
:movement_invert_motor_y,
|
||||||
|
:monitor,
|
||||||
:created_at,
|
:created_at,
|
||||||
:updated_at
|
:updated_at
|
||||||
])
|
])
|
||||||
|
|
|
@ -17,6 +17,7 @@ defmodule Farmbot.Asset.Peripheral do
|
||||||
field(:pin, :integer)
|
field(:pin, :integer)
|
||||||
field(:mode, :integer)
|
field(:mode, :integer)
|
||||||
field(:label, :string)
|
field(:label, :string)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ defmodule Farmbot.Asset.Peripheral do
|
||||||
|
|
||||||
def changeset(peripheral, params \\ %{}) do
|
def changeset(peripheral, params \\ %{}) do
|
||||||
peripheral
|
peripheral
|
||||||
|> cast(params, [:id, :pin, :mode, :label, :created_at, :updated_at])
|
|> cast(params, [:id, :pin, :mode, :label, :monitor, :created_at, :updated_at])
|
||||||
|> validate_required([])
|
|> validate_required([])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,14 +7,51 @@ defmodule Farmbot.Asset.PersistentRegimen do
|
||||||
schema "persistent_regimens" do
|
schema "persistent_regimens" do
|
||||||
belongs_to(:regimen, Farmbot.Asset.Regimen, references: :local_id, type: :binary_id)
|
belongs_to(:regimen, Farmbot.Asset.Regimen, references: :local_id, type: :binary_id)
|
||||||
belongs_to(:farm_event, Farmbot.Asset.FarmEvent, references: :local_id, type: :binary_id)
|
belongs_to(:farm_event, Farmbot.Asset.FarmEvent, references: :local_id, type: :binary_id)
|
||||||
|
field(:epoch, :utc_datetime)
|
||||||
field(:started_at, :utc_datetime)
|
field(:started_at, :utc_datetime)
|
||||||
|
field(:next, :utc_datetime)
|
||||||
|
# Can't use references here.
|
||||||
|
field(:next_sequence_id, :id)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
def changeset(persistent_regimen, params \\ %{}) do
|
def changeset(persistent_regimen, params \\ %{}) do
|
||||||
persistent_regimen
|
persistent_regimen
|
||||||
|> cast(params, [:started_at])
|
|> cast(params, [:started_at, :next, :next_sequence_id, :monitor])
|
||||||
|
|> put_epoch()
|
||||||
|> cast_assoc(:regimen)
|
|> cast_assoc(:regimen)
|
||||||
|> cast_assoc(:farm_event)
|
|> cast_assoc(:farm_event)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp put_epoch(%{valid?: true} = changeset) do
|
||||||
|
started_at = get_field(changeset, :started_at) || DateTime.utc_now()
|
||||||
|
|
||||||
|
if get_field(changeset, :epoch) do
|
||||||
|
changeset
|
||||||
|
else
|
||||||
|
case build_epoch(started_at) do
|
||||||
|
{:ok, epoch} -> put_change(changeset, :epoch, epoch)
|
||||||
|
:error -> add_error(changeset, :epoch, "Missing timezone")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp put_epoch(changeset), do: changeset
|
||||||
|
|
||||||
|
# returns midnight of today
|
||||||
|
@spec build_epoch(DateTime.t()) :: DateTime.t()
|
||||||
|
def build_epoch(%DateTime{} = datetime) do
|
||||||
|
case Farmbot.Asset.device().timezone do
|
||||||
|
nil ->
|
||||||
|
:error
|
||||||
|
|
||||||
|
tz ->
|
||||||
|
%DateTime{} = n = Timex.Timezone.convert(datetime, tz)
|
||||||
|
opts = [hours: -n.hour, seconds: -n.second, minutes: -n.minute]
|
||||||
|
localized_epoch = Timex.shift(n, opts)
|
||||||
|
epoch = Timex.Timezone.convert(localized_epoch, datetime.time_zone)
|
||||||
|
{:ok, epoch}
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,6 +16,7 @@ defmodule Farmbot.Asset.PinBinding do
|
||||||
field(:pin_num, :integer)
|
field(:pin_num, :integer)
|
||||||
field(:sequence_id, :integer)
|
field(:sequence_id, :integer)
|
||||||
field(:special_action, :string)
|
field(:special_action, :string)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -30,7 +31,15 @@ defmodule Farmbot.Asset.PinBinding do
|
||||||
|
|
||||||
def changeset(pin_binding, params \\ %{}) do
|
def changeset(pin_binding, params \\ %{}) do
|
||||||
pin_binding
|
pin_binding
|
||||||
|> cast(params, [:id, :pin_num, :sequence_id, :special_action, :created_at, :updated_at])
|
|> cast(params, [
|
||||||
|
:id,
|
||||||
|
:pin_num,
|
||||||
|
:sequence_id,
|
||||||
|
:special_action,
|
||||||
|
:monitor,
|
||||||
|
:created_at,
|
||||||
|
:updated_at
|
||||||
|
])
|
||||||
|> validate_required([])
|
|> validate_required([])
|
||||||
|> validate_pin_num()
|
|> validate_pin_num()
|
||||||
|> unique_constraint(:pin_num)
|
|> unique_constraint(:pin_num)
|
||||||
|
|
|
@ -22,6 +22,7 @@ defmodule Farmbot.Asset.Point do
|
||||||
field(:x, :float)
|
field(:x, :float)
|
||||||
field(:y, :float)
|
field(:y, :float)
|
||||||
field(:z, :float)
|
field(:z, :float)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -53,6 +54,7 @@ defmodule Farmbot.Asset.Point do
|
||||||
:x,
|
:x,
|
||||||
:y,
|
:y,
|
||||||
:z,
|
:z,
|
||||||
|
:monitor,
|
||||||
:created_at,
|
:created_at,
|
||||||
:updated_at
|
:updated_at
|
||||||
])
|
])
|
||||||
|
|
|
@ -28,6 +28,7 @@ defmodule Farmbot.Asset.Private.LocalMeta do
|
||||||
field(:status, :string)
|
field(:status, :string)
|
||||||
field(:table, :string)
|
field(:table, :string)
|
||||||
field(:asset_local_id, :binary_id)
|
field(:asset_local_id, :binary_id)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
|
|
||||||
belongs_to(:device, Device,
|
belongs_to(:device, Device,
|
||||||
foreign_key: :asset_local_id,
|
foreign_key: :asset_local_id,
|
||||||
|
|
|
@ -43,6 +43,7 @@ defmodule Farmbot.Asset.Regimen do
|
||||||
|
|
||||||
field(:name, :string)
|
field(:name, :string)
|
||||||
embeds_many(:regimen_items, Item, on_replace: :delete)
|
embeds_many(:regimen_items, Item, on_replace: :delete)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@ defmodule Farmbot.Asset.Regimen do
|
||||||
|
|
||||||
def changeset(regimen, params \\ %{}) do
|
def changeset(regimen, params \\ %{}) do
|
||||||
regimen
|
regimen
|
||||||
|> cast(params, [:id, :name, :created_at, :updated_at])
|
|> cast(params, [:id, :name, :monitor, :created_at, :updated_at])
|
||||||
|> cast_embed(:regimen_items)
|
|> cast_embed(:regimen_items)
|
||||||
|> validate_required([])
|
|> validate_required([])
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,6 +17,7 @@ defmodule Farmbot.Asset.Sensor do
|
||||||
field(:pin, :integer)
|
field(:pin, :integer)
|
||||||
field(:mode, :integer)
|
field(:mode, :integer)
|
||||||
field(:label, :string)
|
field(:label, :string)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ defmodule Farmbot.Asset.Sensor do
|
||||||
|
|
||||||
def changeset(sensor, params \\ %{}) do
|
def changeset(sensor, params \\ %{}) do
|
||||||
sensor
|
sensor
|
||||||
|> cast(params, [:id, :pin, :mode, :label, :created_at, :updated_at])
|
|> cast(params, [:id, :pin, :mode, :label, :monitor, :created_at, :updated_at])
|
||||||
|> validate_required([:id, :pin, :mode, :label])
|
|> validate_required([:id, :pin, :mode, :label])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,6 +20,7 @@ defmodule Farmbot.Asset.SensorReading do
|
||||||
field(:x, :float)
|
field(:x, :float)
|
||||||
field(:y, :float)
|
field(:y, :float)
|
||||||
field(:z, :float)
|
field(:z, :float)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ defmodule Farmbot.Asset.SensorReading do
|
||||||
|
|
||||||
def changeset(sensor, params \\ %{}) do
|
def changeset(sensor, params \\ %{}) do
|
||||||
sensor
|
sensor
|
||||||
|> cast(params, [:id, :mode, :pin, :value, :x, :y, :z, :created_at, :updated_at])
|
|> cast(params, [:id, :mode, :pin, :value, :x, :y, :z, :monitor, :created_at, :updated_at])
|
||||||
|> validate_required([])
|
|> validate_required([])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,6 +18,7 @@ defmodule Farmbot.Asset.Sequence do
|
||||||
field(:kind, :string)
|
field(:kind, :string)
|
||||||
field(:args, :map)
|
field(:args, :map)
|
||||||
field(:body, {:array, :map})
|
field(:body, {:array, :map})
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -33,7 +34,7 @@ defmodule Farmbot.Asset.Sequence do
|
||||||
|
|
||||||
def changeset(device, params \\ %{}) do
|
def changeset(device, params \\ %{}) do
|
||||||
device
|
device
|
||||||
|> cast(params, [:id, :args, :name, :kind, :body, :created_at, :updated_at])
|
|> cast(params, [:id, :args, :name, :kind, :body, :monitor, :created_at, :updated_at])
|
||||||
|> validate_required([])
|
|> validate_required([])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,7 +24,7 @@ defmodule Farmbot.Asset.Supervisor do
|
||||||
Repo,
|
Repo,
|
||||||
{AssetSupervisor, module: FbosConfig},
|
{AssetSupervisor, module: FbosConfig},
|
||||||
{AssetSupervisor, module: Device},
|
{AssetSupervisor, module: Device},
|
||||||
{AssetSupervisor, module: PersistentRegimen, preload: [:farm_event, :regimen]},
|
{AssetSupervisor, module: PersistentRegimen},
|
||||||
{AssetSupervisor, module: FarmEvent},
|
{AssetSupervisor, module: FarmEvent},
|
||||||
{AssetSupervisor, module: PinBinding},
|
{AssetSupervisor, module: PinBinding},
|
||||||
{AssetSupervisor, module: Peripheral},
|
{AssetSupervisor, module: Peripheral},
|
||||||
|
|
|
@ -13,6 +13,7 @@ defmodule Farmbot.Asset.Tool do
|
||||||
)
|
)
|
||||||
|
|
||||||
field(:name, :string)
|
field(:name, :string)
|
||||||
|
field(:monitor, :boolean, default: true)
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@ defmodule Farmbot.Asset.Tool do
|
||||||
|
|
||||||
def changeset(tool, params \\ %{}) do
|
def changeset(tool, params \\ %{}) do
|
||||||
tool
|
tool
|
||||||
|> cast(params, [:id, :name, :created_at, :updated_at])
|
|> cast(params, [:id, :name, :monitor, :created_at, :updated_at])
|
||||||
|> validate_required([])
|
|> validate_required([])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,23 +30,31 @@ defmodule Farmbot.AssetMonitor do
|
||||||
# This is helpful for tests, but should probably be avoided
|
# This is helpful for tests, but should probably be avoided
|
||||||
@doc false
|
@doc false
|
||||||
def force_checkup do
|
def force_checkup do
|
||||||
GenServer.call(__MODULE__, :force_checkup)
|
GenServer.call(__MODULE__, :force_checkup, :infinity)
|
||||||
end
|
end
|
||||||
|
|
||||||
def init(_args) do
|
def init(_args) do
|
||||||
state = Map.new(order(), fn module -> {module, %{}} end)
|
state = Map.new(order(), fn module -> {module, %{}} end)
|
||||||
state = Map.put(state, :order, order())
|
state = Map.put(state, :order, order())
|
||||||
state = Map.put(state, :force_caller, nil)
|
state = Map.put(state, :force_callers, [])
|
||||||
{:ok, state, 0}
|
{:ok, state, 0}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_call(:force_checkup, caller, state) do
|
def handle_call(:force_checkup, caller, state) do
|
||||||
{:noreply, %{state | force_caller: caller}, 0}
|
{:noreply, %{state | force_callers: state.force_callers ++ [caller]}, 0}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_info(:timeout, %{order: []} = state) do
|
def handle_info(:timeout, %{order: []} = state) do
|
||||||
if state.force_caller, do: GenServer.reply(state.force_caller, :ok)
|
state = %{state | order: order()}
|
||||||
{:noreply, %{state | order: order(), force_caller: nil}, @checkup_time_ms}
|
|
||||||
|
case state.force_callers do
|
||||||
|
[caller | rest] ->
|
||||||
|
GenServer.reply(caller, :ok)
|
||||||
|
{:noreply, %{state | force_callers: rest}, 0}
|
||||||
|
|
||||||
|
[] ->
|
||||||
|
{:noreply, state, @checkup_time_ms}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_info(:timeout, state) do
|
def handle_info(:timeout, state) do
|
||||||
|
@ -70,13 +78,19 @@ defmodule Farmbot.AssetMonitor do
|
||||||
Enum.reduce(expected, sub_state, fn %{local_id: id, updated_at: updated_at} = asset,
|
Enum.reduce(expected, sub_state, fn %{local_id: id, updated_at: updated_at} = asset,
|
||||||
sub_state ->
|
sub_state ->
|
||||||
cond do
|
cond do
|
||||||
|
asset.monitor == false ->
|
||||||
|
# Logger.debug("#{inspect(kind)} #{id} should not be monitored")
|
||||||
|
Map.put(sub_state, id, updated_at)
|
||||||
|
|
||||||
is_nil(sub_state[id]) ->
|
is_nil(sub_state[id]) ->
|
||||||
Logger.debug("#{inspect(kind)} #{id} needs to be started")
|
Logger.debug("#{inspect(kind)} #{id} needs to be started")
|
||||||
|
asset = Repo.preload(asset, Farmbot.AssetWorker.preload(asset))
|
||||||
Farmbot.AssetSupervisor.start_child(asset)
|
Farmbot.AssetSupervisor.start_child(asset)
|
||||||
Map.put(sub_state, id, updated_at)
|
Map.put(sub_state, id, updated_at)
|
||||||
|
|
||||||
compare_datetimes(updated_at, sub_state[id]) == :gt ->
|
compare_datetimes(updated_at, sub_state[id]) == :gt ->
|
||||||
Logger.warn("#{inspect(kind)} #{id} needs to be updated")
|
Logger.warn("#{inspect(kind)} #{id} needs to be updated")
|
||||||
|
asset = Repo.preload(asset, Farmbot.AssetWorker.preload(asset))
|
||||||
Farmbot.AssetSupervisor.update_child(asset)
|
Farmbot.AssetSupervisor.update_child(asset)
|
||||||
Map.put(sub_state, id, updated_at)
|
Map.put(sub_state, id, updated_at)
|
||||||
|
|
||||||
|
@ -91,7 +105,7 @@ defmodule Farmbot.AssetMonitor do
|
||||||
Device,
|
Device,
|
||||||
FbosConfig,
|
FbosConfig,
|
||||||
FarmEvent,
|
FarmEvent,
|
||||||
# Peripheral,
|
Peripheral,
|
||||||
PersistentRegimen,
|
PersistentRegimen,
|
||||||
PinBinding,
|
PinBinding,
|
||||||
FarmwareInstallation,
|
FarmwareInstallation,
|
||||||
|
|
|
@ -57,7 +57,7 @@ defmodule Farmbot.AssetSupervisor do
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
def worker_spec(%{local_id: id} = asset) do
|
def worker_spec(%{local_id: id, monitor: true} = asset) do
|
||||||
%{
|
%{
|
||||||
id: id,
|
id: id,
|
||||||
start: {AssetWorker, :start_link, [asset]}
|
start: {AssetWorker, :start_link, [asset]}
|
||||||
|
@ -73,11 +73,11 @@ defmodule Farmbot.AssetSupervisor do
|
||||||
@doc false
|
@doc false
|
||||||
def init(args) do
|
def init(args) do
|
||||||
module = Keyword.fetch!(args, :module)
|
module = Keyword.fetch!(args, :module)
|
||||||
preload = Keyword.get(args, :preload, [])
|
|
||||||
|
|
||||||
module
|
module
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
|> Enum.map(&Repo.preload(&1, preload))
|
|> Enum.filter(fn %{monitor: mon} -> mon == false end)
|
||||||
|
|> Enum.map(&Repo.preload(&1, AssetWorker.preload(&1)))
|
||||||
|> Enum.map(&worker_spec/1)
|
|> Enum.map(&worker_spec/1)
|
||||||
|> Supervisor.init(strategy: :one_for_one)
|
|> Supervisor.init(strategy: :one_for_one)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
defprotocol Farmbot.AssetWorker do
|
defprotocol Farmbot.AssetWorker do
|
||||||
|
@doc "List of relational resources that need to be preloaded."
|
||||||
|
def preload(asset)
|
||||||
|
|
||||||
|
@doc "GenServer childspec callback."
|
||||||
def start_link(asset)
|
def start_link(asset)
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,8 @@ defimpl Farmbot.AssetWorker, for: Farmbot.Asset.Device do
|
||||||
use GenServer
|
use GenServer
|
||||||
import Farmbot.Config, only: [update_config_value: 4]
|
import Farmbot.Config, only: [update_config_value: 4]
|
||||||
|
|
||||||
|
def preload(%Device{}), do: []
|
||||||
|
|
||||||
def start_link(%Device{} = device) do
|
def start_link(%Device{} = device) do
|
||||||
GenServer.start_link(__MODULE__, [%Device{} = device])
|
GenServer.start_link(__MODULE__, [%Device{} = device])
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
defimpl Farmbot.AssetWorker, for: Farmbot.Asset.FarmEvent do
|
defimpl Farmbot.AssetWorker, for: Farmbot.Asset.FarmEvent do
|
||||||
|
use GenServer
|
||||||
|
require Logger
|
||||||
|
|
||||||
alias Farmbot.{
|
alias Farmbot.{
|
||||||
Asset,
|
Asset,
|
||||||
Asset.FarmEvent,
|
Asset.FarmEvent,
|
||||||
|
@ -6,9 +9,6 @@ defimpl Farmbot.AssetWorker, for: Farmbot.Asset.FarmEvent do
|
||||||
Asset.Sequence
|
Asset.Sequence
|
||||||
}
|
}
|
||||||
|
|
||||||
require Logger
|
|
||||||
use GenServer
|
|
||||||
|
|
||||||
defstruct [:farm_event, :datetime]
|
defstruct [:farm_event, :datetime]
|
||||||
alias __MODULE__, as: State
|
alias __MODULE__, as: State
|
||||||
|
|
||||||
|
@ -18,12 +18,19 @@ defimpl Farmbot.AssetWorker, for: Farmbot.Asset.FarmEvent do
|
||||||
config :farmbot_core, #{__MODULE__}, checkup_time_ms: 10_000
|
config :farmbot_core, #{__MODULE__}, checkup_time_ms: 10_000
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
def preload(%FarmEvent{}), do: []
|
||||||
|
|
||||||
def start_link(farm_event) do
|
def start_link(farm_event) do
|
||||||
GenServer.start_link(__MODULE__, [farm_event])
|
GenServer.start_link(__MODULE__, [farm_event])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def force_checkup(pid) when is_pid(pid) do
|
||||||
|
Logger.warn("Forcing timeout on #{inspect(pid)}")
|
||||||
|
send(pid, :timeout)
|
||||||
|
end
|
||||||
|
|
||||||
def init([farm_event]) do
|
def init([farm_event]) do
|
||||||
Logger.disable(self())
|
# Logger.disable(self())
|
||||||
ensure_executable!(farm_event)
|
ensure_executable!(farm_event)
|
||||||
now = DateTime.utc_now()
|
now = DateTime.utc_now()
|
||||||
|
|
||||||
|
@ -115,12 +122,12 @@ defimpl Farmbot.AssetWorker, for: Farmbot.Asset.FarmEvent do
|
||||||
|
|
||||||
defp ensure_executed!(%FarmEvent{last_executed: nil} = event, %Regimen{} = exe, next_dt) do
|
defp ensure_executed!(%FarmEvent{last_executed: nil} = event, %Regimen{} = exe, next_dt) do
|
||||||
Logger.warn("Regimen: #{inspect(exe)} has not run before. Executing it.")
|
Logger.warn("Regimen: #{inspect(exe)} has not run before. Executing it.")
|
||||||
Asset.upsert_persistent_regimen(exe, event, %{started_at: next_dt})
|
Asset.upsert_persistent_regimen!(exe, event, %{started_at: next_dt})
|
||||||
Asset.update_farm_event!(event, %{last_executed: next_dt})
|
Asset.update_farm_event!(event, %{last_executed: next_dt})
|
||||||
end
|
end
|
||||||
|
|
||||||
defp ensure_executed!(%FarmEvent{} = event, %Regimen{} = exe, _next_dt) do
|
defp ensure_executed!(%FarmEvent{} = event, %Regimen{} = exe, _next_dt) do
|
||||||
Asset.upsert_persistent_regimen(exe, event)
|
Asset.upsert_persistent_regimen!(exe, event)
|
||||||
event
|
event
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
defimpl Farmbot.AssetWorker, for: Farmbot.Asset.FarmwareEnv do
|
defimpl Farmbot.AssetWorker, for: Farmbot.Asset.FarmwareEnv do
|
||||||
alias Farmbot.Asset.FarmwareEnv
|
|
||||||
use GenServer
|
use GenServer
|
||||||
|
|
||||||
|
alias Farmbot.Asset.FarmwareEnv
|
||||||
|
|
||||||
|
def preload(%FarmwareEnv{}), do: []
|
||||||
|
|
||||||
def start_link(%FarmwareEnv{} = env) do
|
def start_link(%FarmwareEnv{} = env) do
|
||||||
GenServer.start_link(__MODULE__, env)
|
GenServer.start_link(__MODULE__, env)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
defimpl Farmbot.AssetWorker, for: Farmbot.Asset.FarmwareInstallation do
|
defimpl Farmbot.AssetWorker, for: Farmbot.Asset.FarmwareInstallation do
|
||||||
use GenServer
|
use GenServer
|
||||||
|
require Farmbot.Logger
|
||||||
|
|
||||||
alias Farmbot.Asset.Repo
|
alias Farmbot.Asset.Repo
|
||||||
alias Farmbot.Asset.FarmwareInstallation, as: FWI
|
alias Farmbot.Asset.FarmwareInstallation, as: FWI
|
||||||
require Farmbot.Logger
|
|
||||||
config = Application.get_env(:farmbot_core, __MODULE__)
|
config = Application.get_env(:farmbot_core, __MODULE__)
|
||||||
@install_dir config[:install_dir] || Mix.raise("Missing Install Dir")
|
@install_dir config[:install_dir] || Mix.raise("Missing Install Dir")
|
||||||
@error_retry_time_ms config[:error_retry_time_ms] || 30_000
|
@error_retry_time_ms config[:error_retry_time_ms] || 30_000
|
||||||
@manifest_name "manifest.json"
|
@manifest_name "manifest.json"
|
||||||
|
|
||||||
|
def preload(%FWI{}), do: []
|
||||||
|
|
||||||
def start_link(fwi) do
|
def start_link(fwi) do
|
||||||
GenServer.start_link(__MODULE__, [fwi])
|
GenServer.start_link(__MODULE__, [fwi])
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
defimpl Farmbot.AssetWorker, for: Farmbot.Asset.FbosConfig do
|
defimpl Farmbot.AssetWorker, for: Farmbot.Asset.FbosConfig do
|
||||||
use GenServer
|
use GenServer
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
alias Farmbot.Asset.FbosConfig
|
alias Farmbot.Asset.FbosConfig
|
||||||
import Farmbot.Config, only: [update_config_value: 4]
|
import Farmbot.Config, only: [update_config_value: 4]
|
||||||
|
|
||||||
|
def preload(%FbosConfig{}), do: []
|
||||||
|
|
||||||
def start_link(%FbosConfig{} = fbos_config) do
|
def start_link(%FbosConfig{} = fbos_config) do
|
||||||
GenServer.start_link(__MODULE__, [%FbosConfig{} = fbos_config])
|
GenServer.start_link(__MODULE__, [%FbosConfig{} = fbos_config])
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
defimpl Farmbot.AssetWorker, for: Farmbot.Asset.Peripheral do
|
defimpl Farmbot.AssetWorker, for: Farmbot.Asset.Peripheral do
|
||||||
use GenServer
|
use GenServer
|
||||||
|
require Farmbot.Logger
|
||||||
|
|
||||||
|
alias Farmbot.Asset.Peripheral
|
||||||
alias Farmbot.Core.CeleryScript
|
alias Farmbot.Core.CeleryScript
|
||||||
import Farmbot.CeleryScript.Utils
|
import Farmbot.CeleryScript.Utils
|
||||||
require Farmbot.Logger
|
|
||||||
@retry_ms 5_000
|
@retry_ms 5_000
|
||||||
|
|
||||||
|
def preload(%Peripheral{}), do: []
|
||||||
|
|
||||||
def start_link(peripheral) do
|
def start_link(peripheral) do
|
||||||
GenServer.start_link(__MODULE__, [peripheral])
|
GenServer.start_link(__MODULE__, [peripheral])
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,13 +1,90 @@
|
||||||
defimpl Farmbot.AssetWorker, for: Farmbot.Asset.PersistentRegimen do
|
defimpl Farmbot.AssetWorker, for: Farmbot.Asset.PersistentRegimen do
|
||||||
use GenServer
|
use GenServer
|
||||||
|
require Logger
|
||||||
require Farmbot.Logger
|
require Farmbot.Logger
|
||||||
import Farmbot.Config, only: [get_config_value: 3]
|
|
||||||
|
alias Farmbot.Asset
|
||||||
|
alias Farmbot.Asset.{PersistentRegimen, FarmEvent, Regimen}
|
||||||
|
alias Farmbot.Core.CeleryScript
|
||||||
|
|
||||||
|
@checkup_time_ms Application.get_env(:farmbot_core, __MODULE__)[:checkup_time_ms]
|
||||||
|
@checkup_time_ms ||
|
||||||
|
Mix.raise("""
|
||||||
|
config :farmbot_core, #{__MODULE__}, checkup_time_ms: 10_000
|
||||||
|
""")
|
||||||
|
|
||||||
|
def preload(%PersistentRegimen{}), do: [:farm_event, :regimen]
|
||||||
|
|
||||||
def start_link(persistent_regimen) do
|
def start_link(persistent_regimen) do
|
||||||
GenServer.start_link(__MODULE__, [persistent_regimen])
|
GenServer.start_link(__MODULE__, [persistent_regimen])
|
||||||
end
|
end
|
||||||
|
|
||||||
def init([persistent_regimen]) do
|
def init([persistent_regimen]) do
|
||||||
{:ok, persistent_regimen}
|
with %Regimen{} <- persistent_regimen.regimen,
|
||||||
|
%FarmEvent{} <- persistent_regimen.farm_event do
|
||||||
|
{:ok, filter_items(persistent_regimen), 0}
|
||||||
|
else
|
||||||
|
_ -> {:stop, "Persistent Regimen not preloaded."}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_info(:timeout, %PersistentRegimen{next: nil} = pr) do
|
||||||
|
persistent_regimen = filter_items(pr)
|
||||||
|
calculate_next(persistent_regimen, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_info(:timeout, %PersistentRegimen{} = pr) do
|
||||||
|
# Check if pr.next is around 2 minutes in the past
|
||||||
|
# positive if the first date/time comes after the second.
|
||||||
|
comp = Timex.diff(DateTime.utc_now(), pr.next, :minutes)
|
||||||
|
|
||||||
|
cond do
|
||||||
|
# now is more than 2 minutes past expected execution time
|
||||||
|
comp > 2 ->
|
||||||
|
Logger.warn(
|
||||||
|
"Regimen: #{pr.regimen.name || "regimen"} too late: #{comp} minutes difference."
|
||||||
|
)
|
||||||
|
|
||||||
|
calculate_next(pr)
|
||||||
|
|
||||||
|
true ->
|
||||||
|
Logger.warn(
|
||||||
|
"Regimen: #{pr.regimen.name || "regimen"} has not run before: #{comp} minutes difference."
|
||||||
|
)
|
||||||
|
|
||||||
|
exe = Asset.get_sequence!(id: pr.next_sequence_id)
|
||||||
|
CeleryScript.sequence(exe, fn _ -> :ok end)
|
||||||
|
calculate_next(pr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp calculate_next(pr, checkup_time_ms \\ @checkup_time_ms)
|
||||||
|
|
||||||
|
defp calculate_next(%{regimen: %{regimen_items: [next | rest]} = reg} = pr, checkup_time_ms) do
|
||||||
|
next_dt = Timex.shift(pr.epoch, milliseconds: next.time_offset)
|
||||||
|
params = %{next: next_dt, next_sequence_id: next.sequence_id}
|
||||||
|
# TODO(Connor) - This causes the active GenServer to be
|
||||||
|
# Restarted due to the `AssetMonitor`
|
||||||
|
pr = Asset.update_persistent_regimen!(pr, params)
|
||||||
|
|
||||||
|
pr = %{
|
||||||
|
pr
|
||||||
|
| regimen: %{reg | regimen_items: rest}
|
||||||
|
}
|
||||||
|
|
||||||
|
{:noreply, pr, checkup_time_ms}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp calculate_next(%{regimen: %{regimen_items: []}} = pr, _) do
|
||||||
|
Farmbot.Logger.success(1, "#{pr.regimen.name || "regimen"} has no more items.")
|
||||||
|
{:noreply, pr, :hibernate}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp filter_items(%PersistentRegimen{regimen: %Regimen{} = reg} = pr) do
|
||||||
|
items =
|
||||||
|
reg.regimen_items
|
||||||
|
|> Enum.sort(&(&1.time_offset <= &2.time_offset))
|
||||||
|
|
||||||
|
%{pr | regimen: %{reg | regimen_items: items}}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
defimpl Farmbot.AssetWorker, for: Farmbot.Asset.PinBinding do
|
defimpl Farmbot.AssetWorker, for: Farmbot.Asset.PinBinding do
|
||||||
@gpio_handler Application.get_env(:farmbot_core, __MODULE__)[:gpio_handler]
|
use GenServer
|
||||||
@error_retry_time_ms Application.get_env(:farmbot_core, __MODULE__)[:error_retry_time_ms]
|
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
require Farmbot.Logger
|
require Farmbot.Logger
|
||||||
|
|
||||||
import Farmbot.CeleryScript.Utils
|
import Farmbot.CeleryScript.Utils
|
||||||
|
|
||||||
alias Farmbot.{
|
alias Farmbot.{
|
||||||
|
@ -13,6 +12,9 @@ defimpl Farmbot.AssetWorker, for: Farmbot.Asset.PinBinding do
|
||||||
Asset
|
Asset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@gpio_handler Application.get_env(:farmbot_core, __MODULE__)[:gpio_handler]
|
||||||
|
@error_retry_time_ms Application.get_env(:farmbot_core, __MODULE__)[:error_retry_time_ms]
|
||||||
|
|
||||||
@gpio_handler ||
|
@gpio_handler ||
|
||||||
Mix.raise("""
|
Mix.raise("""
|
||||||
config :farmbot_core, #{__MODULE__}, gpio_handler: MyModule
|
config :farmbot_core, #{__MODULE__}, gpio_handler: MyModule
|
||||||
|
@ -36,7 +38,7 @@ defimpl Farmbot.AssetWorker, for: Farmbot.Asset.PinBinding do
|
||||||
"""
|
"""
|
||||||
@callback start_link(pin_number, trigger_fun) :: GenServer.on_start()
|
@callback start_link(pin_number, trigger_fun) :: GenServer.on_start()
|
||||||
|
|
||||||
use GenServer
|
def preload(%PinBinding{}), do: []
|
||||||
|
|
||||||
def start_link(%PinBinding{} = pin_binding) do
|
def start_link(%PinBinding{} = pin_binding) do
|
||||||
GenServer.start_link(__MODULE__, [%PinBinding{} = pin_binding])
|
GenServer.start_link(__MODULE__, [%PinBinding{} = pin_binding])
|
||||||
|
|
|
@ -8,7 +8,7 @@ defmodule Farmbot.BotState.JobProgress do
|
||||||
|
|
||||||
defmodule Percent do
|
defmodule Percent do
|
||||||
@moduledoc "Percent job."
|
@moduledoc "Percent job."
|
||||||
defstruct status: :working, percent: 0, unit: :percent, type: :ota, time: nil
|
defstruct status: :working, percent: 0, unit: :percent, type: :ota, time: nil, file_type: nil
|
||||||
|
|
||||||
defimpl Inspect, for: __MODULE__ do
|
defimpl Inspect, for: __MODULE__ do
|
||||||
def inspect(%{percent: percent}, _) do
|
def inspect(%{percent: percent}, _) do
|
||||||
|
@ -28,7 +28,7 @@ defmodule Farmbot.BotState.JobProgress do
|
||||||
|
|
||||||
defmodule Bytes do
|
defmodule Bytes do
|
||||||
@moduledoc "Bytes job."
|
@moduledoc "Bytes job."
|
||||||
defstruct status: :working, bytes: 0, unit: :bytes, type: :ota, time: nil
|
defstruct status: :working, bytes: 0, unit: :bytes, type: :ota, time: nil, file_type: nil
|
||||||
|
|
||||||
defimpl Inspect, for: __MODULE__ do
|
defimpl Inspect, for: __MODULE__ do
|
||||||
def inspect(%{bytes: bytes}, _) do
|
def inspect(%{bytes: bytes}, _) do
|
||||||
|
|
|
@ -96,6 +96,10 @@ defmodule FarmbotCore.MixProject do
|
||||||
["lib", "../test/support"]
|
["lib", "../test/support"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp elixirc_paths(:dev) do
|
||||||
|
["lib", "../test/support"]
|
||||||
|
end
|
||||||
|
|
||||||
defp elixirc_paths(_), do: ["lib"]
|
defp elixirc_paths(_), do: ["lib"]
|
||||||
|
|
||||||
defp aliases,
|
defp aliases,
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule Farmbot.Asset.Repo.Migrations.CreateDevicesTable do
|
||||||
add(:id, :id)
|
add(:id, :id)
|
||||||
add(:name, :string)
|
add(:name, :string)
|
||||||
add(:timezone, :string)
|
add(:timezone, :string)
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,6 +6,7 @@ defmodule Farmbot.Asset.Repo.Migrations.CreateToolsTable do
|
||||||
add(:local_id, :binary_id, primary_key: true)
|
add(:local_id, :binary_id, primary_key: true)
|
||||||
add(:id, :id)
|
add(:id, :id)
|
||||||
add(:name, :string)
|
add(:name, :string)
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,6 +8,7 @@ defmodule Farmbot.Asset.Repo.Migrations.CreatePeripheralsTable do
|
||||||
add(:pin, :integer)
|
add(:pin, :integer)
|
||||||
add(:mode, :integer)
|
add(:mode, :integer)
|
||||||
add(:label, :string)
|
add(:label, :string)
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,6 +8,7 @@ defmodule Farmbot.Asset.Repo.Migrations.CreateSensorsTable do
|
||||||
add(:pin, :integer)
|
add(:pin, :integer)
|
||||||
add(:mode, :integer)
|
add(:mode, :integer)
|
||||||
add(:label, :string)
|
add(:label, :string)
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,6 +11,7 @@ defmodule Farmbot.Asset.Repo.Migrations.CreateSensorReadingsTable do
|
||||||
add(:x, :float)
|
add(:x, :float)
|
||||||
add(:y, :float)
|
add(:y, :float)
|
||||||
add(:z, :float)
|
add(:z, :float)
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,6 +9,7 @@ defmodule Farmbot.Asset.Repo.Migrations.CreateSequencesTable do
|
||||||
add(:kind, :string)
|
add(:kind, :string)
|
||||||
add(:args, :map)
|
add(:args, :map)
|
||||||
add(:body, {:array, :map})
|
add(:body, {:array, :map})
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule Farmbot.Asset.Repo.Migrations.CreateRegimensTable do
|
||||||
add(:id, :id)
|
add(:id, :id)
|
||||||
add(:regimen_items, {:array, :map})
|
add(:regimen_items, {:array, :map})
|
||||||
add(:name, :string)
|
add(:name, :string)
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,6 +8,7 @@ defmodule Farmbot.Asset.Repo.Migrations.CreatePinBindingsTable do
|
||||||
add(:pin_num, :integer)
|
add(:pin_num, :integer)
|
||||||
add(:sequence_id, :integer)
|
add(:sequence_id, :integer)
|
||||||
add(:special_action, :string)
|
add(:special_action, :string)
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,6 +14,7 @@ defmodule Farmbot.Asset.Repo.Migrations.CreatePointsTable do
|
||||||
add(:x, :float)
|
add(:x, :float)
|
||||||
add(:y, :float)
|
add(:y, :float)
|
||||||
add(:z, :float)
|
add(:z, :float)
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,6 +12,7 @@ defmodule Farmbot.Asset.Repo.Migrations.CreateFarmEventsTable do
|
||||||
add(:start_time, :utc_datetime)
|
add(:start_time, :utc_datetime)
|
||||||
add(:time_unit, :string)
|
add(:time_unit, :string)
|
||||||
add(:last_executed, :utc_datetime)
|
add(:last_executed, :utc_datetime)
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -93,6 +93,7 @@ defmodule Elixir.Farmbot.Asset.Repo.Migrations.CreateFirmwareConfigsTable do
|
||||||
add(:encoder_invert_x, :float)
|
add(:encoder_invert_x, :float)
|
||||||
add(:encoder_missed_steps_max_x, :float)
|
add(:encoder_missed_steps_max_x, :float)
|
||||||
add(:movement_invert_motor_y, :float)
|
add(:movement_invert_motor_y, :float)
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,6 +19,7 @@ defmodule Elixir.Farmbot.Asset.Repo.Migrations.CreateFbosConfigsTable do
|
||||||
add(:sequence_body_log, :boolean)
|
add(:sequence_body_log, :boolean)
|
||||||
add(:sequence_complete_log, :boolean)
|
add(:sequence_complete_log, :boolean)
|
||||||
add(:sequence_init_log, :boolean)
|
add(:sequence_init_log, :boolean)
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule Elixir.Farmbot.Asset.Repo.Migrations.CreateFarmwareInstallationsTable
|
||||||
add(:id, :id)
|
add(:id, :id)
|
||||||
add(:url, :string)
|
add(:url, :string)
|
||||||
add(:manifest, :map)
|
add(:manifest, :map)
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule Elixir.Farmbot.Asset.Repo.Migrations.CreateFarmwareEnvsTable do
|
||||||
add(:id, :id)
|
add(:id, :id)
|
||||||
add(:key, :string)
|
add(:key, :string)
|
||||||
add(:value, :string)
|
add(:value, :string)
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,6 +12,7 @@ defmodule Elixir.Farmbot.Asset.Repo.Migrations.CreateDiagnosticDumpsTable do
|
||||||
add(:firmware_state, :string)
|
add(:firmware_state, :string)
|
||||||
add(:network_interface, :string)
|
add(:network_interface, :string)
|
||||||
add(:fbos_dmesg_dump, :string)
|
add(:fbos_dmesg_dump, :string)
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,6 +20,7 @@ defmodule Elixir.Farmbot.Asset.Repo.Migrations.CreateSyncsTable do
|
||||||
add(:sequences, {:array, :map})
|
add(:sequences, {:array, :map})
|
||||||
add(:tools, {:array, :map})
|
add(:tools, {:array, :map})
|
||||||
add(:now, :utc_datetime)
|
add(:now, :utc_datetime)
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,12 +5,17 @@ defmodule Farmbot.Asset.Repo.Migrations.CreatePersistentRegimensTable do
|
||||||
create table("persistent_regimens", primary_key: false) do
|
create table("persistent_regimens", primary_key: false) do
|
||||||
add(:local_id, :binary_id, primary_key: true)
|
add(:local_id, :binary_id, primary_key: true)
|
||||||
add(:started_at, :utc_datetime)
|
add(:started_at, :utc_datetime)
|
||||||
|
add(:epoch, :utc_datetime)
|
||||||
|
add(:next, :utc_datetime)
|
||||||
|
add(:next_sequence_id, :id)
|
||||||
add(:regimen_id, references("regimens", type: :binary_id, column: :local_id))
|
add(:regimen_id, references("regimens", type: :binary_id, column: :local_id))
|
||||||
add(:farm_event_id, references("farm_events", type: :binary_id, column: :local_id))
|
add(:farm_event_id, references("farm_events", type: :binary_id, column: :local_id))
|
||||||
|
add(:monitor, :boolean, default: true)
|
||||||
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
timestamps(inserted_at: :created_at, type: :utc_datetime)
|
||||||
end
|
end
|
||||||
|
|
||||||
create(unique_index("persistent_regimens", [:local_id, :regimen_id, :farm_event_id]))
|
create(unique_index("persistent_regimens", [:local_id, :regimen_id, :farm_event_id]))
|
||||||
create(unique_index("persistent_regimens", :started_at))
|
create(unique_index("persistent_regimens", :started_at))
|
||||||
|
create(unique_index("persistent_regimens", :epoch))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
defmodule Farmbot.AssetMonitorTest do
|
defmodule Farmbot.AssetMonitorTest do
|
||||||
use ExUnit.Case
|
use ExUnit.Case, async: false
|
||||||
alias Farmbot.Asset
|
alias Farmbot.Asset
|
||||||
alias Farmbot.AssetSupervisor
|
alias Farmbot.AssetSupervisor
|
||||||
import Farmbot.TestSupport.AssetFixtures
|
import Farmbot.TestSupport.AssetFixtures
|
||||||
|
@ -10,7 +10,8 @@ defmodule Farmbot.AssetMonitorTest do
|
||||||
seq = sequence()
|
seq = sequence()
|
||||||
reg = regimen(%{regimen_items: [%{time_offset: 100, sequence_id: seq.id}]})
|
reg = regimen(%{regimen_items: [%{time_offset: 100, sequence_id: seq.id}]})
|
||||||
event = regimen_event(reg)
|
event = regimen_event(reg)
|
||||||
{:ok, pr} = Asset.upsert_persistent_regimen(reg, event)
|
pr = Asset.upsert_persistent_regimen!(reg, event)
|
||||||
|
pr = Asset.update_persistent_regimen!(pr, %{monitor: true})
|
||||||
|
|
||||||
Farmbot.AssetMonitor.force_checkup()
|
Farmbot.AssetMonitor.force_checkup()
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ defmodule Farmbot.AssetMonitorTest do
|
||||||
end_time = Timex.shift(now, minutes: 10)
|
end_time = Timex.shift(now, minutes: 10)
|
||||||
|
|
||||||
params = %{
|
params = %{
|
||||||
|
monitor: true,
|
||||||
start_time: start_time,
|
start_time: start_time,
|
||||||
end_time: end_time,
|
end_time: end_time,
|
||||||
repeat: 1,
|
repeat: 1,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
defmodule Farmbot.AssetTest do
|
defmodule Farmbot.AssetTest do
|
||||||
use ExUnit.Case
|
use ExUnit.Case, async: true
|
||||||
alias Farmbot.Asset.{Repo, Regimen, PersistentRegimen}
|
alias Farmbot.Asset.{Repo, Regimen, PersistentRegimen}
|
||||||
alias Farmbot.Asset
|
alias Farmbot.Asset
|
||||||
import Farmbot.TestSupport.AssetFixtures
|
import Farmbot.TestSupport.AssetFixtures
|
||||||
|
@ -9,17 +9,17 @@ defmodule Farmbot.AssetTest do
|
||||||
seq = sequence()
|
seq = sequence()
|
||||||
reg = regimen(%{regimen_items: [%{time_offset: 100, sequence_id: seq.id}]})
|
reg = regimen(%{regimen_items: [%{time_offset: 100, sequence_id: seq.id}]})
|
||||||
event = regimen_event(reg)
|
event = regimen_event(reg)
|
||||||
assert {:ok, %PersistentRegimen{}} = Asset.upsert_persistent_regimen(reg, event)
|
assert %PersistentRegimen{} = Asset.upsert_persistent_regimen!(reg, event)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "updates a persisten regimen" do
|
test "updates a persisten regimen" do
|
||||||
seq = sequence()
|
seq = sequence()
|
||||||
reg = regimen(%{name: "old", regimen_items: [%{time_offset: 100, sequence_id: seq.id}]})
|
reg = regimen(%{name: "old", regimen_items: [%{time_offset: 100, sequence_id: seq.id}]})
|
||||||
event = regimen_event(reg)
|
event = regimen_event(reg)
|
||||||
{:ok, pr} = Asset.upsert_persistent_regimen(reg, event)
|
pr = Asset.upsert_persistent_regimen!(reg, event)
|
||||||
assert pr.regimen.name == "old"
|
assert pr.regimen.name == "old"
|
||||||
reg = Regimen.changeset(reg, %{name: "new"}) |> Repo.update!()
|
reg = Regimen.changeset(reg, %{name: "new"}) |> Repo.update!()
|
||||||
{:ok, pr} = Asset.upsert_persistent_regimen(reg, event)
|
pr = Asset.upsert_persistent_regimen!(reg, event)
|
||||||
assert pr.regimen.name == "new"
|
assert pr.regimen.name == "new"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,31 +1,12 @@
|
||||||
defmodule Farmbot.FarmEventWorkerTest do
|
defmodule Farmbot.FarmEventWorkerTest do
|
||||||
use ExUnit.Case
|
use ExUnit.Case, async: true
|
||||||
alias Farmbot.Asset.FarmEvent
|
alias Farmbot.Asset.FarmEvent
|
||||||
|
|
||||||
import Farmbot.TestSupport.AssetFixtures
|
import Farmbot.TestSupport.AssetFixtures
|
||||||
alias Farmbot.TestSupport.CeleryScript.TestIOLayer
|
alias Farmbot.TestSupport.CeleryScript.TestIOLayer
|
||||||
import Farmbot.TestSupport
|
import Farmbot.TestSupport
|
||||||
|
|
||||||
describe "regimens" do
|
# Regimen tests are in the PersistentRegimeWorker test
|
||||||
test "always ensure a regimen is started" do
|
|
||||||
seq = sequence()
|
|
||||||
reg = regimen(%{regimen_items: [%{time_offset: 100, sequence_id: seq.id}]})
|
|
||||||
|
|
||||||
now = DateTime.utc_now()
|
|
||||||
start_time = Timex.shift(now, minutes: -20)
|
|
||||||
end_time = Timex.shift(now, minutes: 10)
|
|
||||||
|
|
||||||
params = %{
|
|
||||||
start_time: start_time,
|
|
||||||
end_time: end_time,
|
|
||||||
repeat: 1,
|
|
||||||
time_unit: "never"
|
|
||||||
}
|
|
||||||
|
|
||||||
_event = regimen_event(reg, params)
|
|
||||||
refute :lookup_persistent_regimen_after_sleep?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "sequences" do
|
describe "sequences" do
|
||||||
# TODO(Connor) - this test isn't really that good
|
# TODO(Connor) - this test isn't really that good
|
||||||
|
@ -45,9 +26,12 @@ defmodule Farmbot.FarmEventWorkerTest do
|
||||||
time_unit: "never"
|
time_unit: "never"
|
||||||
}
|
}
|
||||||
|
|
||||||
assert %FarmEvent{} = sequence_event(seq, params)
|
assert %FarmEvent{} = fe = sequence_event(seq, params)
|
||||||
|
{:ok, pid} = Farmbot.AssetWorker.start_link(fe)
|
||||||
|
Farmbot.AssetWorker.Farmbot.Asset.FarmEvent.force_checkup(pid)
|
||||||
|
|
||||||
# This is not really that useful.
|
# This is not really that useful.
|
||||||
refute_receive ^ast, farm_event_timeout()
|
refute_receive ^ast, farm_event_timeout() + 5000
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -67,8 +51,10 @@ defmodule Farmbot.FarmEventWorkerTest do
|
||||||
time_unit: "minutely"
|
time_unit: "minutely"
|
||||||
}
|
}
|
||||||
|
|
||||||
assert %FarmEvent{} = sequence_event(seq, params)
|
assert %FarmEvent{} = fe = sequence_event(seq, params)
|
||||||
assert_receive ^ast, farm_event_timeout()
|
{:ok, pid} = Farmbot.AssetWorker.start_link(fe)
|
||||||
|
Farmbot.AssetWorker.Farmbot.Asset.FarmEvent.force_checkup(pid)
|
||||||
|
assert_receive ^ast, farm_event_timeout() + 5000
|
||||||
end
|
end
|
||||||
|
|
||||||
test "wont start an event after end_time" do
|
test "wont start an event after end_time" do
|
||||||
|
@ -86,7 +72,9 @@ defmodule Farmbot.FarmEventWorkerTest do
|
||||||
time_unit: "minutely"
|
time_unit: "minutely"
|
||||||
}
|
}
|
||||||
|
|
||||||
assert %FarmEvent{} = sequence_event(seq, params)
|
assert %FarmEvent{} = fe = sequence_event(seq, params)
|
||||||
|
{:ok, pid} = Farmbot.AssetWorker.start_link(fe)
|
||||||
|
Farmbot.AssetWorker.Farmbot.Asset.FarmEvent.force_checkup(pid)
|
||||||
# This is not really that useful.
|
# This is not really that useful.
|
||||||
refute_receive ^ast
|
refute_receive ^ast
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
defmodule Farmbot.FbosConfigWorkerTest do
|
defmodule Farmbot.FbosConfigWorkerTest do
|
||||||
use ExUnit.Case
|
use ExUnit.Case, async: true
|
||||||
alias Farmbot.Asset.FbosConfig
|
alias Farmbot.Asset.FbosConfig
|
||||||
|
|
||||||
|
import Farmbot.TestSupport.AssetFixtures
|
||||||
|
|
||||||
test "adds configs to bot state and config_storage" do
|
test "adds configs to bot state and config_storage" do
|
||||||
conf =
|
%FbosConfig{} =
|
||||||
FbosConfig.changeset(%FbosConfig{}, %{
|
conf =
|
||||||
|
fbos_config(%{
|
||||||
|
monitor: true,
|
||||||
arduino_debug_messages: true,
|
arduino_debug_messages: true,
|
||||||
auto_sync: false,
|
auto_sync: false,
|
||||||
beta_opt_in: true,
|
beta_opt_in: true,
|
||||||
|
@ -12,19 +16,18 @@ defmodule Farmbot.FbosConfigWorkerTest do
|
||||||
firmware_hardware: "farmduino_k14",
|
firmware_hardware: "farmduino_k14",
|
||||||
firmware_input_log: false,
|
firmware_input_log: false,
|
||||||
firmware_output_log: false,
|
firmware_output_log: false,
|
||||||
id: 145,
|
|
||||||
network_not_found_timer: nil,
|
network_not_found_timer: nil,
|
||||||
os_auto_update: false,
|
os_auto_update: false,
|
||||||
sequence_body_log: true,
|
sequence_body_log: true,
|
||||||
sequence_complete_log: true,
|
sequence_complete_log: true,
|
||||||
sequence_init_log: true
|
sequence_init_log: true
|
||||||
})
|
})
|
||||||
|> Farmbot.Asset.Repo.insert!()
|
|
||||||
|
|
||||||
:ok = Farmbot.AssetMonitor.force_checkup()
|
{:ok, pid} = Farmbot.AssetWorker.start_link(conf)
|
||||||
|
send(pid, :timeout)
|
||||||
|
|
||||||
# Wait for the timeout to be dispatched
|
# Wait for the timeout to be dispatched
|
||||||
Process.sleep(100)
|
Process.sleep(200)
|
||||||
|
|
||||||
state_conf = Farmbot.BotState.fetch().configuration
|
state_conf = Farmbot.BotState.fetch().configuration
|
||||||
assert state_conf.arduino_debug_messages == conf.arduino_debug_messages
|
assert state_conf.arduino_debug_messages == conf.arduino_debug_messages
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
defmodule Farmbot.PersistentRegimenWorkerTest do
|
||||||
|
use ExUnit.Case, async: true
|
||||||
|
alias Farmbot.{Asset.FarmEvent, Asset.PersistentRegimen}
|
||||||
|
import Farmbot.TestSupport.AssetFixtures
|
||||||
|
alias Farmbot.TestSupport.CeleryScript.TestIOLayer
|
||||||
|
import Farmbot.TestSupport
|
||||||
|
|
||||||
|
test "regimen executes a sequence" do
|
||||||
|
now = DateTime.utc_now()
|
||||||
|
start_time = Timex.shift(now, minutes: -20)
|
||||||
|
end_time = Timex.shift(now, minutes: 10)
|
||||||
|
{:ok, epoch} = PersistentRegimen.build_epoch(now)
|
||||||
|
offset = Timex.diff(now, epoch, :milliseconds) + 500
|
||||||
|
|
||||||
|
TestIOLayer.subscribe()
|
||||||
|
ast = TestIOLayer.debug_ast()
|
||||||
|
seq = sequence(%{body: [ast]})
|
||||||
|
|
||||||
|
reg = regimen(%{regimen_items: [%{time_offset: offset, sequence_id: seq.id}]})
|
||||||
|
|
||||||
|
params = %{
|
||||||
|
start_time: start_time,
|
||||||
|
end_time: end_time,
|
||||||
|
repeat: 1,
|
||||||
|
time_unit: "never"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert %FarmEvent{} = fe = regimen_event(reg, params)
|
||||||
|
|
||||||
|
{:ok, pid} = Farmbot.AssetWorker.start_link(fe)
|
||||||
|
Farmbot.AssetWorker.Farmbot.Asset.FarmEvent.force_checkup(pid)
|
||||||
|
assert_receive ^ast, farm_event_timeout() + persistent_regimen_timeout() + 5000
|
||||||
|
end
|
||||||
|
end
|
|
@ -4,4 +4,9 @@
|
||||||
# Ecto.Adapters.SQL.Sandbox.mode(Farmbot.Config.Repo, :auto)
|
# Ecto.Adapters.SQL.Sandbox.mode(Farmbot.Config.Repo, :auto)
|
||||||
# Ecto.Adapters.SQL.Sandbox.mode(Farmbot.Logger.Repo, {:shared, self()})
|
# Ecto.Adapters.SQL.Sandbox.mode(Farmbot.Logger.Repo, {:shared, self()})
|
||||||
# Ecto.Adapters.SQL.Sandbox.mode(Farmbot.Asset.Repo, :auto)
|
# Ecto.Adapters.SQL.Sandbox.mode(Farmbot.Asset.Repo, :auto)
|
||||||
|
tz = Timex.local().time_zone
|
||||||
|
|
||||||
|
Farmbot.Asset.Device.changeset(Farmbot.Asset.device(), %{timezone: tz})
|
||||||
|
|> Farmbot.Asset.Repo.insert_or_update!()
|
||||||
|
|
||||||
ExUnit.start()
|
ExUnit.start()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use Mix.Config
|
use Mix.Config
|
||||||
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.FarmEvent, checkup_time_ms: 10_000
|
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.FarmEvent, checkup_time_ms: 10_000
|
||||||
|
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.PersistentRegimen, checkup_time_ms: 10_000
|
||||||
|
|
||||||
config :farmbot_core, Elixir.Farmbot.AssetWorker.Farmbot.Asset.PinBinding,
|
config :farmbot_core, Elixir.Farmbot.AssetWorker.Farmbot.Asset.PinBinding,
|
||||||
gpio_handler: Farmbot.PinBindingWorker.StubGPIOHandler,
|
gpio_handler: Farmbot.PinBindingWorker.StubGPIOHandler,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use Mix.Config
|
use Mix.Config
|
||||||
|
|
||||||
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.FarmEvent, checkup_time_ms: 10_000
|
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.FarmEvent, checkup_time_ms: 10_000
|
||||||
|
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.PersistentRegimen, checkup_time_ms: 10_000
|
||||||
|
|
||||||
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.FarmwareInstallation,
|
config :farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.FarmwareInstallation,
|
||||||
error_retry_time_ms: 30_000,
|
error_retry_time_ms: 30_000,
|
||||||
|
|
|
@ -1,19 +1,39 @@
|
||||||
defmodule Farmbot.TestSupport.AssetFixtures do
|
defmodule Farmbot.TestSupport.AssetFixtures do
|
||||||
alias Farmbot.Asset.{Repo, Sequence, Regimen, FarmEvent}
|
alias Farmbot.Asset.{Repo, FarmEvent, FbosConfig, Regimen, Sequence}
|
||||||
|
|
||||||
|
def fbos_config(params \\ %{}) do
|
||||||
|
default = %{
|
||||||
|
id: :rand.uniform(10000),
|
||||||
|
monitor: false
|
||||||
|
}
|
||||||
|
|
||||||
|
FbosConfig
|
||||||
|
|> struct()
|
||||||
|
|> FbosConfig.changeset(Map.merge(default, params))
|
||||||
|
|> Repo.insert!()
|
||||||
|
end
|
||||||
|
|
||||||
def sequence(params \\ %{}) do
|
def sequence(params \\ %{}) do
|
||||||
|
default = %{
|
||||||
|
id: :rand.uniform(10000),
|
||||||
|
monitor: false,
|
||||||
|
kind: "sequence",
|
||||||
|
args: %{},
|
||||||
|
body: []
|
||||||
|
}
|
||||||
|
|
||||||
Sequence
|
Sequence
|
||||||
|> struct()
|
|> struct()
|
||||||
|> Sequence.changeset(
|
|> Sequence.changeset(Map.merge(default, params))
|
||||||
Map.merge(%{id: :rand.uniform(10000), kind: "sequence", args: %{}, body: []}, params)
|
|
||||||
)
|
|
||||||
|> Repo.insert!()
|
|> Repo.insert!()
|
||||||
end
|
end
|
||||||
|
|
||||||
def regimen(params \\ %{}) do
|
def regimen(params \\ %{}) do
|
||||||
|
default = %{id: :rand.uniform(10000), monitor: false, regimen_items: []}
|
||||||
|
|
||||||
Regimen
|
Regimen
|
||||||
|> struct()
|
|> struct()
|
||||||
|> Regimen.changeset(Map.merge(%{id: :rand.uniform(10000), regimen_items: []}, params))
|
|> Regimen.changeset(Map.merge(default, params))
|
||||||
|> Repo.insert!()
|
|> Repo.insert!()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -24,6 +44,7 @@ defmodule Farmbot.TestSupport.AssetFixtures do
|
||||||
Map.merge(
|
Map.merge(
|
||||||
%{
|
%{
|
||||||
id: :rand.uniform(1_000_000),
|
id: :rand.uniform(1_000_000),
|
||||||
|
monitor: false,
|
||||||
executable_type: "Regimen",
|
executable_type: "Regimen",
|
||||||
executable_id: regimen.id,
|
executable_id: regimen.id,
|
||||||
start_time: now,
|
start_time: now,
|
||||||
|
@ -47,6 +68,7 @@ defmodule Farmbot.TestSupport.AssetFixtures do
|
||||||
Map.merge(
|
Map.merge(
|
||||||
%{
|
%{
|
||||||
id: :rand.uniform(1_000_000),
|
id: :rand.uniform(1_000_000),
|
||||||
|
monitor: false,
|
||||||
executable_type: "Sequence",
|
executable_type: "Sequence",
|
||||||
executable_id: sequence.id,
|
executable_id: sequence.id,
|
||||||
start_time: now,
|
start_time: now,
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
defmodule Farmbot.TestSupport do
|
defmodule Farmbot.TestSupport do
|
||||||
|
alias Farmbot.AssetWorker.Farmbot.Asset.{FarmEvent, PersistentRegimen}
|
||||||
def farm_event_timeout do
|
def farm_event_timeout do
|
||||||
Application.get_env(:farmbot_core, Farmbot.AssetWorker.Farmbot.Asset.FarmEvent)[
|
Application.get_env(:farmbot_core, FarmEvent)[
|
||||||
:checkup_time_ms
|
:checkup_time_ms
|
||||||
] + asset_monitor_timeout()
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
def persistent_regimen_timeout do
|
||||||
|
Application.get_env(:farmbot_core, PersistentRegimen)[
|
||||||
|
:checkup_time_ms
|
||||||
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
def asset_monitor_timeout do
|
def asset_monitor_timeout do
|
||||||
Application.get_env(:farmbot_core, Farmbot.AssetMonitor)[:checkup_time_ms] + grace()
|
Application.get_env(:farmbot_core, Farmbot.AssetMonitor)[:checkup_time_ms]
|
||||||
end
|
|
||||||
|
|
||||||
def grace do
|
|
||||||
5000
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue