@jbonnard
That’s a great question. If you are using Typescript (or are willing to give it a try), FarmBotJS is fully typed, meaning that your editor would be able to provide you type hints for these sort of questions. Hovering over a function (or pressing f12
) would show the function’s definition, including the schema of expected inputs.
Feedback Welcome
You are one of the first developers to ask about this and we are eager to provide you with an API you would like to work with. With that being said, there are still some parts of FarmBotJS that could be improved, since it has mostly been used by FarmBot employees with knowledge of system internals. The use case you mention may be one of those cases.
I could provide an alternative API in FarmBotJS if you have any ideas you would like to share. Ideally, I think it would be nice if developers did not need to write CeleryScript by hand, since it can be a challenge to learn.
After reading this response, I would like to ask you the question: “What would a simpler FBJS API look like to you?”. I look forward to hearing your feedback.
In the future, if you are ever unsure about the capabilities of FarmBotJS, it is important to note that the FarmBot Web App was written with FarmBotJS. Anything that can be done with the Web App can be done with FarmBotJS. I am here to answer your questions.
Before We Get Started
I wrote developer documentation to help new developers get started. The documentation is written as a guide (rather than a reference), so it is best to read the documentation from start to finish.
The most important part would be the section on CeleryScript, as it directly relates to the question you are asking.
I’m happy to clarify any of the parts that you have questions about.
Q: “How do I use FarmBotJS in Node”?
I have written an example Node application here. Please let me know if you have any questions.
Q: “How do I apply parameters to a sequence?”
To answer your question quickly, I’ve provided a solution below.
const Farmbot = require("farmbot").Farmbot;
const mySequenceId = 2323;
const myFarmbot = new Farmbot({ token: "***" });
const myToolNode = { kind: "tool", args: { tool_id: 4545 } };
myFarmbot
.connect()
.then(() => {
myFarmbot.execSequence(mySequenceId, [
{
kind: "parameter_application",
args: {
label: "parent",
data_value: myToolNode
}
}
]);
});
Some Background Knowledge
Parameter passing is one of the more complicated parts of the application. Hopefully I am able to describe it properly. Here is some background information that will help you understand the system better.
Sequences offer a visual programming language. Programming languages are parsed into complex structures known as abstract syntax trees (ASTs).
When you edit a sequence in the Web App, you are editing the sequence AST directly. Behind the UI, there is a JSON tree structure that represents the sequence.
FarmBot sequence ASTs follow a strict JSON format known as “CeleryScript”. If you know how to read Typescript interfaces, you can see a description of all CeleryScript node types in this file.
You will need to write CeleryScript by hand to pass a parameter to a sequence. This is a moderately complex task and I am happy to work on simplified solutions. Feature requests welcome!
Line-by-Line Explanation
Assumptions:
- You have already generated an access token.
- The sequence you wish to execute has an id of
2323
.
- The tool you wish to pass to sequence
2323
has an ID of 4545
.
Let’s go through this line-by-line:
First, we pull down the FarmBotJS library and create some local variables with relevant information. In a real world application, you would probably find this information via the REST API.
const Farmbot = require("farmbot").Farmbot;
const mySequenceId = 2323;
const myFarmbot = new Farmbot({ token: "***" });
Now things get more interesting. Since you mentioned that you want to pass a tool to your sequence, we will need to create a tool using the CeleryScript AST. A CeleryScript tool node is not the same thing as the tool
resource you find in the REST API. You will use the tool_id
from the REST API, though.
const myToolNode = { kind: "tool", args: { tool_id: 4545 } };
It is important to note the variable name for later. We will add this CeleryScript tool to a CeleryScript parameter later on.
The next thing we need to do is connect to the server, then wait for success (via Javascript Promises)
myFarmbot
.connect()
.then(() => { /* Continued in next section... */ });
Once connected to the server, we need to call myFarmbot.execSequence()
. This is more complicated than a traditional call to execSequence()
because we are using parameters.
Here are some “secrets” about sequence parameters that might not be obvious if you have only used the sequence editor in the Web App:
- Sequence parameters are passed to a sequence using the CeleryScript
parameter_application
node.
-
paramter_application
nodes are placed into an array.
- The array of
parameter_application
s is passed in as the second argument to execSequence
.
- Every sequence variable must have a
label
. Since the Web App only allows one variable per sequence, the default label
for all sequences created in the sequence editor is parent
. If you want to edit this variable from the Web App, I suggest you keep the name parent
for your variable, otherwise you might not be able to see it from the UI.
- It is technically possible to have a multi-parameter sequence, but do so with caution as we have not tested this usecase much.
With that being said, we need to create an array with a paramter_application
pointing to our tool_id
of 4545
.
We use a parameter label of parent
, since that is the label that all sequences expect (if they were created within the Web App):
myFarmbot.execSequence(mySequenceId, [
{
kind: "parameter_application",
args: {
label: "parent",
/** Remember: `myToolNode` was defined above */
data_value: myToolNode
}
}
]);
Does this help? Please let me know.