Skip to content

Commit a8bf99c

Browse files
authored
Merge pull request #1446 from FarmBot/numeric_variables
Numeric variables, HTTP client bug fix
2 parents a7327b8 + df55e99 commit a8bf99c

14 files changed

+198
-31
lines changed

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ _nerves-tmp
1515
*.db*
1616
*.ez
1717
*.img
18-
*.lua
1918
*.o
2019
*.pem
2120
*.priv

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
# 14.6.2
4+
5+
* Fix bug where firmware parameters would appear to not be uploaded.
6+
* Ability to handle `numeric` sequence variables from Lua
7+
* Silence timeout error messages from user log stream
8+
* Add `photo_grid()` technical preview to Lua VM.
9+
* Better handling of timeout errors in lua `http()` function.
10+
311
# 14.6.2
412

513
* Fix bug where Lua scripts would not stop sending GCode during estop

VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
14.6.2
1+
14.6.4-rc3

lib/celery/compilers/variable_transformer.ex

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ defmodule FarmbotOS.Celery.Compiler.VariableTransformer do
2121
[FarmbotOS.Celery.SysCallGlue.get_toolslot_for_tool(tool_id)]
2222
end
2323

24+
def run!(%{args: %{number: number}}) do
25+
[number]
26+
end
27+
2428
def run!(nil) do
2529
error = "LUA ERROR: Sequence does not contain variable"
2630
[%{kind: :error, error: error, x: nil, y: nil, z: nil}, error]

lib/ext/dirty_worker.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ defmodule FarmbotOS.DirtyWorker do
181181
e = inspect(error)
182182
id = Repo.encode_local_id(dirty.local_id)
183183
msg = "[#{m} #{id} #{inspect(self())}] HTTP Error: #{e}"
184-
FarmbotOS.Logger.error(2, msg)
184+
Logger.error(msg)
185185
error
186186
end
187187

lib/firmware/config_uploader.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ defmodule FarmbotOS.Firmware.ConfigUploader do
6767
key = Parameter.translate(p)
6868
expected = Map.fetch!(conf, key)
6969

70-
unless actual == expected do
70+
if actual == expected do
7171
:ok = BotState.set_firmware_config(key, actual)
7272
end
7373
end

lib/os/lua.ex

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ defmodule FarmbotOS.Lua do
101101

102102
def builtins() do
103103
%{
104+
photo_grid: &DataManipulation.photo_grid/2,
104105
base64: [
105106
{:decode, &DataManipulation.b64_decode/2},
106107
{:encode, &DataManipulation.b64_encode/2}

lib/os/lua/data_manipulation.ex

+29-8
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ defmodule FarmbotOS.Lua.DataManipulation do
66
alias FarmbotOS.{Asset, JSON}
77
alias FarmbotOS.Asset.{Device, FbosConfig, FirmwareConfig}
88
alias FarmbotOS.Lua.Util
9+
alias FarmbotOS.Lua
910
alias FarmbotOS.SysCalls.ResourceUpdate
1011
alias FarmbotOS.HTTP
1112
alias FarmbotOS.Celery.SpecialValue
13+
require FarmbotOS.Logger
1214

1315
@methods %{
1416
"connect" => :connect,
@@ -40,14 +42,22 @@ defmodule FarmbotOS.Lua.DataManipulation do
4042
# {"Content-Type", "application/json; charset=utf-8"},
4143
# ], #Reference<0.3657984643.824705025.36946>}
4244
# }
43-
{:ok, status, resp_headers, client_ref} =
44-
hackney.request(method, url, headers, body, options)
45-
46-
# Example response body: {:ok, "{\"whatever\": \"foo_bar_baz\"}"}
47-
{:ok, resp_body} = hackney.body(client_ref)
48-
result = %{body: resp_body, headers: Map.new(resp_headers), status: status}
49-
50-
{[Util.map_to_table(result)], lua}
45+
with {:ok, status, resp_headers, client_ref} <-
46+
hackney.request(method, url, headers, body, options),
47+
# Example response body: {:ok, "{\"whatever\": \"foo_bar_baz\"}"}
48+
{:ok, resp_body} <- hackney.body(client_ref) do
49+
result = %{
50+
body: resp_body,
51+
headers: Map.new(resp_headers),
52+
status: status
53+
}
54+
55+
{[Util.map_to_table(result)], lua}
56+
else
57+
error ->
58+
FarmbotOS.Logger.error(3, inspect(error))
59+
{[nil, "HTTP CLIENT ERROR - See log for details"], lua}
60+
end
5161
end
5262

5363
def env([key, value], lua) do
@@ -205,4 +215,15 @@ defmodule FarmbotOS.Lua.DataManipulation do
205215
{[nil, data], lua}
206216
end
207217
end
218+
219+
def photo_grid(_, lua) do
220+
lua_code = File.read!("#{:code.priv_dir(:farmbot)}/lua/photo_grid.lua")
221+
222+
with {:ok, result} <- Lua.raw_eval(lua, lua_code) do
223+
{result, lua}
224+
else
225+
error ->
226+
{[nil, "ERROR: #{inspect(error)}"], lua}
227+
end
228+
end
208229
end

priv/lua/photo_grid.lua

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
function round(n) return math.floor(n + 0.5) end
2+
3+
function angleRound(angle)
4+
local remainder = math.abs(angle % 90)
5+
if remainder > 45 then
6+
return 90 - remainder
7+
else
8+
return remainder
9+
end
10+
end
11+
12+
-- Returns an integer that we need to subtract from width/height
13+
-- due to camera rotation issues.
14+
function cropAmount(width, height, angle)
15+
local absAngle = angleRound(angle or 0)
16+
if (absAngle > 0) then
17+
local x = (5.61 - 0.095 * math.pow(absAngle, 2) + 9.06 * absAngle)
18+
local factor = x / 640
19+
local longEdge = math.max(width, height)
20+
local result = round(longEdge * factor)
21+
return result
22+
end
23+
return 0
24+
end
25+
26+
function fwe(key)
27+
local e = env("CAMERA_CALIBRATION_" .. key)
28+
if e then
29+
return tonumber(e)
30+
else
31+
send_message("error", "You must first run camera calibration", "toast")
32+
os.exit()
33+
end
34+
end
35+
36+
local cam_rotation = fwe("total_rotation_angle")
37+
local scale = fwe("coord_scale")
38+
local z = fwe("camera_z")
39+
local raw_img_size_x_px = fwe("center_pixel_location_x") * 2
40+
local raw_img_size_y_px = fwe("center_pixel_location_y") * 2
41+
local raw_img_size_x_mm = raw_img_size_x_px * scale
42+
local raw_img_size_y_mm = raw_img_size_y_px * scale
43+
local margin_mm = cropAmount(raw_img_size_x_px, raw_img_size_y_px, cam_rotation)
44+
local cropped_img_size_x_mm = raw_img_size_x_mm - margin_mm
45+
local cropped_img_size_y_mm = raw_img_size_y_mm - margin_mm
46+
if math.abs(cam_rotation) < 45 then
47+
x_spacing_mm = cropped_img_size_x_mm
48+
y_spacing_mm = cropped_img_size_y_mm
49+
else
50+
x_spacing_mm = cropped_img_size_y_mm
51+
y_spacing_mm = cropped_img_size_x_mm
52+
end
53+
local grid_size_x_mm = garden_size().x - x_spacing_mm
54+
local y_grid_size_mm = garden_size().y - y_spacing_mm
55+
local x_grid_points = math.ceil(grid_size_x_mm / x_spacing_mm)
56+
local y_grid_points = math.ceil(y_grid_size_mm / y_spacing_mm)
57+
local total = (x_grid_points + 1) * (y_grid_points + 1)
58+
local x_grid_start_mm = (x_spacing_mm / 2)
59+
local y_grid_start_mm = (y_spacing_mm / 2)
60+
local x_offset_mm = fwe("camera_offset_x")
61+
local y_offset_mm = fwe("camera_offset_y")
62+
63+
local each = function(callback)
64+
local y = 0
65+
local count = 0
66+
for x_grid_index = 0, x_grid_points do
67+
for y_grid_points = 0, y_grid_points do
68+
count = count + 1
69+
local y_temp1 = (y_spacing_mm * y_grid_points)
70+
if (x_grid_index % 2) == 0 then
71+
y = (y_grid_size_mm + (y_temp1 - y_offset_mm))
72+
else
73+
y = (y_grid_size_mm - (y_temp1 - y_offset_mm))
74+
end
75+
callback({
76+
x = (x_grid_start_mm + (x_spacing_mm * x_grid_index) -
77+
x_offset_mm),
78+
y = y,
79+
z = z,
80+
count = count
81+
})
82+
end
83+
end
84+
end
85+
86+
return {
87+
y_spacing_mm = y_spacing_mm,
88+
y_offset_mm = y_offset_mm,
89+
y_grid_start_mm = y_grid_start_mm,
90+
y_grid_size_mm = y_grid_size_mm,
91+
y_grid_points = y_grid_points,
92+
x_spacing_mm = x_spacing_mm,
93+
x_offset_mm = x_offset_mm,
94+
x_grid_start_mm = x_grid_start_mm,
95+
x_grid_points = x_grid_points,
96+
z = z,
97+
total = total,
98+
each = each
99+
}

test/farmbot_celery_script/variable_transformer_test.exs

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ defmodule FarmbotOS.Celery.VariableTransformerTest do
77

88
setup :verify_on_exit!
99

10+
test "numeric types" do
11+
num = %{kind: :numeric, args: %{number: 26}}
12+
actual = VariableTransformer.run!(num)
13+
assert actual == [26]
14+
end
15+
1016
test "always has an x/y/z value at root" do
1117
actual = VariableTransformer.run!(%{x: 1, y: 2, z: 3.4})
1218
expected = [%{x: 1, y: 2, z: 3.4}]

test/farmbot_ext/api/dirty_worker_test.exs

+8-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ defmodule FarmbotOS.DirtyWorkerTest do
44
use ExUnit.Case
55
use Mimic
66

7+
import ExUnit.CaptureLog
8+
79
alias FarmbotOS.Asset.{
810
FbosConfig,
911
Point,
@@ -52,10 +54,13 @@ defmodule FarmbotOS.DirtyWorkerTest do
5254
Helpers.delete_all_points()
5355
Repo.delete_all(LocalMeta)
5456
Repo.delete_all(FbosConfig)
55-
Helpers.expect_log("HTTP Error: {:error, :other}")
56-
5757
p = Helpers.create_point(%{id: 2, pointer_type: "Weed"})
58-
DirtyWorker.handle_http_response(p, Point, {:error, :other})
58+
59+
t = fn ->
60+
DirtyWorker.handle_http_response(p, Point, {:error, :other})
61+
end
62+
63+
assert capture_log(t) =~ "HTTP Error: {:error, :other}"
5964
end
6065

6166
test "handle_http_response - 409 response" do

test/os/lua/ext/data_manipulation_test.exs

+24
Original file line numberDiff line numberDiff line change
@@ -355,4 +355,28 @@ defmodule FarmbotOS.Lua.DataManipulationTest do
355355
results = DataManipulation.http([params], :fake_lua)
356356
assert results == expected
357357
end
358+
359+
@lua_code File.read!("#{:code.priv_dir(:farmbot)}/lua/photo_grid.lua")
360+
361+
test "photo_grid() - OK" do
362+
expect(FarmbotOS.Lua, :raw_eval, 1, fn lua_state, lua_code ->
363+
assert lua_code == @lua_code
364+
assert lua_state == :fake_lua
365+
{:ok, :result}
366+
end)
367+
368+
result = DataManipulation.photo_grid([], :fake_lua)
369+
assert result == {:result, :fake_lua}
370+
end
371+
372+
test "photo_grid() - KO" do
373+
expect(FarmbotOS.Lua, :raw_eval, 1, fn lua_state, lua_code ->
374+
assert lua_code == @lua_code
375+
assert lua_state == :fake_lua
376+
{:error, :error_result}
377+
end)
378+
379+
result = DataManipulation.photo_grid([], :fake_lua)
380+
assert result == {[nil, "ERROR: {:error, :error_result}"], :fake_lua}
381+
end
358382
end

test/os/lua_test.exs

-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ defmodule FarmbotOS.LuaTest do
9090
{[], lua}
9191
end)
9292

93-
# expect(Command, :move_abs, 1, fn _ -> {:ok, nil} end)
9493
expect(Command, :read_pin, 1, fn _, _ -> {:ok, 1} end)
9594

9695
expect(Firmware, :move_absolute, 4, fn _vec_or_xyz, lua ->

test/test_helper.exs

+16-15
Original file line numberDiff line numberDiff line change
@@ -298,13 +298,19 @@ ExUnit.configure(
298298
Circuits.UART,
299299
Ecto.Changeset,
300300
ExTTY,
301+
FarmbotOS.API,
302+
FarmbotOS.API.Reconciler,
303+
FarmbotOS.API.SyncGroup,
304+
FarmbotOS.APIFetcher,
301305
FarmbotOS.Asset,
302306
FarmbotOS.Asset.Command,
303307
FarmbotOS.Asset.Device,
304308
FarmbotOS.Asset.FbosConfig,
305309
FarmbotOS.Asset.FirmwareConfig,
306310
FarmbotOS.Asset.Private,
307311
FarmbotOS.Asset.Repo,
312+
FarmbotOS.Bootstrap.Authorization,
313+
FarmbotOS.Bootstrap.DropPasswordSupport,
308314
FarmbotOS.BotState,
309315
FarmbotOS.Celery,
310316
FarmbotOS.Celery.AST.Factory,
@@ -314,6 +320,10 @@ ExUnit.configure(
314320
FarmbotOS.Celery.SysCallGlue,
315321
FarmbotOS.Celery.SysCallGlue.Stubs,
316322
FarmbotOS.Config,
323+
FarmbotOS.Configurator.ConfigDataLayer,
324+
FarmbotOS.Configurator.DetsTelemetryLayer,
325+
FarmbotOS.Configurator.FakeNetworkLayer,
326+
FarmbotOS.EagerLoader.Supervisor,
317327
FarmbotOS.FarmwareRuntime,
318328
FarmbotOS.Firmware.Avrdude,
319329
FarmbotOS.Firmware.Command,
@@ -326,36 +336,27 @@ ExUnit.configure(
326336
FarmbotOS.Firmware.UARTCoreSupport,
327337
FarmbotOS.Firmware.UARTDetector,
328338
FarmbotOS.FirmwareEstopTimer,
339+
FarmbotOS.HTTP,
329340
FarmbotOS.Leds,
330341
FarmbotOS.LogExecutor,
331342
FarmbotOS.Logger,
332-
FarmbotOS.API,
333-
FarmbotOS.API.Reconciler,
334-
FarmbotOS.API.SyncGroup,
335-
FarmbotOS.APIFetcher,
336-
FarmbotOS.Bootstrap.Authorization,
337-
FarmbotOS.Bootstrap.DropPasswordSupport,
338-
FarmbotOS.EagerLoader.Supervisor,
343+
FarmbotOS.Lua,
344+
FarmbotOS.Lua.DataManipulation,
345+
FarmbotOS.Lua.Firmware,
346+
FarmbotOS.Lua.Info,
339347
FarmbotOS.MQTT,
340348
FarmbotOS.MQTT.LogHandlerSupport,
341349
FarmbotOS.MQTT.Support,
342350
FarmbotOS.MQTT.SyncHandlerSupport,
343351
FarmbotOS.MQTT.TerminalHandlerSupport,
344352
FarmbotOS.MQTT.TopicSupervisor,
345-
FarmbotOS.Time,
346-
FarmbotOS.Configurator.ConfigDataLayer,
347-
FarmbotOS.Configurator.DetsTelemetryLayer,
348-
FarmbotOS.Configurator.FakeNetworkLayer,
349-
FarmbotOS.HTTP,
350-
FarmbotOS.Lua.DataManipulation,
351-
FarmbotOS.Lua.Firmware,
352-
FarmbotOS.Lua.Info,
353353
FarmbotOS.SysCalls,
354354
FarmbotOS.SysCalls.ChangeOwnership.Support,
355355
FarmbotOS.SysCalls.Farmware,
356356
FarmbotOS.SysCalls.Movement,
357357
FarmbotOS.SysCalls.ResourceUpdate,
358358
FarmbotOS.System,
359+
FarmbotOS.Time,
359360
FarmbotOS.UpdateSupport,
360361
FarmbotTelemetry,
361362
File,

0 commit comments

Comments
 (0)