moving some stuff aroun
parent
a5934a1f71
commit
6b2eb071b9
|
@ -8,7 +8,6 @@ config :uart,
|
|||
|
||||
config :fb,
|
||||
state_path: "/state",
|
||||
db_path: "/db",
|
||||
dnsmasq_path: "/root/dnsmasq.lease"
|
||||
|
||||
config :json_rpc,
|
||||
|
|
|
@ -69,7 +69,7 @@ defmodule BotState do
|
|||
throttled
|
||||
end
|
||||
|
||||
def load(%{target: target, compat_version: compat_version}) do
|
||||
def load(%{target: target, compat_version: compat_version, env: env, version: version}) do
|
||||
token = case FarmbotAuth.get_token() do
|
||||
{:ok, token} -> token
|
||||
_ -> nil
|
||||
|
@ -82,11 +82,12 @@ defmodule BotState do
|
|||
steps_per_mm: 500
|
||||
},
|
||||
informational_settings: %{
|
||||
controller_version: Fw.version,
|
||||
controller_version: version,
|
||||
private_ip: nil,
|
||||
throttled: get_throttled,
|
||||
target: target,
|
||||
compat_version: compat_version
|
||||
compat_version: compat_version,
|
||||
environment: env
|
||||
},
|
||||
authorization: %{
|
||||
token: token,
|
||||
|
@ -193,6 +194,12 @@ defmodule BotState do
|
|||
{:reply, maybe_index, state}
|
||||
end
|
||||
|
||||
def handle_call(:get_version, _from, state) do
|
||||
{:reply,
|
||||
BotState.get_status.informational_settings.controller_version,
|
||||
state}
|
||||
end
|
||||
|
||||
# Lock the frontend from doing stuff
|
||||
def handle_cast({:add_lock, string}, state) do
|
||||
maybe_index = Enum.find_index(state.locks, fn(%{reason: str}) -> str == string end)
|
||||
|
@ -295,11 +302,11 @@ defmodule BotState do
|
|||
Logger.debug(msg)
|
||||
spawn fn -> RPC.MessageHandler.log(msg, [], ["BotUpdates"]) end
|
||||
if(state.configuration.os_auto_update == true) do
|
||||
spawn fn -> Fw.check_and_download_os_update end
|
||||
spawn fn -> Downloader.check_and_download_os_update end
|
||||
end
|
||||
|
||||
if(state.configuration.fw_auto_update == true) do
|
||||
spawn fn -> Fw.check_and_download_fw_update end
|
||||
spawn fn -> Downloader.check_and_download_fw_update end
|
||||
end
|
||||
check_updates
|
||||
{:noreply, state}
|
||||
|
@ -322,6 +329,10 @@ defmodule BotState do
|
|||
GenServer.call(__MODULE__, :get_token)
|
||||
end
|
||||
|
||||
def get_version do
|
||||
GenServer.call(__MODULE__, :get_version)
|
||||
end
|
||||
|
||||
@spec get_lock(String.t) :: integer | nil
|
||||
def get_lock(string) when is_bitstring(string) do
|
||||
GenServer.call(__MODULE__, {:get_lock, string})
|
||||
|
|
|
@ -4,11 +4,18 @@ defmodule Controller do
|
|||
|
||||
def init(_args) do
|
||||
children = [
|
||||
# these handle communications between the frontend and bot.
|
||||
supervisor(Mqtt.Supervisor, [[]], restart: :permanent ),
|
||||
supervisor(RPC.Supervisor, [[]], restart: :permanent ),
|
||||
|
||||
# handles communications between bot and arduino
|
||||
supervisor(Serial.Supervisor, [[]], restart: :permanent ),
|
||||
|
||||
# Handle communications betwen bot and api
|
||||
worker(BotSync, [[]], restart: :permanent ),
|
||||
worker(Farmbot.Scheduler, [[]], restart: :permanent)
|
||||
|
||||
# Just handles Farmbot scheduler stuff.
|
||||
worker(Farmbot.Scheduler, [[]], restart: :permanent )
|
||||
]
|
||||
opts = [strategy: :one_for_one, name: Controller.Supervisor]
|
||||
supervise(children, opts)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
defmodule Downloader do
|
||||
@log_tag "BotUpdates"
|
||||
require Logger
|
||||
def download_and_install_os_update(url) do
|
||||
RPC.MessageHandler.log("Downloading OS update!", [:warning_toast], [@log_tag])
|
||||
File.rm("/tmp/update.fw")
|
||||
|
@ -51,4 +52,90 @@ defmodule Downloader do
|
|||
number = bytes / 1_048_576 |> Float.round(2)
|
||||
"#{number} MB"
|
||||
end
|
||||
|
||||
@doc """
|
||||
Looks for the latest asset of given extension (ie: ".exe")
|
||||
on a Github Release API.
|
||||
Returns {:update, url_to_latest_download} or :no_updates
|
||||
TODO: Rewrite this using 'with'
|
||||
"""
|
||||
def check_updates(url, extension) when is_bitstring(extension) do
|
||||
Logger.debug(url)
|
||||
resp = HTTPotion.get url,
|
||||
[headers: ["User-Agent": "Farmbot"]]
|
||||
current_version = BotState.get_version
|
||||
case resp do
|
||||
%HTTPotion.ErrorResponse{message: error} ->
|
||||
RPC.MessageHandler.log("Update check failed: #{inspect error}", [:error_toast], ["BotUpdates"])
|
||||
{:error, "Check Updates failed", error}
|
||||
%HTTPotion.Response{body: body,
|
||||
headers: _headers,
|
||||
status_code: 200} ->
|
||||
json = Poison.decode!(body)
|
||||
"v"<>new_version = Map.get(json, "tag_name")
|
||||
new_version_url = Map.get(json, "assets")
|
||||
|> Enum.find(fn asset ->
|
||||
String.contains?(Map.get(asset, "browser_download_url"),
|
||||
extension) end)
|
||||
|> Map.get("browser_download_url")
|
||||
Logger.debug("new version: #{new_version}, current_version: #{current_version}")
|
||||
case (new_version != current_version) do
|
||||
true ->
|
||||
RPC.MessageHandler.log("New update available!", [:success_toast, :ticker], ["BotUpdates"])
|
||||
{:update, new_version_url}
|
||||
_ ->
|
||||
RPC.MessageHandler.log("Bot up to date!", [:success_toast, :ticker], ["BotUpdates"])
|
||||
:no_updates
|
||||
end
|
||||
|
||||
%HTTPotion.Response{body: body,
|
||||
headers: _headers,
|
||||
status_code: 301} ->
|
||||
msg = Poison.decode!(body)
|
||||
Map.get(msg, "url") |> check_updates(extension)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Shortcut for check_updates
|
||||
"""
|
||||
def check_os_updates do
|
||||
with {:ok, token} <- FarmbotAuth.get_token,
|
||||
do: check_updates(
|
||||
Map.get(token, "unencoded") |> Map.get("os_update_server"),
|
||||
".fw")
|
||||
end
|
||||
|
||||
@doc """
|
||||
Shortcut for check_updates
|
||||
"""
|
||||
def check_fw_updates do
|
||||
with {:ok, token} <- FarmbotAuth.get_token,
|
||||
do: check_updates(
|
||||
Map.get(token, "unencoded") |> Map.get("fw_update_server"),
|
||||
".hex")
|
||||
end
|
||||
|
||||
def check_and_download_os_update do
|
||||
case check_os_updates do
|
||||
:no_updates -> RPC.MessageHandler.log("Bot OS up to date!", [:success_toast, :ticker], ["BotUpdates"])
|
||||
{:update, url} ->
|
||||
Logger.debug("NEW OS UPDATE")
|
||||
spawn fn -> Downloader.download_and_install_os_update(url) end
|
||||
{:error, message} ->
|
||||
RPC.MessageHandler.log("Error fetching update: #{message}", [:error_toast], ["BotUpdates"])
|
||||
error ->
|
||||
RPC.MessageHandler.log("Error fetching update: #{inspect error}", [:error_toast], ["BotUpdates"])
|
||||
end
|
||||
end
|
||||
|
||||
def check_and_download_fw_update do
|
||||
case check_fw_updates do
|
||||
:no_updates -> RPC.MessageHandler.log("Bot FW up to date!", [:success_toast, :ticker], ["BotUpdates"])
|
||||
{:update, url} ->
|
||||
Logger.debug("NEW FIRMWARE UPDATE")
|
||||
spawn fn -> Downloader.download_and_install_fw_update(url) end
|
||||
{:error, message} -> RPC.MessageHandler.log("Error fetching update: #{message}", [:error_toast], ["BotUpdates"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -85,7 +85,7 @@ defmodule Farmbot.Scheduler do
|
|||
end
|
||||
|
||||
# tell all the regimens to pause.
|
||||
Enum.each(state.regimens, fn({pid, regimen, items, start_time, flag}) ->
|
||||
Enum.each(state.regimens, fn({pid, _regimen, _items, _start_time, _flag}) ->
|
||||
Logger.debug("Pausing regimens")
|
||||
GenServer.cast(pid, :pause)
|
||||
end)
|
||||
|
@ -100,7 +100,7 @@ defmodule Farmbot.Scheduler do
|
|||
# tell all the regimens to resume.
|
||||
# Maybe a problem? the user might not want to restart EVERY regimen
|
||||
# there might have been regimens that werent paused by e stop?
|
||||
Enum.each(state.regimens, fn({pid, regimen, items, start_time, flag}) ->
|
||||
Enum.each(state.regimens, fn({pid, _regimen, _items, _start_time, _flag}) ->
|
||||
GenServer.cast(pid, :resume)
|
||||
end)
|
||||
# set current sequence to nil to allow sequences to continue.
|
||||
|
@ -113,7 +113,7 @@ defmodule Farmbot.Scheduler do
|
|||
|
||||
# This strips out pids, tuples and whatnot for json status updates
|
||||
def handle_call(:jsonable, _from, state) do
|
||||
regimen_info_list = Enum.map(state.regimens, fn({_pid, regimen, time, items, flag}) ->
|
||||
regimen_info_list = Enum.map(state.regimens, fn({_pid, regimen, time, _items, flag}) ->
|
||||
%{regimen: regimen,
|
||||
info: %{
|
||||
start_time: time,
|
||||
|
|
124
lib/fw.ex
124
lib/fw.ex
|
@ -1,9 +1,6 @@
|
|||
defmodule Fw do
|
||||
require Logger
|
||||
use Supervisor
|
||||
@env Mix.env
|
||||
@target System.get_env("NERVES_TARGET") || "rpi3"
|
||||
@version Path.join(__DIR__ <> "/..", "VERSION") |> File.read! |> String.strip
|
||||
@state_path Application.get_env(:fb, :state_path)
|
||||
|
||||
@doc """
|
||||
|
@ -29,9 +26,12 @@ defmodule Fw do
|
|||
System.cmd("mkfs.ext4", ["/dev/mmcblk0p3", "-F"])
|
||||
System.cmd("mount", ["/dev/mmcblk0p3", "/state", "-t", "ext4"])
|
||||
File.write("/state/.formatted", "DONT CAT ME\n")
|
||||
:ok
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks for a .formatted file on the state/data partition, if it doesnt exit
|
||||
it formats the partition
|
||||
"""
|
||||
def fs_init(:prod) do
|
||||
with {:error, :enoent} <- File.read("#{@state_path}/.formatted") do
|
||||
format_state_part
|
||||
|
@ -39,119 +39,35 @@ defmodule Fw do
|
|||
end
|
||||
|
||||
def fs_init(_) do
|
||||
:ok
|
||||
{:ok, :development}
|
||||
end
|
||||
|
||||
def init([%{target: target, compat_version: compat_version}]) do
|
||||
def init([%{target: target, compat_version: compat_version, version: version, env: env}]) do
|
||||
children = [
|
||||
worker(SafeStorage, [@env], restart: :permanent),
|
||||
worker(BotState, [%{target: target, compat_version: compat_version}], restart: :permanent),
|
||||
worker(Command.Tracker, [[]], restart: :permanent),
|
||||
worker(SSH, [@env], restart: :permanent),
|
||||
# Storage that needs to persist across reboots.
|
||||
worker(SafeStorage, [env], restart: :permanent),
|
||||
|
||||
# master state tracker.
|
||||
worker(BotState, [%{target: target, compat_version: compat_version, version: version, env: env}], restart: :permanent),
|
||||
|
||||
# something sarcastic
|
||||
worker(SSH, [env], restart: :permanent),
|
||||
|
||||
# Main controller stuff.
|
||||
supervisor(Controller, [[]], restart: :permanent)
|
||||
]
|
||||
opts = [strategy: :one_for_one, name: Fw]
|
||||
supervise(children, opts)
|
||||
end
|
||||
|
||||
def start(_type, args) do
|
||||
fs_init(@env)
|
||||
Logger.debug("Starting Firmware on Target: #{@target}")
|
||||
Supervisor.start_link(__MODULE__, args)
|
||||
end
|
||||
|
||||
def version do
|
||||
@version
|
||||
def start(_type, [%{target: target, compat_version: compat_version, version: version, env: env}]) do
|
||||
{:ok, _} = fs_init(env)
|
||||
Logger.debug("Starting Firmware on Target: #{target}")
|
||||
Supervisor.start_link(__MODULE__, [%{target: target, compat_version: compat_version, version: version, env: env}])
|
||||
end
|
||||
|
||||
def factory_reset do
|
||||
GenServer.stop SafeStorage, :reset
|
||||
Nerves.Firmware.reboot
|
||||
end
|
||||
|
||||
@doc """
|
||||
Looks for the latest asset of given extension (ie: ".exe")
|
||||
on a Github Release API.
|
||||
Returns {:update, url_to_latest_download} or :no_updates
|
||||
TODO: Rewrite this using 'with'
|
||||
"""
|
||||
def check_updates(url, extension) when is_bitstring(extension) do
|
||||
Logger.debug(url)
|
||||
resp = HTTPotion.get url,
|
||||
[headers: ["User-Agent": "Farmbot"]]
|
||||
current_version = Fw.version
|
||||
case resp do
|
||||
%HTTPotion.ErrorResponse{message: error} ->
|
||||
RPC.MessageHandler.log("Update check failed: #{inspect error}", [:error_toast], ["BotUpdates"])
|
||||
{:error, "Check Updates failed", error}
|
||||
%HTTPotion.Response{body: body,
|
||||
headers: _headers,
|
||||
status_code: 200} ->
|
||||
json = Poison.decode!(body)
|
||||
"v"<>new_version = Map.get(json, "tag_name")
|
||||
new_version_url = Map.get(json, "assets")
|
||||
|> Enum.find(fn asset ->
|
||||
String.contains?(Map.get(asset, "browser_download_url"),
|
||||
extension) end)
|
||||
|> Map.get("browser_download_url")
|
||||
Logger.debug("new version: #{new_version}, current_version: #{current_version}")
|
||||
case (new_version != current_version) do
|
||||
true ->
|
||||
RPC.MessageHandler.log("New update available!", [:success_toast, :ticker], ["BotUpdates"])
|
||||
{:update, new_version_url}
|
||||
_ ->
|
||||
RPC.MessageHandler.log("Bot up to date!", [:success_toast, :ticker], ["BotUpdates"])
|
||||
:no_updates
|
||||
end
|
||||
|
||||
%HTTPotion.Response{body: body,
|
||||
headers: _headers,
|
||||
status_code: 301} ->
|
||||
msg = Poison.decode!(body)
|
||||
Map.get(msg, "url") |> check_updates(extension)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Shortcut for check_updates
|
||||
"""
|
||||
def check_os_updates do
|
||||
with {:ok, token} <- FarmbotAuth.get_token,
|
||||
do: check_updates(
|
||||
Map.get(token, "unencoded") |> Map.get("os_update_server"),
|
||||
".fw")
|
||||
end
|
||||
|
||||
@doc """
|
||||
Shortcut for check_updates
|
||||
"""
|
||||
def check_fw_updates do
|
||||
with {:ok, token} <- FarmbotAuth.get_token,
|
||||
do: check_updates(
|
||||
Map.get(token, "unencoded") |> Map.get("fw_update_server"),
|
||||
".hex")
|
||||
end
|
||||
|
||||
def check_and_download_os_update do
|
||||
case Fw.check_os_updates do
|
||||
:no_updates -> RPC.MessageHandler.log("Bot OS up to date!", [:success_toast, :ticker], ["BotUpdates"])
|
||||
{:update, url} ->
|
||||
Logger.debug("NEW OS UPDATE")
|
||||
spawn fn -> Downloader.download_and_install_os_update(url) end
|
||||
{:error, message} ->
|
||||
RPC.MessageHandler.log("Error fetching update: #{message}", [:error_toast], ["BotUpdates"])
|
||||
error ->
|
||||
RPC.MessageHandler.log("Error fetching update: #{inspect error}", [:error_toast], ["BotUpdates"])
|
||||
end
|
||||
end
|
||||
|
||||
def check_and_download_fw_update do
|
||||
case Fw.check_fw_updates do
|
||||
:no_updates -> RPC.MessageHandler.log("Bot FW up to date!", [:success_toast, :ticker], ["BotUpdates"])
|
||||
{:update, url} ->
|
||||
Logger.debug("NEW FIRMWARE UPDATE")
|
||||
spawn fn -> Downloader.download_and_install_fw_update(url) end
|
||||
{:error, message} -> RPC.MessageHandler.log("Error fetching update: #{message}", [:error_toast], ["BotUpdates"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -172,12 +172,12 @@ defmodule RPC.MessageHandler do
|
|||
end
|
||||
|
||||
def do_handle("check_updates", _) do
|
||||
Fw.check_and_download_os_update
|
||||
Downloader.check_and_download_os_update
|
||||
:ok
|
||||
end
|
||||
|
||||
def do_handle("check_arduino_updates", _) do
|
||||
Fw.check_and_download_fw_update
|
||||
Downloader.check_and_download_fw_update
|
||||
:ok
|
||||
end
|
||||
|
||||
|
|
|
@ -2,7 +2,10 @@ defmodule Serial.Supervisor do
|
|||
@moduledoc false
|
||||
def start_link(_args) do
|
||||
import Supervisor.Spec
|
||||
children = [worker(Serial.Handler, [[]], restart: :permanent)]
|
||||
children = [
|
||||
worker(Command.Tracker, [[]], restart: :permanent),
|
||||
worker(Serial.Handler, [[]], restart: :permanent)
|
||||
]
|
||||
Supervisor.start_link(children, strategy: :one_for_one, name: __MODULE__)
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue