Farmware
FarmBot OS plugins
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.