For developers only

This documentation is meant for Farmware developers. For use of Farmware in the Web App, see here.

Farmware is custom Python code that runs on the FarmBot CPU. It is useful when you need to control the device, but cannot control the device remotely due to design considerations. Farmware should only be used in cases when it would be impractical to run software remotely, such as operations that require offline support or extremely low latency.

Don’t Author New Farmware!

There are better ways to write third party software. The current Farmware system will be superceeded by a non-compatible replacement.

Farmware has been plagued by low adoption and an extremely high maintenance burden to support a very small pool of authors. Because of low adoption and numerous legacy issues, FarmBot has made the decision to eventually terminate the current Farmware system in favor of a new, non-compatible replacement. Do not write Farmware if you do not need to.

Farmware is not the only way to write custom Farmbot software. Please see this document for more information

Currently supported languages and packages

  • Python 3.8: opencv, numpy, requests, serial, farmware_tools

Example

For a complete Farmware example, see Hello Farmware. Each of the code samples below can be run as a Farmware by replacing the contents of hello.py in Hello Farmware with the copied code.

Web App API

Use: long term information storage

Farmware can access FarmBot Web App database resources, such as plants, sequences, and points, via app actions as shown in this example:

GET: Python API request example:

from farmware_tools import app

plants = app.get_plants()

other actions:

from farmware_tools import app

tools = app.get(endpoint='tools')
points = app.search_points(search_payload={'x': 100})
plants = app.download_plants()
points = app.get_points()  # Shown as circles in the Farm Designer (weeds)
plants = app.get_plants()
toolslots = app.get_toolslots()
device_name = app.get_property(endpoint='device', field='name')
sequence_id = app.find_sequence_by_name(name='my sequence')

GET example 2:

#!/usr/bin/env python

'Get specific data (such as timezone) from the FarmBot Web App.'

from farmware_tools import app

# Device timezone info (set via the dropdown in the Web App Device widget)
timezone_string = app.get_property('device', 'timezone')
tz_offset_hours = app.get_property('device', 'tz_offset_hours')

print('My device timezone is: {} (UTC{})'.format(timezone_string, tz_offset_hours))
# Example output (to FTDI): My device timezone is: America/Los_Angeles (UTC-7)

POST: Python API request example:

from farmware_tools import app

new_plant = app.add_plant(x=100, y=200)

other actions:

from farmware_tools import app

app.patch(endpoint='device', payload={'name': 'My FarmBot'})
app.put(endpoint='device', payload={'name': 'My FarmBot'})
app.delete(endpoint='point', _id=1)

output of add_plant (new_plant):

{
  "pointer_type": "Plant",
  "name": "Unknown Plant",
  "openfarm_slug": "not-set",
  "created_at": "2017-06-22T15:14:55.652Z",
  "updated_at": "2017-06-22T15:14:55.652Z",
  "plant_status": "planned",
  "meta": {},
  "radius": 50,
  "y": 200,
  "x": 100,
  "z": 0,
  "id": 101,
  "device_id": 1
}

For a list of available resources, see Web App API resources.

Environment Variables

Use: Farmware API information

Environment variables are used to get Farmware API information and special locations.

environment variables:

from farmware_tools import env

ENV = env.Env()
FARMBOT_OS_VERSION = ENV.fbos_version
IMAGES_DIR = ENV.images_dir

Farmware API

Use: get information from FarmBot OS (bot state)

The Farmware API can be used to get information such as position and pin status as shown in this example:

bot info:

from farmware_tools import device

position_x = device.get_current_position('x')
pin_13_value = device.get_pin_value(13)

bot_state = device.get_bot_state()

See FarmBotJS BotStateTree for a complete list of information available in the the bot’s state.

Celery Script

Use: real-time web app communication and bot actions

Celery Script is JSON sent to FarmBot OS to perform actions such as device movements and setting environment variables.

Send Celery Script via device actions as shown in this example:

send message:

from farmware_tools import device

device.log('Bot is at position , , .', 'success', ['toast'])

# or
# device.log(message='Hello!', message_type='success', channels=['toast'])

all:

from farmware_tools import device

