It is possible for FarmBot to upload images to a 3rd party API for further processing, archiving, machine learning, and more. In this tutorial, we will demonstrate how to upload images from FarmBot to the Plant.ID API using this abbreviated process:

  1. FarmBot takes six photos in a circle around a plant.
  2. FarmBot encodes the images in base64 and performs an HTTP POST to the Plant.ID API.
  3. Plant.ID returns a JSON object including its guesses as to which plant is in the images.
  4. FarmBot decodes the JSON and formats a user friendly toast notification and log that are sent to the web app.

Step 1: Add your Plant.ID token

Before you begin, you will need to request a Plant.ID API token.

Once you have a token, you must add it to your FarmBot’s custom settings. Enter PLANT_ID_TOKEN into the Setting name (key) field and paste your token into the value field. Then click the button.

Step 2: Create a sequence

Navigate to the sequence editor and create a new sequence. Add a location variable named “Plant to ID” and set it to a plant you would like to identify.

Plant.ID supports garden vegetables as well as weeds and native plant species.

Step 3: Add Lua code

Add a Lua command to the sequence and paste in the following code:

plant = variable("Plant to ID")
radius = 40
angle = (math.pi * 2) / 6
offset_x = tonumber(env("CAMERA_CALIBRATION_camera_offset_x") or "0")
offset_y = tonumber(env("CAMERA_CALIBRATION_camera_offset_y") or "0")
token = env("PLANT_ID_TOKEN")
job_name = "Identifying " ..

-- Check for token
if not token then
  toast("Plant.ID token required", "error")

-- Move, then capture and encode image
function capture(num)
    set_job(job_name, {
      percent = (num / 6) * 75,
      status = "Capturing image " .. num
    x = plant.x - offset_x + (radius * math.cos(angle * num))
    y = plant.y - offset_y + (radius * math.sin(angle * num))
    z = 0
    move_absolute(x, y, z)
    data = take_photo_raw()
    return base64.encode(data)

-- Capture six images
images = {capture(1), capture(2), capture(3), capture(4), capture(5), capture(6)}

-- Send images to Plant.ID API
set_job(job_name, {
  percent = 90,
  status = "Talking to Plant.ID"
headers = {}
headers["Content-Type"] = "application/json"
headers["Api-Key"] = token
body = {
    images = images,
    modifiers = {"health_all", "crops_medium"},
    plant_details = {"common_names"}
response, err = http({
    url = "",
    method = "POST",
    headers = headers,
    body = json.encode(body)

-- Parse common name from Plant.ID response
function common_name(num)
  local suggestions = data["suggestions"][num]
  if suggestions and suggestions["plant_details"] then
    return suggestions["plant_details"]["common_names"][1] or "Unknown"
  return "Unknown"

-- Parse probability from Plant.ID response
function probability(num)
  local suggestion = data["suggestions"][num]
  if suggestion then
    return math.floor((suggestion["probability"] or 0) * 100 + 0.5)
  return 0

-- Format result
function result(num)
  return common_name(num) .. " (" .. probability(num) .. "%)"

-- Display top 3 results
if err then
  toast(inspect(err), "error")
  data = json.decode(response.body)
  toast("Possible plants: " .. result(1) .. ", " .. result(2) .. ", " .. result(3))


Step 4: Run the sequence

SAVE the sequence and wait for it to sync with the FarmBot. You can then test it with the RUN button to make sure it functions as expected.

Note that the Lua code does not upload the images to the FarmBot API (it only uploads them to the Plant.ID API), so you will not see them in the web app or be able to access them later.

If you would like the images to be saved, you can add a take_photo() command to the capture() function before moving to the next location. This will take a second photo from the same position and upload it to the FarmBot API while the first image is encoded and uploaded to the Plant.ID API.

Once the sequence is verified to be working, you can run it in a variety of ways:

  • By using the RUN button in the sequence editor.
  • By binding the sequence to a physical button on the device via a pin binding.
  • From within a parent sequence.
  • On a recurring schedule, via an event.
  • Via third party software, using FarmBot JS.