Create a Pomodoro timer using Golang

Do you find yourself getting distracted or overwhelmed during work? The Pomodoro technique is a time management method that can help you stay focused and productive. It involves breaking your workday into 25-minute work sessions, followed by 5-minute breaks. After four work sessions, you take a longer break. This technique can help you stay focused, avoid burnout, and increase productivity. I’m in the pursuit to learn Go and I have been building small projects. You may have read my Password Generator CLI utility tutorial, this is the next step in my journey. I want to make a wellness-type application at the end of all this, so I wanted to experiment and make a Pomodoro timer that plays a sound after every iteration.
In this tutorial, we’ll create a simple Pomodoro timer using Go. Our timer will have 25-minute work sessions and 5-minute breaks, with four work sessions in total. We’ll play a sound at the end of each work and break session to indicate when it’s time to switch.
To play sounds in Go, we’ll use the “github.com/faiface/beep” library. This library allows us to load and play audio files like WAV or MP3. Full code and imports are at the bottom of the tutorial.
Before we get started, we need to download the sound library.
go get -u github.com/faiface/beepFirst, let’s define our work session and break durations and the number of Pomodoros we want to complete. We’ll set these to 25 minutes, 5 minutes, and 4 Pomodoros, respectively:
workDuration := 25 * time.Minute
breakDuration := 5 * time.Minute
numPomodoros := 4Next, we’ll loop through each Pomodoro and start a work session, followed by a break session. In each session, we’ll start a timer and wait for it to finish. After the timer finishes, we’ll play a sound to indicate that it’s time to switch to the next session, to get a beep sound audio file, you can download a wav file here.
for i := 0; i < numPomodoros; i++ {
fmt.Println("Starting work session...")
startTimer(workDuration)
playSound("beep.wav")
fmt.Println("Starting break session...")
startTimer(breakDuration)
playSound("beep.wav")
}To start the timer, we’ll create a new timer with the specified duration and wait for it to finish:
func startTimer(duration time.Duration) {
timer := time.NewTimer(duration)
<-timer.C
fmt.Println("Time's up!")
}The code below simply loads in an audio file using the OS library then decodes it to a wav file and initializes the speaker with the sample rate and buffer size of the audio data. The buffer size is set to one-tenth of a second. If there is an error while initializing the speaker, it will cause the program to panic and terminate. We assign a boolean channel called done and play the sound. After the sound is done, we assign it to true, then done.
func playSound(soundFile string) {
f, err := os.Open(soundFile)
if err != nil {
panic(err)
}
s, format, err := wav.Decode(f)
if err != nil {
log.Fatal(err)
}
defer s.Close()
err = speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
if err != nil {
panic(err)
}
done := make(chan bool)
speaker.Play(beep.Seq(s, beep.Callback(func() {
done <- true
})))
<-done
}Finally, after all the Pomodoros are complete, we’ll print a message to congratulate the user on their hard work:
fmt.Println("All done! Good job!")let's see it in action:

Awesome, it works! I have this set to 1-minute working, 1-minute break, and 2 cycles for testing purposes. I cannot show the beeping functionality via the blog, but it does beep.

And that’s it! With just a few lines of code, we’ve created a simple Pomodoro timer using Go. You can modify this code to suit your needs, such as changing the session durations or playing different sounds. Remember, the Pomodoro technique is all about staying focused and avoiding burnout, so take breaks and practice self-care as needed. Happy coding!
Full Code:
package main
import (
"fmt"
"time"
"os"
"log"
"github.com/faiface/beep"
"github.com/faiface/beep/speaker"
"github.com/faiface/beep/wav"
)
func main() {
workDuration := 25 * time.Minute
breakDuration := 5 * time.Minute
numPomodoros := 4
for i := 0; i < numPomodoros; i++ {
fmt.Println("Starting work session...")
startTimer(workDuration)
playSound("beep.wav")
fmt.Println("Starting break session...")
startTimer(breakDuration)
playSound("beep.wav")
}
fmt.Println("All done! Good job!")
}
func startTimer(duration time.Duration) {
timer := time.NewTimer(duration)
<-timer.C
fmt.Println("Time's up!")
}
func playSound(soundFile string) {
f, err := os.Open(soundFile)
if err != nil {
panic(err)
}
s, format, err := wav.Decode(f)
if err != nil {
log.Fatal(err)
}
defer s.Close()
err = speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
if err != nil {
panic(err)
}
done := make(chan bool)
speaker.Play(beep.Seq(s, beep.Callback(func() {
done <- true
})))
<-done
}