device.log(message='hi')
device.send_message(message='hi', message_type='info')
device.calibrate(axis='x')
device.check_updates(package='farmbot_os')
device.emergency_lock()
device.emergency_unlock()
device.execute(sequence_id=1)
device.execute_script(label='take-photo')
device.run_farmware(label='take-photo')
device.factory_reset(package='farmbot_os')
device.find_home(axis='x')
device.home(axis='x')
device.install_farmware(url='https://raw.githubusercontent.com/FarmBot-Labs/hello-farmware/main/manifest.json')
device.install_first_party_farmware()
device.move_absolute(location=device.assemble_coordinate(1, 2, 3), speed=100, offset=device.assemble_coordinate(0, 0, 0))
device.move_relative(x=100, y=0, z=0, speed=100)
device.power_off()
device.read_pin(pin_number=1, label='', pin_mode=0)
device.read_status()
device.reboot()
device.remove_farmware(package='hello-farmware')
device.set_pin_io_mode(pin_number=1, pin_io_mode=0)
device.set_servo_angle(pin_number=4, pin_value=0)
device.set_user_env(key='hello_farmware_key', value='0')
device.sync()
device.take_photo()
device.toggle_pin(pin_number=1)
device.update_farmware(package='take-photo')
device.wait(milliseconds=1000)
device.write_pin(pin_number=1, pin_value=0, pin_mode=0)
device.zero(axis='x')
device.send_celery_script({'kind': 'take_photo', 'args': ''})

For a list of all available actions, see the second tab of the above example code, all.

Also see the Celery Script developer documentation and the corpus for more information.

Inputs

If a Farmware requires inputs, an input form can be added to the Web App Farmware page by adding the config field to the manifest:

Form Building (FarmBot OS v8+):

{
  "package": "Farmware Name",
  // Other fields omitted for clarity (see the `Farmware manifest` section)
  "config": {
    "1": {
      "name": "key",
      "label": "Input Name",
      "value": 10
    }
  }
}

Input values are retrieved in a Farmware via get_config_value, as shown in this example:

Using inputs:

from farmware_tools import get_config_value

VALUE = get_config_value('Farmware Name', 'key')

# or
# VALUE = get_config_value(farmware_name='Farmware Name', config_name='key', value_type=int)

The default value in config is provided if no change has been made to the Web App Farmware input form.

The default input value type is int (integer). For string input, use a value_type of str.

See Hello Farmware Input for a complete working example.

Farmware manifest

To install a Farmware, you need to create a manifest.json file and host it. The manifest URL will be the URL used when installing the Farmware.

For example, entering https://raw.githubusercontent.com/FarmBot-Labs/hello-farmware/main/manifest.json and clicking install on the Farmware page of the Web App would install the Hello Farmware Farmware, whose source code is located at the GitHub project here.

The Farmware manifest format changed between FarmBot OS v7 and FarmBot OS v8. Be sure to use the manifest format that matches your FarmBot OS version, as shown below.

Farmware Manifest Example (FarmBot OS v8+):

{
 "package": "Hello Farmware",
 "language": "python",
 "author": "FarmBot, Inc.",
 "description": "A simple Farmware example that tells FarmBot to log a new message.",
 "farmware_manifest_version": "2.0.0",
 "package_version": "1.0.0",
 "farmbot_os_version_requirement": ">= 8.0.0",
 "url": "https://raw.githubusercontent.com/FarmBot-Labs/hello-farmware/main/manifest.json",
 "zip": "https://github.com/FarmBot-Labs/hello-farmware/archive/main.zip",
 "executable": "python",
 "args": "hello-farmware-main/hello.py"
}

zip points to the hosted source code zip file. Github makes this easy: just add /archive/main.zip to the end of the GitHub repository URL, and insert <repository name>-main/ to the beginning of the script filename to run, as seen in the manifest example above.

A Farmware manifest must be valid JSON and can be checked by any JSON parser or validator.

For additional manifest hosting methods, see Farmware Hosting and Workflows.

More about Farmware Tools

As shown in the examples on this page, a farmware_tools package comes pre-installed on FarmBot OS for ease of Farmware development.

Local Farmware development

To view a list of available commands, install farmware_tools on your computer,

pip install --user farmware_tools

and open a Python console (run python in a terminal window). In the Python console, type:

import farmware_tools
help(farmware_tools.device)

Also see help(farmware_tools.app) and help(farmware_tools.get_config_value)

An HTML interface of the function list is also available, but may be missing some information.

Install a specific version

While the latest version of farmware_tools is available for import in any Farmware when executed on FarmBot OS, you can install a specific version by specifying the version in the Farmware manifest:

Optional version specification (v8+):

{
  "package": "Farmware Name",
  // Other fields omitted for clarity (see the `Farmware manifest` section)
  "farmware_tools_version_requirement": ">= 3.3.0",
}

For local development you can install a specific version via pip install --user farmware_tools==3.3.0. Use pip install --user --upgrade farmware_tools to upgrade.

What’s next?