Developer Guide

This document provides guide to hacking and extending PieTime.

Setup

To develop PieTime or cards, some additional setup is required. First, it’s recommended to use a virtual environment, to separate from OS Python and extensions. Secondly, use requirements-dev.txt to install additional modules and tools used in development.

Custom card example

from pie_time.card import AbstractCard

import pygame

class ExampleCard(AbstractCard):
    def initialize(self):
        self.sprite = pygame.surface.Surface((20, 20))
        self.sprite.fill((255, 0, 0))
        self.orig_sprite_rect = self.sprite.get_rect()
        self.orig_speed = [2, 2]
        self.sprite_rect = self.orig_sprite_rect
        self.speed = self.orig_speed

    def show(self):
        self.sprite_rect = self.orig_sprite_rect
        self.speed = self.orig_speed

    def tick(self):
        self.sprite_rect = self.sprite_rect.move(self.speed)

        if self.sprite_rect.left < 0 or self.sprite_rect.right > self.width:
            self.speed[0] = -self.speed[0]
        if self.sprite_rect.top < 0 or self.sprite_rect.bottom > self.height:
            self.speed[1] = -self.speed[1]

        self.surface.fill(self.background_color)
        self.surface.blit(self.sprite, self.sprite_rect)

This example shows how easy it is to create custom cards for use in PieTime decks.

Start by creating a custom class that inherits from AbstractCard. Then implement a few methods to make it display the information you need (in this example, a red square moving on the screen). Having done that, you’ll be ready to use your custom card in a deck.

Head on to pie_time.AbstractCard documentation for more information about PieTime card API.

Speed considerations

Since PieTime targets the Raspberry Pi, it’s important to keep speed in mind. When developing cards, take care to do as little work as possible in the pie_time.AbstractCard.tick() method.

For example, WeatherCard redraws its surface only when weather conditions change. By doing so, the CPU load is reduced because the only thing PieTime has to do is blit the surface to screen.

Always test the behavior of your card in low FPS. Remember, that PieTime targets small GPIO-connected LCD screens. For many of them, 20 FPS will be the best refresh rate. If your card behaves badly in such conditions, users may refrain from using it.

Threading considerations

Sometimes, it’s required to perform background tasks during lifetime of the card. API exposed by Python’s builtin threading module should come in handy is such situations.

Take WeatherCard as an example. Once every 10 minutes, it fetches current conditions from the Internet. If you look into the card’s code, there’s _refresh_conditions method. It uses threading.Timer class to schedule fetching of the conditions in a separate thread of control. This way, the HTTP request (which may take some time depending on the network conditions) won’t cause the PieTime application to freeze.

As always with threads, you should be aware of the standard pitfalls - variable access synchronization, error handling, the GIL. Also, spawning too many threads will impact PieTime’s performance. If you use threads in your card, make sure to test it on the device to see how it impacts the load.

Handling events

In every iteration of the main loop, PieTime reads list of current events from PyGame. This list is available for the cards to use through pie_time.PieTime.events.

The application itself handles the following events:

  • QUIT (e.g. SIGTERM) - if this event appears, the application quits.
  • KEYDOWN on the key specified by pie_time.PieTime.KEY_QUIT - quits the application,
  • MOUSEBUTTONDOWN anywhere on the screen when it’s blanked - if click to unblank is enabled,
  • MOUSEBUTTONDOWN in one of the regions used to manually switch bedween cards.