I recently built a Messenger Bot. This is the fourth part in a series describing how I built it and what I learned.
After implementing Alexa, I realized that it wouldn’t be a huge step to do something similar on Messenger. After all, push notifications was my top requirement.
Thankful for tutorials
I had no experience building bots, let alone anything modern. It’s been over a decade since I graduated with my degree in Computer Science and I’ve never worked as a software engineer.
So I jumped straight into a step-by-step tutorial about building a Messenger bot on Heroku in Python. I know enough Python to be dangerous. I heard about this Heroku platform as a service thing for years and this was my chance to try it.
Heroku was a breeze to setup: creating keys, a CLI environment, integrating with git (I never used this before, just SVN). Then I created a Messenger bot, linked it to a Page and App, and auth’d it.
The next step was to hack the tutorial script and combine what I was able to do with the Alexa skill.
So I was able to pull solar data by manually executing python code in the CLI, but how would I push notify? How could I do this in the “free” dyno tier?
I had to figure out a data model for my bot so I could cache solar data. I didn’t want to have to query the Enphase API if I didn’t need to. The free developer tier has fairly low limits.
Creating a database and writing queries was the last thing I wanted to do. It’s also the thing I’m most experienced in over the last decade. So I googled around and all signs pointed to using a key-value store.
I discovered the redis revolution. Turns out this software is a big deal – there’s even a convention in SF about it. Of course, user turnkey Heroku offers a redis package that I simply had to add to my requirements.txt.
It’s pretty easy to store and retrieve in redis using hashed keys
hget(). I set it up using a Heroku worker so that it would run asynchronously and not stall the rest of the Python code.
So now I had some efficiency. How would I schedule notifications? How do I cache this data?
Caching solar power data in Redis
I scheduled a job to pull from the solar system API every 10 minutes and store in redis. That way it would avoid hitting the Enphase solar power API too often in case this bot becomes super popular or gets DOS’d (yeah right).
The essence is pulling from the solar power API and storing those values in Redis
r = redis.from_url(os.environ.get("REDIS_URL")) def setsolar(key,user_id,system_id): request = Request('https://api.enphaseenergy.com/api/v2/systems/' +system_id +'/summary?key=' +key +'&user_id='+user_id) response = urlopen(request) solar = json.loads(response.read()) r.hset(user_id,'energy_today',solar['energy_today']) r.hset(user_id,'current_power',solar['current_power'])
This was the easiest but most valuable part. I wanted to be notified once a day about my power output. How many Kilowatt hours I’m producing at the moment and how many I produced throughout the day.
Thinking back to my prior life as a Computer Science student, I started reading about cron jobs and other scheduling tools. Turns out Heroku offers a simple scheduling GUI that let’s you execute a script one-time or on a schedule.
Everyday at 11am, the Heroku worker hgets the most recent production data and packages that as a message:
r = redis.from_url(os.environ.get("REDIS_URL")) def getsolar(key,user_id,system_id): message = str(r.hget(user_id,'energy_today')) + "Wh were produced today. " + str(r.hget(user_id,'current_power')) + "W this moment." return message
This is what my conversation looks like. One message for each day, each with a push notification. It’s more of a monologue actually, but that will change.
Now I know my power
This bot solves for the 80/20 base case – I can confirm that my solar is working on a daily basis. It only does that one thing. I can’t pull weekly or monthly stats. I can’t ask it questions. It won’t work for anyone else’s solar system (yet).
I also haven’t uploaded my code to GitHub (this would be my first contribution).
Next post I’ll share what else I’m thinking of doing next. What ideas do you have? What’s obvious that I’m missing?