Rework default sequences/pin_bindings
parent
9a26a9c531
commit
1ffa365642
|
@ -52,13 +52,6 @@ config :farmbot, :farmware,
|
||||||
first_part_farmware_manifest_url: "https://raw.githubusercontent.com/FarmBot-Labs/farmware_manifests/master/manifest.json"
|
first_part_farmware_manifest_url: "https://raw.githubusercontent.com/FarmBot-Labs/farmware_manifests/master/manifest.json"
|
||||||
|
|
||||||
config :farmbot, :builtins,
|
config :farmbot, :builtins,
|
||||||
sequence: [
|
|
||||||
emergency_lock: -1,
|
|
||||||
emergency_unlock: -2,
|
|
||||||
sync: -3,
|
|
||||||
reboot: -4,
|
|
||||||
power_off: -5
|
|
||||||
],
|
|
||||||
pin_binding: [
|
pin_binding: [
|
||||||
emergency_lock: -1,
|
emergency_lock: -1,
|
||||||
emergency_unlock: -2,
|
emergency_unlock: -2,
|
||||||
|
|
|
@ -5,7 +5,6 @@ lib/farmbot/farmware/runtime.ex
|
||||||
lib/farmbot/farmware/runtime_error.ex
|
lib/farmbot/farmware/runtime_error.ex
|
||||||
lib/farmbot/farmware/supervisor.ex
|
lib/farmbot/farmware/supervisor.ex
|
||||||
lib/farmbot/repo/worker.ex
|
lib/farmbot/repo/worker.ex
|
||||||
lib/farmbot/pin_binding/handler.ex
|
|
||||||
lib/farmbot/pin_binding/pin_binding.ex
|
lib/farmbot/pin_binding/pin_binding.ex
|
||||||
lib/farmbot/pin_binding/stub_handler.ex
|
lib/farmbot/pin_binding/stub_handler.ex
|
||||||
lib/farmbot/asset/farm_event.ex
|
lib/farmbot/asset/farm_event.ex
|
||||||
|
|
|
@ -9,9 +9,10 @@ defmodule Farmbot.Asset.PinBinding do
|
||||||
schema "pin_bindings" do
|
schema "pin_bindings" do
|
||||||
field(:pin_num, :integer)
|
field(:pin_num, :integer)
|
||||||
field(:sequence_id, :integer)
|
field(:sequence_id, :integer)
|
||||||
|
field(:special_action, :string)
|
||||||
end
|
end
|
||||||
|
|
||||||
@required_fields [:id, :pin_num, :sequence_id]
|
@required_fields [:id, :pin_num]
|
||||||
|
|
||||||
def changeset(pin_binding, params \\ %{}) do
|
def changeset(pin_binding, params \\ %{}) do
|
||||||
pin_binding
|
pin_binding
|
||||||
|
|
|
@ -8,13 +8,13 @@ defmodule Farmbot.PinBinding.Manager do
|
||||||
@handler || Mix.raise("No pin binding handler.")
|
@handler || Mix.raise("No pin binding handler.")
|
||||||
|
|
||||||
@doc "Register a pin number to execute sequence."
|
@doc "Register a pin number to execute sequence."
|
||||||
def register_pin(pin_num, sequence_id) do
|
def register_pin(%PinBinding{} = binding) do
|
||||||
GenStage.call(__MODULE__, {:register_pin, pin_num, sequence_id})
|
GenStage.call(__MODULE__, {:register_pin, binding})
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "Unregister a sequence."
|
@doc "Unregister a sequence."
|
||||||
def unregister_pin(pin_num) do
|
def unregister_pin(%PinBinding{} = binding) do
|
||||||
GenStage.call(__MODULE__, {:unregister_pin, pin_num})
|
GenStage.call(__MODULE__, {:unregister_pin, binding})
|
||||||
end
|
end
|
||||||
|
|
||||||
def confirm_asset_storage_up do
|
def confirm_asset_storage_up do
|
||||||
|
@ -38,8 +38,6 @@ defmodule Farmbot.PinBinding.Manager do
|
||||||
case @handler.start_link() do
|
case @handler.start_link() do
|
||||||
{:ok, handler} ->
|
{:ok, handler} ->
|
||||||
state = initial_state([], struct(State, handler: handler))
|
state = initial_state([], struct(State, handler: handler))
|
||||||
Process.send_after(self(), :update_fb_state_tree, 10)
|
|
||||||
|
|
||||||
{:producer_consumer, state,
|
{:producer_consumer, state,
|
||||||
subscribe_to: [handler], dispatcher: GenStage.BroadcastDispatcher}
|
subscribe_to: [handler], dispatcher: GenStage.BroadcastDispatcher}
|
||||||
|
|
||||||
|
@ -50,22 +48,24 @@ defmodule Farmbot.PinBinding.Manager do
|
||||||
|
|
||||||
defp initial_state([], state), do: state
|
defp initial_state([], state), do: state
|
||||||
|
|
||||||
defp initial_state(
|
defp initial_state([%PinBinding{pin_num: pin} = binding | rest], state) do
|
||||||
[%PinBinding{pin_num: pin, sequence_id: sequence_id} | rest],
|
|
||||||
state
|
|
||||||
) do
|
|
||||||
case @handler.register_pin(pin) do
|
case @handler.register_pin(pin) do
|
||||||
:ok ->
|
:ok ->
|
||||||
initial_state(rest, %{
|
new_state = do_register(state, binding)
|
||||||
state
|
initial_state(rest, new_state)
|
||||||
| registered: Map.put(state.registered, pin, sequence_id)
|
|
||||||
})
|
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
initial_state(rest, state)
|
initial_state(rest, state)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp do_register(state, %PinBinding{pin_num: pin} = binding) do
|
||||||
|
%{state | registered: Map.put(state.registered, pin, binding)}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_unregister(state, %PinBinding{pin_num: pin_num}) do
|
||||||
|
%{state | registered: Map.delete(state.registered, pin_num)}
|
||||||
|
end
|
||||||
|
|
||||||
def handle_events(_, _, %{repo_up: false} = state) do
|
def handle_events(_, _, %{repo_up: false} = state) do
|
||||||
Logger.warn(3, "Not handling gpio events until Asset storage is up.")
|
Logger.warn(3, "Not handling gpio events until Asset storage is up.")
|
||||||
{:noreply, [], state}
|
{:noreply, [], state}
|
||||||
|
@ -76,11 +76,11 @@ defmodule Farmbot.PinBinding.Manager do
|
||||||
|
|
||||||
new_env =
|
new_env =
|
||||||
Enum.reduce(t, state.env, fn {:pin_trigger, pin}, env ->
|
Enum.reduce(t, state.env, fn {:pin_trigger, pin}, env ->
|
||||||
sequence_id = state.registered[pin]
|
binding = state.registered[pin]
|
||||||
|
|
||||||
if sequence_id do
|
if binding do
|
||||||
Logger.busy(1, "Starting Sequence: #{sequence_id} from pin: #{pin}")
|
Logger.busy(1, "PinBinding #{pin} triggered.")
|
||||||
do_execute(sequence_id, env)
|
%Macro.Env{} = do_execute(binding, env)
|
||||||
else
|
else
|
||||||
Logger.warn(3, "No sequence assosiated with: #{pin}")
|
Logger.warn(3, "No sequence assosiated with: #{pin}")
|
||||||
env
|
env
|
||||||
|
@ -90,22 +90,14 @@ defmodule Farmbot.PinBinding.Manager do
|
||||||
{:noreply, [], %{state | env: new_env}}
|
{:noreply, [], %{state | env: new_env}}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_info(:update_fb_state_tree, state) do
|
def handle_call({:register_pin, %PinBinding{pin_num: pin_num} = binding}, _from, state) do
|
||||||
{:noreply, [{:gpio_registry, state.registered}], state}
|
Logger.info 1, "Registering PinBinding #{pin_num}"
|
||||||
end
|
|
||||||
|
|
||||||
def handle_call({:register_pin, pin_num, sequence_id}, _from, state) do
|
|
||||||
Logger.info 1, "Registering #{pin_num} to sequence by id: #{sequence_id}"
|
|
||||||
case state.registered[pin_num] do
|
case state.registered[pin_num] do
|
||||||
nil ->
|
nil ->
|
||||||
case @handler.register_pin(pin_num) do
|
case @handler.register_pin(pin_num) do
|
||||||
:ok ->
|
:ok ->
|
||||||
new_state = %{
|
new_state = do_register(state, binding)
|
||||||
state
|
{:reply, :ok, [{:gpio_registry, %{}}], new_state}
|
||||||
| registered: Map.put(state.registered, pin_num, sequence_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
{:reply, :ok, [{:gpio_registry, new_state.registered}], new_state}
|
|
||||||
|
|
||||||
{:error, _} = err ->
|
{:error, _} = err ->
|
||||||
{:reply, err, [], state}
|
{:reply, err, [], state}
|
||||||
|
@ -116,23 +108,17 @@ defmodule Farmbot.PinBinding.Manager do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_call({:unregister_pin, pin_num}, _from, state) do
|
def handle_call({:unregister_pin, %PinBinding{pin_num: pin_num}}, _from, state) do
|
||||||
|
|
||||||
case state.registered[pin_num] do
|
case state.registered[pin_num] do
|
||||||
nil ->
|
nil ->
|
||||||
{:reply, {:error, :unregistered}, [], state}
|
{:reply, {:error, :unregistered}, [], state}
|
||||||
|
|
||||||
sequence_id ->
|
%PinBinding{} = old ->
|
||||||
Logger.info 1, "Unregistering #{pin_num} from sequence by id: #{sequence_id}"
|
Logger.info 1, "Unregistering PinBinding #{pin_num}"
|
||||||
case @handler.unregister_pin(pin_num) do
|
case @handler.unregister_pin(pin_num) do
|
||||||
:ok ->
|
:ok ->
|
||||||
|
new_state = do_unregister(state, old)
|
||||||
new_state = %{
|
{:reply, :ok, [{:gpio_registry, %{}}], new_state}
|
||||||
state
|
|
||||||
| registered: Map.delete(state.registered, pin_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
{:reply, :ok, [{:gpio_registry, new_state.registered}], new_state}
|
|
||||||
|
|
||||||
err ->
|
err ->
|
||||||
{:reply, err, [], state}
|
{:reply, err, [], state}
|
||||||
|
@ -154,7 +140,24 @@ defmodule Farmbot.PinBinding.Manager do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp do_execute(sequence_id, env) do
|
defp do_execute(%PinBinding{pin_num: num, special_action: kind}, env) when is_binary(kind) do
|
||||||
|
celery = %{kind: kind, args: %{}, body: []}
|
||||||
|
{:ok, seq} = Farmbot.CeleryScript.AST.decode(celery)
|
||||||
|
try do
|
||||||
|
case Farmbot.CeleryScript.execute(seq, env) do
|
||||||
|
{:ok, env} -> env
|
||||||
|
{:error, _, env} -> env
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
err ->
|
||||||
|
message = Exception.message(err)
|
||||||
|
Logger.warn(2, "Failed to execute sequence PinBinding #{num}: " <> message)
|
||||||
|
IO.warn "", System.stacktrace()
|
||||||
|
env
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_execute(%PinBinding{sequence_id: sequence_id}, env) when is_integer(sequence_id) do
|
||||||
import Farmbot.CeleryScript.AST.Node.Execute, only: [execute: 3]
|
import Farmbot.CeleryScript.AST.Node.Execute, only: [execute: 3]
|
||||||
|
|
||||||
try do
|
try do
|
||||||
|
@ -166,6 +169,7 @@ defmodule Farmbot.PinBinding.Manager do
|
||||||
err ->
|
err ->
|
||||||
message = Exception.message(err)
|
message = Exception.message(err)
|
||||||
Logger.warn(2, "Failed to execute sequence #{sequence_id} " <> message)
|
Logger.warn(2, "Failed to execute sequence #{sequence_id} " <> message)
|
||||||
|
IO.warn "", System.stacktrace()
|
||||||
env
|
env
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,19 +26,19 @@ defmodule Farmbot.Repo.AfterSyncWorker do
|
||||||
{:noreply, state}
|
{:noreply, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_info({Farmbot.Repo.Registry, :addition, Farmbot.Asset.PinBinding, %{pin_num: pin, sequence_id: sequence_id}}, state) do
|
def handle_info({Farmbot.Repo.Registry, :addition, Farmbot.Asset.PinBinding, binding}, state) do
|
||||||
Farmbot.PinBinding.Manager.register_pin(pin, sequence_id)
|
Farmbot.PinBinding.Manager.register_pin(binding)
|
||||||
{:noreply, state}
|
{:noreply, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_info({Farmbot.Repo.Registry, :updated, Farmbot.Asset.PinBinding, %{pin_num: pin, sequence_id: sequence_id}}, state) do
|
def handle_info({Farmbot.Repo.Registry, :updated, Farmbot.Asset.PinBinding, binding}, state) do
|
||||||
Farmbot.PinBinding.Manager.unregister_pin(pin)
|
Farmbot.PinBinding.Manager.unregister_pin(binding)
|
||||||
Farmbot.PinBinding.Manager.register_pin(pin, sequence_id)
|
Farmbot.PinBinding.Manager.register_pin(binding)
|
||||||
{:noreply, state}
|
{:noreply, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_info({Farmbot.Repo.Registry, :deletion, Farmbot.Asset.PinBinding, %{pin_num: pin, sequence_id: _sequence_id}}, state) do
|
def handle_info({Farmbot.Repo.Registry, :deletion, Farmbot.Asset.PinBinding, binding}, state) do
|
||||||
Farmbot.PinBinding.Manager.unregister_pin(pin)
|
Farmbot.PinBinding.Manager.unregister_pin(binding)
|
||||||
{:noreply, state}
|
{:noreply, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -9,25 +9,20 @@ defmodule Farmbot.Repo.SeedDB do
|
||||||
end
|
end
|
||||||
|
|
||||||
def init([]) do
|
def init([]) do
|
||||||
sequence(builtin(:sequence, :emergency_lock), "emergency_lock")
|
pin_binding(builtin(:pin_binding, :emergency_lock), "emergency_lock", 17)
|
||||||
sequence(builtin(:sequence, :emergency_unlock), "emergency_unlock")
|
pin_binding(builtin(:pin_binding, :emergency_unlock), "emergency_unlock", 23)
|
||||||
sequence(builtin(:sequence, :sync), "sync")
|
|
||||||
sequence(builtin(:sequence, :reboot), "reboot")
|
|
||||||
sequence(builtin(:sequence, :power_off), "power_off")
|
|
||||||
|
|
||||||
pin_binding(builtin(:pin_binding, :emergency_lock), builtin(:sequence, :emergency_lock), 17)
|
|
||||||
pin_binding(builtin(:pin_binding, :emergency_unlock), builtin(:sequence, :emergency_unlock), 23)
|
|
||||||
|
|
||||||
:ignore
|
:ignore
|
||||||
end
|
end
|
||||||
|
|
||||||
def sequence(id, kind, args \\ %{}, body \\ []) do
|
def pin_binding(id, special_action, pin_num) do
|
||||||
ConfigStorage.register_sync_cmd(id, "Sequence", %{id: id, name: "__#{kind}", kind: kind, args: args, body: body})
|
body = %{
|
||||||
|> Farmbot.Repo.apply_sync_cmd()
|
id: id,
|
||||||
end
|
sequence_id: nil,
|
||||||
|
special_action: special_action,
|
||||||
def pin_binding(id, sequence_id, pin_num) do
|
pin_num: pin_num
|
||||||
ConfigStorage.register_sync_cmd(id, "PinBinding", %{id: id, sequence_id: sequence_id, pin_num: pin_num})
|
}
|
||||||
|
ConfigStorage.register_sync_cmd(id, "PinBinding", body)
|
||||||
|> Farmbot.Repo.apply_sync_cmd()
|
|> Farmbot.Repo.apply_sync_cmd()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
defmodule Farmbot.Repo.Migrations.PinBindingsSpecialAction do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
alter table("pin_bindings") do
|
||||||
|
add(:special_action, :string)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue