Giter Site home page Giter Site logo

farmbot-js's Introduction

npm ci Coverage Status

FarmbotJS: Farmbot RPC wrapper

Browser Support

Works on all modern browsers that were released in the last 12 months.

NodeJS Support

Independent developers have reported success when using FarmBotJS in a Node environment, but we do not test against Node based setups, nor do we (FarmBot, Inc) use FarmBotJS in a production Node environment. Issue reports related to NodeJS are highly appreciated.

Installation (NPM)

npm install farmbot

Installation (Vanilla JS)

<script src="https://cdn.jsdelivr.net/npm/farmbot@latest/dist/farmbot_single_file.js"></script>
<script>
  var farmbot123 = new fbjs.Farmbot({ token: "foo.bar.baz" });
</script>

Running the Test Suite (Advanced)

npm run test

Other Package Managers

Please raise an issue if you require support with other package managers.

Login with an API Token

Login using your API token from the Farmbot Web App.

Click here for instructions on how to generate an API token.

Example:

import { Farmbot } from "farmbot";

var SUPER_SECRET_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ0ZXN0MTIzQHRlc3QuY29tIiwiaWF0IjoxNDU5MTA5NzI4LCJqdGkiOiI5MjJhNWEwZC0wYjNhLTQ3NjctOTMxOC0xZTQxYWU2MDAzNTIiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAvIiwiZXhwIjoxNDU5NDU1MzI4LCJtcXR0IjoibG9jYWxob3N0IiwiYm90IjoiYWE3YmIzN2YtNWJhMy00NjU0LWIyZTQtNThlZDU3NDY1MDhjIn0.KpkNGR9YH68AF3iHP48GormqXzspBJrDGm23aMFGyL_eRIN8iKzy4gw733SaJgFjmebJOqZkz3cly9P5ZpCKwlaxAyn9RvfjQgFcUK0mywWAAvKp5lHfOFLhBBGICTW1r4HcZBgY1zTzVBw4BqS4zM7Y0BAAsflYRdl4dDRG_236p9ETCj0MSYxFagfLLLq0W63943jSJtNwv_nzfqi3TTi0xASB14k5vYMzUDXrC-Z2iBdgmwAYUZUVTi2HsfzkIkRcTZGE7l-rF6lvYKIiKpYx23x_d7xGjnQb8hqbDmLDRXZJnSBY3zGY7oEURxncGBMUp4F_Yaf3ftg4Ry7CiA";

let bot = new Farmbot({ token: SUPER_SECRET_TOKEN });

bot
  .connect()
  .then(function () {
    return bot.moveRelative({ x: 1, y: 2, z: 3, speed: 100 });
  });

Sending Commands to a Farmbot Object

bot
  .connect()
  .then(function(bot){
    console.log("Bot online!");
    return bot.emergencyStop(); // You can chain commands.
  })
  .then(function(bot){
    console.log("Bot has stopped!");
  })
  .catch(function(error) {
    console.log("Something went wrong :(");
  });

Basic RPC Commands

Call RPC commands using the corresponding method on bot. All RPC commands return a promise.

Example:

bot
  .home({ axis: "x", speed: 800 })
  .then(function (ack) {
    console.log("X Axis is now at 0.");
  })
  .catch(function (err) {
    console.log("Failed to bring X axis home.");
  })

Currently supported commands:

See the annotated type definitions for available methods and properties.

Using Events

  var bot = Farmbot({ token: '---'});
  bot.on("eventName", function(data, eventName) {
    console.log("I just got an" + eventName + " event!");
    console.log("This is the payload: " + data);
  })
   // "I just got an eventName event!"
   // "This is the payload: any javascript object or primitive"
  bot.emit("eventName", "any javascript object or primitive");
  var eventHandlers = bot.event("eventName");
   // [function(){...}]

Routine Events

  • "status": Most important. When the REMOTE device state changes (eg: "x" goes from 0 to 100), the bot will emit this event.
  • "logs": The bot will send logs to this channel.
  • "offline": Connection lost. Note: FarmbotJS will try to auto-reconnect.
  • "online": Client is connected and subscribed to bot.
  • "sent": Triggered when the application begins sending a message.
  • "sync": A resource on the API has changed.

Special Events

  • <random uuid>: RPC commands have UUIDs when they leave the browser. When the bot responds to that message, FarmbotJS will emit an event named after the request's UUID. Mostly for internal use.
  • "malformed": When the bot gets a bad RPC command, it will notify you via this channel.
  • *: Catch all events (for debugging).

Q: Where do I report security issues?

We take security seriously and value the input of independent researchers. Please see our responsible disclosure guidelines.

farmbot-js's People

Contributors

amilajack avatar connorrigby avatar gabrielburnworth avatar phrohdoh avatar rickcarlino avatar roryaronson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

farmbot-js's Issues

Verbose event logging required

To allow other developers maximum usefulness from building apps with FarmBotJS, it's imperative that it has a verbose event logging system which apps can tap into.

Proposing a new eventName : 'verbose', which FarmBot can use to log an entire range of internal state changes and actions. Each of these events is emitted with a verbosity level that increases when the events become less ambiguous. I've written an example below.

Proposed event structure

verbose events should have the same structure across all levels.

{
	verbosity : 3,
	ancestors : 1,
	created_at : '2017-05-12T14:58:10Z',
	type : 'command',
	payload : {
		commandName : 'move_absolute',
		speed : 800,
		x : 0,
		y : 0,
		z : 0,
		xOffset : 0,
		yOffset : 0,
		zOffset : 0
	},
	message : "Absolute move to 200,400,0"
}

Example

