A Touchy Subject

I made a thing:

Who knew you could make the touchbar actually do something useful!
It refreshes every 60s. I could put other goals there, but my goal spiht is by far the largest, requiring 4hrs of work each day.

8 Likes

I found a more appropriate field in the API, so now it looks like this:

2 Likes

You definitely should be using safesum for this! (Is that an extra space before the 6, or some fancy font spacing, or do I just need to sleep?)

2 Likes

Definitely! That’s the “more appropriate” field I switched to :slight_smile:

Indeed! Interesting. I do not know why the font is rendering this way. And that’s not just a screenshot thing – it’s rendered like this on the touchbar as well. Nicely observed!

Addendum: There is actually an additional space in the JSON of .safesum:

"+02:56 hours due by  8pm"

And once again for the renegade master:

{ echo -n 'SPIHT: ' & curl 'https://www.beeminder.com/api/v1/users/me/goals/spiht.json?auth_token=DEADBEEF&datapoints=false' 2> /dev/null | /usr/local/bin/jq '.safesum'; } | tr -d '\n' | tr -s ' '

This is the code I am using and which now takes care of the superfluous space that is returned by the API. This gets passed to a bash -c and the resulting string is then displayed in my Mac’s touchbar. I could instead return JSON which would allow me to dynamically change the text’s color, background, icon, … There is a lot of opportunity here. If interested I can export the whole thing for other users of BetterTouchTool (which is what is doing the touchbar magic)

3 Likes

Wow… How do you put the text to the touch bar?

1 Like

With BetterTouchTool :slight_smile:
It’s the swiss army knife for doing stuff like this.
Fun fact: it’s made by a single person in Germany, actually only two hours away from here.

4 Likes

When you get safesum for that goal, does it have the appropriate number of spaces?

1 Like

No, it does not:

"+03:59 hours due by  8pm"
1 Like

I integrated RescueTime and everything got an icon now :slight_smile:

(The now properly looking spacing in the safesum is because of tr -s ' ')

4 Likes

Turns out, RescueTime does not provide today’s productivity pulse, but only that of the past 14 days via their API. At first I thought that today would be included in that list, but no. It starts with yesterday. Which is what my touchbar is showing: Yesterday’s productivity pulse. No wonder it’s not changing :crazy_face: :man_facepalming:
That’s surprising giving that the current day’s pulse is the first thing you see on the dashboard and is also the only thing you see when you resize the window small enough.

However, they do provide a way to look at past events:

GET https://www.rescuetime.com/anapi/data?key={{apiKey}}&perspective=interval&restrict_kind=productivity&interval=hour&restrict_begin=2020-05-29&restrict_end=2020-05-29&format=json

which gives you this:

{
  "notes": "data is an array of arrays (rows), column names for rows in row_headers",
  "row_headers": [
    "Date",
    "Time Spent (seconds)",
    "Number of People",
    "Productivity"
  ],
  "rows": [
    [
      "2020-05-29T00:00:00",
      129,
      1,
      1
    ],
    [
      "2020-05-29T10:00:00",
      845,
      1,
      2
    ],
    [
      "2020-05-29T10:00:00",
      19,
      1,
      1
    ],
    …

I assume I can get a productivity pulse out of that myself since it’s just the average. Some quick and dirty Scala:

val productivitiesTimesSeconds = for {
  (_, seconds, _, productivity) <- rows
} yield seconds * productivity

val avg = Try(productivitiesTimesSeconds.sum / productivitiesTimesSeconds.length) // because div 0

val secondsRecordedL = for {
  (_, seconds, _, _) <- rows
} yield seconds

val secondsRecorded = secondsRecordedL.sum
val pulse = avg.map(_ / theoreticalMax * 100)

val msg = pulse match {
  case None => "No data logged for today!"
  case Some(p) => s"Your productivity pulse is $p"
}

println(msg)

def theoreticalMax = 2 * secondsRecorded

Haven’t tried that, since I actually got stuff to do and this is kinda distracting, but if someone here knows how the productivity pulse is calculated and can tell me if I’m going in the right direction, that would be swell!

3 Likes

Glad to see this thread! I’ve been meaning to share my own Beeminder TouchBar widget:

Mine is set up to…

  • Only appears while I’m scheduled to derail today (technically within the next 30 hours). Once I’ve cleared all my derailments, the widget disappears.
  • Shows the number of goals I’m going to derail on, and the total monetary fine if I derail on all of them. In the screenshot below, I have 3 goals that will derail tonight, for a total of $15.
  • Tapping the widget 1) opens my Beeminder page and 2) refreshes the widget
  • I have it set to automatically update every 5 minutes, but you can change that in BTT settings

