Planting Trees with Good Habits and Bad Code

Setting up a personal tree-planting API with Habitica, DigitalHumani, and WeForest

My brain, as anyone who knows me well can attest, is prone to inspiration and, consequently, distraction. This means that, in order to get things done, I rely on external aides to assist me in breaking tasks down, following through on each step, and delivering the final thing.

This is not unusual among STEAMy folks, therefore systems like Kanban boards have become popular in the tech industry (and would probably be helpful if adopted by other STEM). I have used a variety of systems to help keep my projects in order and could happily recommend a few, and warn off a few others.

Last year I started using Habitica, and overall it's been a positive experience. I could complain that their early-game experience is far more compelling than the later-game “collect all these pets” or “grind bosses to earn money to buy stuff” bits, but half the point of Habitica is that you're meant to try and team up with others and build accountability and camaradie, which provides the true motivation. I've been using it with one of my daughters and find that it's great to have that external, semicasual form of accountability and motivation to get things done.

However, it would also be cool if I could pull in other kinds of external motivators, so that I'd feel even more satisfied ticking off otherwise inane things in my Habitica Dailies and TODO columns, and to keep on top of my good habits, avoiding the bad ones.

I'm not very good of thinking up external rewards to provide myself in this regard. A lot of the things that would really feel like a reward to me, like “Hours of Uninterrupted Hacking on Interesting Problems” are not actually attainable whether or not I feel I've earned them, because I have kids. I'm too purist to reward myself with things I consider bad for me. I don't have many vices that aren't bad for me.

One reward that would appeal to me is to improve the world in some material way, and what better way than to help mitigate the effects of climate collapse? If the grind of paying to survive under capitalism were not necessary, that's what I'd be doing full-time right now, after all, but perhaps there's a way to turn that grind into at least token action against looming mass extinction?

First-Pass Concept: Private Mini Webapp

I considered building a little daemon that I could run somewhere that could be triggered to deduct cash from my Habitica account and direct real money to an environmental service somewhere.

The first problem was that there are surprisingly few orgs out there who offer automated ways to receive payment for environmental causes. Thankfully, there's at least one group who “get” that this would be a good thing to have, so I chose DigitalHumani for this. I did check in with some other tree-planting groups that offer APIs and they literally just stopped responding when they heard that I wasn't an Airline buying indulgences or whatever. So, thanks DigitalHumani, for humouring me so far! :)

Looking at Habitica's API though.. it's OK, but the API is kinda all over the place, usability wise. I didn't really feel like building something to handle.. all that, and trying to make it consistent, especially as some of the docs appeared to represent a transitional state between API versions and were possibly outdated. I'll probably develop something for the API for other purposes but it felt like too much overhead, here.

However, Habitica supports Webhooks albeit with poor documentation. You can provide an endpoint, and when (some!) things happen in your Habits/Dailies/TODO/Reward columns, a POST containing a JSON event will be sent to your desired endpoint. Cool!

Problem is, I had no way to receive Webhooks, yet. Typically, people use untrustworthy, proprietary, Five-Eyes hosted services for setting up Webhooks and gluing stuff together, which is Not Okay with me.

Second-Pass Concept: Webhook to MQTT

Now that I knew I was looking at a Webhooking scenario, it offered a nice trivial case to develop a solution that had been nagging me lately. I have an MQTT service running for other purposes (I use Zigbee2MQTT to control some home automation stuff), and it can integrate into all sorts of other fun things like Home Auto servers (e.g. OpenHab) and visual-programming environments like Node-Red.

So, I figure it would be cool to receive Webhooks and direct them into an MQTT topic, where other applications can subscribe and react to the message Queue and set their own Quality of Service needs, etcetera.

I went looking, and found a few pet projects that came close, but none met the following basic requirements:

  • Receive Webhooks and dump as much metadata as possible into the topic so the HTTP context is preserved.
  • Dump the data into a caller-specified topic, BUT…
  • …under a server-configured top-level topic, so callers can't attack other MQTT topics! Seriously otherwise someone who picks up the Webhook URL could start posting ‘blindly’ into well-known topic trees like Zigbee2MQTT's, and cause some trouble.

Most of the existing tools failed on the third one, which I felt was a big oversight and security flaw.

So, long story short, I ended up building my own little server in Rust. It's still very beta-grade and the code needs tidying and documenting, but you can find it over at wh2mqtt if you feel like experimenting.

Armed with this and a reverse proxy to mount it on a long, random URL for further obfuscation and security, I was able to set up some secure-ish looking compound URLs that I could provide to Habitica and start receiving notifications.

Aside: DigitalHumani

So, now that I could receive notifications from Habitica, that meant that I could start doing fun things like using custom rewards to trigger things. Time to look into my effectors: DigitalHumani, the “Reforestation as a Service” folks.