Consider this pseudo-sequence for watering a couple of carrots:

  • Starting sequence Water The Carrots
    This is the message of a verbose event with verbosity : 1. It indicates a top-level event. If your app is only listening on verbosity-level 1, it only gets this message, and one more when the sequence finishes (that'd also be a verbosity : 1 event).
  • Moving to 60,225,100
    This is verbosity : 2, because it's an individual sequence command.
  • Executing sequence Attach Watering Tool
    Similar to the previous event, this is also a verbosity : 2 event, because a sequence can execute another sequence as one of its commands. Now something interesting can happen:
  • Starting sequence Attach Watering Tool
    Because this is a sequence of its own, it will emit a verbosity : 1 event. But your app might not be interested in nested sequences at all. This is where ancestors : 1 comes in. Each nested sequence adds one ancestor to its events. So your app could be interested in all verbosity 1 and 2 events, but only from the root sequence. So it would ignore any events with ancestors higher than 0.
  • Relative move to 0,0,100
    If the move event above is a verbosity : 2 event, this would be a verbosity : 3 event originating from the same action. You give an app the opportunity to listen for general moves (just destination) or specific moves. Basically, a level 3 move complements a level 2 move event by telling you how it's going to reach that destination.
{ verbosity : 1, ancestors : 0, message : 'Starting sequence "Water The Carrots".' }
{ verbosity : 2, ancestors : 0, message : 'Executing sequence "Attach Watering Tool".' } // called by parent sequence "Water The Carrots"
{ verbosity : 1, ancestors : 1, message : 'Starting sequence "Attach Watering Tool".' }  // stepping into child sequence "Attach Watering Tool"
{ verbosity : 2, ancestors : 1, message : 'Moving to 2532,1230,0.' }
{ verbosity : 3, ancestors : 1, message : 'Homing Z-Axis.' }
{ verbosity : 3, ancestors : 1, message : 'Relative move to 0,0,-230.' }
{ verbosity : 3, ancestors : 1, message : 'Homed Z-Axis.' }
{ verbosity : 2, ancestors : 1, message : 'Moving to 60,225,0.' }
{ verbosity : 3, ancestors : 1, message : 'Absolute move to 60,225,0.' }
{ verbosity : 2, ancestors : 1, message : 'Moving to 60,225,493.' }
{ verbosity : 3, ancestors : 1, message : 'Relative move to 0,0,493.' }
{ verbosity : 2, ancestors : 1, message : 'Moving to 85,225,493.' }
{ verbosity : 3, ancestors : 1, message : 'Relative move to 25,0,0.' }
{ verbosity : 2, ancestors : 1, message : 'Moving to 85,225,0.' }
{ verbosity : 3, ancestors : 1, message : 'Homing Z-Axis.' }
{ verbosity : 3, ancestors : 1, message : 'Relative move to 0,0,-493.' }
{ verbosity : 3, ancestors : 1, message : 'Homed Z-Axis.' }
{ verbosity : 1, ancestors : 1, message : 'Finished sequence "Attach Watering Tool".' }  // last event from child sequence
{ verbosity : 2, ancestors : 0, message : 'Executed sequence "Attach Watering Tool".' }  // we're back in parent sequence "Water The Carrots"
{ verbosity : 2, ancestors : 0, message : 'Executing sequence "Water Carrot Row One".' } // called by parent sequence "Water The Carrots"
{ verbosity : 1, ancestors : 1, message : 'Starting sequence "Water Carrot Row One".' }  // stepping into child sequence "Water Carrot Row One"
{ verbosity : 2, ancestors : 1, message : 'Moving to 200,200,0.' }
{ verbosity : 3, ancestors : 1, message : 'Absolute move to 200,200,0.' }
{ verbosity : 2, ancestors : 1, message : 'Executing sequence "Medium Water".' }         // called by parent sequence "Water Carrot Row One"
{ verbosity : 1, ancestors : 2, message : 'Starting sequence "Medium Water".' }
{ verbosity : 2, ancestors : 2, message : 'Activating Peripheral "Solenoid Valve".' }
{ verbosity : 3, ancestors : 2, message : 'Writing Pin 9. Value is now 1.' }
{ verbosity : 2, ancestors : 2, message : 'Waiting.' }
{ verbosity : 3, ancestors : 2, message : 'Wait 2300 milliseconds.' }
{ verbosity : 2, ancestors : 2, message : 'Deactivating Peripheral "Solenoid Valve".' }
{ verbosity : 3, ancestors : 2, message : 'Writing Pin 9. Value is now 0.' }
{ verbosity : 1, ancestors : 2, message : 'Finished sequence "Medium Water".' }
{ verbosity : 2, ancestors : 1, message : 'Executed sequence "Medium Water".' }          // we're back in parent sequence "Water Carrot Row One"
{ verbosity : 2, ancestors : 1, message : 'Moving to 200,300,0.' }
{ verbosity : 3, ancestors : 1, message : 'Absolute move to 200,300,0.' }
{ verbosity : 2, ancestors : 1, message : 'Executing sequence "Medium Water".' }         // called by parent sequence "Water Carrot Row One"
{ verbosity : 1, ancestors : 2, message : 'Starting sequence "Medium Water".' }
{ verbosity : 2, ancestors : 2, message : 'Activating Peripheral "Solenoid Valve".' }
{ verbosity : 3, ancestors : 2, message : 'Writing Pin 9. Value is now 1.' }
{ verbosity : 2, ancestors : 2, message : 'Waiting.' }
{ verbosity : 3, ancestors : 2, message : 'Wait 2300 milliseconds.' }
{ verbosity : 2, ancestors : 2, message : 'Deactivating Peripheral "Solenoid Valve".' }
{ verbosity : 3, ancestors : 2, message : 'Writing Pin 9. Value is now 0.' }
{ verbosity : 1, ancestors : 2, message : 'Finished sequence "Medium Water".' }
{ verbosity : 2, ancestors : 1, message : 'Executed sequence "Medium Water".' }          // we're back in parent sequence "Water Carrot Row One"
{ verbosity : 2, ancestors : 1, message : 'Moving to 200,400,0.' }
{ verbosity : 3, ancestors : 1, message : 'Absolute move to 200,400,0.' }
{ verbosity : 2, ancestors : 1, message : 'Executing sequence "Medium Water".' }         // called by parent sequence "Water Carrot Row One"
{ verbosity : 1, ancestors : 2, message : 'Starting sequence "Medium Water".' }
{ verbosity : 1, ancestors : 2, message : 'Activating Peripheral "Solenoid Valve".' }
{ verbosity : 1, ancestors : 2, message : 'Writing Pin 9. Value is now 1.' }
{ verbosity : 1, ancestors : 2, message : 'Waiting.' }
{ verbosity : 1, ancestors : 2, message : 'Wait 2300 milliseconds.' }
{ verbosity : 1, ancestors : 2, message : 'Deactivating Peripheral "Solenoid Valve".' }
{ verbosity : 1, ancestors : 2, message : 'Writing Pin 9. Value is now 0.' }
{ verbosity : 1, ancestors : 2, message : 'Finished sequence "Medium Water".' }
{ verbosity : 2, ancestors : 1, message : 'Executed sequence "Medium Water".' }          // we're back in parent sequence "Water Carrot Row One"
{ verbosity : 1, ancestors : 1, message : 'Finished sequence "Water Carrot Row One".' }
{ verbosity : 2, ancestors : 0, message : 'Executed sequence "Water Carrot Row One".' }  // we're back in parent sequence "Water The Carrots"
{ verbosity : 2, ancestors : 0, message : 'Executing sequence "Water Carrot Row Two".' }
{ verbosity : 1, ancestors : 1, message : 'Starting sequence "Water Carrot Row Two".' }
{ verbosity : 2, ancestors : 1, message : 'Moving to 200,200,0.' }
{ verbosity : 3, ancestors : 1, message : 'Absolute move to 200,200,0.' }
{ verbosity : 2, ancestors : 1, message : 'Executing sequence "Medium Water".' }
{ verbosity : 1, ancestors : 2, message : 'Starting sequence "Medium Water".' }
{ verbosity : 2, ancestors : 2, message : 'Activating Peripheral "Solenoid Valve".' }
{ verbosity : 3, ancestors : 2, message : 'Writing Pin 9. Value is now 1.' }
{ verbosity : 2, ancestors : 2, message : 'Waiting.' }
{ verbosity : 3, ancestors : 2, message : 'Wait 2300 milliseconds.' }
{ verbosity : 2, ancestors : 2, message : 'Deactivating Peripheral "Solenoid Valve".' }
{ verbosity : 3, ancestors : 2, message : 'Writing Pin 9. Value is now 0.' }
{ verbosity : 1, ancestors : 2, message : 'Finished sequence "Medium Water".' }
{ verbosity : 2, ancestors : 1, message : 'Executed sequence "Medium Water".' }
{ verbosity : 2, ancestors : 1, message : 'Moving to 200,300,0.' }
{ verbosity : 3, ancestors : 1, message : 'Absolute move to 200,300,0.' }
{ verbosity : 2, ancestors : 1, message : 'Executing sequence "Medium Water".' }
{ verbosity : 1, ancestors : 2, message : 'Starting sequence "Medium Water".' }
{ verbosity : 2, ancestors : 2, message : 'Activating Peripheral "Solenoid Valve".' }
{ verbosity : 3, ancestors : 2, message : 'Writing Pin 9. Value is now 1.' }
{ verbosity : 2, ancestors : 2, message : 'Waiting.' }
{ verbosity : 3, ancestors : 2, message : 'Wait 2300 milliseconds.' }
{ verbosity : 2, ancestors : 2, message : 'Deactivating Peripheral "Solenoid Valve".' }
{ verbosity : 3, ancestors : 2, message : 'Writing Pin 9. Value is now 0.' }
{ verbosity : 1, ancestors : 2, message : 'Finished sequence "Medium Water".' }
{ verbosity : 2, ancestors : 1, message : 'Executed sequence "Medium Water".' }
{ verbosity : 2, ancestors : 1, message : 'Moving to 200,400,0.' }
{ verbosity : 3, ancestors : 1, message : 'Absolute move to 200,400,0.' }
{ verbosity : 2, ancestors : 1, message : 'Executing sequence "Medium Water".' }
{ verbosity : 1, ancestors : 2, message : 'Starting sequence "Medium Water".' }
{ verbosity : 1, ancestors : 2, message : 'Activating Peripheral "Solenoid Valve".' }
{ verbosity : 1, ancestors : 2, message : 'Writing Pin 9. Value is now 1.' }
{ verbosity : 1, ancestors : 2, message : 'Waiting.' }
{ verbosity : 1, ancestors : 2, message : 'Wait 2300 milliseconds.' }
{ verbosity : 1, ancestors : 2, message : 'Deactivating Peripheral "Solenoid Valve".' }
{ verbosity : 1, ancestors : 2, message : 'Writing Pin 9. Value is now 0.' }
{ verbosity : 1, ancestors : 2, message : 'Finished sequence "Medium Water".' }
{ verbosity : 2, ancestors : 1, message : 'Executed sequence "Medium Water".' }
{ verbosity : 1, ancestors : 1, message : 'Finished sequence "Water Carrot Row Two".' }
{ verbosity : 2, ancestors : 0, message : 'Executed sequence "Water Carrot Row Two".' }
{ verbosity : 2, ancestors : 0, message : 'Executing sequence "Detach Watering Tool".' }
{ verbosity : 1, ancestors : 1, message : 'Starting sequence "Detach Watering Tool".' }
{ verbosity : 2, ancestors : 1, message : 'Moving to 200,400,0.' }
{ verbosity : 3, ancestors : 1, message : 'Homing Z-Axis.' }
{ verbosity : 3, ancestors : 1, message : 'Relative move to 0,0,0.' }
{ verbosity : 3, ancestors : 1, message : 'Homed Z-Axis.' }
{ verbosity : 2, ancestors : 1, message : 'Moving to 85,225,0.' }
{ verbosity : 3, ancestors : 1, message : 'Absolute move to 60,225,0.' }
{ verbosity : 2, ancestors : 1, message : 'Moving to 85,225,493.' }
{ verbosity : 3, ancestors : 1, message : 'Relative move to 0,0,493.' }
{ verbosity : 2, ancestors : 1, message : 'Moving to 60,225,493.' }
{ verbosity : 3, ancestors : 1, message : 'Relative move to -25,0,0.' }
{ verbosity : 2, ancestors : 1, message : 'Moving to 60,225,0.' }
{ verbosity : 3, ancestors : 1, message : 'Homing Z-Axis.' }
{ verbosity : 3, ancestors : 1, message : 'Relative move to 0,0,-493.' }
{ verbosity : 3, ancestors : 1, message : 'Homed Z-Axis.' }
{ verbosity : 1, ancestors : 1, message : 'Finished sequence "Detach Watering Tool".' }
{ verbosity : 2, ancestors : 0, message : 'Executed sequence "Detach Watering Tool".' }
{ verbosity : 1, ancestors : 0, message : 'Finished sequence "Water The Carrots".' }

Events picked up by an app listening to verbosity : 2, ancestors : 0

This is basically an app which sees the top-level sequence execute, command by command:

  1. Starting sequence "Water The Carrots".
  2. Executing sequence "Attach Watering Tool".
  3. Executed sequence "Attach Watering Tool".
  4. Executing sequence "Water Carrot Row One".
  5. Executed sequence "Water Carrot Row One".
  6. Executing sequence "Water Carrot Row Two".
  7. Executed sequence "Water Carrot Row Two".
  8. Executing sequence "Detach Watering Tool".
  9. Executed sequence "Detach Watering Tool".
  10. Finished sequence "Water The Carrots".

Events picked up by an app listening to verbosity : 1, ancestors : 4

This app only sees key events (does not see individual sequence actions like move or write pin or execute, but it will listen to events from any nested actions up to 4 layers deep:

  1. Starting sequence "Water The Carrots".
  2. Starting sequence "Attach Watering Tool".
  3. Finished sequence "Attach Watering Tool".
  4. Starting sequence "Water Carrot Row One".
  5. Starting sequence "Medium Water".
  6. Finished sequence "Medium Water".
  7. Starting sequence "Medium Water".
  8. Finished sequence "Medium Water".
  9. Starting sequence "Medium Water".
  10. Finished sequence "Medium Water".
  11. Finished sequence "Water Carrot Row One".
  12. Starting sequence "Water Carrot Row Two".
  13. Starting sequence "Medium Water".
  14. Finished sequence "Medium Water".
  15. Starting sequence "Medium Water".
  16. Finished sequence "Medium Water".
  17. Starting sequence "Medium Water".
  18. Finished sequence "Medium Water".
  19. Finished sequence "Water Carrot Row Two".
  20. Starting sequence "Detach Watering Tool".
  21. Finished sequence "Detach Watering Tool".
  22. Finished sequence "Water The Carrots".

Deps outdated

Updated farmbot latest from NPMJS.com ( v13.1.0 ) and then did npm install to a fresh directory for my app.
Got trouble with jest and ts-jest versioning 🔢 as picture shows . . also mqtt has had a major version update (f.w.i.w.)

Screenshot from 2021-04-02 15-19-43

project showcase MQTT from openhab

Here´s a sample call to trigger a sequence from a .rules file in openhab2:

You only need to exchange XXX below in the device_XXX with your device number and
call up the correct sequence id in:
"args": {"sequence_id":"7817"}

msg_payload = '{
"kind": "rpc_request",
"args": {
"label": "cb77760b-d2f7-4dd1-b8ad-ce0626b3ba43"
},
"body": [{
"kind": "execute",
"args": {"sequence_id":"7817" }
}]
}'
publish("fb", "bot/device_XXX/from_clients", msg_payload)

With this sample below, you can read pin 64 inside a .items file in openhab2:

Number pin_64 "[%d]" (gFarmBot, gReadings) {mqtt="<[fb:bot/device_XX/status:state:JSONPATH($.pins.64.value):.*]"}

Turn on light

Hi there, having difficulty turning on the farmbot lightstrip. its on pin number 7.

currently im using the following but it dosent work

function toggleLight() {
  var farmbot123 = new fbjs.Farmbot({ token: TOKEN });

  farmbot123
  .connect()
  .then(function () {
    return farmbot123.togglePin({7});
  });
}

I can take photos and move the farmbot, so my connection and API are fine

Execute a sequence by sending CeleryScript

Hi, is it possible to execute a sequence by simply sending the CeleryScript?

Currently, the way I execute them is by:

  1. Creating a script and sending it to store in the sequences folder. Which looks like this:
var celeryScript = { "kind": "wait", "args": { "milliseconds": 1000 } };
var sequenceName = "testName";
var settings = {
  "url": "https://my.farmbot.io/api/sequences",
  "method": "POST",
  "timeout": 0,
  "headers": {
    "Authorization": "Bearer " + TOKEN,
    "Access-Control-Allow-Origin": "*",
    "Content-Type": "application/json"
  },
  "data": JSON.stringify({
    "color": "red",
    "name": sequenceName,
    "pinned": false,
    "kind": "sequence",
    "body": [
      celeryScript
    ]
  }),
};

$.ajax(settings).done(function (response) {
  console.log(response);
});
  1. Then I grab the response and retrieve the ID of the newly generated sequence.
  2. Then I execute the sequence by its ID. This is how it looks:
var farmbot123 = new fbjs.Farmbot({ token: TOKEN });

	farmbot123
	.connect()
	.then(function () {
		return farmbot123.execSequence(NewSequenceID);
	}).then(function(farmbot123){
    console.log("Bot has stopped!");
  })
  .catch(function(error) {
    console.log("Something went wrong :(");
  });

So I was wondering if I could cut to the chase and simply send Celeryscript for it to execute? Thanks

Packaging support for running this lib in the browser

Hi,

Looking to do a simple FarmBot front end for "management" to use when showing our clients :)

