BrewFather Batch status

Shows the current status of your batch fermentation in BrewFather.

Image preview of BrewFather Batch status plugin.

brewfather-batch-status.15m.js

Edit
Open on GitHub
#!/usr/local/bin/node

// <xbar.title>BrewFather Batch status</xbar.title>
// <xbar.version>v1.0</xbar.version>
// <xbar.author>Joost Slijkoort</xbar.author>
// <xbar.author.github>JoostSlijkoort</xbar.author.github>
// <xbar.desc>Shows the current status of your batch fermentation in BrewFather.</xbar.desc>
// <xbar.dependencies>node</xbar.dependencies>
// <xbar.image>https://i.imgur.com/bJuU1Xp.png</xbar.image>

//  <xbar.var>string(VAR_USERID="ABCWHATEVER"): Your user ID, you see it when creating an API key.</xbar.var>
//  <xbar.var>string(VAR_APIKEY=123WHATEVER): Your API key.</xbar.var>

if(!process.env.VAR_USERID || !process.env.VAR_APIKEY) {
  console.log('🚱 please fill in your credentials in the plugin settings.');
  return;
}

const https = require('https');

const userid = process.env.VAR_USERID;
const apiKey = process.env.VAR_APIKEY;
const options = {
  headers: {
    'Authorization': 'Basic ' + Buffer.from(userid + ':' + apiKey).toString('base64')
  }
}

let brews = [];

function fetchBatchDetails(id) {
  return new Promise((resolve, reject) => {
        https.get(`https://api.brewfather.app/v1/batches/${id}/readings/last`, options, (res) => {
          let responseBody = '';

          res.on('data', (chunk) => {
            responseBody += chunk;
          });

          res.on('end', () => {
            const responseJSON = JSON.parse(responseBody);
            resolve({...responseJSON, _id: id});
          })

        }).on('error', (e) => {
          reject(e);
        });
    });
}

function getProgressPercentage(max,min,v) {
  const progress = (max - v) / ((max - min) / 100);
  return Math.round(progress * 10) / 10;
}

function mapBatchProgress(batches, batchProgresses) {
  return batches.map(batch => {
      const matchingProgress = batchProgresses.find((batchProgress) => batchProgress._id == batch._id);
      const sg = matchingProgress.sg;

      return {
        ...batch,
        progressPercentage: getProgressPercentage(batch.measuredOg || batch.estimatedOg, batch.estimatedFg, sg),
        sg,
      }
    }
  )
}

function fetchBatches() {
  https.get('https://api.brewfather.app/v1/batches?status=Fermenting&include=estimatedFg,estimatedOg,measuredOg', options, (resp) => {
    let data = '';

    // A chunk of data has been received.
    resp.on('data', (chunk) => {
      data += chunk;
    });

    // The whole response has been received. Print out the result.
    resp.on('end', () => {
      batches = JSON.parse(data);

      if(batches.length < 1) {
        console.log(':beer: No batches')
        return;
      }

      Promise.all(batches.map(v => fetchBatchDetails(v._id))).then((batchProgresses) => {
        const completeMap = mapBatchProgress(batches, batchProgresses);
        const titleString = completeMap.map(v => `${v.recipe.name}@${v.sg} (${v.progressPercentage}%)`).find((v, i) => i == 0);

        if(completeMap.length === 1) {
          console.log(`:beer: ${titleString}|dropdown=false`);
          return;
        }

        const contentString = completeMap.map(v => `\n${v.recipe.name}@${v.sg} (${v.progressPercentage}%)`).filter((v, i) => i > 0).join('');

        console.log(`:beer: ${titleString}|dropdown=false \n---${contentString}`);

      })
    });

  }).on("error", (err) => {
    console.log(':beer:Error|dropdown=false \n---\n ' + err.message);
  });
}

fetchBatches()