You should be able to install it by downloading the preset here: https://github.com/dbyler/applescript-misc/raw/master/Beeminder%20Touch%20Bar%20Widget.bttpreset

To configure:

p.s. In the screenshot, the flag widget to the left of Beeminder shows how many flagged+available items I have in OmniFocus. There’s also a red one that will show up if there are Due items. Happy to share if there’s interest

4 Likes

The extra space should be fixed now.

3 Likes

Is there something similar for the menu bar for us lower people without touchbars?

3 Likes

@apolyton I think you mentioned this one before Beeminder for BitBar?

I actually found your post because of this one and tried BitBar. There is a plugin for BitBar I found related to beeminder (also you can check the code in github here)

Also I tweaked it a bit so it looks like this:


shows the nearest goal to derail in the menu bar. But the whole logic is credit for Ben. Thanks a lot Ben if you see this! :smile: https://getbitbar.com/contributors/bcongdon

This is the code tweaked I have in case you want it:

#!/usr/bin/python
# -*- coding: utf-8 -*-

# <bitbar.title>Beeminder</bitbar.title>
# <bitbar.version>v1.0</bitbar.version>
# <bitbar.author>Ben Congdon</bitbar.author>
# <bitbar.author.github>bcongdon</bitbar.author.github>
# <bitbar.image>https://i.imgur.com/XamwU1E.png</bitbar.image>
# <bitbar.desc>Displays your active Beeminder goals and their due dates/amounts</bitbar.desc>
# <bitbar.dependencies>python,requests</bitbar.dependencies>

import requests

# NOTE: Change these to set your credentials
USERNAME = 'your_username'
AUTH_TOKEN = 'your_api_key' # you can find it in https://www.beeminder.com/api/v1/auth_token.json

# Don't change anythine below this line
if not USERNAME or not AUTH_TOKEN:
  print('⚠️\n---\nBeeminder: No username and/or auth token provided!')
  exit(1)
API_URL = 'https://www.beeminder.com/api/v1/users/{}.json'.format(USERNAME)

req = requests.get(API_URL, params=dict(auth_token=AUTH_TOKEN, datapoints_count=1, associations=True))

data = req.json()
goals = data['goals']

output = '{} for {}|color={} font=Monaco\n---\n'.format(goals[0]['limsumdate'], goals[0]['slug'], goals[0]['roadstatuscolor'])
  
max_slug_len = max(len(goal['slug']) + 1 for goal in goals)

for goal in goals:
  if goal.get('coasting'):
    continue

  goal_url = 'https://www.beeminder.com/{}/{}'.format(USERNAME, goal['slug'])

  output += "{}".format(goal['limsumdate'].ljust(27)) + " {}".format(goal['slug'].rjust(21)) + "|href={} color={} font=Monaco\n".format(goal_url, goal['roadstatuscolor'])

print(output)

I remember I needed to install requests package for python using pip. This article might help you with that.

I’m trying also to get data from Rescuetime now. I found another plugin for it but I’m looking to get my daily time spent in a particular category instead of my productivity pulse. If you find a way to get that would it be cool!

2 Likes