Thinking it would be a single page app, with a login box and then some buttons to trigger a few sequences.

I could do it via direct calls using ajax myself, but since this lib is in place, it seems the way to go.

Don't care which package manager - don't do much front end generally. Bower, browserify, yarn, jspm etc.

In fact, if packaging is not needed - please let me know :)

Thanks, Chris

Send log using web

Hi, this time im using the web file, Im looking to send a log to my farmbot. How is this done, the documentation is a bit confusing.

Thanks

Disconnecting Farmbot mqtt connection

For a project I am automating the farmbot to execute tasks automatically via a cloud server solution.
For this project I'd like to be able to stop the mqtt connection which is created with the farmbot.connect method.
Is this possible and if so what is the best way to do so?

Unicode characters not properly decoded

In _onmessage (used by Farmbot.connect), the buffer is decoded one byte at a time. Unicode characters may use multiple bytes, resulting in garbled text when non-English characters are displayed in logs (and in other messages received from the broker).

const original = bufferToString(buffer);

farmbot-js/src/util.ts

Lines 18 to 22 in 37503da

export function bufferToString(buffer: Uint8Array) {
const chars: string[] = [];
buffer.forEach(x => chars.push(String.fromCharCode(x)));
return chars.join("");
}

For example, a buffer with the following values

