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

File tree

14 files changed

+198
-31
lines changed

14 files changed

+198
-31
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
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

Lines changed: 8 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 4 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 29 additions & 8 deletions
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

Lines changed: 99 additions & 0 deletions
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

Lines changed: 6 additions & 0 deletions
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}]

0 commit comments

Comments
 (0)