519 lines
12 KiB
Elixir
519 lines
12 KiB
Elixir
defmodule FarmbotCore.Asset do
|
|
@moduledoc """
|
|
Top level module, with some helpers. Persists application resources to disk.
|
|
Submodules of this module usually (but not always) correspond to a
|
|
resource in the REST API. See official REST API docs for details.
|
|
"""
|
|
|
|
alias FarmbotCore.Asset.{
|
|
Repo,
|
|
Device,
|
|
DeviceCert,
|
|
DiagnosticDump,
|
|
FarmwareEnv,
|
|
FirstPartyFarmware,
|
|
FarmwareInstallation,
|
|
FarmEvent,
|
|
FbosConfig,
|
|
FirmwareConfig,
|
|
Peripheral,
|
|
PinBinding,
|
|
Point,
|
|
PointGroup,
|
|
PublicKey,
|
|
Regimen,
|
|
RegimenInstance,
|
|
Sequence,
|
|
Sensor,
|
|
SensorReading,
|
|
Tool
|
|
}
|
|
|
|
alias FarmbotCore.AssetSupervisor
|
|
|
|
import Ecto.Query
|
|
|
|
## Begin Device
|
|
|
|
def device() do
|
|
Repo.one(Device) || %Device{}
|
|
end
|
|
|
|
def update_device!(params) do
|
|
device()
|
|
|> Device.changeset(params)
|
|
|> Repo.insert_or_update!()
|
|
end
|
|
|
|
def delete_device!(id) do
|
|
if device = Repo.get_by(Device, id: id) do
|
|
Repo.delete!(device)
|
|
end
|
|
:ok
|
|
end
|
|
|
|
## End Device
|
|
|
|
## Begin FarmEvent
|
|
|
|
def new_farm_event!(params) do
|
|
%FarmEvent{}
|
|
|> FarmEvent.changeset(params)
|
|
|> Repo.insert!()
|
|
end
|
|
|
|
@doc "Returns a FarmEvent by its API id."
|
|
def get_farm_event(id) do
|
|
Repo.get_by(FarmEvent, id: id)
|
|
end
|
|
|
|
def update_farm_event!(farm_event, params) do
|
|
farm_event =
|
|
farm_event |>
|
|
FarmEvent.changeset(params)
|
|
|> Repo.update!()
|
|
|
|
if farm_event.executable_type == "Regimen" do
|
|
regimen_instance = get_regimen_instance(farm_event)
|
|
if regimen_instance do
|
|
regimen_instance
|
|
|> Repo.preload([:farm_event, :regimen])
|
|
|> RegimenInstance.changeset(%{updated_at: DateTime.utc_now()})
|
|
|> Repo.update!()
|
|
end
|
|
end
|
|
|
|
farm_event
|
|
end
|
|
|
|
def delete_farm_event!(farm_event) do
|
|
ri = get_regimen_instance(farm_event)
|
|
ri && Repo.delete!(ri)
|
|
Repo.delete!(farm_event)
|
|
end
|
|
|
|
def add_execution_to_farm_event!(%FarmEvent{} = farm_event, params \\ %{}) do
|
|
%FarmEvent.Execution{}
|
|
|> FarmEvent.Execution.changeset(params)
|
|
|> Ecto.Changeset.put_assoc(:farm_event, farm_event)
|
|
|> Repo.insert!()
|
|
end
|
|
|
|
def get_farm_event_execution(%FarmEvent{} = farm_event, scheduled_at) do
|
|
Repo.one(
|
|
from e in FarmEvent.Execution,
|
|
where: e.farm_event_local_id == ^farm_event.local_id
|
|
and e.scheduled_at == ^scheduled_at
|
|
)
|
|
end
|
|
|
|
## End FarmEvent
|
|
|
|
## Begin FbosConfig
|
|
|
|
@doc "Gets the local config"
|
|
def fbos_config() do
|
|
Repo.one(FbosConfig) || %FbosConfig{}
|
|
end
|
|
|
|
@doc "Gets a field on the local config."
|
|
def fbos_config(field) do
|
|
Map.fetch!(fbos_config(), field)
|
|
end
|
|
|
|
@doc """
|
|
This function updates Farmbot OS's local database. It will **NOT** send any
|
|
HTTP requests to the API. To do this, `FarmbotCore.Asset.Private.mark_dirty!/2`
|
|
is almost certainly what you want.
|
|
"""
|
|
def update_fbos_config!(fbos_config \\ nil, params) do
|
|
new_data =
|
|
FbosConfig.changeset(fbos_config || fbos_config(), params)
|
|
|> Repo.insert_or_update!()
|
|
|
|
AssetSupervisor.cast_child(new_data, {:new_data, new_data})
|
|
new_data
|
|
end
|
|
|
|
def delete_fbos_config!(id) do
|
|
if fbos_config = Repo.get_by(FbosConfig, id: id) do
|
|
Repo.delete!(fbos_config)
|
|
end
|
|
:ok
|
|
end
|
|
|
|
## End FbosConfig
|
|
|
|
## Begin FirmwareConfig
|
|
|
|
def firmware_config() do
|
|
Repo.one(FirmwareConfig) || %FirmwareConfig{}
|
|
end
|
|
|
|
def firmware_config(field) do
|
|
Map.fetch!(firmware_config(), field)
|
|
end
|
|
|
|
def update_firmware_config!(firmware_config \\ nil, params) do
|
|
new_data =
|
|
FirmwareConfig.changeset(firmware_config || firmware_config(), params)
|
|
|> Repo.insert_or_update!()
|
|
|
|
AssetSupervisor.cast_child(new_data, {:new_data, new_data})
|
|
new_data
|
|
end
|
|
|
|
def delete_firmware_config!(id) do
|
|
if firmware_config = Repo.get_by(FirmwareConfig, id: id) do
|
|
Repo.delete!(firmware_config)
|
|
end
|
|
:ok
|
|
end
|
|
|
|
## End FirmwareConfig
|
|
|
|
## Begin RegimenInstance
|
|
|
|
def get_regimen_instance(%FarmEvent{} = farm_event) do
|
|
regimen = Repo.one(from r in Regimen, where: r.id == ^farm_event.executable_id)
|
|
regimen && Repo.one(from ri in RegimenInstance, where: ri.regimen_id == ^regimen.local_id and ri.farm_event_id == ^farm_event.local_id)
|
|
end
|
|
|
|
def new_regimen_instance!(%FarmEvent{} = farm_event, params \\ %{}) do
|
|
regimen = Repo.one!(from r in Regimen, where: r.id == ^farm_event.executable_id)
|
|
RegimenInstance.changeset(%RegimenInstance{}, params)
|
|
|> Ecto.Changeset.put_assoc(:regimen, regimen)
|
|
|> Ecto.Changeset.put_assoc(:farm_event, farm_event)
|
|
|> Repo.insert!()
|
|
end
|
|
|
|
def delete_regimen_instance!(%RegimenInstance{} = ri) do
|
|
Repo.delete!(ri)
|
|
end
|
|
|
|
def add_execution_to_regimen_instance!(%RegimenInstance{} = ri, params \\ %{}) do
|
|
%RegimenInstance.Execution{}
|
|
|> RegimenInstance.Execution.changeset(params)
|
|
|> Ecto.Changeset.put_assoc(:regimen_instance, ri)
|
|
|> Repo.insert!()
|
|
end
|
|
|
|
def get_regimen_instance_execution(%RegimenInstance{} = ri, scheduled_at) do
|
|
Repo.one(
|
|
from e in RegimenInstance.Execution,
|
|
where: e.regimen_instance_local_id == ^ri.local_id
|
|
and e.scheduled_at == ^scheduled_at
|
|
)
|
|
end
|
|
|
|
## End RegimenInstance
|
|
|
|
## Begin PinBinding
|
|
|
|
@doc "Lists all available pin bindings"
|
|
def list_pin_bindings do
|
|
Repo.all(PinBinding)
|
|
end
|
|
|
|
## End PinBinding
|
|
|
|
## Begin Point
|
|
|
|
def get_point(params) do
|
|
Repo.get_by(Point, params)
|
|
end
|
|
|
|
def update_point(point, params) do
|
|
point
|
|
|> Point.changeset(params)
|
|
|> Repo.update()
|
|
end
|
|
|
|
@doc "Returns all points matching Point.pointer_type"
|
|
def get_all_points_by_type(type) do
|
|
Repo.all(from p in Point, where: p.pointer_type == ^type)
|
|
end
|
|
|
|
## End Point
|
|
|
|
## Begin PointGroup
|
|
|
|
def get_point_group(params) do
|
|
Repo.get_by(PointGroup, params)
|
|
end
|
|
|
|
## End PointGroup
|
|
|
|
## Begin PublicKey
|
|
|
|
def get_public_key(id) do
|
|
Repo.get_by(PublicKey, id: id)
|
|
end
|
|
|
|
def new_public_key!(params) do
|
|
%PublicKey{}
|
|
|> PublicKey.changeset(params)
|
|
|> Repo.insert!()
|
|
end
|
|
|
|
def update_public_key!(public_key, params) do
|
|
public_key
|
|
|> PublicKey.changeset(params)
|
|
|> Repo.update!()
|
|
end
|
|
|
|
def delete_public_key!(public_key) do
|
|
Repo.delete!(public_key)
|
|
end
|
|
|
|
def new_public_key_from_home!() do
|
|
public_key_path = Path.join([System.get_env("HOME"), ".ssh", "id_rsa.pub"])
|
|
public_key = File.read!(public_key_path)
|
|
%PublicKey{}
|
|
|> PublicKey.changeset(%{public_key: public_key})
|
|
|> Repo.insert()
|
|
end
|
|
|
|
def new_public_key_from_string!(public_key) do
|
|
%PublicKey{}
|
|
|> PublicKey.changeset(%{public_key: public_key})
|
|
|> Repo.insert()
|
|
end
|
|
|
|
## End PublicKey
|
|
|
|
## Begin Regimen
|
|
|
|
@doc "Get a regimen by it's API id"
|
|
def get_regimen(id) do
|
|
Repo.get_by(Regimen, id: id)
|
|
end
|
|
|
|
@doc "Enter a new regimen into the DB"
|
|
def new_regimen!(params) do
|
|
%Regimen{}
|
|
|> Regimen.changeset(params)
|
|
|> Repo.insert!()
|
|
end
|
|
|
|
def delete_regimen!(regimen) do
|
|
regimen_instances = Repo.all(from ri in RegimenInstance, where: ri.regimen_id == ^regimen.local_id)
|
|
for ri <- regimen_instances do
|
|
IO.puts "deleting regimen instance: #{inspect(ri)}"
|
|
delete_regimen_instance!(ri)
|
|
end
|
|
Repo.delete!(regimen)
|
|
end
|
|
|
|
@doc "Update an existing regimen"
|
|
def update_regimen!(regimen, params) do
|
|
regimen_instances = Repo.all(from ri in RegimenInstance, where: ri.regimen_id == ^regimen.local_id)
|
|
|> Repo.preload([:farm_event, :regimen])
|
|
for ri <- regimen_instances do
|
|
ri
|
|
|> RegimenInstance.changeset(%{updated_at: DateTime.utc_now()})
|
|
|> Repo.update!()
|
|
end
|
|
|
|
regimen
|
|
|> Regimen.changeset(params)
|
|
|> Repo.update!()
|
|
end
|
|
|
|
## End Regimen
|
|
|
|
## Begin Sequence
|
|
|
|
@doc "Get a sequence by it's API id"
|
|
def get_sequence(id) do
|
|
Repo.get_by(Sequence, id: id)
|
|
end
|
|
|
|
def update_sequence!(%Sequence{} = sequence, params \\ %{}) do
|
|
sequence_id = sequence.id
|
|
farm_events = Repo.all(from f in FarmEvent,
|
|
where: f.executable_type == "Sequence"
|
|
and f.executable_id == ^sequence_id)
|
|
|
|
regimen_instances = RegimenInstance
|
|
|> Repo.all()
|
|
|> Repo.preload([:regimen, :farm_event])
|
|
|> Enum.filter(fn
|
|
%{regimen: %{regimen_items: items}} ->
|
|
Enum.find(items, fn
|
|
%{sequence_id: ^sequence_id} -> true
|
|
%{sequence_id: _} -> true
|
|
end)
|
|
|
|
%{regimen: nil} -> false
|
|
end)
|
|
|
|
for asset <- farm_events ++ regimen_instances do
|
|
FarmbotCore.AssetSupervisor.update_child(asset)
|
|
end
|
|
|
|
Sequence.changeset(sequence, params)
|
|
|> Repo.update!()
|
|
end
|
|
|
|
def new_sequence!(params \\ %{}) do
|
|
Sequence.changeset(%Sequence{}, params)
|
|
|> Repo.insert!()
|
|
end
|
|
|
|
## End Sequence
|
|
|
|
## Begin FarmwareInstallation
|
|
|
|
@doc "Get a FarmwareManifest by it's name."
|
|
def get_farmware_manifest(package) do
|
|
first_party_farmwares = Repo.all(from(fwi in FirstPartyFarmware, select: fwi.manifest))
|
|
regular_farmwares = Repo.all(from(fwi in FarmwareInstallation, select: fwi.manifest))
|
|
Enum.find(
|
|
first_party_farmwares ++ regular_farmwares,
|
|
fn %{package: pkg} -> pkg == package end
|
|
)
|
|
end
|
|
|
|
def get_farmware_installation(package) do
|
|
first_party_farmwares = Repo.all(from(fwi in FirstPartyFarmware))
|
|
regular_farmwares = Repo.all(from(fwi in FarmwareInstallation))
|
|
Enum.find(
|
|
first_party_farmwares ++ regular_farmwares,
|
|
fn %{manifest: %{package: pkg}} -> pkg == package end
|
|
)
|
|
end
|
|
|
|
def upsert_farmware_manifest_by_id(id, params) do
|
|
fwi = Repo.get_by(FarmwareInstallation, id: id) || %FarmwareInstallation{}
|
|
FarmwareInstallation.changeset(fwi, params)
|
|
|> Repo.insert_or_update()
|
|
end
|
|
|
|
def upsert_first_party_farmware_manifest_by_id(id, params) do
|
|
fwi = Repo.get_by(FirstPartyFarmware, id: id) || %FirstPartyFarmware{}
|
|
FirstPartyFarmware.changeset(fwi, params)
|
|
|> Repo.insert_or_update()
|
|
end
|
|
|
|
## End FarmwareInstallation
|
|
|
|
## Begin FarmwareEnv
|
|
|
|
def list_farmware_env() do
|
|
Repo.all(FarmwareEnv)
|
|
end
|
|
|
|
def upsert_farmware_env_by_id(id, params) do
|
|
fwe = Repo.get_by(FarmwareEnv, id: id) || %FarmwareEnv{}
|
|
|
|
FarmwareEnv.changeset(fwe, params)
|
|
|> Repo.insert_or_update()
|
|
end
|
|
|
|
def new_farmware_env(params) do
|
|
key = params["key"] || params[:key]
|
|
fwe = with key when is_binary(key) <- key,
|
|
[fwe | _] <- Repo.all(from fwe in FarmwareEnv, where: fwe.key == ^key) do
|
|
fwe
|
|
else
|
|
_ -> %FarmwareEnv{}
|
|
end
|
|
|
|
FarmwareEnv.changeset(fwe, params)
|
|
|> Repo.insert_or_update()
|
|
end
|
|
|
|
## End FarmwareEnv
|
|
|
|
## Begin Peripheral
|
|
|
|
def get_peripheral(args) do
|
|
Repo.get_by(Peripheral, args)
|
|
end
|
|
|
|
def get_peripheral_by_pin(pin) do
|
|
Repo.get_by(Peripheral, pin: pin)
|
|
end
|
|
|
|
## End Peripheral
|
|
|
|
## Begin Sensor
|
|
|
|
def get_sensor(id) do
|
|
Repo.get_by(Sensor, id: id)
|
|
end
|
|
|
|
def get_sensor_by_pin(pin) do
|
|
Repo.get_by(Sensor, pin: pin)
|
|
end
|
|
|
|
def new_sensor!(params) do
|
|
Sensor.changeset(%Sensor{}, params)
|
|
|> Repo.insert!()
|
|
end
|
|
|
|
def update_sensor!(sensor, params) do
|
|
sensor
|
|
|> Sensor.changeset(params)
|
|
|> Repo.update!()
|
|
end
|
|
|
|
## End Sensor
|
|
|
|
## Begin SensorReading
|
|
|
|
def get_sensor_reading(id) do
|
|
Repo.get_by(SensorReading, id: id)
|
|
end
|
|
|
|
def new_sensor_reading!(params) do
|
|
SensorReading.changeset(%SensorReading{}, params)
|
|
|> Repo.insert!()
|
|
end
|
|
|
|
def update_sensor_reading!(sensor_reading, params) do
|
|
sensor_reading
|
|
|> SensorReading.changeset(params)
|
|
|> Repo.update!()
|
|
end
|
|
|
|
## End SensorReading
|
|
|
|
## Begin DiagnosticDump
|
|
|
|
def new_diagnostic_dump(params) do
|
|
DiagnosticDump.changeset(%DiagnosticDump{}, params)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
## End DiagnosticDump
|
|
|
|
## Begin DeviceCert
|
|
|
|
def new_device_cert(params) do
|
|
DeviceCert.changeset(%DeviceCert{}, params)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
def get_device_cert(args) do
|
|
Repo.get_by(DeviceCert, args)
|
|
end
|
|
|
|
def update_device_cert(cert, params) do
|
|
cert
|
|
|> DeviceCert.changeset(params)
|
|
|> Repo.update()
|
|
end
|
|
|
|
## End DeviceCert
|
|
|
|
## Begin Tool
|
|
|
|
def get_tool(args) do
|
|
Repo.get_by(Tool, args)
|
|
end
|
|
|
|
## End Tool
|
|
end
|