Skip to content

Commit

Permalink
Merge pull request #181 from ConnorRigby/master
Browse files Browse the repository at this point in the history
Getting ready for new release 2.0.1
  • Loading branch information
ConnorRigby authored Oct 5, 2016
2 parents c89839a + abefac9 commit 40b7bf8
Show file tree
Hide file tree
Showing 17 changed files with 170 additions and 89 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ If you are setting up your FarmBot for the first time, download the latest FarmB
0. From a WiFi enabled device*, search for the SSID `FarmbotConfigurator`
0. Connect to that and open a web browser to [http://192.168.24.1/](http://192.168.24.1)
0. Follow the on screen instructions to configure your FarmBot. Once you save your configuration FarmBot will connect to your home WiFi network and to the FarmBot web application.

Asterisk: If you are using a smartphone you may need to disable cellular data to allow your phone's browser to connect to the configurator.

## Updating the firmware
To update the firmware on the Raspberry Pi and the Arduino, simply use the "update" buttons on the web application. There is no need to reinstall the entire OS.



# Building / Development (for developers only)

Expand Down Expand Up @@ -74,7 +74,7 @@ In the `erlinit.config` file change `-c ttyS0` to `-c ttyS1`. This requires a us
## Development Tips

You can connect IEx to the running pi by running
`iex -name console@localhost --remsh farmbot@<FARMBOT IP ADDRESS> --cookie democookie`.
`iex --name console@localhost --remsh farmbot@<FARMBOT IP ADDRESS> --cookie democookie`.

Debug message still only will print to UART or HDMI (whichever you have configured)

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.0.0
2.0.1
3 changes: 2 additions & 1 deletion config/prod.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ config :uart,

config :fb,
ro_path: "/root",
os_update_server: System.get_env("OS_UPDATE_SERVER") || "https://api.github.com/repos/farmbot/farmbot-raspberry-pi-controller/releases/latest",
factory_reset_pin: 21,
os_update_server: System.get_env("OS_UPDATE_SERVER") || "https://api.github.com/repos/farmbot/farmbot_os/releases/latest",
fw_update_server: System.get_env("FW_UPDATE_SERVER") || "https://api.github.com/repos/FarmBot/farmbot-arduino-firmware/releases/latest"

config :json_rpc,
Expand Down
33 changes: 20 additions & 13 deletions lib/auth.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ defmodule Auth do
def get_public_key(server) do
resp = HTTPotion.get("#{server}/api/public_key")
case resp do
%HTTPotion.ErrorResponse{message: "enetunreach"} -> get_public_key(server)
%HTTPotion.ErrorResponse{message: "ehostunreach"} -> get_public_key(server)
%HTTPotion.ErrorResponse{message: "nxdomain"} -> get_public_key(do_magic(server))
%HTTPotion.ErrorResponse{message: "econnrefused"} -> {:error, "econnrefused"}
_ -> RSA.decode_key(resp.body)
%HTTPotion.ErrorResponse{message: "enetunreach"} -> get_public_key(server)
%HTTPotion.ErrorResponse{message: "ehostunreach"} -> get_public_key(server)
%HTTPotion.ErrorResponse{message: "nxdomain"} -> get_public_key(do_magic(server))
%HTTPotion.ErrorResponse{message: message} -> {:error, message}
%HTTPotion.Response{body: body,
headers: _headers,
status_code: 200} -> RSA.decode_key(body)
end
end

Expand Down Expand Up @@ -49,19 +51,27 @@ defmodule Auth do

# Gets a token from the API with given secret and server
def get_token(secret, server) do
if(!Wifi.connected?) do
Process.sleep(80)
get_token(secret, server)
end
payload = Poison.encode!(%{user: %{credentials: :base64.encode_to_string(secret) |> String.Chars.to_string }} )
resp = HTTPotion.post "#{server}/api/tokens", [body: payload, headers: ["Content-Type": "application/json"]]
case resp do
case HTTPotion.post "#{server}/api/tokens", [body: payload, headers: ["Content-Type": "application/json"]] do
%HTTPotion.ErrorResponse{message: "enetunreach"} -> get_token(secret, server)
%HTTPotion.ErrorResponse{message: "nxdomain"} -> do_magic(server)
%HTTPotion.ErrorResponse{message: "nxdomain"} -> get_token(secret, do_magic(server))
%HTTPotion.ErrorResponse{message: reason} -> {:error, reason}
%HTTPotion.Response{body: body, headers: _headers, status_code: 200} ->
Map.get(Poison.decode!(body), "token")
end
end

def get_token do
GenServer.call(__MODULE__, {:get_token})
end

# some black magic to fix RickCarlino's Env.
def do_magic("http://"<>host) do
Logger.debug("Doing magic")
case HTTPotion.get("http://dig.jsondns.org/IN/#{host}/A") do
%HTTPotion.ErrorResponse{message: reason} -> {:error, reason}
%HTTPotion.Response{body: body, headers: _headers, status_code: 203} ->
Expand All @@ -86,18 +96,14 @@ defmodule Auth do
end
end

def get_token do
GenServer.call(__MODULE__, {:get_token})
end

# Infinite recursion until we have a token.
# Not concerned about performance yet because the bot can't do anything yet.
def fetch_token do
case Auth.get_token do
nil -> fetch_token
{:error, reason} -> IO.puts("something weird happened")
IO.inspect(reason)
Elixir.IEx.start
{:error, reason}
token -> token
end
end
Expand All @@ -119,6 +125,7 @@ defmodule Auth do
true ->
GenServer.call(__MODULE__, {:login, email,pass,server}, 15000 )
_ ->
Process.sleep(10001)
login(email,pass,server) # Probably process heavy here but im lazy
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/bot_status/bot_status.ex
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ defmodule BotStatus do
end

def handle_cast({:set_end_stop, _stop, _value}, current_status) do
#TODO: this?
#TODO: Endstop reporting
# Logger.debug("EndStop reporting is TODO")
{:noreply, current_status}
end
Expand All @@ -79,7 +79,7 @@ defmodule BotStatus do
GenServer.cast(__MODULE__, {:set_param, param, value})
end

def set_param(param, value) when is_bitstring(param)
def set_param(param, value) when is_bitstring(param)
and is_bitstring(value) do
set_param(param, String.to_integer(value))
end
Expand Down
43 changes: 17 additions & 26 deletions lib/bot_sync/bot_sync.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,38 @@ defmodule BotSync do
use GenServer
require Logger
def init(_args) do
{:ok, %{token: token, server: server, sequences: [] }}
{:ok, %{token: Auth.fetch_token, resources: %{} }}
end

def start_link(args) do
GenServer.start_link(__MODULE__, args, name: __MODULE__)
end

def handle_cast(:sync, state) do
resp = HTTPotion.get "#{server}/api/sequences",
def handle_cast(:sync, %{token: token, resources: _old_resources}) do
server = Map.get(token, "unencoded") |> Map.get("iss")
auth = Map.get(token, "encoded")

case HTTPotion.get "#{server}/api/sync",
[headers: ["Content-Type": "application/json",
"Authorization": "Bearer" <> Map.get(state.token, "encoded")]]
case resp do
%HTTPotion.ErrorResponse{message: reason} ->
Logger.debug("Error Fetching sequences: #{inspect reason}")
{:noreply, Map.update(state, :sequences, [], fn _cur -> [] end)}
_ ->
sequences = Poison.decode!(resp.body)
Logger.debug("Successfully Fetched Sequences")
{:noreply, Map.update(state, :sequences, [], fn _cur -> sequences end)}
"Authorization": "Bearer " <> auth]] do

%HTTPotion.Response{body: body,
headers: _headers,
status_code: 200} ->
{:noreply, %{token: token, resources: Poison.decode!(body)}}
error -> {:fail, error}
end
end

def handle_call(:sequences, _from, state) do
{:reply, Map.get(state, :sequences), state}
def handle_call(:fetch, _from, %{token: token, resources: resources}) do
{:reply, resources, %{token: token, resources: resources}}
end

def sync do
GenServer.cast(__MODULE__, :sync)
end

def sequences do
GenServer.call(__MODULE__, :sequences)
end

defp token do
Auth.fetch_token
def fetch do
GenServer.call(__MODULE__, :fetch)
end

defp server do
Map.get(token, "unencoded")
|> Map.get("iss")
end

end
4 changes: 2 additions & 2 deletions lib/controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ defmodule Controller do
worker(BotStatus, [[]] , restart: :permanent ),
supervisor(SerialSupervisor, [[]], restart: :permanent ),
supervisor(MqttSupervisor, [[]], restart: :permanent ),
supervisor(SequenceSupervisor, [[]], restart: :permanent )
# worker(BotSync, [[]] , restart: :permanent )
supervisor(SequenceSupervisor, [[]], restart: :permanent ),
worker(BotSync, [[]] , restart: :permanent )
]
opts = [strategy: :one_for_all, name: Controller.Supervisor]
Supervisor.start_link(children, opts)
Expand Down
2 changes: 2 additions & 0 deletions lib/downloader.ex
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
defmodule Downloader do
def download_and_install_os_update(url) do
RPCMessageHandler.log("Downloading an OS Update!")
File.rm("/tmp/update.fw")
run(url, "/tmp/update.fw") |> Nerves.Firmware.upgrade_and_finalize
RPCMessageHandler.log("Going down for OS update. See you soon!")
Nerves.Firmware.reboot
end

def download_and_install_fw_update(url) do
RPCMessageHandler.log("Downloading an FW Update!")
File.rm("/tmp/update.hex")
file = run(url, "/tmp/update.hex")
install_avr_update(file)
RPCMessageHandler.log("Updated FW")
Expand Down
42 changes: 42 additions & 0 deletions lib/factory_reset.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
defmodule FactoryReset do
@reset_pin Application.get_env(:fb, :factory_reset_pin)
require Logger
use GenServer

def init(_args) do
Process.flag(:trap_exit, true)
{:ok, spawn_link(fn -> Shush.start end)}
end

def start_link(args) do
GenServer.start_link(__MODULE__, args, name: __MODULE__)
end

def handle_info({:EXIT, pid, reason}, state) do
Logger.debug("hes dead jim")
{:noreply, state}
end

def handle_info(event, state) do
Logger.debug("got event: #{inspect event}" )
{:noreply, state}
end
end

defmodule Shush do
@reset_pin Application.get_env(:fb, :factory_reset_pin)
def start do
{:ok, pid} = Gpio.start_link(@reset_pin, :input)
Gpio.set_int(pid, :both)
do_stuff(pid)
end

def do_stuff(pid) do
receive do
{:gpio_interrupt, @reset_pin, :falling} -> IO.puts("falling")
{:gpio_interrupt, @reset_pin, :rising} -> IO.puts("rising")
end
Process.sleep(80)
do_stuff(pid)
end
end
16 changes: 12 additions & 4 deletions lib/fw.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ defmodule Fw do
end

def start(_type, args) do
File.write("/tmp/resolv.conf", "nameserver 8.8.8.8\n")
File.write("/tmp/resolv.conf", "nameserver 8.8.8.8\n nameserver 8.8.4.4\n ")
Logger.debug("Starting Firmware on Target: #{@target}")
Supervisor.start_link(__MODULE__, args)
end
Expand All @@ -46,18 +46,26 @@ defmodule Fw do
case resp do
%HTTPotion.ErrorResponse{message: error} ->
{:error, "Check Updates failed", error}
_ ->
json = Poison.decode!(resp.body)
%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)
extension) end)
|> Map.get("browser_download_url")
case (new_version != current_version) do
true -> {:update, new_version_url}
_ -> :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

Expand Down
29 changes: 24 additions & 5 deletions lib/json_rpc/json_rpc_message_handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,21 @@ defmodule RPCMessageHandler do
end

def do_handle("reboot", _ ) do
log("Bot Going down for reboot.")
Nerves.Firmware.reboot
log("Something Weird happened...")
log("Bot Going down for reboot in 5 seconds")
spawn fn ->
Process.sleep(5000)
Nerves.Firmware.reboot
end
:ok
end

def do_handle("power_off", _ ) do
log("Bot Going down. Pls remeber me.")
Nerves.Firmware.poweroff
log("Bot Going down in 5 seconds. Pls remeber me.")
spawn fn ->
Process.sleep(5000)
Nerves.Firmware.poweroff
end
:ok
end

# "{\"update_calibration\", [%{\"movement_home_up_y\" => 0}]}"}
Expand All @@ -198,6 +205,18 @@ defmodule RPCMessageHandler do
end
end

def do_handle("sync", _) do
BotSync.sync
:ok
end

def do_hanlde("force_update", [%{"url" => url}] ) do
Logger.debug("forcing new update")
log("Forcing new update")
spawn fn -> Downloader.download_and_install_os_update(url) end
:ok
end

# Unhandled event. Probably not implemented if it got this far.
def do_handle(event, params) do
Logger.debug("[RPC_HANDLER] got valid rpc, but event is not implemented.")
Expand Down
Loading

0 comments on commit 40b7bf8

Please sign in to comment.