The workflow for DigitalHumani (who offer the service completely for free, by the way) looks like this:

  • With your ‘enterprise ID’ and an API key, you make a request to an endpoint of theirs, choosing one of several projects run by third-party reforestation services. In the request you name your ‘user’, apparently by just providing an arbitrary string or email address. There's no workflow to ‘add’ users, DigitalHumani just log things under the specified string you provide with each tree-planting request. The API is very clean and lightweight, like that.
  • DigitalHumani log the request, issue the planting request to the service, and the end-service are then responsible for invoicing you for the tree-planting at their own pace. DigitalHumani do not store payment details of any kind and have no further involvement, making the workflow very clean at the integration end.
  • At any later point, DigitalHumani's API lets you query for summary info on the ‘enterprise’ and on the ‘users’, so you can collect data like how many trees you or others in your group have planted. Cool!

Armed with this, integration should be straightforward. A little service needs to listen on the wh2mqtt topic for incoming Habitica events, filter for a custom reward that plants a tree, and issue requests to DigitalHumani to plant the tree. At a later point, you'll be invoiced by the tree-planting project for the cost of doing so, at USD$1 per tree.

Integration through Caddy, wh2mqtt, MQTT, and Node-Red

For fun and for visuals, let's look at how this could be set up.

MQTT: Mosquitto

Setting up MQTT is left as an exercise to the reader: in Ubuntu, the “Mosquitto” MQTT server ought to be just an apt install away and possibly a service configuration, but lots of guides exist. You should be able to get this going quickly on nearly any machine running Ubuntu or Debian, so a single-board computer would do in a pinch.

wh2mqtt

Setting up wh2mqtt is something that, in theory, could be done directly on the open internet, though I would recommend using a fronting web-server and reverse-proxying through a long random URL for a little extra safety. wh2mqtt is based on Rocket and should be pretty performant, not that it will matter in this case. It will not work unless it can successfully connect to the target MQTT server, and it does not support all kinds of MQTT configuration, right now. A standard, localhost MQTT server on the usual unencrypted port is the default and should work out of the box. Configure your service so that wh2mqtt starts after mosquitto (or your preferred MQTT server).

In your Rocket.toml config for wh2mqtt, let's imagine that you define your mqtt_base_topic as wh2mqtt/webhooks.

Server: Caddy

For a fronting server, I prefer Caddy, which by default will handle automatic HTTPS certificate issuance through Let's Encrypt, and has a straightforward, low-legacy-baggage config format that's fairly well documented. Any server can be used here, but in Caddy a config for your wh2mqtt server running at localhost:9080 might look as simple as:

mydomain.com {
  # Note the random path: if you use something like "/webhooks"
  # it will be easy to guess for a spammer, DOS attacker, hacker, etc.
  proxy /kjnwvuyohi81239d98awk3lj54 localhost:9080/publish { 
    without "/kjnwvuyohi81239d98awk3lj54"
    transparent
  }
}

Those three should give you the ability to provide URLs like https://mydomain.com/kjnwvuyohi81239d98awk3lj54/habitica-87ynboacf543jkladf as Webhook URLs in Habitica, and have your Habitica events start appearing in MQTT at the topic: wh2mqtt/webhooks/habitica-87ynboacf543jkladf/data (the data from the full HTTP request appears at the base Webhook path, but /data gives you just the body, which in this case is the JSON string). You can then consume this data somehow to make Trees appear..

Effector: Node-Red

You could in this case whip up a small Python script to subscribe to that feed, filter for the event of interest (consider using the event ID so you can freely rename it or change details without breaking your integrations!). However, for a more visual blogpost, let's imagine that you set up Node-Red and use that.

Warning: Node-Red is a JS based webapp that lets you define arbitrary code that executes with Node-Red's permissions. Even if they pretended it were safe to expose this on the web, I would tell you that it is not. But even the Node-Red folks warn that it cannot be exposed to the open web safely. So don't! Localhost or LAN access only, lock it down as well as you can.

That said, Node-Red is convenient because it lets you jump between dropping input nodes on a canvas, linking them with little data-flow lines, and then writing the crunchier bits in Javascript (ew, but it beats relying on templating) to glue it all together. Some of the built in nodes include the ability to make HTTP requests.

So, let's see a few images showing this glued together:

habitica-screenshot-rewardscolumn
nodered-screenshot-habiticafilters
nodered-screenshot-treeplantingflow

Result!

At the end, I have a little reward set up in my Habitica that directs a small donation to WeForest with each purchase, priced approximately according to the real-money value of the “Gold” you can earn in Habitica (approximated against “Gems” which can be purchased for real money).

If I keep my habits, then I can reward myself periodically by having a tree planted in Ethiopia, close to the Equator for maximum climate impact, and planted in food and produce forestry projects for maximum human value. I might never see the Trees, but I do get to post my little triumph automatically to our Party chat in Habitica to offer encouragement to my Habitica Comrades.

 Share, if you like. Fediverse sharing is preferred, though.