var buffer = new Uint8Array([229, 144, 141])

is decoded by bufferToString as

�

The correct text can be obtained by something like

var decoder = new TextDecoder("utf-8");
decoder.decode(buffer)

Cannot use import statement outside a module (NodeJS)

Hi, I'm working with a group to make an open source project that makes a 3D render of the garden through photogrammetry.

It is my understanding that I first have to:

  1. Download the FarmbotJS file from github
  2. Extract it
  3. open visual studio code, start new terminal
  4. execute this command npm install farmbot
  5. then execute this command npm run test (This command fails for me btw)
  6. Then to run the first example code, i create a new file in the root of the farmbotJS directory that i recently downloaded and extracted, i called this file example.js and then I pasted these lines inside the file (I Changed the token to mine, as it works with the python API for farmbot)
import { Farmbot } from "farmbot";

var SUPER_SECRET_TOKEN = "eyJ....7CiA";

let bot = new Farmbot({ token: SUPER_SECRET_TOKEN });

bot
  .connect()
  .then(function () {
    return bot.moveRelative({ x: 1, y: 2, z: 3, speed: 100 });
  });
  1. Then in the visual studio code terminal, I ran example.js
  2. Then I get the error
PS C:\Users\Owner\Desktop\farmbot-js-main> node .\example.js
(node:14300) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
C:\Users\Owner\Desktop\farmbot-js-main\example.js:2
import { Farmbot } from "farmbot";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at wrapSafe (internal/modules/cjs/loader.js:1053:16)
    at Module._compile (internal/modules/cjs/loader.js:1101:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)
    at Module.load (internal/modules/cjs/loader.js:985:32)
    at Function.Module._load (internal/modules/cjs/loader.js:878:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
    at internal/main/run_main_module.js:17:47
PS C:\Users\Owner\Desktop\farmbot-js-main>

Heres a screenshot:
error

Could you please help me with this? im looking to make a nice youtube tutorial for this once I get it working, so others can also follow the video steps to make it work,

thanks in advance!

Regards,
Wathik

js api executeSequence requires ID..but where to get?

I have my nodeJS client working now and I can do almost all I want to do...except starting sequences.

The "executeSequence" requires an ID according to the farmbot.d.ts
/** Execute a sequence by its ID on the API. */
execSequence(sequence_id: number): Promise<{}>;

But how I can find the ID of a sequence? The sequences are not listed in the "getState" or in the getStatus.

The WebUI also does not show the sequence ID.

Is this missing in the API or am I overlooking something?

Thanks
Chris

Need to handle errors in Farmbot.proto.publish

Source of the Uncaught Error: Not connected to server errors.

Spotted this today while writing a test:

(node:23271) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Not connected to server
(node:23271) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Poking around led me to this:

    Farmbot.prototype.publish = function (msg) {
        if (this.client) {
            this.client.publish(this.channel.toDevice, JSON.stringify(msg));
        }
        else {
            throw new Error("Not connected to server");
        }
    };

Node JS issue: ReferenceError: atob is not defined

Problem:

Running in a Node environment creates the following error:

ReferenceError: atob is not defined
    at Farmbot._decodeThatToken

Fix

npm install atob --save

then before loading farmbot-js:

global.atob = require("atob");

Does this library work with the current OS/cloud platform?

Hi,

When I try to connect today, I get a timeout:

(node:47641) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Failed to connect to MQTT after 30000 ms.

Get something similar via a browserified old version:

WebSocket connection to 'wss://brisk-bear.rmq.cloudamqp.com/' failed: Error during WebSocket handshake: Unexpected response code: 200
WebSocketStream @ farmbot-browserified.js:13511
buildBuilderBrowser @ farmbot-browserified.js:12753
wrapper @ farmbot-browserified.js:12592
MqttClient._setupStream @ farmbot-browserified.js:11766
MqttClient._reconnect @ farmbot-browserified.js:12094
(anonymous) @ farmbot-browserified.js:12109

I appreciate that the move to RabbitMQ has begun and so this probably just needs to catch up... but thought I'd check :)

Thanks.

Trouble compiling or running in browser

First of all: I love the Farmbot!

My company is in the IoT business and I would like to connect the Farmbot to our IoT Solution.
Also I am super happy to see that you embrace TypeScript - which we also use for our JS engine.

but...

I cannot get the JavaScript libraries to work correctly in a (chrome) browser.
According to your readme - only a browser with WebSockets, JSON and native Promise is required - all three is available in Chrome.

Still it fails to run. Can you list the other requirements needed?
For example:
MQTT is required
ATOB is required
what else is missing?

It loads and works fine in NodeJS but I don't want to carry around this huge amount of NodeJS...schtuff:)

could you create a sample project that runs (with as little code/libraries as possible)?
Eventually I will run this in C# but before I convert the project, I like to see it run in a browser first.

Thanks,
Chris
C-Labs

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.