Example: Node.js+CoffeeScript version of FarmBot-Python-Examples :: publish_example

As suggested by @RickCarlino, here is a loose translation from Python to Node.js ( in CoffeeScript )
of the publish_example.py program from FarmBot-Python-Examples suite.

#
#  A loose translation of the Python example 'publish_example.py'
#  in FarmBot-Labs/FarmBot-Python-Examples repository
#  to Node.js and CoffeeScript
#
#  John Simmonds 2019-11-13
#
#  Flow:
#     * Request a FarmBot web token
#     * Connect to the FarmBot MQTT server over Secure Web Sockets
#     * Subscribe to 1 topic
#     * Every 5 seconds, Publish a 'toggle_pin' RPC to 1 topic
#
#  Comment: At line 39, edit-in appropriate values for
#           Your current FarmBot WebApp Account credentials
#

mqtt = require 'mqtt'
util = require 'util'


cs_toggle_pin = JSON.stringify {
    "kind": "rpc_request",
    "args": {
        "label": "cb78760b-d2f7-4dd1-b8ad-ce0626b3ba53"
    },
    "body": [{
        "kind": "toggle_pin",
        "args": {
            "pin_number": 2
        }
    }]
}


# Fetch a FarmBot JWT via the FarmBot API

fb_api_client = (require 'restify-clients').createJsonClient {url: 'https://my.farm.bot'}
fb_api_client.post '/api/tokens', {"user":{"email":"farmbot-user","password":"farmbot-user-password-cleartext"}}, (err, req, res, obj) ->

    unless err
        util.log('Starting MQTT work')

        mqtt_client = mqtt.connect obj.token.unencoded.mqtt_ws, {username: obj.token.unencoded.bot, password: obj.token.encoded}
        mqtt_client.on 'connect', (connack) ->
            util.log "-- connect -- #{util.inspect connack}"

            mqtt_client.subscribe "bot/#{obj.token.unencoded.bot}/from_device", {}, (err, subs) ->
                util.log "  -- granted subs -- #{util.inspect subs, {depth: 6}}"

            pub_times = setInterval () =>
                mqtt_client.publish "bot/#{obj.token.unencoded.bot}/from_clients", cs_toggle_pin, {}, (err) ->
                    if err
                        util.log "  -- publish err -- #{util.inspect err, {depth: 6}}"
                    else
                        util.log "  -- publish to bot/#{obj.token.unencoded.bot}/from_clients"
               , 5000

        mqtt_client.on 'message', (topic, message, packet) ->
            util.log "-- message -- #{util.inspect topic}"
            util.log "  #{util.inspect JSON.parse(message.toString()), {depth: 6}}"

        mqtt_client.on 'reconnect', () ->
            util.log '-- re-connect --'
    else
        util.log "#{err}"
2 Likes

Thanks for sharing @jsimmonds!

For those who use vanilla JS, here’s the transpiled output. I did some minor cleanup since compiler output can be a bit “noisy” sometimes:


//  A loose translation of the Python example "publish_example.py"
//  in FarmBot-Labs/FarmBot-Python-Examples repository
//  to Node.js and CoffeeScript

//  John Simmonds 2019-11-13

//  Flow:
//     * Request a FarmBot web token
//     * Connect to the FarmBot MQTT server over Secure Web Sockets
//     * Subscribe to 1 topic
//     * Every 5 seconds, Publish a "toggle_pin" RPC to 1 topic

//  Comment: At line 39, edit-in appropriate values for
//           Your current FarmBot WebApp Account credentials

const mqtt = require("mqtt");

const { log, inspect } = require("util");

const cs_toggle_pin = JSON.stringify({
  kind: "rpc_request",
  args: { label: "cb78760b-d2f7-4dd1-b8ad-ce0626b3ba53" },
  body: [{ kind: "toggle_pin", args: { pin_number: 2 } }]
});

// Fetch a FarmBot JWT via the FarmBot API
const fb_api_client = (require("restify-clients"))
  .createJsonClient({ url: "https://my.farm.bot" });

fb_api_client.post("/api/tokens", {
  user: {
    email: "farmbot-user",
    password: "farmbot-user-password-cleartext"
  }
}, function (err, _req, _res, obj) {
  if (!err) {
    log("Starting MQTT work");

    const mqtt_client = mqtt.connect(obj.token.unencoded.mqtt_ws, {
      username: obj.token.unencoded.bot,
      password: obj.token.encoded
    });

    mqtt_client.on("connect", function (connack) {
      log(`-- connect -- ${inspect(connack)}`);

      mqtt_client.subscribe(`bot/${obj.token.unencoded.bot}/from_device`,
        {},
        function (_err, subs) {
          log(`  -- granted subs -- ${inspect(subs, {
            depth: 6
          })}`);
        });

      setInterval(() => {
        mqtt_client.publish(`bot/${obj.token.unencoded.bot}/from_clients`,
          cs_toggle_pin,
          {}, function (_err) {
            if (err) {
              log(`  -- publish err -- ${inspect(err, {
                depth: 6
              })}`);
            } else {
              log(`  -- publish to bot/${obj.token.unencoded.bot}/from_clients`);
            }
          });
      }, 5000);
    });

    mqtt_client.on("message", function (topic, message, packet) {
      log(`-- message -- ${inspect(topic)}`);
      log(`  ${inspect(JSON.parse(message.toString()), {
        depth: 6
      })}`);
    });

    mqtt_client.on("reconnect", function () {
      log("-- re-connect --");
    });
  } else {
    log(`${err}`);
  }
});

And for those like me, who are Linux cmd-liners, this little script executes CoffeeScript ( with transparent Compile and Run )

#!/usr/bin/env node
require('coffeescript/register');
module.exports = require('./publish_example');
1 Like