moving some stuff aroun

pull/200/head
connor rigby 2016-11-14 09:27:08 -08:00
parent a5934a1f71
commit 6b2eb071b9
9 changed files with 141 additions and 118 deletions

View File

@ -8,7 +8,6 @@ config :uart,
config :fb,
state_path: "/state",
db_path: "/db",
dnsmasq_path: "/root/dnsmasq.lease"
config :json_rpc,

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

@ -35,7 +35,7 @@ defmodule Fw.Mixfile do
end
def application do
[mod: {Fw, [%{target: target(Mix.env), compat_version: @compat_version}]},
[mod: {Fw, [%{target: target(Mix.env), compat_version: @compat_version, version: @version, env: Mix.env}]},
applications: apps(Mix.env)]
end