Move pinbindings from config_storage to asset storage to store in API

pull/576/head
connor rigby 2018-07-10 09:57:18 -07:00 committed by Connor Rigby
parent 56954a3790
commit fc43da88f3
24 changed files with 115 additions and 119 deletions

View File

@ -44,7 +44,7 @@ config :farmbot, :behaviour,
authorization: Farmbot.Bootstrap.Authorization,
firmware_handler: Farmbot.Firmware.StubHandler,
http_adapter: Farmbot.HTTP.HTTPoisonAdapter,
gpio_handler: Farmbot.System.GPIO.StubHandler,
pin_binding_handler: Farmbot.PinBinding.StubHandler,
json_parser: Farmbot.JSON.JasonParser
config :farmbot, :farmware,

View File

@ -57,7 +57,7 @@ config :farmbot, :behaviour,
system_tasks: Farmbot.Target.SystemTasks,
firmware_handler: Farmbot.Firmware.StubHandler,
update_handler: Farmbot.Target.UpdateHandler,
gpio_handler: Farmbot.Target.GPIO.AleHandler
pin_binding_handler: Farmbot.Target.PinBinding.AleHandler
local_file = Path.join(System.user_home!(), ".ssh/id_rsa.pub")
local_key = if File.exists?(local_file), do: [File.read!(local_file)], else: []

View File

@ -55,7 +55,7 @@ config :farmbot, :behaviour,
system_tasks: Farmbot.Target.SystemTasks,
firmware_handler: Farmbot.Firmware.StubHandler,
update_handler: Farmbot.Target.UpdateHandler,
gpio_handler: Farmbot.Target.GPIO.AleHandler
pin_binding_handler: Farmbot.Target.PinBinding.AleHandler
config :shoehorn,
init: [:nerves_runtime],

View File

@ -5,7 +5,9 @@ lib/farmbot/farmware/runtime.ex
lib/farmbot/farmware/runtime_error.ex
lib/farmbot/farmware/supervisor.ex
lib/farmbot/repo/worker.ex
lib/farmbot/system/gpio/gpio.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
lib/farmbot/asset/regimen.ex
lib/farmbot/jwt.ex

View File

@ -9,6 +9,7 @@ defmodule Farmbot.Asset do
Device,
FarmEvent,
Peripheral,
PinBinding,
Point,
Regimen,
Sensor,
@ -30,6 +31,10 @@ defmodule Farmbot.Asset do
:ok
end
def all_pin_bindings do
Farmbot.Repo.all(PinBinding)
end
@doc "Information about _this_ device."
def device do
Farmbot.Repo.one(Device)

View File

@ -0,0 +1,22 @@
defmodule Farmbot.Asset.PinBinding do
@moduledoc """
When a pin binding is triggered a sequence fires.
"""
use Ecto.Schema
import Ecto.Changeset
schema "pin_bindings" do
field(:pin_num, :integer)
field(:sequence_id, :integer)
end
@required_fields [:id, :pin_num, :sequence_id]
def changeset(pin_binding, params \\ %{}) do
pin_binding
|> cast(params, @required_fields)
|> validate_required(@required_fields)
|> unique_constraint(:id)
end
end

View File

@ -34,13 +34,11 @@ defmodule Farmbot.Bootstrap.AuthTask do
auth_task = Application.get_env(:farmbot, :behaviour)[:authorization]
{email, pass, server} = {fetch_email(), fetch_pass(), fetch_server()}
# Logger.busy(3, "refreshing token: #{email} - #{server}")
Farmbot.System.GPIO.Leds.led_status_err()
case auth_task.authorize(email, pass, server) do
{:ok, token} ->
# Logger.success(3, "Successful authorization: #{email} - #{server}")
update_config_value(:bool, "settings", "first_boot", false)
update_config_value(:string, "authorization", "token", token)
Farmbot.System.GPIO.Leds.led_status_ok()
if get_config_value(:bool, "settings", "auto_sync") do
# Force an auto sync
Farmbot.Repo.sync(2)

View File

@ -14,7 +14,6 @@ defmodule Farmbot.Bootstrap.Authorization do
@type token :: binary
use Farmbot.Logger
alias Farmbot.System.GPIO.Leds
alias Farmbot.System.ConfigStorage
import ConfigStorage, only: [update_config_value: 4, get_config_value: 3]
@ -51,7 +50,6 @@ defmodule Farmbot.Bootstrap.Authorization do
{:ok, resp} <- request_token(server, payload),
{:ok, body} <- Poison.decode(resp),
{:ok, map} <- Map.fetch(body, "token") do
Leds.led_status_ok()
last_reset_reason_file = Path.join(@data_path, "last_shutdown_reason")
File.rm(last_reset_reason_file)
Map.fetch(map, "encoded")
@ -86,7 +84,6 @@ defmodule Farmbot.Bootstrap.Authorization do
update_config_value(:bool, "settings", "first_boot", false)
last_reset_reason_file = Path.join(@data_path, "last_shutdown_reason")
File.rm(last_reset_reason_file)
Leds.led_status_ok()
Map.fetch(map, "encoded")
else
:error -> {:error, "unknown error."}

View File

@ -127,6 +127,7 @@ defmodule Farmbot.Bootstrap.Supervisor do
supervisor(Farmbot.HTTP.Supervisor, []),
worker(Farmbot.Bootstrap.SettingsSync, []),
supervisor(Farmbot.Firmware.Supervisor, []),
supervisor(Farmbot.PinBinding.Supervisor, []),
supervisor(Farmbot.BotState.Supervisor, []),
supervisor(Farmbot.BotState.Transport.Supervisor, []),
supervisor(Farmbot.Repo.Supervisor, []),

View File

@ -161,7 +161,7 @@ defmodule Farmbot.BotState do
info_settings = %{initial_state.informational_settings | node_name: node()}
state = %{initial_state | informational_settings: info_settings}
gen_stage_opts = [
subscribe_to: [Firmware, ConfigStorage.Dispatcher, Farmbot.System.GPIO],
subscribe_to: [Firmware, ConfigStorage.Dispatcher, Farmbot.PinBinding.Manager],
dispatcher: GenStage.BroadcastDispatcher
]
{:producer_consumer, state, gen_stage_opts}

View File

@ -1,20 +0,0 @@
defmodule Farmbot.CeleryScript.AST.Node.RegisterGpio do
@moduledoc false
use Farmbot.CeleryScript.AST.Node
allow_args [:sequence_id, :pin_number]
use Farmbot.Logger
alias Farmbot.Asset
def execute(%{sequence_id: id, pin_number: pin_num}, _, env) do
env = mutate_env(env)
case Asset.get_sequence_by_id(id) do
nil -> {:error, "Could not find sequence by id: #{id}", env}
seq ->
Logger.busy 1, "Registering gpio: #{pin_num} to sequence: #{seq.name}"
case Farmbot.System.GPIO.register_pin(pin_num, id) do
:ok -> {:ok, env}
{:error, reason} -> {:error, reason, env}
end
end
end
end

View File

@ -1,14 +0,0 @@
defmodule Farmbot.CeleryScript.AST.Node.UnregisterGpio do
@moduledoc false
use Farmbot.CeleryScript.AST.Node
allow_args [:pin_number]
use Farmbot.Logger
def execute(%{pin_number: pin_num}, _, env) do
env = mutate_env(env)
case Farmbot.System.GPIO.unregister_pin(pin_num)do
:ok -> {:ok, env}
{:error, reason} -> {:error, reason, env}
end
end
end

View File

@ -260,7 +260,6 @@ defmodule Farmbot.Firmware do
:ok ->
timer = start_timer(current, state.timeout_ms)
if fun == :emergency_unlock do
Farmbot.System.GPIO.Leds.led_status_ok()
new_dispatch = [{:informational_settings, %{busy: false, locked: false}} | dispatch]
{:noreply, new_dispatch, %{state | current: current, timer: timer}}
else
@ -503,7 +502,6 @@ defmodule Farmbot.Firmware do
end
defp handle_gcode(:report_emergency_lock, state) do
Farmbot.System.GPIO.Leds.led_status_err
maybe_send_email()
if state.current do
do_reply(state, {:error, :emergency_lock})

View File

@ -1,8 +1,8 @@
defmodule Farmbot.System.GPIO.Handler do
@moduledoc "Behaviour for GPIO handlers to implement."
defmodule Farmbot.PinBinding.Handler do
@moduledoc "Behaviour for PinBinding handlers to implement."
@doc "Start the handler."
@callback start_link :: GenServer.on_start
@callback start_link :: GenServer.on_start()
@doc "Register a pin."
@callback register_pin(integer) :: :ok | {:error, term}

View File

