Hammerspoon: Toggl API Calls and Secret Tokens

I use Hammerspoon to enhance my OSX with custom UI and automations, while also creating "monotasking" deep work environments to keep me focused.
Ok… I'm really excited to show you the tool in the next post, but some context has to be laid first.
Toggl
I've experimented with toggl for time tracking on and off for over a year now. My current methodology is lifted and modified from CGPGrey's comments in Cortex Ep. 101. To summarize his thoughts…
Grey is always running a timer, usually from Timery on iOS. He uses the act of choosing a timer as a moment of intention: "what am I intending to do?" He retroactively marks time spent unintentionally (e.g. ending up on social media instead of writing) as "bad." Periodically he will check the reports in Toggl, using the color coding to judge how much time he is spending on what moves the needle.
I really like the idea of timing as a means of intentionality. I haven't been timing my whole day, but the past month or two I've been experimenting with using time tracking next to my Focus Budget. I've isolated a few work activities that I highly value, and I'm attempting to graph how much time per week I spend on those high-value activities.

Here is last week's report from toggl... light blue is things like meetings and time spent in slack/email. Dark blue is the activities I've decided will "move the needle."
I have a lot of room to grow. 🙇
And of course, this lends itself to automation, so I started writing a toggl.lua. (I was really surprised I couldn't find anything on github!) So it's time to hit some REST APIs with Hammerspoon!
An earlier version of this module used the curl
executable, but once again Hammerspoon's handy stdlib has a hs.http
library that works perfectly.
module.start_timer = function(project_id, description)
local key = module.key()
hs.http.asyncPost(
"https://www.toggl.com/api/v8/time_entries/start",
hs.json.encode(
{
['time_entry'] = {
['description'] = description,
['pid'] = project_id,
['created_with'] = 'hammerspoon'
}
}
),
{
["Content-Type"] = "application/json; charset=UTF-8",
["Authorization"] = "Basic " .. hs.base64.encode(key .. ":api_token")
},
function(http_number, body, headers)
print(http_number)
print(body)
end
)
end
Between hs.json
and hs.base64
, writing a simple toggl client was really fun and easy!1 I wrote some other functions, but they pretty much all follow the same structure.
Now I have the ability to start, stop, and view the current timer from within my Hammerspoon setup!
Handling secrets via json
As I got into writing the code for toggl.lua, I realized I needed an easy way to get secrets like API keys into memory. I started with a simple file loading system, then realized that hs.json
is perfect for this.
Here is the entire module.
module = {}
module.start = function()
hs.settings.set("secrets", hs.json.read(".secrets.json"))
end
return module
Yep. Isn't that beautiful? I could add some error handling for when the file doesn't exist and such, but it's simple enough. As it is, it supports inserting a nested table into hs.settings
that you can access from any module.
Here's an example of a .secrets.json for my uses...
{
"standupURL": "http://evantravers.com",
"standupCall": "https://meet.google.com/respect-op-sec",
"toggl": {
"key": "<my key>",
"projects": {
"communications": "123456789",
"meetings": "123456789",
"planning": "123456789",
"reading": "123456789",
"design": "123456789",
"research": "123456789",
"play": "123456789",
"leadership": "123456789"
}
}
}
I can access any of these keys using dot notation... like:
hs.settings.get('secret').toggl.key
.
To wrap that up and add some error handling, I have some small abstractions like this one:
module.key = function()
if hs.settings.get("secrets").toggl.key then
return hs.settings.get("secrets").toggl.key
else
print("You need to load a Toggl.com API key in to hs.settings under secrets.toggl.key")
end
end
hs.settings
is a cool little module for some shared state. It's even persistent between sessions if you want.
Well… we are nearly at the finish line. If you are still reading these posts, thanks. I'm glad there's another person who cares. I have been so excited to share the next idea with y'all…
-
I should say… I really dislike lua as a language, but the two modules I've written here almost make me like it a little. ↩
Changelog
-
2022-06-08 11:31:29 -0500Rename articles
-
2020-09-28 09:20:43 -0500Change repo name
I decided to change the name of my hammerspoon configuration repo to
`hammerspoon-config` to avoid confusion... it's not the actual
hammerspoon executable, it's a configuration for that executable. -
2020-06-18 14:26:02 -0500Move everything to CST
Don't know why I didn't do that before. It caused _no_ end of
problems. -
2020-06-14 15:51:50 -0500Update articles with series and series partials
After the refactor, needed to move the series metadata to the actual
name. -
2020-06-13 15:41:50 -0500Try to reduce the scrollbar
-
2020-06-13 08:53:29 -0500Post: Toggl API and Secrets