Merge branch 'staging' into remove-dnsmasq
commit
c480887d16
|
@ -2,7 +2,7 @@ version: 2.0
|
||||||
defaults: &defaults
|
defaults: &defaults
|
||||||
working_directory: /nerves/build
|
working_directory: /nerves/build
|
||||||
docker:
|
docker:
|
||||||
- image: nervesproject/nerves_system_br:latest
|
- image: nervesproject/nerves_system_br:1.11.3
|
||||||
|
|
||||||
install_elixir: &install_elixir
|
install_elixir: &install_elixir
|
||||||
run:
|
run:
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* Deprecate `resource_update` RPC
|
* Deprecate `resource_update` RPC
|
||||||
* Introduce `update_resource` RPC, which allows users to modify variables from the sequence editor.
|
* Introduce `update_resource` RPC, which allows users to modify variables from the sequence editor.
|
||||||
* Genesis v1.5 and Express v1.0 firmware updates.
|
* Genesis v1.5 and Express v1.0 firmware updates.
|
||||||
|
* Fix a bug where FBOS would not honor an "AUTO UPDATE" value of "false".
|
||||||
|
|
||||||
# 9.2.2
|
# 9.2.2
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@ defmodule FarmbotCeleryScript.Compiler.UpdateResource do
|
||||||
me = unquote(__MODULE__)
|
me = unquote(__MODULE__)
|
||||||
variable = unquote(Map.fetch!(args, :resource))
|
variable = unquote(Map.fetch!(args, :resource))
|
||||||
update = unquote(unpair(body, %{}))
|
update = unquote(unpair(body, %{}))
|
||||||
|
|
||||||
# Go easy on the API...
|
# Go easy on the API...
|
||||||
Process.sleep(1234)
|
|
||||||
case variable do
|
case variable do
|
||||||
%AST{kind: :identifier} ->
|
%AST{kind: :identifier} ->
|
||||||
args = Map.fetch!(variable, :args)
|
args = Map.fetch!(variable, :args)
|
||||||
|
@ -49,7 +49,6 @@ defmodule FarmbotCeleryScript.Compiler.UpdateResource do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp unpair([pair | rest], acc) do
|
defp unpair([pair | rest], acc) do
|
||||||
IO.puts("TODO: Need to apply handlebars to `value`s.")
|
|
||||||
key = Map.fetch!(pair.args, :label)
|
key = Map.fetch!(pair.args, :label)
|
||||||
val = Map.fetch!(pair.args, :value)
|
val = Map.fetch!(pair.args, :value)
|
||||||
next_acc = Map.merge(acc, DotProps.create(key, val))
|
next_acc = Map.merge(acc, DotProps.create(key, val))
|
||||||
|
|
|
@ -47,8 +47,8 @@ defmodule FarmbotCeleryScript.CompilerGroupsTest do
|
||||||
canary_actual = :crypto.hash(:sha, Macro.to_string(result))
|
canary_actual = :crypto.hash(:sha, Macro.to_string(result))
|
||||||
|
|
||||||
canary_expected =
|
canary_expected =
|
||||||
<<157, 69, 5, 38, 188, 78, 10, 183, 154, 99, 151, 193, 214, 208, 187, 130,
|
<<136, 140, 48, 226, 216, 155, 178, 103, 244, 88, 225, 146, 130, 216, 125,
|
||||||
183, 73, 13, 48>>
|
72, 113, 195, 65, 1>>
|
||||||
|
|
||||||
# READ THE NOTE ABOVE IF THIS TEST FAILS!!!
|
# READ THE NOTE ABOVE IF THIS TEST FAILS!!!
|
||||||
assert canary_expected == canary_actual
|
assert canary_expected == canary_actual
|
||||||
|
|
|
@ -79,7 +79,7 @@ defmodule FarmbotCeleryScript.CompilerTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "identifier sanitization" do
|
test "identifier sanitization" do
|
||||||
label = "System.cmd(\"rm\", [\"-rf /*\"])"
|
label = "System.cmd(\"echo\", [\"lol\"])"
|
||||||
value_ast = AST.Factory.new("coordinate", x: 1, y: 1, z: 1)
|
value_ast = AST.Factory.new("coordinate", x: 1, y: 1, z: 1)
|
||||||
identifier_ast = AST.Factory.new("identifier", label: label)
|
identifier_ast = AST.Factory.new("identifier", label: label)
|
||||||
|
|
||||||
|
@ -120,11 +120,19 @@ defmodule FarmbotCeleryScript.CompilerTest do
|
||||||
[
|
[
|
||||||
fn params ->
|
fn params ->
|
||||||
_ = inspect(params)
|
_ = inspect(params)
|
||||||
|
unsafe_U3lzdGVtLmNtZCgiZWNobyIsIFsibG9sIl0p = FarmbotCeleryScript.SysCalls.coordinate(1, 1, 1)
|
||||||
|
|
||||||
#{var_name} =
|
better_params = %{
|
||||||
FarmbotCeleryScript.SysCalls.coordinate(1, 1, 1)
|
"System.cmd(\\"echo\\", [\\"lol\\"])" => %FarmbotCeleryScript.AST{
|
||||||
|
args: %{x: 1, y: 1, z: 1},
|
||||||
|
body: [],
|
||||||
|
comment: nil,
|
||||||
|
kind: :coordinate,
|
||||||
|
meta: nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[fn -> #{var_name} end]
|
[fn -> unsafe_U3lzdGVtLmNtZCgiZWNobyIsIFsibG9sIl0p end]
|
||||||
end
|
end
|
||||||
]
|
]
|
||||||
""")
|
""")
|
||||||
|
@ -372,19 +380,38 @@ defmodule FarmbotCeleryScript.CompilerTest do
|
||||||
unsafe_cGFyZW50 =
|
unsafe_cGFyZW50 =
|
||||||
Keyword.get(params, :unsafe_cGFyZW50, FarmbotCeleryScript.SysCalls.coordinate(1, 2, 3))
|
Keyword.get(params, :unsafe_cGFyZW50, FarmbotCeleryScript.SysCalls.coordinate(1, 2, 3))
|
||||||
|
|
||||||
|
better_params = %{}
|
||||||
|
|
||||||
[
|
[
|
||||||
fn ->
|
fn ->
|
||||||
FarmbotCeleryScript.Compiler.UpdateResource.do_update(
|
me = FarmbotCeleryScript.Compiler.UpdateResource
|
||||||
%FarmbotCeleryScript.AST{
|
|
||||||
args: %{label: "parent"},
|
variable = %FarmbotCeleryScript.AST{
|
||||||
body: [],
|
args: %{label: "parent"},
|
||||||
comment: nil,
|
body: [],
|
||||||
kind: :identifier,
|
comment: nil,
|
||||||
meta: nil
|
kind: :identifier,
|
||||||
},
|
meta: nil
|
||||||
%{"plant_stage" => "removed"},
|
}
|
||||||
[]
|
|
||||||
)
|
update = %{"plant_stage" => "removed"}
|
||||||
|
|
||||||
|
case(variable) do
|
||||||
|
%AST{kind: :identifier} ->
|
||||||
|
args = Map.fetch!(variable, :args)
|
||||||
|
label = Map.fetch!(args, :label)
|
||||||
|
resource = Map.fetch!(better_params, label)
|
||||||
|
me.do_update(resource, update)
|
||||||
|
|
||||||
|
%AST{kind: :point} ->
|
||||||
|
me.do_update(variable.args(), update)
|
||||||
|
|
||||||
|
%AST{kind: :resource} ->
|
||||||
|
me.do_update(variable.args(), update)
|
||||||
|
|
||||||
|
res ->
|
||||||
|
raise("Resource error. Please notfiy support: \#{inspect(res)}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
@ -405,20 +432,38 @@ defmodule FarmbotCeleryScript.CompilerTest do
|
||||||
[
|
[
|
||||||
fn params ->
|
fn params ->
|
||||||
_ = inspect(params)
|
_ = inspect(params)
|
||||||
|
better_params = %{}
|
||||||
|
|
||||||
[
|
[
|
||||||
fn ->
|
fn ->
|
||||||
FarmbotCeleryScript.Compiler.UpdateResource.do_update(
|
me = FarmbotCeleryScript.Compiler.UpdateResource
|
||||||
%FarmbotCeleryScript.AST{
|
|
||||||
args: %{resource_id: 23, resource_type: "Plant"},
|
variable = %FarmbotCeleryScript.AST{
|
||||||
body: [],
|
args: %{resource_id: 23, resource_type: "Plant"},
|
||||||
comment: nil,
|
body: [],
|
||||||
kind: :resource,
|
comment: nil,
|
||||||
meta: nil
|
kind: :resource,
|
||||||
},
|
meta: nil
|
||||||
%{"plant_stage" => "planted", "r" => 23},
|
}
|
||||||
[]
|
|
||||||
)
|
update = %{"plant_stage" => "planted", "r" => 23}
|
||||||
|
|
||||||
|
case(variable) do
|
||||||
|
%AST{kind: :identifier} ->
|
||||||
|
args = Map.fetch!(variable, :args)
|
||||||
|
label = Map.fetch!(args, :label)
|
||||||
|
resource = Map.fetch!(better_params, label)
|
||||||
|
me.do_update(resource, update)
|
||||||
|
|
||||||
|
%AST{kind: :point} ->
|
||||||
|
me.do_update(variable.args(), update)
|
||||||
|
|
||||||
|
%AST{kind: :resource} ->
|
||||||
|
me.do_update(variable.args(), update)
|
||||||
|
|
||||||
|
res ->
|
||||||
|
raise("Resource error. Please notfiy support: \#{inspect(res)}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,15 +6,15 @@ defmodule FarmbotCore.Asset do
|
||||||
"""
|
"""
|
||||||
|
|
||||||
alias FarmbotCore.Asset.{
|
alias FarmbotCore.Asset.{
|
||||||
Repo,
|
CriteriaRetriever,
|
||||||
Device,
|
Device,
|
||||||
DeviceCert,
|
DeviceCert,
|
||||||
FarmwareEnv,
|
|
||||||
FirstPartyFarmware,
|
|
||||||
FarmwareInstallation,
|
|
||||||
FarmEvent,
|
FarmEvent,
|
||||||
|
FarmwareEnv,
|
||||||
|
FarmwareInstallation,
|
||||||
FbosConfig,
|
FbosConfig,
|
||||||
FirmwareConfig,
|
FirmwareConfig,
|
||||||
|
FirstPartyFarmware,
|
||||||
Peripheral,
|
Peripheral,
|
||||||
PinBinding,
|
PinBinding,
|
||||||
Point,
|
Point,
|
||||||
|
@ -22,11 +22,11 @@ defmodule FarmbotCore.Asset do
|
||||||
PublicKey,
|
PublicKey,
|
||||||
Regimen,
|
Regimen,
|
||||||
RegimenInstance,
|
RegimenInstance,
|
||||||
Sequence,
|
Repo,
|
||||||
Sensor,
|
Sensor,
|
||||||
SensorReading,
|
SensorReading,
|
||||||
|
Sequence,
|
||||||
Tool,
|
Tool,
|
||||||
CriteriaRetriever
|
|
||||||
}
|
}
|
||||||
|
|
||||||
alias FarmbotCore.AssetSupervisor
|
alias FarmbotCore.AssetSupervisor
|
||||||
|
@ -251,7 +251,7 @@ defmodule FarmbotCore.Asset do
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_point(point, params) do
|
def update_point(point, params) do
|
||||||
# TODO: RC 8 MAY 20202 - We need to hard refresh the point.
|
# TODO: RC 8 MAY 2020 - We need to hard refresh the point.
|
||||||
# The CSVM appears to be caching resources. This leads
|
# The CSVM appears to be caching resources. This leads
|
||||||
# to problems when a user runs a sequence that has two
|
# to problems when a user runs a sequence that has two
|
||||||
# MARK AS steps.
|
# MARK AS steps.
|
||||||
|
|
|
@ -45,9 +45,7 @@ defmodule FarmbotCore.Asset.Private do
|
||||||
# error being thrown.
|
# error being thrown.
|
||||||
changeset = LocalMeta.changeset(local_meta, Map.merge(params, %{table: table, status: "dirty"}))
|
changeset = LocalMeta.changeset(local_meta, Map.merge(params, %{table: table, status: "dirty"}))
|
||||||
try do
|
try do
|
||||||
result = Repo.insert_or_update!(changeset)
|
Repo.insert_or_update!(changeset)
|
||||||
%FarmbotCore.Asset.Private.LocalMeta{} = result
|
|
||||||
result
|
|
||||||
catch
|
catch
|
||||||
:error, %Sqlite.DbConnection.Error{
|
:error, %Sqlite.DbConnection.Error{
|
||||||
message: "UNIQUE constraint failed: local_metas.table, local_metas.asset_local_id",
|
message: "UNIQUE constraint failed: local_metas.table, local_metas.asset_local_id",
|
||||||
|
|
|
@ -6,8 +6,9 @@ defmodule FarmbotExt.API.DirtyWorker do
|
||||||
import API.View, only: [render: 2]
|
import API.View, only: [render: 2]
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
require FarmbotCore.Logger
|
||||||
use GenServer
|
use GenServer
|
||||||
@timeout 4700
|
@timeout 500
|
||||||
|
|
||||||
# these resources can't be accessed by `id`.
|
# these resources can't be accessed by `id`.
|
||||||
@singular [
|
@singular [
|
||||||
|
@ -35,66 +36,68 @@ defmodule FarmbotExt.API.DirtyWorker do
|
||||||
@impl GenServer
|
@impl GenServer
|
||||||
def init(args) do
|
def init(args) do
|
||||||
module = Keyword.fetch!(args, :module)
|
module = Keyword.fetch!(args, :module)
|
||||||
timeout = Keyword.get(args, :timeout, @timeout)
|
Process.send_after(self(), :do_work, @timeout)
|
||||||
timer = Process.send_after(self(), :timeout, timeout)
|
{:ok, %{module: module}}
|
||||||
{:ok, %{module: module, timeout: timeout, timer: timer}}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl GenServer
|
@impl GenServer
|
||||||
def handle_info(:timeout, %{module: module} = state) do
|
def handle_info(:do_work, %{module: module} = state) do
|
||||||
dirty = Private.list_dirty(module)
|
Process.sleep(@timeout)
|
||||||
local = Private.list_local(module)
|
list = Enum.uniq(Private.list_dirty(module) ++ Private.list_local(module))
|
||||||
{:noreply, state, {:continue, Enum.uniq(dirty ++ local)}}
|
|
||||||
|
unless has_race_condition?(module, list) do
|
||||||
|
Enum.map(list, fn dirty -> work(dirty, module) end)
|
||||||
|
end
|
||||||
|
|
||||||
|
Process.send_after(self(), :do_work, @timeout)
|
||||||
|
{:noreply, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl GenServer
|
def work(dirty, module) do
|
||||||
def handle_continue([], state) do
|
# Go easy on the API
|
||||||
timer = Process.send_after(self(), :timeout, state.timeout)
|
Process.sleep(333)
|
||||||
{:noreply, %{state | timer: timer}}
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_continue([dirty | rest], %{module: module} = state) do
|
case http_request(dirty, module) do
|
||||||
case http_request(dirty, state) do
|
|
||||||
# Valid data
|
# Valid data
|
||||||
{:ok, %{status: s, body: body}} when s > 199 and s < 300 ->
|
{:ok, %{status: s, body: body}} when s > 199 and s < 300 ->
|
||||||
dirty |> module.changeset(body) |> handle_changeset(rest, state)
|
dirty |> module.changeset(body) |> handle_changeset(module)
|
||||||
|
|
||||||
# Invalid data
|
# Invalid data
|
||||||
{:ok, %{status: s, body: %{} = body}} when s > 399 and s < 500 ->
|
{:ok, %{status: s, body: %{} = body}} when s > 399 and s < 500 ->
|
||||||
|
FarmbotCore.Logger.error(2, "HTTP Error #{s}. #{inspect(body)}")
|
||||||
changeset = module.changeset(dirty)
|
changeset = module.changeset(dirty)
|
||||||
|
|
||||||
Enum.reduce(body, changeset, fn {key, val}, changeset ->
|
Enum.reduce(body, changeset, fn {key, val}, changeset ->
|
||||||
Ecto.Changeset.add_error(changeset, key, val)
|
Ecto.Changeset.add_error(changeset, key, val)
|
||||||
end)
|
end)
|
||||||
|> handle_changeset(rest, state)
|
|> handle_changeset(module)
|
||||||
|
|
||||||
# Invalid data, but the API didn't say why
|
# Invalid data, but the API didn't say why
|
||||||
{:ok, %{status: s, body: _body}} when s > 399 and s < 500 ->
|
{:ok, %{status: s, body: _body}} when s > 399 and s < 500 ->
|
||||||
|
FarmbotCore.Logger.error(2, "HTTP Error #{s}. #{inspect(dirty)}")
|
||||||
|
|
||||||
module.changeset(dirty)
|
module.changeset(dirty)
|
||||||
|> Map.put(:valid?, false)
|
|> Map.put(:valid?, false)
|
||||||
|> handle_changeset(rest, state)
|
|> handle_changeset(module)
|
||||||
|
|
||||||
# HTTP Error. (500, network error, timeout etc.)
|
# HTTP Error. (500, network error, timeout etc.)
|
||||||
error ->
|
error ->
|
||||||
Logger.error(
|
FarmbotCore.Logger.error(
|
||||||
"[#{module} #{dirty.local_id} #{inspect(self())}] HTTP Error: #{state.module} #{
|
2,
|
||||||
|
"[#{module} #{dirty.local_id} #{inspect(self())}] HTTP Error: #{module} #{
|
||||||
inspect(error)
|
inspect(error)
|
||||||
}"
|
}"
|
||||||
)
|
)
|
||||||
|
|
||||||
{:noreply, state, @timeout}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# If the changeset was valid, update the record.
|
# If the changeset was valid, update the record.
|
||||||
def handle_changeset(%{valid?: true} = changeset, rest, state) do
|
def handle_changeset(%{valid?: true} = changeset, _module) do
|
||||||
Repo.update!(changeset)
|
Private.mark_clean!(Repo.update!(changeset))
|
||||||
|> Private.mark_clean!()
|
:ok
|
||||||
|
|
||||||
{:noreply, state, {:continue, rest}}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_changeset(%{valid?: false, data: data} = changeset, rest, state) do
|
def handle_changeset(%{valid?: false, data: data} = changeset, module) do
|
||||||
message =
|
message =
|
||||||
Enum.map(changeset.errors, fn
|
Enum.map(changeset.errors, fn
|
||||||
{key, {msg, _meta}} when is_binary(key) -> "\t#{key}: #{msg}"
|
{key, {msg, _meta}} when is_binary(key) -> "\t#{key}: #{msg}"
|
||||||
|
@ -102,26 +105,64 @@ defmodule FarmbotExt.API.DirtyWorker do
|
||||||
end)
|
end)
|
||||||
|> Enum.join("\n")
|
|> Enum.join("\n")
|
||||||
|
|
||||||
Logger.error("Failed to sync: #{state.module} \n #{message}")
|
FarmbotCore.Logger.error(3, "Failed to sync: #{module} \n #{message}")
|
||||||
_ = Repo.delete!(data)
|
_ = Repo.delete!(data)
|
||||||
{:noreply, state, {:continue, rest}}
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
defp http_request(%{id: nil} = dirty, state) do
|
defp http_request(%{id: nil} = dirty, module) do
|
||||||
path = state.module.path()
|
path = module.path()
|
||||||
data = render(state.module, dirty)
|
data = render(module, dirty)
|
||||||
API.post(API.client(), path, data)
|
API.post(API.client(), path, data)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp http_request(dirty, %{module: module} = state) when module in @singular do
|
defp http_request(dirty, module) when module in @singular do
|
||||||
path = path = state.module.path()
|
path = path = module.path()
|
||||||
data = render(state.module, dirty)
|
data = render(module, dirty)
|
||||||
API.patch(API.client(), path, data)
|
API.patch(API.client(), path, data)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp http_request(dirty, state) do
|
defp http_request(dirty, module) do
|
||||||
path = Path.join(state.module.path(), to_string(dirty.id))
|
path = Path.join(module.path(), to_string(dirty.id))
|
||||||
data = render(state.module, dirty)
|
data = render(module, dirty)
|
||||||
API.patch(API.client(), path, data)
|
API.patch(API.client(), path, data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This is a fix for a race condtion. The root cause is unknown
|
||||||
|
# as of 18 May 2020. The problem is that records are marked
|
||||||
|
# diry _before_ the dirty data is saved. That means that FBOS
|
||||||
|
# knows a record has changed, but for a brief moment, it only
|
||||||
|
# has the old copy of the record (not the changes).
|
||||||
|
# Because of this race condtion,
|
||||||
|
# The race condition:
|
||||||
|
#
|
||||||
|
# * Is nondeterministic
|
||||||
|
# * Happens frequently when running many MARK AS steps in one go.
|
||||||
|
# * Happens frequently when Erlang VM only has one thread
|
||||||
|
# * Ie: `iex --erl '+S 1 +A 1' -S mix`
|
||||||
|
# * Happens frequently when @timeout is decreased to `1`.
|
||||||
|
#
|
||||||
|
# This function PREVENTS CORRUPTION OF API DATA. It can be
|
||||||
|
# removed once the root cause of the data race is determined.
|
||||||
|
# - RC 18 May 2020
|
||||||
|
def has_race_condition?(module, list) do
|
||||||
|
Enum.find(list, fn item ->
|
||||||
|
if item.id do
|
||||||
|
if item == Repo.get_by(module, id: item.id) do
|
||||||
|
# This item is OK - no race condition.
|
||||||
|
false
|
||||||
|
else
|
||||||
|
# There was a race condtion. We probably can't trust
|
||||||
|
# any of the data in this list. We need to wait and
|
||||||
|
# try again later.
|
||||||
|
Process.sleep(@timeout * 3)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# This item only exists on the FBOS side.
|
||||||
|
# It will never be affected by the data race condtion.
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -16,6 +16,7 @@ defmodule FarmbotFirmware.CommandTest do
|
||||||
@tag :capture_log
|
@tag :capture_log
|
||||||
test "command() runs RPCs" do
|
test "command() runs RPCs" do
|
||||||
pid = fake_pid()
|
pid = fake_pid()
|
||||||
|
|
||||||
assert {:error, :emergency_lock} ==
|
assert {:error, :emergency_lock} ==
|
||||||
FarmbotFirmware.command(pid, {:command_emergency_lock, []})
|
FarmbotFirmware.command(pid, {:command_emergency_lock, []})
|
||||||
|
|
||||||
|
|
|
@ -16,19 +16,19 @@ defmodule FarmbotFirmware.ParamTest do
|
||||||
|
|
||||||
t(:pin_guard_5_time_out, 12, {"pin guard 5 timeout", "(seconds)", "12"})
|
t(:pin_guard_5_time_out, 12, {"pin guard 5 timeout", "(seconds)", "12"})
|
||||||
t(:pin_guard_5_pin_nr, 12, {"pin guard 5 pin number", nil, "12"})
|
t(:pin_guard_5_pin_nr, 12, {"pin guard 5 pin number", nil, "12"})
|
||||||
t(:pin_guard_5_active_state, 0, {"pin guard 5 safe state", nil, "HIGH"})
|
t(:pin_guard_5_active_state, 0, {"pin guard 5 safe state", nil, "ON"})
|
||||||
t(:pin_guard_4_time_out, 12, {"pin guard 4 timeout", "(seconds)", "12"})
|
t(:pin_guard_4_time_out, 12, {"pin guard 4 timeout", "(seconds)", "12"})
|
||||||
t(:pin_guard_4_pin_nr, 12, {"pin guard 4 pin number", nil, "12"})
|
t(:pin_guard_4_pin_nr, 12, {"pin guard 4 pin number", nil, "12"})
|
||||||
t(:pin_guard_4_active_state, 0, {"pin guard 4 safe state", nil, "HIGH"})
|
t(:pin_guard_4_active_state, 0, {"pin guard 4 safe state", nil, "ON"})
|
||||||
t(:pin_guard_3_time_out, 1.0, {"pin guard 3 timeout", "(seconds)", "1"})
|
t(:pin_guard_3_time_out, 1.0, {"pin guard 3 timeout", "(seconds)", "1"})
|
||||||
t(:pin_guard_3_pin_nr, 1.0, {"pin guard 3 pin number", nil, "1"})
|
t(:pin_guard_3_pin_nr, 1.0, {"pin guard 3 pin number", nil, "1"})
|
||||||
t(:pin_guard_3_active_state, 0, {"pin guard 3 safe state", nil, "HIGH"})
|
t(:pin_guard_3_active_state, 0, {"pin guard 3 safe state", nil, "ON"})
|
||||||
t(:pin_guard_2_time_out, 1.0, {"pin guard 2 timeout", "(seconds)", "1"})
|
t(:pin_guard_2_time_out, 1.0, {"pin guard 2 timeout", "(seconds)", "1"})
|
||||||
t(:pin_guard_2_pin_nr, 1.0, {"pin guard 2 pin number", nil, "1"})
|
t(:pin_guard_2_pin_nr, 1.0, {"pin guard 2 pin number", nil, "1"})
|
||||||
t(:pin_guard_2_active_state, 0, {"pin guard 2 safe state", nil, "HIGH"})
|
t(:pin_guard_2_active_state, 0, {"pin guard 2 safe state", nil, "ON"})
|
||||||
t(:pin_guard_1_time_out, 1.0, {"pin guard 1 timeout", "(seconds)", "1"})
|
t(:pin_guard_1_time_out, 1.0, {"pin guard 1 timeout", "(seconds)", "1"})
|
||||||
t(:pin_guard_1_pin_nr, 1.0, {"pin guard 1 pin number", nil, "1"})
|
t(:pin_guard_1_pin_nr, 1.0, {"pin guard 1 pin number", nil, "1"})
|
||||||
t(:pin_guard_1_active_state, 0, {"pin guard 1 safe state", nil, "HIGH"})
|
t(:pin_guard_1_active_state, 0, {"pin guard 1 safe state", nil, "ON"})
|
||||||
t(:param_use_eeprom, 1, {"use eeprom", nil, true})
|
t(:param_use_eeprom, 1, {"use eeprom", nil, true})
|
||||||
t(:param_test, 1, {"param_test", nil, true})
|
t(:param_test, 1, {"param_test", nil, true})
|
||||||
t(:param_mov_nr_retry, 1.0, {"max retries", nil, "1"})
|
t(:param_mov_nr_retry, 1.0, {"max retries", nil, "1"})
|
||||||
|
|
|
@ -32,11 +32,11 @@ defmodule FarmbotOS.SysCalls.ResourceUpdate do
|
||||||
"Weed" => "weed"
|
"Weed" => "weed"
|
||||||
}
|
}
|
||||||
|
|
||||||
def notify_user_of_updates(kind, params) do
|
def notify_user_of_updates(kind, params, id \\ nil) do
|
||||||
Enum.map(params, fn {k, v} ->
|
Enum.map(params, fn {k, v} ->
|
||||||
name = @friendly_names[kind] || kind
|
name = @friendly_names[kind] || kind
|
||||||
property = @friendly_names["#{k}"] || k
|
property = @friendly_names["#{k}"] || k
|
||||||
msg = "Setting #{name} #{property} to #{inspect(v)}"
|
msg = "Setting #{name} #{id} #{property} to #{inspect(v)}"
|
||||||
FarmbotCore.Logger.info(3, msg)
|
FarmbotCore.Logger.info(3, msg)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
@ -53,7 +53,7 @@ defmodule FarmbotOS.SysCalls.ResourceUpdate do
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_resource(kind, id, params) when kind in @point_kinds do
|
def update_resource(kind, id, params) when kind in @point_kinds do
|
||||||
notify_user_of_updates(kind, params)
|
notify_user_of_updates(kind, params, id)
|
||||||
params = do_handlebars(params)
|
params = do_handlebars(params)
|
||||||
point_update_resource(kind, id, params)
|
point_update_resource(kind, id, params)
|
||||||
end
|
end
|
||||||
|
|
|
@ -542,7 +542,7 @@ defmodule FarmbotOS.Platform.Target.NervesHubClient do
|
||||||
"ota_hour = #{ota_hour || "null"} timezone = #{timezone || "null"}"
|
"ota_hour = #{ota_hour || "null"} timezone = #{timezone || "null"}"
|
||||||
)
|
)
|
||||||
|
|
||||||
true
|
!!auto_update
|
||||||
end
|
end
|
||||||
|
|
||||||
result && !currently_downloading?()
|
result && !currently_downloading?()
|
||||||
|
|
Loading…
Reference in New Issue