Fix More CeleryScript
* Add diapatcher for config updates. * Add env updater for each cs_node. * Fix logging.
This commit is contained in:
parent
fceef7ee74
commit
3836336f90
|
@ -50,8 +50,8 @@ defmodule Farmbot.BotState do
|
|||
def init([]) do
|
||||
{
|
||||
:producer_consumer,
|
||||
struct(__MODULE__),
|
||||
subscribe_to: [Farmbot.Firmware], dispatcher: GenStage.BroadcastDispatcher
|
||||
struct(__MODULE__, configuration: Farmbot.System.ConfigStorage.get_config_as_map()["settings"]),
|
||||
subscribe_to: [Farmbot.Firmware, Farmbot.System.ConfigStorage.Dispatcher], dispatcher: GenStage.BroadcastDispatcher
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -70,9 +70,18 @@ defmodule Farmbot.BotState do
|
|||
|
||||
defp do_handle([], state), do: state
|
||||
|
||||
defp do_handle([{:config, "settings", key, val} | rest], state) do
|
||||
new_config = Map.put(state.configuration, key, val)
|
||||
new_state = %{state | configuration: new_config}
|
||||
do_handle(rest, new_state)
|
||||
end
|
||||
|
||||
defp do_handle([{:config, _, _, _} | rest], state) do
|
||||
do_handle(rest, state)
|
||||
end
|
||||
|
||||
defp do_handle([{key, diff} | rest], state) do
|
||||
state = %{state | key => Map.merge(Map.get(state, key), diff)}
|
||||
Logger.debug "Got #{key} => #{inspect diff} #{inspect state}"
|
||||
do_handle(rest, state)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -106,7 +106,7 @@ defmodule Farmbot.BotState.Transport.GenMQTT.Client do
|
|||
end
|
||||
|
||||
def handle_cast({:emit, ast}, state) do
|
||||
Logger.debug "Emitting #{inspect ast} | #{inspect AST.encode(ast) |> elem(1)}"
|
||||
# Logger.debug "Emitting #{inspect ast} | #{inspect AST.encode(ast) |> elem(1)}"
|
||||
{:ok, encoded_ast} = AST.encode(ast)
|
||||
json = Poison.encode!(encoded_ast)
|
||||
GenMQTT.publish(self(), frontend_topic(state.device), json, 0, false)
|
||||
|
|
|
@ -25,7 +25,9 @@ defmodule Farmbot.BotState.Transport.GenMQTT do
|
|||
end
|
||||
|
||||
def handle_log_events(logs, {%{client: client} = internal_state, old_bot_state}) do
|
||||
for log <- logs do
|
||||
location_data = Map.get(old_bot_state || %{}, :location_data, %{position: %{x: -1, y: -1, z: -1}})
|
||||
for log_without_pos <- logs do
|
||||
log = add_position_to_log(log_without_pos, location_data)
|
||||
Client.push_bot_log(client, log)
|
||||
end
|
||||
|
||||
|
@ -46,4 +48,9 @@ defmodule Farmbot.BotState.Transport.GenMQTT do
|
|||
def handle_bot_state_events([], {internal, bot_state}) do
|
||||
{:noreply, [], {internal, bot_state}}
|
||||
end
|
||||
|
||||
defp add_position_to_log(%{meta: meta} = log, %{position: pos}) do
|
||||
new_meta = Map.merge(meta, pos)
|
||||
%{log | meta: new_meta}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,6 +4,8 @@ defmodule Farmbot.CeleryScript.AST.Arg.Package do
|
|||
|
||||
def decode("farmbot_os"), do: {:ok, :farmbot_os}
|
||||
def decode("arduino_firmware"), do: {:ok, :arduino_firmware}
|
||||
def decode(:farmbot_os), do: {:ok, :farmbot_os}
|
||||
def decode(:arduino_firmware), do: {:ok, :arduino_firmware}
|
||||
def decode(other), do: {:ok, {:farmware, other}}
|
||||
|
||||
def encode(:farmbot_os), do: {:ok, "farmbot_os"}
|
||||
|
|
|
@ -21,7 +21,7 @@ defmodule Farmbot.CeleryScript.AST.Node do
|
|||
@doc false
|
||||
defmacro __using__(_) do
|
||||
quote do
|
||||
import AST.Node, only: [allow_args: 1, return_self: 0, rebuild_self: 2]
|
||||
import AST.Node, only: [allow_args: 1, return_self: 0, rebuild_self: 2, mutate_env: 1]
|
||||
@behaviour AST.Node
|
||||
@after_compile AST.Node
|
||||
require Logger
|
||||
|
@ -90,6 +90,7 @@ defmodule Farmbot.CeleryScript.AST.Node do
|
|||
defmacro return_self do
|
||||
quote do
|
||||
def execute(args, body, env) do
|
||||
env = mutate_env(env)
|
||||
{:ok, rebuild_self(args, body), env}
|
||||
end
|
||||
end
|
||||
|
@ -102,6 +103,15 @@ defmodule Farmbot.CeleryScript.AST.Node do
|
|||
end
|
||||
end
|
||||
|
||||
defmacro mutate_env(env) do
|
||||
quote do
|
||||
%{unquote(env) | file: __ENV__.file,
|
||||
line: __ENV__.line,
|
||||
function: __ENV__.function,
|
||||
module: __ENV__.module}
|
||||
end
|
||||
end
|
||||
|
||||
@doc "Allow a list of args."
|
||||
defmacro allow_args(args) do
|
||||
arg_mod_base = AST.Arg
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.If do
|
|||
allow_args [:lhs, :op, :rhs, :_then, :_else]
|
||||
|
||||
def execute(%{_else: else_, _then: then_, lhs: lhs, op: op, rhs: rhs }, _body, env) do
|
||||
env = mutate_env(env)
|
||||
left = eval_lhs(lhs)
|
||||
|
||||
if is_number(left) or is_nil(left) do
|
||||
|
|
|
@ -2,4 +2,9 @@ defmodule Farmbot.CeleryScript.AST.Node.AddPoint do
|
|||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:location]
|
||||
|
||||
def execute(_, _, env) do
|
||||
env = mutate_env(env)
|
||||
{:ok, env}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,10 +6,12 @@ defmodule Farmbot.CeleryScript.AST.Node.Calibrate do
|
|||
@default_speed 100
|
||||
|
||||
def execute(%{axis: :all}, _, env) do
|
||||
env = mutate_env(env)
|
||||
do_reduce([:y, :z, :x], @default_speed, env)
|
||||
end
|
||||
|
||||
def execute(%{speed: speed, axis: axis}, _, env) do
|
||||
env = mutate_env(env)
|
||||
case Farmbot.Firmware.calibrate(axis, speed) do
|
||||
:ok -> {:ok, env}
|
||||
{:error, reason} -> {:error, reason, env}
|
||||
|
|
|
@ -2,4 +2,6 @@ defmodule Farmbot.CeleryScript.AST.Node.Channel do
|
|||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:channel_name]
|
||||
|
||||
return_self()
|
||||
end
|
||||
|
|
|
@ -3,15 +3,18 @@ defmodule Farmbot.CeleryScript.AST.Node.CheckUpdates do
|
|||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:package]
|
||||
|
||||
def execute(%{package: :farmbot_os}, _, _env) do
|
||||
{:error, "No implementation for updating fbos right now."}
|
||||
def execute(%{package: :farmbot_os}, _, env) do
|
||||
env = mutate_env(env)
|
||||
{:error, "No implementation for updating fbos right now.", env}
|
||||
end
|
||||
|
||||
def execute(%{package: :arduino_firmware}, _, env) do
|
||||
env = mutate_env(env)
|
||||
{:error, "Arduino firmware can not be updated manually.", env}
|
||||
end
|
||||
|
||||
def execute(%{package: {:farmware, fw}}, _, env) do
|
||||
env = mutate_env(env)
|
||||
case Farmbot.Farmware.lookup(fw) do
|
||||
{:ok, %Farmbot.Farmware{} = fw} -> do_update_farmware(fw, env)
|
||||
{:error, reason} -> {:error, reason, env}
|
||||
|
|
|
@ -3,18 +3,60 @@ defmodule Farmbot.CeleryScript.AST.Node.ConfigUpdate do
|
|||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:package]
|
||||
|
||||
def execute(%{package: :farmbot_os}, _body, env) do
|
||||
{:error, "#{__MODULE__} :farmbot_os stub", env}
|
||||
def execute(%{package: :farmbot_os}, body, env) do
|
||||
env = mutate_env(env)
|
||||
do_reduce_os(body, env)
|
||||
end
|
||||
|
||||
def execute(%{package: :arduino_firmware}, _body, env) do
|
||||
{:error, "#{__MODULE__} :arduino_firmware stub", env}
|
||||
def execute(%{package: :arduino_firmware}, body, env) do
|
||||
env = mutate_env(env)
|
||||
do_reduce_fw(body, env)
|
||||
end
|
||||
|
||||
def execute(%{package: {:farmware, fw}}, body, env) do
|
||||
def execute(%{package: {:farmware, fw}}, _body, env) do
|
||||
case Farmbot.Farmware.lookup(fw) do
|
||||
{:ok, _fw} -> {:error, "Farmware config updates not working", env}
|
||||
{:error, reason} -> {:error, reason, env}
|
||||
end
|
||||
end
|
||||
|
||||
defp do_reduce_os([%{args: %{label: key, value: value}} | rest], env) do
|
||||
Logger.info "Updating: #{inspect key}: #{value}"
|
||||
case lookup_os_config(key, value) do
|
||||
{:ok, {type, group, value}} ->
|
||||
Farmbot.System.ConfigStorage.update_config_value(type, group, key, value)
|
||||
do_reduce_os(rest, env)
|
||||
{:error, reason} ->
|
||||
{:error, reason, env}
|
||||
end
|
||||
end
|
||||
|
||||
defp do_reduce_os([], env) do
|
||||
{:ok, env}
|
||||
end
|
||||
|
||||
defp do_reduce_fw([%{args: %{label: key, value: value}} | rest], env) do
|
||||
case Farmbot.Firmware.update_param(key, value) do
|
||||
:ok -> do_reduce_fw(rest, env)
|
||||
{:error, reason} -> {:error, reason, env}
|
||||
end
|
||||
end
|
||||
|
||||
defp do_reduce_fw([], env), do: {:ok, env}
|
||||
|
||||
defp lookup_os_config("first_boot", val), do: {:ok, {:bool, "settings", format_bool_for_os(val)}}
|
||||
defp lookup_os_config("os_auto_update", val), do: {:ok, {:bool, "settings", format_bool_for_os(val)}}
|
||||
defp lookup_os_config("first_party_farmware", val), do: {:ok, {:bool, "settings", format_bool_for_os(val)}}
|
||||
defp lookup_os_config("auto_sync", val), do: {:ok, {:bool, "settings", format_bool_for_os(val)}}
|
||||
defp lookup_os_config("first_party_farmware_url", val), do: {:ok, {:string, "settings", val}}
|
||||
defp lookup_os_config("timezone", val), do: {:ok, {:string, "settings", val}}
|
||||
defp lookup_os_config("firmware_hardware", "farmduino"), do: {:ok, {:string, "settings", "farmduino"}}
|
||||
defp lookup_os_config("firmware_hardware", "arduino"), do: {:ok, {:string, "settings", "arduino" }}
|
||||
defp lookup_os_config("firmware_hardware", unknown), do: {:error, "unknown hardware: #{unknown}" }
|
||||
defp lookup_os_config(unknown_config, _), do: {:error, "unknown config: #{unknown_config}"}
|
||||
|
||||
defp format_bool_for_os(1), do: true
|
||||
defp format_bool_for_os(0), do: false
|
||||
defp format_bool_for_os(true), do: true
|
||||
defp format_bool_for_os(false), do: false
|
||||
end
|
||||
|
|
|
@ -2,4 +2,6 @@ defmodule Farmbot.CeleryScript.AST.Node.Coordinate do
|
|||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:x, :y, :z]
|
||||
|
||||
return_self()
|
||||
end
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
defmodule Farmbot.CeleryScript.AST.Node.DataUpdate do
|
||||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:value]
|
||||
end
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.EmergencyLock do
|
|||
allow_args []
|
||||
|
||||
def execute(_, _, env) do
|
||||
env = mutate_env(env)
|
||||
case Farmbot.Firmware.emergency_lock do
|
||||
:ok -> {:ok, env}
|
||||
{:error, reason} -> {:error, reason, env}
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.EmergencyUnlock do
|
|||
allow_args []
|
||||
|
||||
def execute(_, _, env) do
|
||||
env = mutate_env(env)
|
||||
case Farmbot.Firmware.emergency_unlock do
|
||||
:ok -> {:ok, env}
|
||||
{:error, reason} -> {:error, reason, env}
|
||||
|
|
|
@ -6,6 +6,7 @@ defmodule Farmbot.CeleryScript.AST.Node.Execute do
|
|||
import Ecto.Query
|
||||
|
||||
def execute(%{sequence_id: id}, _, env) do
|
||||
env = mutate_env(env)
|
||||
repo = Farmbot.Repo.current_repo()
|
||||
seq = repo.one(from s in Farmbot.Repo.Sequence, where: s.id == ^id)
|
||||
case seq do
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.ExecuteScript do
|
|||
allow_args [:label]
|
||||
|
||||
def execute(%{label: label}, _, env) do
|
||||
env = mutate_env(env)
|
||||
case Farmbot.Farmware.lookup(label) do
|
||||
{:ok, fw} -> do_execute(fw, env)
|
||||
{:error, reason} -> {:error, reason, env}
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.FactoryReset do
|
|||
allow_args [:package]
|
||||
|
||||
def execute(_, _, env) do
|
||||
env = mutate_env(env)
|
||||
Farmbot.System.factory_reset "CeleryScript request."
|
||||
{:ok, env}
|
||||
end
|
||||
|
|
|
@ -4,10 +4,12 @@ defmodule Farmbot.CeleryScript.AST.Node.FindHome do
|
|||
allow_args [:speed, :axis]
|
||||
|
||||
def execute(%{speed: speed, axis: :all}, _, env) do
|
||||
env = mutate_env(env)
|
||||
do_reduce([:y, :z, :x], speed, env)
|
||||
end
|
||||
|
||||
def execute(%{speed: speed, axis: axis}, _, env) do
|
||||
env = mutate_env(env)
|
||||
case Farmbot.Firmware.find_home(axis, speed) do
|
||||
:ok -> {:ok, env}
|
||||
{:error, reason} -> {:error, reason, env}
|
||||
|
|
|
@ -4,10 +4,12 @@ defmodule Farmbot.CeleryScript.AST.Node.Home do
|
|||
allow_args [:speed, :axis]
|
||||
|
||||
def execute(%{speed: speed, axis: :all}, _, env) do
|
||||
env = mutate_env(env)
|
||||
do_reduce([:y, :z, :x], speed, env)
|
||||
end
|
||||
|
||||
def execute(%{speed: speed, axis: axis}, _, env) do
|
||||
env = mutate_env(env)
|
||||
case Farmbot.Firmware.home(axis, speed) do
|
||||
:ok -> {:ok, env}
|
||||
{:error, reason} -> {:error, reason, env}
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.InstallFarmware do
|
|||
allow_args [:url]
|
||||
|
||||
def execute(%{url: url}, _, env) do
|
||||
env = mutate_env(env)
|
||||
case Farmbot.Farmware.Installer.install(url) do
|
||||
{:ok, _} -> {:ok, env}
|
||||
{:error, reason} -> {:error, reason, env}
|
||||
|
|
|
@ -6,6 +6,7 @@ defmodule Farmbot.CeleryScript.AST.Node.InstallFirstPartyFarmware do
|
|||
@fpf_url "https://raw.githubusercontent.com/FarmBot-Labs/farmware_manifests/master/manifest.json"
|
||||
|
||||
def execute(_, _, env) do
|
||||
env = mutate_env(env)
|
||||
case Farmbot.Farmware.Installer.add_repo(@fpf_url) do
|
||||
{:ok, _} -> do_sync_repo(env)
|
||||
{:error, :repo_already_exists} -> do_sync_repo(env)
|
||||
|
|
|
@ -6,6 +6,7 @@ defmodule Farmbot.CeleryScript.AST.Node.MoveAbsolute do
|
|||
allow_args [:location, :speed, :offset]
|
||||
|
||||
def execute(%{location: location, speed: speed, offset: offset}, _, env) do
|
||||
env = mutate_env(env)
|
||||
with {:ok, pos_a} <- ast_to_vec3(location),
|
||||
{:ok, pos_b} <- ast_to_vec3(offset)
|
||||
do
|
||||
|
|
|
@ -5,6 +5,7 @@ defmodule Farmbot.CeleryScript.AST.Node.MoveRelative do
|
|||
allow_args [:x, :y, :z, :speed]
|
||||
|
||||
def execute(%{x: x, y: y, z: z, speed: speed}, _, env) do
|
||||
env = mutate_env(env)
|
||||
%{location_data: %{position: %{x: cur_x, y: cur_y, z: cur_z}}} = Farmbot.BotState.force_state_push
|
||||
location = new_vec3(cur_x, cur_y, cur_z)
|
||||
offset = new_vec3(x, y, z)
|
||||
|
|
|
@ -3,5 +3,5 @@ defmodule Farmbot.CeleryScript.AST.Node.Nothing do
|
|||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args []
|
||||
|
||||
def execute(_, _, env), do: {:ok, env}
|
||||
return_self()
|
||||
end
|
||||
|
|
|
@ -2,4 +2,6 @@ defmodule Farmbot.CeleryScript.AST.Node.Pair do
|
|||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:label, :value]
|
||||
|
||||
return_self()
|
||||
end
|
||||
|
|
|
@ -2,4 +2,6 @@ defmodule Farmbot.CeleryScript.AST.Node.Point do
|
|||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:pointer_type, :pointer_id]
|
||||
|
||||
return_self()
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.PowerOff do
|
|||
allow_args []
|
||||
|
||||
def execute(_, _, env) do
|
||||
env = mutate_env(env)
|
||||
Farmbot.System.shutdown("CeleryScript request")
|
||||
{:ok, env}
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.ReadPin do
|
|||
allow_args [:pin_number, :label, :pin_mode]
|
||||
|
||||
def execute(%{pin_number: pin_num, pin_mode: mode}, _, env) do
|
||||
env = mutate_env(env)
|
||||
case Farmbot.Firmware.read_pin(pin_num, mode) do
|
||||
{:ok, _} -> {:ok, env}
|
||||
{:error, reason} -> {:error, reason, env}
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.ReadStatus do
|
|||
allow_args []
|
||||
|
||||
def execute(_, _, env) do
|
||||
env = mutate_env(env)
|
||||
Farmbot.BotState.force_state_push()
|
||||
{:ok, env}
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.Reboot do
|
|||
allow_args []
|
||||
|
||||
def execute(_, _, env) do
|
||||
env = mutate_env(env)
|
||||
Farmbot.System.reboot("CeleryScript request.")
|
||||
{:ok, env}
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.RemoveFarmware do
|
|||
allow_args [:package]
|
||||
|
||||
def execute(%{package: {:farmware, name}}, _, env) do
|
||||
env = mutate_env(env)
|
||||
case Farmbot.Farmware.lookup(name) do
|
||||
{:ok, fw} -> do_uninstall(fw, env)
|
||||
{:error, _} -> {:ok, env}
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.RpcError do
|
|||
allow_args [:label]
|
||||
|
||||
def execute(%{label: _label} = args, body, env) do
|
||||
env = mutate_env(env)
|
||||
ast = rebuild_self(args, body)
|
||||
case Farmbot.BotState.emit(ast) do
|
||||
:ok -> {:ok, env}
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.RpcOk do
|
|||
allow_args [:label]
|
||||
|
||||
def execute(%{label: _label} = args, body, env) do
|
||||
env = mutate_env(env)
|
||||
ast = rebuild_self(args, body)
|
||||
case Farmbot.BotState.emit(ast) do
|
||||
:ok -> {:ok, env}
|
||||
|
|
|
@ -11,7 +11,7 @@ defmodule Farmbot.CeleryScript.AST.Node.RpcRequest do
|
|||
defp do_reduce([ast | rest], label, env) do
|
||||
case Farmbot.CeleryScript.execute(ast, env) do
|
||||
{:ok, new_env} -> do_reduce(rest, label, new_env)
|
||||
{:error, reason, new_env} -> handle_error(ast, reason, new_env)
|
||||
{:error, reason, new_env} -> handle_error(ast, label, reason, new_env)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -19,9 +19,9 @@ defmodule Farmbot.CeleryScript.AST.Node.RpcRequest do
|
|||
Node.RpcOk.execute(%{label: label}, [], env)
|
||||
end
|
||||
|
||||
defp handle_error(ast, reason, env) do
|
||||
defp handle_error(ast, label, reason, env) do
|
||||
case Node.Explanation.execute(%{message: "#{inspect ast} failed: #{inspect reason}"}, [], env) do
|
||||
{:ok, expl, new_env} -> Node.RpcError.execute(%{label: ast.args.label}, [expl], new_env)
|
||||
{:ok, expl, new_env} -> Node.RpcError.execute(%{label: label}, [expl], new_env)
|
||||
{:error, reason, env} -> {:error, reason, env}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,4 +2,24 @@ defmodule Farmbot.CeleryScript.AST.Node.SendMessage do
|
|||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:message, :message_type]
|
||||
|
||||
def execute(%{message: m, message_type: type}, _, env) do
|
||||
env = mutate_env(env)
|
||||
String.replace(m, "{{", "<%=")
|
||||
|> String.replace("}}", "%>")
|
||||
|> EEx.eval_string(fetch_bindings())
|
||||
|> Logger.info([message_type: type])
|
||||
{:ok, env}
|
||||
rescue
|
||||
e in CompileError ->
|
||||
{:error, Exception.message(e), env}
|
||||
e -> reraise(e, System.stacktrace())
|
||||
end
|
||||
|
||||
defp fetch_bindings do
|
||||
bot_state = Farmbot.BotState.force_state_push()
|
||||
pins = Enum.map(bot_state.pins, fn({pin, %{value: value}}) -> {pin, value} end)
|
||||
location = Enum.map(bot_state.location_data.position, fn({axis, val}) -> {axis, val} end)
|
||||
pins ++ location
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.Sequence do
|
|||
allow_args [:version, :is_outdated]
|
||||
|
||||
def execute(%{version: _, is_outdated: _}, body, env) do
|
||||
env = mutate_env(env)
|
||||
do_reduce(body, env)
|
||||
end
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.SetUserEnv do
|
|||
allow_args []
|
||||
|
||||
def execute(args, body, env) do
|
||||
env = mutate_env(env)
|
||||
Logger.warn "FIXME"
|
||||
{:ok, env}
|
||||
end
|
||||
|
|
|
@ -3,4 +3,9 @@ defmodule Farmbot.CeleryScript.AST.Node.Sync do
|
|||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args []
|
||||
|
||||
def execute(_, _, env) do
|
||||
env = mutate_env(env)
|
||||
Logger.warn "SYNC BROKE"
|
||||
{:ok, env}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.TakePhoto do
|
|||
allow_args []
|
||||
|
||||
def execute(_, _, env) do
|
||||
env = mutate_env(env)
|
||||
Farmbot.CeleryScript.AST.Node.ExecuteScript.execute(%{label: "take-photo"}, [], env)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,6 +5,7 @@ defmodule Farmbot.CeleryScript.AST.Node.TogglePin do
|
|||
allow_args [:pin_number]
|
||||
|
||||
def execute(%{pin_number: num}, _, env) do
|
||||
env = mutate_env(env)
|
||||
case Farmbot.Firmware.read_pin(num, :digital) do
|
||||
{:ok, 0} -> Node.WritePin.execute(%{pin_mode: :digital, pin_number: num, pin_value: 1}, [], env)
|
||||
{:ok, 1} -> Node.WritePin.execute(%{pin_mode: :digital, pin_number: num, pin_value: 0}, [], env)
|
||||
|
|
|
@ -2,4 +2,6 @@ defmodule Farmbot.CeleryScript.AST.Node.Tool do
|
|||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:tool_id]
|
||||
|
||||
return_self()
|
||||
end
|
||||
|
|
|
@ -2,4 +2,9 @@ defmodule Farmbot.CeleryScript.AST.Node.UpdateFarmware do
|
|||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:package]
|
||||
|
||||
def execute(%{package: args}, body, env) do
|
||||
env = mutate_env(env)
|
||||
Farmbot.CeleryScript.AST.Node.InstallFarmware.execute(args, body, env)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,4 +2,10 @@ defmodule Farmbot.CeleryScript.AST.Node.Wait do
|
|||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:milliseconds]
|
||||
|
||||
def execute(%{milliseconds: ms}, _, env) do
|
||||
env = mutate_env(env)
|
||||
Process.sleep(ms)
|
||||
{:ok, env}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule Farmbot.CeleryScript.AST.Node.WritePin do
|
|||
allow_args [:pin_number, :pin_value, :pin_mode]
|
||||
|
||||
def execute(%{pin_mode: mode, pin_value: value, pin_number: num}, [], env) do
|
||||
env = mutate_env(env)
|
||||
case Farmbot.Firmware.write_pin(num, mode, value) do
|
||||
:ok -> {:ok, env}
|
||||
{:error, reason} -> {:error, reason, env}
|
||||
|
|
|
@ -2,4 +2,29 @@ defmodule Farmbot.CeleryScript.AST.Node.Zero do
|
|||
@moduledoc false
|
||||
use Farmbot.CeleryScript.AST.Node
|
||||
allow_args [:axis]
|
||||
@default_speed 100
|
||||
|
||||
def execute(%{axis: :all}, _, env) do
|
||||
env = mutate_env(env)
|
||||
do_reduce([:z, :y, :x], env)
|
||||
end
|
||||
|
||||
def execute(%{axis: axis}, _, env) do
|
||||
env = mutate_env(env)
|
||||
case Farmbot.Firmware.zero(axis, @default_speed) do
|
||||
:ok -> {:ok, env}
|
||||
{:error, reason} -> {:error, reason, env}
|
||||
end
|
||||
end
|
||||
|
||||
defp do_reduce([axis | rest], env) do
|
||||
case execute(%{axis: axis}, [], env) do
|
||||
{:ok, new_env} -> do_reduce(rest, env)
|
||||
{:error, _, _} = err -> err
|
||||
end
|
||||
end
|
||||
|
||||
defp do_reduce([], env) do
|
||||
{:ok, env}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,8 +15,9 @@ defmodule Farmbot.CeleryScript do
|
|||
case kind.execute(args, body, env) do
|
||||
{:ok, %Macro.Env{} = _env} = res -> res
|
||||
{:ok, %AST{} = ast} -> execute(ast, env)
|
||||
{:error, reason, _env} when is_binary(reason) -> raise reason
|
||||
{:error, reason, _env} -> raise inspect(reason)
|
||||
{:error, reason, env} ->
|
||||
Logger.error "CS Failed: #{env.module} - #{inspect reason}"
|
||||
{:error, reason, env}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ defmodule Farmbot.Firmware do
|
|||
end
|
||||
|
||||
defp handle_gcode({:report_pin_mode, pin, mode_atom}, state) do
|
||||
Logger.debug "Got pin mode report: #{pin}: #{mode_atom}"
|
||||
# Logger.debug "Got pin mode report: #{pin}: #{mode_atom}"
|
||||
mode = if(mode_atom == :digital, do: 0, else: 1)
|
||||
case state.pins[pin] do
|
||||
%{mode: _, value: _} = pin_map ->
|
||||
|
@ -151,7 +151,7 @@ defmodule Farmbot.Firmware do
|
|||
end
|
||||
|
||||
defp handle_gcode({:report_pin_value, pin, value}, state) do
|
||||
Logger.debug "Got pin value report: #{pin}: #{value} old: #{inspect state.pins[pin]}"
|
||||
# Logger.debug "Got pin value report: #{pin}: #{value} old: #{inspect state.pins[pin]}"
|
||||
case state.pins[pin] do
|
||||
%{mode: _, value: _} = pin_map ->
|
||||
{:pins, %{pin => %{pin_map | value: value}}, %{state | pins: %{state.pins | pin => %{pin_map | value: value}}}}
|
||||
|
|
|
@ -263,7 +263,7 @@ defmodule Farmbot.Firmware.Gcode.Param do
|
|||
def parse_param(:pin_guard_5_time_out), do: 222
|
||||
def parse_param(:pin_guard_5_active_state), do: 223
|
||||
|
||||
def parse_param(param_string) when is_bitstring(param_string),
|
||||
def parse_param(param_string) when is_binary(param_string),
|
||||
do: param_string |> String.to_atom() |> parse_param
|
||||
|
||||
def parse_param(_), do: nil
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
defmodule Farmbot.Log.Meta do
|
||||
defstruct [:x, :y, :z]
|
||||
defstruct [:x, :y, :z, :type]
|
||||
end
|
||||
|
||||
defmodule Farmbot.Log do
|
||||
@moduledoc "Farmbot Log Object."
|
||||
alias Farmbot.Log.Meta
|
||||
|
||||
defstruct meta: %Meta{x: -1, y: -1, z: -1},
|
||||
defstruct meta: %Meta{x: -1, y: -1, z: -1, type: :info},
|
||||
message: nil,
|
||||
created_at: nil,
|
||||
channels: []
|
||||
|
||||
def new(message, created_at, channels, type) do
|
||||
meta = struct(Meta, [type: type])
|
||||
struct(__MODULE__, [message: message, created_at: created_at, channels: channels, meta: meta])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
defmodule Farmbot.Logger do
|
||||
@moduledoc "Logger."
|
||||
use GenStage
|
||||
alias Farmbot.Log
|
||||
|
||||
@doc false
|
||||
def start_link() do
|
||||
|
@ -10,40 +9,19 @@ defmodule Farmbot.Logger do
|
|||
|
||||
def init([]) do
|
||||
Logger.add_backend(Logger.Backends.Farmbot, [])
|
||||
|
||||
{
|
||||
:producer_consumer,
|
||||
%{meta: %Log.Meta{x: -1, y: -1, z: -1}},
|
||||
subscribe_to: [Farmbot.Firmware],
|
||||
dispatcher: GenStage.BroadcastDispatcher
|
||||
}
|
||||
{:producer,%{}, dispatcher: GenStage.BroadcastDispatcher}
|
||||
end
|
||||
|
||||
def handle_demand(_, state) do
|
||||
{:noreply, [], state}
|
||||
end
|
||||
|
||||
def handle_events(gcodes, _from, state) do
|
||||
case find_position_report(gcodes) do
|
||||
{x, y, z} ->
|
||||
{:noreply, [], %{state | meta: %{state.meta | x: x, y: y, z: z}}}
|
||||
|
||||
nil ->
|
||||
{:noreply, [], state}
|
||||
end
|
||||
end
|
||||
|
||||
defp find_position_report(gcodes) do
|
||||
Enum.find_value(gcodes, fn code ->
|
||||
case code do
|
||||
{:report_current_position, x, y, z} -> {x, y, z}
|
||||
_ -> false
|
||||
end
|
||||
end)
|
||||
def handle_events(_, _from, state) do
|
||||
{:noreply, [], state}
|
||||
end
|
||||
|
||||
def handle_info({:log, log}, state) do
|
||||
{:noreply, [%{log | meta: state.meta}], state}
|
||||
{:noreply, [log], state}
|
||||
end
|
||||
|
||||
def terminate(_, _state) do
|
||||
|
|
|
@ -52,6 +52,7 @@ defmodule Farmbot.System.ConfigStorage do
|
|||
|> apply(:"get_#{type}_value", [group_name, key_name])
|
||||
|> Ecto.Changeset.change(value: value)
|
||||
|> update!()
|
||||
|> Farmbot.System.ConfigStorage.Dispatcher.dispatch(key_name)
|
||||
end
|
||||
|
||||
def update_config_value(type, _, _, _) do
|
||||
|
|
31
lib/farmbot/system/config_storage/dispatcher.ex
Normal file
31
lib/farmbot/system/config_storage/dispatcher.ex
Normal file
|
@ -0,0 +1,31 @@
|
|||
defmodule Farmbot.System.ConfigStorage.Dispatcher do
|
||||
@moduledoc "Handles dispatching config changes."
|
||||
|
||||
use GenStage
|
||||
|
||||
def dispatch(%{value: value}, group, key) do
|
||||
GenStage.call(__MODULE__, {:dispatch, group, key, value})
|
||||
end
|
||||
|
||||
def start_link do
|
||||
GenStage.start_link(__MODULE__, [], [name: __MODULE__])
|
||||
end
|
||||
|
||||
def init([]) do
|
||||
{
|
||||
:producer, [], [dispatcher: GenStage.BroadcastDispatcher]
|
||||
}
|
||||
end
|
||||
|
||||
def handle_events(_, _, state) do
|
||||
{:noreply, [], state}
|
||||
end
|
||||
|
||||
def handle_demand(_, state) do
|
||||
{:noreply, [], state}
|
||||
end
|
||||
|
||||
def handle_call({:dispatch, group, key, val}, _, state) do
|
||||
{:reply, :ok, [{:config, group, key, val}], state}
|
||||
end
|
||||
end
|
|
@ -14,7 +14,8 @@ defmodule Farmbot.System.Supervisor do
|
|||
children = [
|
||||
worker(Farmbot.System.Init.FSCheckup, [[], []]),
|
||||
supervisor(Farmbot.System.Init.Ecto, [[], []]),
|
||||
supervisor(Farmbot.System.ConfigStorage, [])
|
||||
supervisor(Farmbot.System.ConfigStorage, []),
|
||||
worker(Farmbot.System.ConfigStorage.Dispatcher, [])
|
||||
]
|
||||
|
||||
init_mods =
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
defmodule Logger.Backends.Farmbot do
|
||||
@moduledoc "Farmbot Loggerr Backend."
|
||||
alias Farmbot.Log
|
||||
@blacklist [__MODULE__,
|
||||
Farmbot.BotState.Transport.GenMQTT.Client]
|
||||
|
||||
def init(_opts) do
|
||||
{:ok, %{}}
|
||||
|
@ -10,42 +12,13 @@ defmodule Logger.Backends.Farmbot do
|
|||
{:ok, state}
|
||||
end
|
||||
|
||||
def handle_event(
|
||||
{
|
||||
level,
|
||||
_gl,
|
||||
{Logger, message, {{year, month, day}, {hour, minute, second, _millisecond}}, metadata}
|
||||
},
|
||||
state
|
||||
) do
|
||||
mod_split = (metadata[:module] || Logger) |> Module.split()
|
||||
|
||||
case mod_split do
|
||||
["Farmbot" | _] ->
|
||||
t =
|
||||
%DateTime{
|
||||
year: year,
|
||||
month: month,
|
||||
day: day,
|
||||
hour: hour,
|
||||
minute: minute,
|
||||
calendar: Calendar.ISO,
|
||||
microsecond: {0, 0},
|
||||
second: second,
|
||||
std_offset: 0,
|
||||
time_zone: "Etc/UTC",
|
||||
utc_offset: 0,
|
||||
zone_abbr: "UTC"
|
||||
}
|
||||
|> DateTime.to_unix()
|
||||
|
||||
l = %Log{message: message, channels: [level], created_at: t}
|
||||
GenStage.async_info(Farmbot.Logger, {:log, l})
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
def handle_event({level, _gl, {Logger, _msg, _, metadata} = log}, state) do
|
||||
module = (metadata[:module] || Logger)
|
||||
if module in @blacklist do
|
||||
:ok
|
||||
else
|
||||
do_log(Module.split(module), level, log)
|
||||
end
|
||||
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
|
@ -56,4 +29,39 @@ defmodule Logger.Backends.Farmbot do
|
|||
def handle_info(_, state) do
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
defp do_log(["Farmbot" | _], level, {_, unformated_message, timestamp, meta}) do
|
||||
{{year, month, day}, {hour, minute, second, _millisecond}} = timestamp
|
||||
message = format_message(unformated_message)
|
||||
t =
|
||||
%DateTime{
|
||||
year: year,
|
||||
month: month,
|
||||
day: day,
|
||||
hour: hour,
|
||||
minute: minute,
|
||||
calendar: Calendar.ISO,
|
||||
microsecond: {0, 0},
|
||||
second: second,
|
||||
std_offset: 0,
|
||||
time_zone: "Etc/UTC",
|
||||
utc_offset: 0,
|
||||
zone_abbr: "UTC"
|
||||
}
|
||||
|> DateTime.to_unix()
|
||||
l = Log.new(message, t, meta[:channels] || [:ticker], meta[:message_type] || level)
|
||||
GenStage.async_info(Farmbot.Logger, {:log, l})
|
||||
end
|
||||
|
||||
defp do_log(_, _level, _msg), do: :ok
|
||||
|
||||
defp format_message(msg) when is_binary(msg) or is_atom(msg) do
|
||||
msg
|
||||
end
|
||||
|
||||
defp format_message(msg) do
|
||||
msg |> to_string
|
||||
rescue
|
||||
_ -> inspect msg
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ defmodule Farmbot.System.ConfigStorage.Migrations.SeedGroups do
|
|||
alias ConfigStorage.{Config, Group, StringValue, BoolValue, FloatValue}
|
||||
import Ecto.Query, only: [from: 2]
|
||||
|
||||
@group_names ["authorization", "hardware", "hardware_params", "settings", "user_env"]
|
||||
@group_names ["authorization", "hardware_params", "settings", "user_env"]
|
||||
|
||||
def change do
|
||||
populate_config_groups()
|
||||
|
@ -36,19 +36,16 @@ defmodule Farmbot.System.ConfigStorage.Migrations.SeedGroups do
|
|||
create_value(StringValue, nil) |> create_config(group_id, "last_shutdown_reason")
|
||||
end
|
||||
|
||||
defp populate_config_values("hardware", group_id) do
|
||||
create_value(StringValue, nil) |> create_config(group_id, "firmware_hardware")
|
||||
end
|
||||
|
||||
defp populate_config_values("hardware_params", group_id) do
|
||||
end
|
||||
|
||||
defp populate_config_values("settings", group_id) do
|
||||
create_value(BoolValue, false) |> create_config(group_id, "os_auto_update")
|
||||
create_value(BoolValue, true) |> create_config(group_id, "first_boot")
|
||||
create_value(BoolValue, true) |> create_config(group_id, "first_party_farmware")
|
||||
create_value(BoolValue, false) |> create_config(group_id, "os_auto_update")
|
||||
create_value(BoolValue, true) |> create_config(group_id, "first_boot")
|
||||
create_value(BoolValue, true) |> create_config(group_id, "first_party_farmware")
|
||||
create_value(BoolValue, false) |> create_config(group_id, "auto_sync")
|
||||
create_value(StringValue, nil) |> create_config(group_id, "timezone")
|
||||
create_value(StringValue, nil) |> create_config(group_id, "firmware_hardware")
|
||||
create_value(StringValue, nil) |> create_config(group_id, "timezone")
|
||||
fpf_url = Application.get_env(:farmbot, :farmware)[:first_part_farmware_manifest_url]
|
||||
create_value(StringValue, fpf_url) |> create_config(group_id, "first_party_farmware_url")
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue