Permalink
Browse files

Rework default sequences/pin_bindings

  • Loading branch information...
ConnorRigby committed Jul 13, 2018
1 parent 9a26a9c commit 1ffa365642394c3ec7974a0c8638f1db8330acb7
@@ -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,
@@ -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
@@ -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
@@ -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
@@ -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

@@ -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

@@ -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

0 comments on commit 1ffa365

Please sign in to comment.