#Writing my own watchface

Some time ago, I bought a Pebble Time 2. It's one of the dumbest smartwatches you can buy. Functionality is limited. It has an e-paper screen with two colors (black and white).

However, it can be fully programmed. It also has notifications, decent battery life and can communicate with the mobile phone over Bluetooth. The fact that it's programmable makes it very appealing for me. I can write my own watchface with the information I want easily available.

The heavy lifting is done by the mobile phone. The mobile does requests to external API's on the watches' behalf. Once results are ready, it is forwarded to the watch using Bluetooth.

flow.png
Watch receives messages from the mobile app. The mobile app receives data from external API's such as Home Assistant (departure times, calendar events) and met.no (for weather).

#Knowing the next tram departure

One thing that I would like my watch to show is the next departure for my current location. If I am home, I want to see the next departure from the local tram station towards the city centre. When I'm at work, I want to know the next departure going home.

To achieve this, I've configured several Entur sensors in Home Assistant. Every 30 seconds, it fetches the next departure in the appropriate direction. Home Assistant also has my current GPS-coordinates1. That way, I always know what the closest tram location is.

map
Three stops registered in Home Assistant. You are closest to stop number 2, so that's what gets displayed on the watch. The next departure is in 11 minutes

I've given the mobile app API keys to my Home Assistant instance. On the mobile app, fetching states from Home Assistant looks something like the code snippet below. Notice that we have to use XMLHttpRequest. The JS runtime Pebble uses is quite old.

function fetchDeparture() {
  var req = new XMLHttpRequest();  // yes, really. it's 2026.

  req.onload = function() {
    var data = JSON.parse(req.responseText);
    // HA sensor returns minutes until next departure
    var minutes = parseInt(data.state);
    var stop = data.attributes.stop_name;

    // Send over Bluetooth to the watch
    Pebble.sendAppMessage({
      'Minutes': minutes,
      'StopName': stop
    });
  };

  req.open('GET', HA_URL + '/api/states/sensor.ruter_closest');
  req.setRequestHeader('Authorization', 'Bearer ' + HA_TOKEN);
  req.send();
}

#Knowing the next meeting

I also have an ICS file for my work calendar in Home Assistant. That lets me read the next calendar events at work. I peridocally fetch the next calendar event, and display it on the watch. The meeting room is also displayed.

Three minutes before the meeting starts, the watch gives me a gentle reminder with a small vibration. Just enough time for me to wrap up things and get prepare another cup of coffee before entering the room.

The beauty of being able to program these things yourself is that three minutes plus a vibration is perfect for me. If I figure out I want five minutes, it's pretty straightforward to change to that. Want a different vibration pattern? Also customizable.

#Letting Claude do the implementation

I would lie if I told you I wrote the code. I asked Claude to read the documentation and find some reference projects. The Pebble SDK even has an emulator, making local development easier.

The workflow was something like this: I provided a prompt + a drawing to Claude. He wrote the code and updated the emulator, took screenshot and iterated until it looked fine. This went on for a few hours until we were both somewhat happy with the functionality and layout.

Most of the time was spent on moving pixels around and rendering text. Claude figured out the data fetching relatively quickly. Having Claude take screenshots to compare results was just fun to watch.

tldr.png
End result. In addition to showing time and date, we show the next departure, weather, meeting, battery and number of steps walked.

#A note on battery life

Initially I had pretty aggressive polling on the mobile phone for fetching data. That drained battery life, so I resorted to fetching calendar and weather events much more rarely (every 15 minutes and hour, respectively. Up from every 30 seconds). Similarly, during idle times, we fetch departure times every 2 minutes and when I've interracted with the watch (clicking on some buttons), we temporarily fetch every 30 seconds for 10 minutes. The idea is that when I intend to catch the tram and want to know when it departs, I'll fetch a bit more often.

battery.png
70 000 packets in 13 hours drains the battery life on the mobile phone

#Going forward

Honestly, I'm pretty happy with this setup. Knowing departure times, weather and calendar events without having to open the phone is really great.


  1. Home Assistant runs on a a small server at home and is exposed through a Cloudlare tunnel. Sharing GPS-coordinates and other sensitive information is fine as it's kept local.