@ -1,11 +1,11 @@
defmodule Farmbot.System.GPIO do
@moduledoc "Handles GPIO inputs."
defmodule Farmbot.PinBinding.Manager do
@moduledoc "Handles PinBinding inputs and outputs"
use GenStage
use Farmbot.Logger
alias Farmbot.System.ConfigStorage
alias ConfigStorage.GpioRegistry
@handler Application.get_env(:farmbot, :behaviour)[:gpio_handler]
alias Farmbot.Asset
alias Asset.PinBinding
@handler Application.get_env(:farmbot, :behaviour)[:pin_binding_handler]
@handler || Mix.raise("No pin binding handler.")
@doc "Register a pin number to execute sequence."
def register_pin(pin_num, sequence_id) do
@ -13,8 +13,8 @@ defmodule Farmbot.System.GPIO do
end
@doc "Unregister a sequence."
def unregister_pin(sequence_id) do
GenStage.call(__MODULE__, {:unregister_pin, sequence_id})
def unregister_pin(pin_num) do
GenStage.call(__MODULE__, {:unregister_pin, pin_num})
end
def confirm_asset_storage_up do
@ -22,8 +22,8 @@ defmodule Farmbot.System.GPIO do
end
@doc false
def start_link do
GenStage.start_link(__MODULE__, [], name: __MODULE__)
def start_link(args) do
GenStage.start_link(__MODULE__, args, name: __MODULE__)
end
defmodule State do
@ -37,8 +37,7 @@ defmodule Farmbot.System.GPIO do
def init([]) do
case @handler.start_link() do
{:ok, handler} ->
all_gpios = ConfigStorage.all_gpios()
state = initial_state(all_gpios, struct(State, handler: handler))
state = initial_state([], struct(State, handler: handler))
Process.send_after(self(), :update_fb_state_tree, 10)
{:producer_consumer, state,
@ -52,7 +51,7 @@ defmodule Farmbot.System.GPIO do
defp initial_state([], state), do: state
defp initial_state(
[%GpioRegistry{pin: pin, sequence_id: sequence_id} | rest],
[%PinBinding{pin_num: pin, sequence_id: sequence_id} | rest],
state
) do
case @handler.register_pin(pin) do
@ -96,12 +95,11 @@ defmodule Farmbot.System.GPIO do
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
nil ->
case @handler.register_pin(pin_num) do
:ok ->
ConfigStorage.add_gpio_registry(pin_num, sequence_id)
new_state = %{
state
| registered: Map.put(state.registered, pin_num, sequence_id)
@ -119,14 +117,15 @@ defmodule Farmbot.System.GPIO do
end
def handle_call({:unregister_pin, 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}"
case @handler.unregister_pin(pin_num) do
:ok ->
ConfigStorage.delete_gpio_registry(pin_num, sequence_id)
new_state = %{
state
@ -142,6 +141,8 @@ defmodule Farmbot.System.GPIO do
end
def handle_call(:confirm_asset_storage_up, _, state) do
all_bindings = Asset.all_pin_bindings()
state = initial_state(all_bindings, state)
{:reply, :ok, [], %{state | repo_up: true}}
end

View File

@ -1,6 +1,6 @@
defmodule Farmbot.System.GPIO.StubHandler do
@moduledoc "Stub for handling GPIO."
@behaviour Farmbot.System.GPIO.Handler
defmodule Farmbot.PinBinding.StubHandler do
@moduledoc "Stub for handling PinBinding."
@behaviour Farmbot.PinBinding.Handler
use GenStage
def test_fire(pin) do
@ -16,7 +16,7 @@ defmodule Farmbot.System.GPIO.StubHandler do
end
def start_link do
GenStage.start_link(__MODULE__, [], [name: __MODULE__])
GenStage.start_link(__MODULE__, [], name: __MODULE__)
end
def init([]) do
@ -37,9 +37,11 @@ defmodule Farmbot.System.GPIO.StubHandler do
def handle_call({:test_fire, pin}, _from, state) do
case state[pin] do
nil -> {:reply, :error, [], state}
nil ->
{:reply, :error, [], state}
:enabled ->
send self(), {:do_test_fire, pin}
send(self(), {:do_test_fire, pin})
{:reply, :ok, [], state}
end
end

View File

@ -0,0 +1,15 @@
defmodule Farmbot.PinBinding.Supervisor do
@moduledoc false
use Supervisor
def start_link() do
Supervisor.start_link(__MODULE__, [], [name: __MODULE__])
end
def init([]) do
children = [
{Farmbot.PinBinding.Manager, []}
]
Supervisor.init(children, [strategy: :one_for_one])
end
end

View File

@ -10,7 +10,7 @@ defmodule Farmbot.Repo.AfterSyncWorker do
def init([]) do
Farmbot.Repo.Registry.subscribe()
Farmbot.System.GPIO.confirm_asset_storage_up()
Farmbot.PinBinding.Manager.confirm_asset_storage_up()
{:ok, %{}}
end
@ -26,6 +26,22 @@ 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)
{: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)
{: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)
{:noreply, state}
end
def handle_info(_, state) do
{:noreply, state}
end

View File

@ -16,6 +16,7 @@ defmodule Farmbot.Repo do
Device,
FarmEvent,
Peripheral,
PinBinding,
Point,
Regimen,
Sensor,
@ -69,6 +70,7 @@ defmodule Farmbot.Repo do
results = Farmbot.Repo.all(Device) ++
Farmbot.Repo.all(FarmEvent) ++
Farmbot.Repo.all(Peripheral) ++
Farmbot.Repo.all(PinBinding) ++
Farmbot.Repo.all(Point) ++
Farmbot.Repo.all(Regimen) ++
Farmbot.Repo.all(Sensor) ++
@ -86,6 +88,7 @@ defmodule Farmbot.Repo do
Task.async(fn() -> {Device, HTTP.get!("/api/device.json") |> Map.fetch!(:body) |> Poison.decode!(as: struct(Device))} end),
Task.async(fn() -> {FarmEvent, HTTP.get!("/api/farm_events.json") |> Map.fetch!(:body) |> Poison.decode!(as: [struct(FarmEvent)])} end),
Task.async(fn() -> {Peripheral, HTTP.get!("/api/peripherals.json") |> Map.fetch!(:body) |> Poison.decode!(as: [struct(Peripheral)])} end),
Task.async(fn() -> {PinBinding, HTTP.get!("/api/pin_bindings.json") |> Map.fetch!(:body) |> Poison.decode!(as: [struct(PinBinding)])} end),
Task.async(fn() -> {Point, HTTP.get!("/api/points.json") |> Map.fetch!(:body) |> Poison.decode!(as: [struct(Point)])} end),
Task.async(fn() -> {Regimen, HTTP.get!("/api/regimens.json") |> Map.fetch!(:body) |> Poison.decode!(as: [struct(Regimen)])} end),
Task.async(fn() -> {Sensor, HTTP.get!("/api/sensors.json") |> Map.fetch!(:body) |> Poison.decode!(as: [struct(Sensor)])} end),

View File

@ -1,40 +0,0 @@
defmodule Farmbot.System.GPIO.Leds do
@moduledoc false
use GenServer
@led_status_on Application.get_env(:farmbot, :gpio, :status_led_off) || true
def led_status_ok do
GenServer.call(__MODULE__, :led_status_ok)
end
def led_status_err do
GenServer.call(__MODULE__, :led_status_err)
end
@doc false
def start_link do
GenServer.start_link(__MODULE__, [], [name: __MODULE__])
end
def init([]) do
names = Application.get_env(:nerves_leds, :names) || []
status_led_name = Keyword.get(names, :status)
{:ok, %{status: status_led_name}}
end
def handle_call(_, _from, %{status: nil} = state) do
{:reply, :ok, state}
end
def handle_call(:led_status_ok, _from, %{status: _} = state) do
Nerves.Leds.set status: @led_status_on
{:reply, :ok, state}
end
def handle_call(:led_status_err, _from, %{status: _} = state) do
Nerves.Leds.set status: :slowblink
{:reply, :ok, state}
end
end

View File

@ -18,7 +18,6 @@ defmodule Farmbot.System.Supervisor do
supervisor(Farmbot.System.Init.Ecto, [[], []]),
supervisor(Farmbot.System.ConfigStorage, []),
worker(Farmbot.System.ConfigStorage.Dispatcher, []),
worker(Farmbot.System.GPIO.Leds, []),
]
init_mods =
@ -27,7 +26,6 @@ defmodule Farmbot.System.Supervisor do
after_init_children = [
supervisor(Farmbot.System.Updates, []),
worker(Farmbot.System.GPIO, []),
worker(Farmbot.EasterEggs, []),
]

View File

@ -67,7 +67,6 @@ defmodule Farmbot.Target.Bootstrap.Configurator do
Logger.info(3, "Building new configuration.")
import Supervisor.Spec
:ets.new(:session, [:named_table, :public, read_concurrency: true])
Farmbot.System.GPIO.Leds.led_status_err()
ConfigStorage.destroy_all_network_configs()
children = [
worker(Configurator.CaptivePortal, [], restart: :transient),

View File

@ -1,11 +1,11 @@
defmodule Farmbot.Target.GPIO.AleHandler do
@moduledoc "GPIO handler that uses Elixir.Ale"
defmodule Farmbot.Target.PinBinding.AleHandler do
@moduledoc "PinBinding handler that uses Elixir.Ale"
use GenStage
alias ElixirALE.GPIO
@behaviour Farmbot.System.GPIO.Handler
@behaviour Farmbot.PinBinding.Handler
# GPIO Handler Callbacks
# PinBinding.Handler Callbacks
def start_link do
GenStage.start_link(__MODULE__, [], [name: __MODULE__])
end

View File

@ -0,0 +1,13 @@
defmodule Farmbot.Repo.Migrations.CreatePinBindingsTable do
use Ecto.Migration
def change do
create table("pin_bindings", primary_key: false) do
add(:id, :integer)
add(:pin_num, :integer)
add(:sequence_id, :integer)
end
create(unique_index("pin_bindings", [:id]))
end
end