Farmware
FarmBot OS plug-Ins to expand FarmBot functionality
For Developers
This documentation is meant for Farmware developers. For use of Farmware in the Web App, see the FarmBot Web App Farmware documentation.
Alpha
Farmware should be considered experimental at this point in time. Some features may be unstable.
Examples
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.
Farmware can connect with FarmBot in the following ways:
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)
legacy GET:
import os
import requests
headers = {'Authorization': 'Bearer ' + os.environ['API_TOKEN'],
'content-type': "application/json"}
response = requests.get('https://my.farmbot.io/api/points', headers=headers)
points = response.json()
legacy GET 2:
#!/usr/bin/env python
'Get specific data (such as timezone) from the FarmBot Web App.'
import os
import requests
headers = {'Authorization': 'Bearer ' + os.environ['API_TOKEN'],
'content-type': "application/json"}
response = requests.get('https://my.farmbot.io/api/device', headers=headers)
device_data = response.json()
# Device timezone info (set via the dropdown in the Web App Device widget)
timezone_string = device_data['timezone']
tz_offset_hours = device_data['tz_offset_hrs']
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)
legacy:
import os
import requests
headers = {'Authorization': 'Bearer ' + os.environ['API_TOKEN'],
'content-type': "application/json"}
payload = {'pointer_type': 'Plant', 'x': 100, 'y': 200}
response = requests.post('https://my.farmbot.io/api/points',
headers=headers, json=payload)
new_plant = response.json()
output of add_plant (new_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: credentials and locations
Environment variables are used to get Farmware API information and special locations.
Python example:
import os
FARMBOT_OS_VERSION = os.environ['FARMBOT_OS_VERSION']
legacy:
import os
API_TOKEN = os.environ['API_TOKEN']
FARMWARE_URL = os.environ['FARMWARE_URL']
FARMWARE_TOKEN = os.environ['FARMWARE_TOKEN']
IMAGES_DIR = os.environ['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()
legacy:
import os
import requests
headers = {
'Authorization': 'bearer {}'.format(os.environ['FARMWARE_TOKEN']),
'content-type': "application/json"}
response = requests.get(os.environ['FARMWARE_URL'] + '/api/v1/bot/state',
headers=headers)
bot_state = response.json()
position_x = bot_state['location_data']['position']['x']
pin_13_value = bot_state['pins']['13']['value']
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/master/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': ''})
legacy:
import os
import requests
send_message = {
"kind": "send_message",
"args": {
"message": "Bot is at position , , .",
"message_type": "success"
},
"body": [
{
"kind": "channel",
"args": {
"channel_name": "toast"
}
}
]
}
headers = {
'Authorization': 'bearer {}'.format(os.environ['FARMWARE_TOKEN']),
'content-type': "application/json"}
payload = send_message
requests.post(os.environ['FARMWARE_URL'] + '/api/v1/celery_script',
json=payload, headers=headers)
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:
"package": "Farmware Name",
// Other fields omitted for clarity (see the `Farmware manifest` section)
"config": [
{
"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)
legacy:
import os
VALUE = os.environ['farmware_name_key']
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.
Currently supported languages and packages
- Python 3.7: opencv, numpy, requests, serial, farmware_tools
Python 3
FarmBot OS (v7+) now uses Python 3. Python 2 is no longer supported.
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/master/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.
Farmware Manifest Example:
"package": "Hello Farmware",
"language": "python",
"author": "FarmBot, Inc.",
"description": "A simple Farmware example that tells FarmBot to log a new message.",
"version": "1.0.0",
"min_os_version_major": 6,
"url": "https://raw.githubusercontent.com/FarmBot-Labs/hello-farmware/master/manifest.json",
"zip": "https://github.com/FarmBot-Labs/hello-farmware/archive/master.zip",
"executable": "python",
"args": ["hello-farmware-master/hello.py"]
zip
points to the hosted source code zip file. Github makes this easy: just add /archive/master.zip
to the end of the GitHub repository URL, and insert <repository name>-master/
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 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:
"package": "Farmware Name",
// Other fields omitted for clarity (see the `Farmware manifest` section)
"farmware_tools_version": "v3.0.0",
For local development you can install a specific version via pip install --user farmware_tools==3.0.0
. Use pip install --user --upgrade farmware_tools
to upgrade.