Use api for fw storage.
parent
a03a8ca8f7
commit
45a7ce57c4
|
@ -1,42 +1,114 @@
|
|||
defmodule Farmbot.Bootstrap.SettingsSync do
|
||||
@moduledoc "Handles uploading and downloading of FBOS configs."
|
||||
use Task, restart: :transient
|
||||
use Farmbot.Logger
|
||||
import Farmbot.System.ConfigStorage, only: [get_config_value: 3, update_config_value: 4, get_config_as_map: 0]
|
||||
|
||||
def start_link() do
|
||||
Task.start_link(__MODULE__, :run, [])
|
||||
end
|
||||
@fbos_keys [
|
||||
"auto_sync",
|
||||
"beta_opt_in",
|
||||
"disable_factory_reset",
|
||||
"firmware_output_log",
|
||||
"firmware_input_log",
|
||||
"sequence_body_log",
|
||||
"sequence_complete_log",
|
||||
"sequence_init_log",
|
||||
"arduino_debug_messages",
|
||||
"os_auto_update",
|
||||
"firmware_hardware",
|
||||
"network_not_found_timer"
|
||||
]
|
||||
|
||||
def run() do
|
||||
with {:ok, %{body: body, status_code: 200}} <- Farmbot.HTTP.get("/api/fbos_config"),
|
||||
{:ok, data} <- Poison.decode(body)
|
||||
do
|
||||
do_sync_settings(data)
|
||||
else
|
||||
{:ok, status_code: code} ->
|
||||
Logger.error 1, "HTTP error syncing settings: #{code}"
|
||||
:ok
|
||||
err ->
|
||||
Logger.error 1, "Error syncing settings: #{inspect err}"
|
||||
:ok
|
||||
end
|
||||
rescue
|
||||
err ->
|
||||
Logger.error 1, "Error syncing settings: #{Exception.message(err)} #{inspect System.stacktrace()}"
|
||||
end
|
||||
|
||||
def apply_map(old_map, new_map) do
|
||||
old_map = take_valid(old_map)
|
||||
new_map = take_valid(new_map)
|
||||
Map.new(new_map, fn({key, new_value}) ->
|
||||
# Logger.debug 1, "Applying #{key} #{inspect old_map[key]} over #{inspect new_value}"
|
||||
if old_map[key] != new_value do
|
||||
apply_to_config_storage key, new_value
|
||||
end
|
||||
{key, new_value}
|
||||
end)
|
||||
end
|
||||
@firmware_keys [
|
||||
"param_version",
|
||||
"param_test",
|
||||
"param_config_ok",
|
||||
"param_use_eeprom",
|
||||
"param_e_stop_on_mov_err",
|
||||
"param_mov_nr_retry",
|
||||
"movement_timeout_x",
|
||||
"movement_timeout_y",
|
||||
"movement_timeout_z",
|
||||
"movement_keep_active_x",
|
||||
"movement_keep_active_y",
|
||||
"movement_keep_active_z",
|
||||
"movement_home_at_boot_x",
|
||||
"movement_home_at_boot_y",
|
||||
"movement_home_at_boot_z",
|
||||
"movement_invert_endpoints_x",
|
||||
"movement_invert_endpoints_y",
|
||||
"movement_invert_endpoints_z",
|
||||
"movement_enable_endpoints_x",
|
||||
"movement_enable_endpoints_y",
|
||||
"movement_enable_endpoints_z",
|
||||
"movement_invert_motor_x",
|
||||
"movement_invert_motor_y",
|
||||
"movement_invert_motor_z",
|
||||
"movement_secondary_motor_x",
|
||||
"movement_secondary_motor_invert_x",
|
||||
"movement_steps_acc_dec_x",
|
||||
"movement_steps_acc_dec_y",
|
||||
"movement_steps_acc_dec_z",
|
||||
"movement_stop_at_home_x",
|
||||
"movement_stop_at_home_y",
|
||||
"movement_stop_at_home_z",
|
||||
"movement_home_up_x",
|
||||
"movement_home_up_y",
|
||||
"movement_home_up_z",
|
||||
"movement_step_per_mm_x",
|
||||
"movement_step_per_mm_y",
|
||||
"movement_step_per_mm_z",
|
||||
"movement_min_spd_x",
|
||||
"movement_min_spd_y",
|
||||
"movement_min_spd_z",
|
||||
"movement_home_spd_x",
|
||||
"movement_home_spd_y",
|
||||
"movement_home_spd_z",
|
||||
"movement_max_spd_x",
|
||||
"movement_max_spd_y",
|
||||
"movement_max_spd_z",
|
||||
"encoder_enabled_x",
|
||||
"encoder_enabled_y",
|
||||
"encoder_enabled_z",
|
||||
"encoder_type_x",
|
||||
"encoder_type_y",
|
||||
"encoder_type_z",
|
||||
"encoder_missed_steps_max_x",
|
||||
"encoder_missed_steps_max_y",
|
||||
"encoder_missed_steps_max_z",
|
||||
"encoder_scaling_x",
|
||||
"encoder_scaling_y",
|
||||
"encoder_scaling_z",
|
||||
"encoder_missed_steps_decay_x",
|
||||
"encoder_missed_steps_decay_y",
|
||||
"encoder_missed_steps_decay_z",
|
||||
"encoder_use_for_pos_x",
|
||||
"encoder_use_for_pos_y",
|
||||
"encoder_use_for_pos_z",
|
||||
"encoder_invert_x",
|
||||
"encoder_invert_y",
|
||||
"encoder_invert_z",
|
||||
"movement_axis_nr_steps_x",
|
||||
"movement_axis_nr_steps_y",
|
||||
"movement_axis_nr_steps_z",
|
||||
"movement_stop_at_max_x",
|
||||
"movement_stop_at_max_y",
|
||||
"movement_stop_at_max_z",
|
||||
"pin_guard_1_pin_nr",
|
||||
"pin_guard_1_time_out",
|
||||
"pin_guard_1_active_state",
|
||||
"pin_guard_2_pin_nr",
|
||||
"pin_guard_2_time_out",
|
||||
"pin_guard_2_active_state",
|
||||
"pin_guard_3_pin_nr",
|
||||
"pin_guard_3_time_out",
|
||||
"pin_guard_3_active_state",
|
||||
"pin_guard_4_pin_nr",
|
||||
"pin_guard_4_time_out",
|
||||
"pin_guard_4_active_state",
|
||||
"pin_guard_5_pin_nr",
|
||||
"pin_guard_5_time_out",
|
||||
"pin_guard_5_active_state",
|
||||
]
|
||||
|
||||
# TODO: This should be moved to ConfigStorage module maybe?
|
||||
@bool_keys [
|
||||
|
@ -56,10 +128,50 @@ defmodule Farmbot.Bootstrap.SettingsSync do
|
|||
"firmware_hardware"
|
||||
]
|
||||
|
||||
@float_keys [
|
||||
@float_keys @firmware_keys ++ [
|
||||
"network_not_found_timer"
|
||||
]
|
||||
|
||||
@doc false
|
||||
def start_link() do
|
||||
run()
|
||||
:ignore
|
||||
end
|
||||
|
||||
@doc false
|
||||
def run() do
|
||||
do_sync_fbos_configs()
|
||||
do_sync_fw_configs()
|
||||
rescue
|
||||
err ->
|
||||
message = Exception.message(err)
|
||||
err_msg = "#{} #{inspect System.stacktrace()}"
|
||||
Logger.error 1, "Error syncing settings: #{err_msg}"
|
||||
{:error, message}
|
||||
end
|
||||
|
||||
def apply_fbos_map(old_map, new_map) do
|
||||
old_map = take_valid_fbos(old_map)
|
||||
new_map = take_valid_fbos(new_map)
|
||||
Map.new(new_map, fn({key, new_value}) ->
|
||||
if old_map[key] != new_value do
|
||||
apply_to_config_storage key, new_value
|
||||
end
|
||||
{key, new_value}
|
||||
end)
|
||||
end
|
||||
|
||||
def apply_fw_map(old_map, new_map) do
|
||||
old_map = take_valid_fw(old_map)
|
||||
new_map = take_valid_fw(new_map)
|
||||
Map.new(new_map, fn({key, new_value}) ->
|
||||
if old_map[key] != new_value do
|
||||
apply_to_config_storage key, new_value
|
||||
end
|
||||
{key, new_value}
|
||||
end)
|
||||
end
|
||||
|
||||
defp apply_to_config_storage(key, val)
|
||||
when key in @bool_keys and (is_nil(val) or is_boolean(val)) do
|
||||
Logger.success 2, "Updating: #{key} => #{inspect val}"
|
||||
|
@ -72,6 +184,16 @@ defmodule Farmbot.Bootstrap.SettingsSync do
|
|||
update_config_value(:string, "settings", key, val)
|
||||
end
|
||||
|
||||
defp apply_to_config_storage(key, val)
|
||||
when key in @firmware_keys and is_number(val) do
|
||||
Logger.success 2, "Updating: #{key} => #{inspect val}"
|
||||
if val do
|
||||
update_config_value(:float, "hardware_params", key, val / 1)
|
||||
else
|
||||
update_config_value(:float, "hardware_params", key, val)
|
||||
end
|
||||
end
|
||||
|
||||
defp apply_to_config_storage(key, val)
|
||||
when key in @float_keys and (is_nil(val) or is_number(val)) do
|
||||
Logger.success 2, "Updating: #{key} => #{inspect val}"
|
||||
|
@ -84,17 +206,67 @@ defmodule Farmbot.Bootstrap.SettingsSync do
|
|||
|
||||
defp apply_to_config_storage(key, val) do
|
||||
Logger.error 1, "Unknown pair: #{key} => #{inspect val}"
|
||||
{:error, {:unknown_pair, {key, val}}}
|
||||
end
|
||||
|
||||
def do_sync_settings(%{"api_migrated" => true} = api_data) do
|
||||
Logger.info 3, "API is the source of truth; Downloading data."
|
||||
old_config = get_config_as_map()["settings"]
|
||||
apply_map(old_config, api_data)
|
||||
@doc "Sync the settings related to the Firmware."
|
||||
def do_sync_fw_configs do
|
||||
with {:ok, %{body: body, status_code: 200}} <- Farmbot.HTTP.get("/api/firmware_config"),
|
||||
{:ok, data} <- Poison.decode(body)
|
||||
do
|
||||
do_sync_fw_configs(data)
|
||||
else
|
||||
{:ok, status_code: code} ->
|
||||
Logger.error 1, "HTTP error syncing settings: #{code}"
|
||||
:ok
|
||||
err ->
|
||||
Logger.error 1, "Error syncing settings: #{inspect err}"
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def do_sync_fw_configs(%{"api_migrated" => true} = api_data) do
|
||||
Logger.info 3, "API is the source of truth for Firmware configs. Downloading data."
|
||||
old_config = get_config_as_map()["hardware_params"]
|
||||
apply_fw_map(old_config, api_data)
|
||||
:ok
|
||||
end
|
||||
|
||||
def do_sync_settings(_unimportant_data) do
|
||||
Logger.info 3, "FBOS is the source of truth; Uploading data."
|
||||
# %{"api_migrated" => false}
|
||||
def do_sync_fw_configs(_) do
|
||||
Logger.info 3, "FBOS is the source of truth for Firmware configs. Uploading data."
|
||||
current = get_config_as_map()["hardware_params"]
|
||||
payload = Map.put(current, "api_migrated", true) |> Poison.encode!()
|
||||
Farmbot.HTTP.delete!("/api/firmware_config")
|
||||
Farmbot.HTTP.put!("/api/firmware_config", payload)
|
||||
:ok
|
||||
end
|
||||
|
||||
@doc "Sync the settings related to FBOS"
|
||||
def do_sync_fbos_configs do
|
||||
with {:ok, %{body: body, status_code: 200}} <- Farmbot.HTTP.get("/api/fbos_config"),
|
||||
{:ok, data} <- Poison.decode(body)
|
||||
do
|
||||
do_sync_fbos_configs(data)
|
||||
else
|
||||
{:ok, status_code: code} ->
|
||||
Logger.error 1, "HTTP error syncing settings: #{code}"
|
||||
:ok
|
||||
err ->
|
||||
Logger.error 1, "Error syncing settings: #{inspect err}"
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def do_sync_fbos_configs(%{"api_migrated" => true} = api_data) do
|
||||
Logger.info 3, "API is the source of truth for FBOS configs. Downloading data."
|
||||
old_config = get_config_as_map()["settings"]
|
||||
apply_fbos_map(old_config, api_data)
|
||||
:ok
|
||||
end
|
||||
|
||||
def do_sync_fbos_configs(_unimportant_data) do
|
||||
Logger.info 3, "FBOS is the source of truth for FBOS configs. Uploading data."
|
||||
auto_sync = get_config_value(:bool, "settings", "auto_sync")
|
||||
beta_opt_in = get_config_value(:bool, "settings", "beta_opt_in")
|
||||
disable_factory_reset = get_config_value(:bool, "settings", "disable_factory_reset")
|
||||
|
@ -127,21 +299,11 @@ defmodule Farmbot.Bootstrap.SettingsSync do
|
|||
:ok
|
||||
end
|
||||
|
||||
@keys [
|
||||
"auto_sync",
|
||||
"beta_opt_in",
|
||||
"disable_factory_reset",
|
||||
"firmware_output_log",
|
||||
"firmware_input_log",
|
||||
"sequence_body_log",
|
||||
"sequence_complete_log",
|
||||
"sequence_init_log",
|
||||
"arduino_debug_messages",
|
||||
"os_auto_update",
|
||||
"firmware_hardware",
|
||||
"network_not_found_timer"
|
||||
]
|
||||
def take_valid(map) do
|
||||
Map.take(map, @keys ++ Enum.map(@keys, &String.to_atom(&1)))
|
||||
def take_valid_fbos(map) do
|
||||
Map.take(map, @fbos_keys ++ Enum.map(@fbos_keys, &String.to_atom(&1)))
|
||||
end
|
||||
|
||||
def take_valid_fw(map) do
|
||||
Map.take(map, @firmware_keys ++ Enum.map(@firmware_keys, &String.to_atom(&1)))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -126,7 +126,7 @@ defmodule Farmbot.Bootstrap.Supervisor do
|
|||
children = [
|
||||
worker(Farmbot.Bootstrap.AuthTask, []),
|
||||
supervisor(Farmbot.HTTP.Supervisor, []),
|
||||
worker(Farmbot.Bootstrap.SettingsSync, [], [restart: :transient]),
|
||||
worker(Farmbot.Bootstrap.SettingsSync, []),
|
||||
supervisor(Farmbot.Firmware.Supervisor, []),
|
||||
supervisor(Farmbot.BotState.Supervisor, []),
|
||||
supervisor(Farmbot.BotState.Transport.Supervisor, []),
|
||||
|
|
|
@ -178,8 +178,8 @@ defmodule Farmbot.BotState.Transport.AMQP do
|
|||
["bot", ^device, "sync", resource, _]
|
||||
when resource in ["Log", "User", "Image", "WebcamFeed"] ->
|
||||
{:noreply, [], state}
|
||||
["bot", ^device, "sync", "FbosConfig", id] ->
|
||||
handle_fbos_config(id, payload, state)
|
||||
["bot", ^device, "sync", "FbosConfig", id] -> handle_fbos_config(id, payload, state)
|
||||
["bot", ^device, "sync", "FirmwareConfig", id] -> handle_fw_config(id, payload, state)
|
||||
["bot", ^device, "sync", resource, id] ->
|
||||
handle_sync_cmd(resource, id, payload, state)
|
||||
["bot", ^device, "logs"] -> {:noreply, [], state}
|
||||
|
@ -240,12 +240,26 @@ defmodule Farmbot.BotState.Transport.AMQP do
|
|||
{:ok, %{"body" => config}} ->
|
||||
# Logger.info 1, "Got fbos config from amqp: #{inspect config}"
|
||||
old = state.state_cache.configuration
|
||||
updated = Farmbot.Bootstrap.SettingsSync.apply_map(old, config)
|
||||
updated = Farmbot.Bootstrap.SettingsSync.apply_fbos_map(old, config)
|
||||
push_bot_state(state.chan, state.bot, %{state.state_cache | configuration: updated})
|
||||
{:noreply, [], state}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_fw_config(_id, payload, state) do
|
||||
case Poison.decode(payload) do
|
||||
{:ok, %{"body" => nil}} -> {:noreply, [], state}
|
||||
{:ok, %{"body" => config}} ->
|
||||
old = state.state_cache.mcu_params
|
||||
updated = Farmbot.Bootstrap.SettingsSync.apply_fw_map(old, config)
|
||||
for {key, val} <- updated do
|
||||
Farmbot.Firmware.update_param(key, val)
|
||||
end
|
||||
push_bot_state(state.chan, state.bot, %{state.state_cache | mcu_params: updated})
|
||||
{:noreply, [], state}
|
||||
end
|
||||
end
|
||||
|
||||
defp push_bot_log(chan, bot, log) do
|
||||
json = Poison.encode!(log)
|
||||
:ok = AMQP.Basic.publish chan, @exchange, "bot.#{bot}.logs", json
|
||||
|
|
|
@ -131,6 +131,7 @@ defmodule Farmbot.Firmware do
|
|||
|
||||
case handler_mod.start_link() do
|
||||
{:ok, handler} ->
|
||||
# Farmbot.System.Registry.subscribe(self())
|
||||
Process.flag(:trap_exit, true)
|
||||
{
|
||||
:producer_consumer,
|
||||
|
@ -161,6 +162,25 @@ defmodule Farmbot.Firmware do
|
|||
end
|
||||
end
|
||||
|
||||
# def handle_info({Farmbot.System.Registry, {:config_storage, {"hardware_params", key, val}}}, state) do
|
||||
# Logger.debug 3, "Applying firmware config: #{key} => #{val} from registry."
|
||||
# cond do
|
||||
# state.params[key] == val ->
|
||||
# Logger.debug 3, "Values the same not applying."
|
||||
# {:noreply, [], state}
|
||||
# is_number(val) ->
|
||||
# spawn __MODULE__, :update_param, [key, val]
|
||||
# {:noreply, [], state}
|
||||
# is_nil(val) ->
|
||||
# Logger.warn 3, "Not applying firmware config: #{key} because the value is nil."
|
||||
# {:noreply, [], state}
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# def handle_info({Farmbot.System.Registry, _}, state) do
|
||||
# {:noreply, [], state}
|
||||
# end
|
||||
|
||||
def handle_info({:EXIT, _pid, :normal}, state) do
|
||||
{:stop, :normal, state}
|
||||
end
|
||||
|
|
|
@ -207,7 +207,8 @@ defmodule Farmbot.Firmware.StubHandler do
|
|||
end
|
||||
|
||||
def handle_call(:read_all_params, _from, state) do
|
||||
{:reply, :ok, [:report_params_complete, :done], state}
|
||||
response = build_resp [:report_params_complete, :done]
|
||||
{:reply, build_reply(:ok), response, state}
|
||||
end
|
||||
|
||||
def handle_call(:emergency_lock, _from, state) do
|
||||
|
|
|
@ -4,13 +4,13 @@ defmodule Farmbot.Bootstrap.SettingsSyncTest do
|
|||
import Farmbot.System.ConfigStorage, only: [update_config_value: 4, get_config_value: 3]
|
||||
|
||||
test "Applies new configs in the form of a map." do
|
||||
SettingsSync.apply_map(%{"firmware_output_log" => true}, %{"firmware_output_log" => false})
|
||||
SettingsSync.apply_fbos_map(%{"firmware_output_log" => true}, %{"firmware_output_log" => false})
|
||||
refute get_config_value(:bool, "settings", "firmware_output_log")
|
||||
|
||||
SettingsSync.apply_map(%{"firmware_hardware" => "arduino"}, %{"firmware_hardware" => "farmduino"})
|
||||
SettingsSync.apply_fbos_map(%{"firmware_hardware" => "arduino"}, %{"firmware_hardware" => "farmduino"})
|
||||
assert get_config_value(:string, "settings", "firmware_hardware") == "farmduino"
|
||||
|
||||
SettingsSync.apply_map(%{"network_not_found_timer" => nil}, %{"network_not_found_timer" => 100})
|
||||
SettingsSync.apply_fbos_map(%{"network_not_found_timer" => nil}, %{"network_not_found_timer" => 100})
|
||||
assert get_config_value(:float, "settings", "network_not_found_timer") == 100.0
|
||||
end
|
||||
|
||||
|
@ -22,8 +22,8 @@ defmodule Farmbot.Bootstrap.SettingsSyncTest do
|
|||
"some_random_string" => "hello world",
|
||||
"some_random_bool" => false
|
||||
}
|
||||
SettingsSync.apply_map(bad_map, %{})
|
||||
SettingsSync.apply_map(%{}, bad_map)
|
||||
SettingsSync.apply_fbos_map(bad_map, %{})
|
||||
SettingsSync.apply_fbos_map(%{}, bad_map)
|
||||
refute_receive {Farmbot.System.Registry, {:config_storage, {"settings", "some_random_float", _}}}
|
||||
refute_receive {Farmbot.System.Registry, {:config_storage, {"settings", "some_random_string", _}}}
|
||||
refute_receive {Farmbot.System.Registry, {:config_storage, {"settings", "some_random_bool", _}}}
|
||||
|
@ -38,7 +38,7 @@ defmodule Farmbot.Bootstrap.SettingsSyncTest do
|
|||
assert_receive {Farmbot.System.Registry, {:config_storage, {"settings", "os_auto_update", false}}}
|
||||
|
||||
%{status_code: 200} = Farmbot.HTTP.put!("/api/fbos_config", config_bin)
|
||||
Farmbot.Bootstrap.SettingsSync.run()
|
||||
Farmbot.Bootstrap.SettingsSync.do_sync_fbos_configs()
|
||||
assert_receive {Farmbot.System.Registry, {:config_storage, {"settings", "os_auto_update", true}}}, 2000
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue