From 1ffa365642394c3ec7974a0c8638f1db8330acb7 Mon Sep 17 00:00:00 2001 From: connor rigby Date: Fri, 13 Jul 2018 11:58:25 -0700 Subject: [PATCH] Rework default sequences/pin_bindings --- config/config.exs | 7 -- formatted_files | 1 - lib/farmbot/asset/pin_binding.ex | 3 +- lib/farmbot/pin_binding/manager.ex | 90 ++++++++++--------- lib/farmbot/repo/after_sync_worker.ex | 14 +-- lib/farmbot/repo/seed_db.ex | 25 +++--- ...0713180958_pin_bindings_special_action.exs | 9 ++ 7 files changed, 75 insertions(+), 74 deletions(-) create mode 100644 priv/repo/migrations/20180713180958_pin_bindings_special_action.exs diff --git a/config/config.exs b/config/config.exs index 891eee57b..f8b8cc24d 100644 --- a/config/config.exs +++ b/config/config.exs @@ -52,13 +52,6 @@ config :farmbot, :farmware, first_part_farmware_manifest_url: "https://raw.githubusercontent.com/FarmBot-Labs/farmware_manifests/master/manifest.json" config :farmbot, :builtins, - sequence: [ - emergency_lock: -1, - emergency_unlock: -2, - sync: -3, - reboot: -4, - power_off: -5 - ], pin_binding: [ emergency_lock: -1, emergency_unlock: -2, diff --git a/formatted_files b/formatted_files index df30fe3d5..a618a4cf7 100644 --- a/formatted_files +++ b/formatted_files @@ -5,7 +5,6 @@ lib/farmbot/farmware/runtime.ex lib/farmbot/farmware/runtime_error.ex lib/farmbot/farmware/supervisor.ex lib/farmbot/repo/worker.ex -lib/farmbot/pin_binding/handler.ex lib/farmbot/pin_binding/pin_binding.ex lib/farmbot/pin_binding/stub_handler.ex lib/farmbot/asset/farm_event.ex diff --git a/lib/farmbot/asset/pin_binding.ex b/lib/farmbot/asset/pin_binding.ex index f80b0d0bc..ab3ee2a51 100644 --- a/lib/farmbot/asset/pin_binding.ex +++ b/lib/farmbot/asset/pin_binding.ex @@ -9,9 +9,10 @@ defmodule Farmbot.Asset.PinBinding do schema "pin_bindings" do field(:pin_num, :integer) field(:sequence_id, :integer) + field(:special_action, :string) end - @required_fields [:id, :pin_num, :sequence_id] + @required_fields [:id, :pin_num] def changeset(pin_binding, params \\ %{}) do pin_binding diff --git a/lib/farmbot/pin_binding/manager.ex b/lib/farmbot/pin_binding/manager.ex index 0bbda82ed..5888d93c5 100644 --- a/lib/farmbot/pin_binding/manager.ex +++ b/lib/farmbot/pin_binding/manager.ex @@ -8,13 +8,13 @@ defmodule Farmbot.PinBinding.Manager do @handler || Mix.raise("No pin binding handler.") @doc "Register a pin number to execute sequence." - def register_pin(pin_num, sequence_id) do - GenStage.call(__MODULE__, {:register_pin, pin_num, sequence_id}) + def register_pin(%PinBinding{} = binding) do + GenStage.call(__MODULE__, {:register_pin, binding}) end @doc "Unregister a sequence." - def unregister_pin(pin_num) do - GenStage.call(__MODULE__, {:unregister_pin, pin_num}) + def unregister_pin(%PinBinding{} = binding) do + GenStage.call(__MODULE__, {:unregister_pin, binding}) end def confirm_asset_storage_up do @@ -38,8 +38,6 @@ defmodule Farmbot.PinBinding.Manager do case @handler.start_link() do {:ok, handler} -> state = initial_state([], struct(State, handler: handler)) - Process.send_after(self(), :update_fb_state_tree, 10) - {:producer_consumer, state, subscribe_to: [handler], dispatcher: GenStage.BroadcastDispatcher} @@ -50,22 +48,24 @@ defmodule Farmbot.PinBinding.Manager do defp initial_state([], state), do: state - defp initial_state( - [%PinBinding{pin_num: pin, sequence_id: sequence_id} | rest], - state - ) do + defp initial_state([%PinBinding{pin_num: pin} = binding | rest], state) do case @handler.register_pin(pin) do :ok -> - initial_state(rest, %{ - state - | registered: Map.put(state.registered, pin, sequence_id) - }) - + new_state = do_register(state, binding) + initial_state(rest, new_state) _ -> initial_state(rest, state) 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 Logger.warn(3, "Not handling gpio events until Asset storage is up.") {:noreply, [], state} @@ -76,11 +76,11 @@ defmodule Farmbot.PinBinding.Manager do new_env = Enum.reduce(t, state.env, fn {:pin_trigger, pin}, env -> - sequence_id = state.registered[pin] + binding = state.registered[pin] - if sequence_id do - Logger.busy(1, "Starting Sequence: #{sequence_id} from pin: #{pin}") - do_execute(sequence_id, env) + if binding do + Logger.busy(1, "PinBinding #{pin} triggered.") + %Macro.Env{} = do_execute(binding, env) else Logger.warn(3, "No sequence assosiated with: #{pin}") env @@ -90,22 +90,14 @@ defmodule Farmbot.PinBinding.Manager do {:noreply, [], %{state | env: new_env}} end - def handle_info(:update_fb_state_tree, state) do - {:noreply, [{:gpio_registry, state.registered}], state} - 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}" + def handle_call({:register_pin, %PinBinding{pin_num: pin_num} = binding}, _from, state) do + Logger.info 1, "Registering PinBinding #{pin_num}" case state.registered[pin_num] do nil -> case @handler.register_pin(pin_num) do :ok -> - new_state = %{ - state - | registered: Map.put(state.registered, pin_num, sequence_id) - } - - {:reply, :ok, [{:gpio_registry, new_state.registered}], new_state} + new_state = do_register(state, binding) + {:reply, :ok, [{:gpio_registry, %{}}], new_state} {:error, _} = err -> {:reply, err, [], state} @@ -116,23 +108,17 @@ defmodule Farmbot.PinBinding.Manager do 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 nil -> {:reply, {:error, :unregistered}, [], state} - sequence_id -> - Logger.info 1, "Unregistering #{pin_num} from sequence by id: #{sequence_id}" + %PinBinding{} = old -> + Logger.info 1, "Unregistering PinBinding #{pin_num}" case @handler.unregister_pin(pin_num) do :ok -> - - new_state = %{ - state - | registered: Map.delete(state.registered, pin_num) - } - - {:reply, :ok, [{:gpio_registry, new_state.registered}], new_state} + new_state = do_unregister(state, old) + {:reply, :ok, [{:gpio_registry, %{}}], new_state} err -> {:reply, err, [], state} @@ -154,7 +140,24 @@ defmodule Farmbot.PinBinding.Manager do 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] try do @@ -166,6 +169,7 @@ defmodule Farmbot.PinBinding.Manager do err -> message = Exception.message(err) Logger.warn(2, "Failed to execute sequence #{sequence_id} " <> message) + IO.warn "", System.stacktrace() env end end diff --git a/lib/farmbot/repo/after_sync_worker.ex b/lib/farmbot/repo/after_sync_worker.ex index 1e70195bd..59c078011 100644 --- a/lib/farmbot/repo/after_sync_worker.ex +++ b/lib/farmbot/repo/after_sync_worker.ex @@ -26,19 +26,19 @@ defmodule Farmbot.Repo.AfterSyncWorker do {:noreply, state} end - def handle_info({Farmbot.Repo.Registry, :addition, Farmbot.Asset.PinBinding, %{pin_num: pin, sequence_id: sequence_id}}, state) do - Farmbot.PinBinding.Manager.register_pin(pin, sequence_id) + def handle_info({Farmbot.Repo.Registry, :addition, Farmbot.Asset.PinBinding, binding}, state) do + Farmbot.PinBinding.Manager.register_pin(binding) {:noreply, state} end - def handle_info({Farmbot.Repo.Registry, :updated, Farmbot.Asset.PinBinding, %{pin_num: pin, sequence_id: sequence_id}}, state) do - Farmbot.PinBinding.Manager.unregister_pin(pin) - Farmbot.PinBinding.Manager.register_pin(pin, sequence_id) + def handle_info({Farmbot.Repo.Registry, :updated, Farmbot.Asset.PinBinding, binding}, state) do + Farmbot.PinBinding.Manager.unregister_pin(binding) + Farmbot.PinBinding.Manager.register_pin(binding) {:noreply, state} end - def handle_info({Farmbot.Repo.Registry, :deletion, Farmbot.Asset.PinBinding, %{pin_num: pin, sequence_id: _sequence_id}}, state) do - Farmbot.PinBinding.Manager.unregister_pin(pin) + def handle_info({Farmbot.Repo.Registry, :deletion, Farmbot.Asset.PinBinding, binding}, state) do + Farmbot.PinBinding.Manager.unregister_pin(binding) {:noreply, state} end diff --git a/lib/farmbot/repo/seed_db.ex b/lib/farmbot/repo/seed_db.ex index e97f84d82..7d07ec15b 100644 --- a/lib/farmbot/repo/seed_db.ex +++ b/lib/farmbot/repo/seed_db.ex @@ -9,25 +9,20 @@ defmodule Farmbot.Repo.SeedDB do end def init([]) do - sequence(builtin(:sequence, :emergency_lock), "emergency_lock") - sequence(builtin(:sequence, :emergency_unlock), "emergency_unlock") - 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) + pin_binding(builtin(:pin_binding, :emergency_lock), "emergency_lock", 17) + pin_binding(builtin(:pin_binding, :emergency_unlock), "emergency_unlock", 23) :ignore end - def sequence(id, kind, args \\ %{}, body \\ []) do - ConfigStorage.register_sync_cmd(id, "Sequence", %{id: id, name: "__#{kind}", kind: kind, args: args, body: body}) - |> Farmbot.Repo.apply_sync_cmd() - end - - def pin_binding(id, sequence_id, pin_num) do - ConfigStorage.register_sync_cmd(id, "PinBinding", %{id: id, sequence_id: sequence_id, pin_num: pin_num}) + def pin_binding(id, special_action, pin_num) do + body = %{ + id: id, + sequence_id: nil, + special_action: special_action, + pin_num: pin_num + } + ConfigStorage.register_sync_cmd(id, "PinBinding", body) |> Farmbot.Repo.apply_sync_cmd() end diff --git a/priv/repo/migrations/20180713180958_pin_bindings_special_action.exs b/priv/repo/migrations/20180713180958_pin_bindings_special_action.exs new file mode 100644 index 000000000..1efc1e9ba --- /dev/null +++ b/priv/repo/migrations/20180713180958_pin_bindings_special_action.exs @@ -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