Welcome to Watering My Digital Plant with Emacs Timers, a talk by Christopher Howard for Emacs Conference 2024.
The goal of this talk is to give a brief introduction to Emacs Timers using the illustration of how I created a bot for the Astro Botany service.
What is Astrobotany?
Let me jump to the home page.
Astrobotany is a botany game or a simulation that is played using the Gemini protocol and gem text documents.
What is Gemini?
The Gemini protocol is a small web protocol, similar to the Hypertext transfer protocol, but with differing goals of simplicity, non-extensibility, and protecting privacy.
Gemtext is a simple hyperlinking document format, the analog of the Hypertext markup language, or HTML.
Much more could be said about the design and goals of the Gemini project, but that is not the focus of this talk.
And how do you play Astro Botany?
First, you need to get a Gemini client or what you might call a browser.
Many clients are available, but I am using Elfer, a Gemini client for Emacs.
Once you have your client running, navigate to the home page for Astra Botany, which is shown in this window.
You'll see the URL for the home page displayed at the top of the window.
On your first visit to Astra Botany, you will need to create a client certificate, which will be used instead of a password.
Your Gemini client will help you to create the certificate.
Then you will go to the Visit Your Plant page in order to view your plant, to water it, and to collect things from it, including money.
So here you see the plant that I'm currently growing in glorious ASCII graphics.
There's also a color version available from this page.
Back at the home page, you can do other things like go to the item shop,
to buy items like badges, fertilizer, or post on the message board.
In Astrobotany, gardener bots are fully legal.
And to do an action on your plant, like watering the plant, all your bot needs to do is to access the appropriate Gemini URL or page while presenting the appropriate certificate for your plant.
and this brings us to Emax Timers.
So the main function of interest to us is the run at time function.
Here is the help documentation, which is available in any recent EMACS installation.
As you see, the purpose of the function is to perform an action at a specific time to repeat it after a specific number of seconds.
And so basically, all you have to do is pass in a function to run at time, telling Emacs how soon you want to run the function, and then how often you want to run the function after that.
The function has a variety of options for specifying the time parameter, that is, how soon you want the function to run.
For our application, in which we'll be running our functions once or twice a day at specific times, it is most useful to specify the number of seconds until the event.
This does, however, require calculating the number of seconds until a specific time of day.
I will provide code for this shortly.
The run a time function does allow you to specify the time parameter as a string, representing the hours and minutes.
For example, 05 colon 40.
However, there is an oddity in the design of run at time, such that if the specified time of day has already passed, then the timer will run immediately, rather than in the future, as you might expect.
This can be problematic, for example, if run at time is being called from your init file, since the timer will run immediately every time you restart Emacs for any reason.
I noticed recently that run at time also allows you to pass in a value from encode time.
which maybe does what we want, but I never bothered with testing that.
Actually, I have a vague memory of once looking into it and it didn't seem to do what I wanted, but honestly I can't clearly remember, so you may want to look into that yourself.
What I ended up using was just passing in a number of seconds.
So now we'll move over to the code.
So I'll skip down here first to the code that I wrote for calculating the number of seconds.
It's a function that calculates the number of seconds until a particular time of day in the future.
You can see that you pass in the hour as a number from 0 to 23 and the minutes as a number from 0 to 59.
And here's the code, which will also be available later.
I wrote another function, seconds until weekly, which we do not need for this talk, but which is useful if you're running events which need to happen once per week.
This function also requires a target hour and a target minute, but also requires passing in a target day.
And while we're on the subject of timers specifically, I should mention that Emacs has a very useful function called list timers.
So if I call the interactive function list timers, it will give me a list of all the timers currently running.
This page shows not only which timers exist, but also how long it will be until they run again, along with the periodic repeat value that you specified.
Furthermore, any timer can be canceled by moving point over the timer
and running timer list cancel, which on my system is bound to the letter C by default.
This is very helpful while you are developing some timer function.
So I could cancel the timer that I already have running for shaking the plant, as well as the one for watering the plant.
and back to the code.
So now we'll talk about the actual code for managing the plant.
So you see I have a variable set up here that specifies where the certificate file, the public certificate file, as well as the secret key file is located.
This is where it is in my system.
Of course, depending on your specific Gemini client, it may be in a different space and will likely have a different name.
And here is the code for watering the plant, which I can call interactively.
And the core of it here is that it uses the GMNI utility, command line utility to call a particular URL while also loading up or presenting the required certificate.
So in this case, you can see it is the URL that is required for watering the plant.
This idea is very simple and the GMNI client or GMNI command line program makes this very simple to do.
Here's another function for shaking the plant.
Again it is almost identical except that we use a different URL.
One for shaking the plant instead of watering it.
And again we want to shake the plant in order to get money to fall off of it.
You need to water your plant at least once per day or it'll die.
and I usually water mine twice and just in case something happens where I e-max was turned off because of power outage or something like that that I'm more likely to get it watered and I shake it once per day because there isn't any purpose to shaking it more than that if you try to shake it more than that then money no more money will fall off or not much
So you see down here I have the code that actually calls run at time.
I left here commented my original forms of this which used the just specify directly the time of day.
As I mentioned the problem with that was that it would these functions would also get called whenever I restarted Emacs for any reason and that was kind of annoying.
So instead we have here the functions down here which uses seconds until daily.
to water the plant and then seconds until daily to shake the plant.
You see, I've specified the plant to get watered at 4 in the morning and then the function is run again after that every 43,200 seconds which translates to every 12 hours and then I shake the plants, shake the plant
every morning at 4.15 a.m.
and once every 12 hours.
With a little bit more sophistication, a little bit more work on the code, I could actually have multiple plants be watering and shaking multiple plants with multiple certificates, but I never got around to that.
Didn't seem worth the bother to me.
so thank you for watching my video watering my digital plant with the max timers you'll see at the bottom of this page links to the code for this talk as well as other things that I mentioned like the
source code for the Elfer Gemini client, the URL for the Astro Botany capsule, as well as a link to more information about Project Gemini and my own personal Gemini capsule that's being run off my own server at home.
Thank you very much.