Technology Solutions for Everyday Folks
Slack Tempest WeatherBot App Home tab display with current conditions and daily statistics

Expanding Interactivity with the Tempest WeatherBot

In the last post I wrote about the basics of building the Slack Tempest WeatherBot and its basic set of command arguments. This post builds on those commands with an overview of expanding the Slack interactivity by adding a bot app home tab.

Why More Interactivity?

While the slash command functionality was useful, especially to see summarized data for a period (e.g. /weather last month), folks in the workspace had to remember the command arguments...and that seemed less than awesome. The idea was to make it easy to interact with the station/data...which meant eliminating as much "remembering" as possible for basic usage.

I discovered that the Slack bot had built-in capacity to curate an "app home" tab which, on load, could be used to automatically populate the current stats, basic forecast, and so on.

As the bot is built on a lot of cached or file-based data (this becomes important later), adding interactivity doesn't necessarily impact the overall performance or "force" unnecessary API calls. Keep in mind Slack requests require a response within a few seconds of the request, so anything the bot is expected to do must happen with a fairly quick turnaround.

But...The Data Doesn't Scale Well

As a uni-tasker, the initial version of the bot code never dealt with multiple sets of data beyond the interaction with Tempest observations (or forecast responses). Adding functionality like the app home changed this scope dramatically. It was necessary to convert the Tempest responses to an object-based model for both consistency and simplicity reasons. Everything coming out of Tempest would be handled as an object, and could be processed or formatted accordingly. This conversion also reduced and eliminated a boatload of duplicate code that was going to be coming down the pipe without such a change.

With the TempestObservation class in place, I could much more easily generate and maintain block structure specific to observations and the data...and just clean up a lot of the other crap and technical/maintenance debt that had already accumulated. Furthermore, the reduction in code and overhead kept the bot responding per Slack's requirements.

A Whole New World (of Blocks)

Building an app home tab itself was pretty trivial, but it added several components to the bot source, specifically the ability to respond to "events" which is different than responding to slash command requests. Further, the Block structure for the app home tab is different than for an individual message.

The first step was to consolidate the app home bits into one Thing: in this case, a set of functions intended to handle the curation of the app home. The "request handler" for the slash command was fine, but it was designed to uni-task: it took argument(s) and responded accordingly with data. That did not translate or scale up to handling multiple things without a serious rewrite. I always had a couple of things in the development queue through the process, so a major re-architecture was going to draw away from any other progress...and my intent with the project was always about the journey and building something cool...not architecting the perfect solution.

Once the app home bits were consolidated and a request triggered, the resulting block structure is included in the JSON payload sent to Slack and looks a bit like this:

Screenshot of a large chunk of JSON-formatted data representing the block structure for Slack app home payload

What About In-Place Refresh?

As the bot app home tab came into production, a more practical feature came into view: how to refresh the data without having to totally re-load the tab (which in Slack requires clicking on something else and then returning to the app home tab)? Enter another responder process: the interactive listener.

In this case, the interactive listener "endpoint" is also a uni-tasker: it only responds to the event created when the refresh_data action is encountered (set in the details for the refresh button in the Block source). Fortunately, the rest of the process is basically a call back to re-generate the app home content (a trigger "identical" to clicking into the tab). Voila!

Massive Improvement in Usability

I discovered pretty quickly that it was super helpful to have the app home tab functionality in place. Not only was it a "one stop location" for common queries (current conditions, short-term forecast, today's stats, etc.), it almost totally eliminated most of the routine commands I was invoking manually. Not to mention it's just cool.

Screenshot of Tempest WeatherBot App Home screen with current conditions, daily summary, and daily/multi-day/hourly forecast detail

As a result, I found myself only using slash commands for specific purposes, like /weather last month to get the monthly average temperature (which I use for my energy use PowerBI report)...or when looking for specific history or forecasts. Thanks to the /weather help command, I also didn't have to use muscle memory to remember any of the other stuff I'd made in the original iteration.

Great, but What's Next?

As I built these features, I also wanted to include stuff from other/external sources, most specifically the National Weather Service (NWS) API for alerts and forecasts. In the next post, I detail adding that functionality to the bot.

Headline image of App Home tab via Matt Zaske