Fix More CeleryScript

* Add diapatcher for config updates.
* Add env updater for each cs_node.
* Fix logging.
This commit is contained in:
connor rigby 2017-11-06 09:46:24 -08:00
parent fceef7ee74
commit 3836336f90
59 changed files with 294 additions and 100 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +0,0 @@
defmodule Farmbot.CeleryScript.AST.Node.DataUpdate do
@moduledoc false
use Farmbot.CeleryScript.AST.Node
allow_args [:value]
end

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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

View file

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

View file

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

View file

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