7. API - pi-top Peripheral Devices

7.1. pi-topPROTO+

_images/pi-topPROTO%2B.jpg

This module provides 2 classes - a simple way to use a pi-topPROTO+’s onboard ADC (analog-to-digital converter), and another to use it as a distance sensor.

These classes will work with original pi-top, pi-topCEED and pi-top [3]. pi-top [4] does not support the pi-topPROTO+’s modular rail connector, and so will not work.

7.1.1. Using the pi-topPROTO+ as a Distance Sensor

from time import sleep

from pitop.protoplus import DistanceSensor

ultrasonic = DistanceSensor()

while True:
    print(ultrasonic.distance)
    sleep(1)

7.1.2. Class Reference: pi-topPROTO+ Distance Sensor

class pitop.protoplus.sensors.DistanceSensor(*args, **kwargs)[source]

Encapsulates the behaviour of a simple DistanceSensor that can be turned on and off.

Parameters:
  • trigger_gpio_pin (str) – GPIO pin for trigger input

  • echo_gpio_pin (str) – GPIO pin for echo response

close()[source]

Shut down the device and release all associated resources. This method can be called on an already closed device without raising an exception.

This method is primarily intended for interactive use at the command line. It disables the device and releases its pin(s) for use by another device.

You can attempt to do this simply by deleting an object, but unless you’ve cleaned up all references to the object this may not work (even if you’ve cleaned up all references, there’s still no guarantee the garbage collector will actually delete the object at that point). By contrast, the close method provides a means of ensuring that the object is shut down.

For example, if you have a buzzer connected to port D0, but then wish to attach an LED instead:

>>> from pitop import Buzzer, LED
>>> bz = Buzzer("D0")
>>> bz.on()
>>> bz.off()
>>> bz.close()
>>> led = LED("D0")
>>> led.blink()

Device descendents can also be used as context managers using the with statement. For example:

>>> from pitop import Buzzer, LED
>>> with Buzzer("D0") as bz:
...     bz.on()
...
>>> with LED("D0") as led:
...     led.on()
...
property raw_distance
get_raw_distance()[source]
get_distance()[source]

7.1.3. Using the pi-topPROTO+’s onboard ADC

from time import sleep

from pitop.protoplus import ADCProbe

temp_sensor = ADCProbe()

while True:
    print(temp_sensor.read_value(1))
    sleep(0.5)

7.1.4. Class Reference: pi-topPROTO+ ADC Probe

class pitop.protoplus.adc.ADCProbe(i2c_device_name='/dev/i2c-1')[source]
read_value(channel)[source]
read_all()[source]
poll(delay=0.5)[source]

7.2. pi-topPULSE

_images/pi-topPULSE.jpg

This module provides a simple way to use a pi-topPULSE, and will work with any Raspberry Pi and/or pi-top.

The hardware representation of each color is 5 bits (i.e. only 32 different values). Without gamma correction, this would mean the actual color value changes only every 8th color intensity value. This module applies gamma correction, which means that pixels with seemingly different intensities actually have the same.

7.2.1. Using the pi-topPULSE’s microphone

from time import sleep

from pitop.pulse import ledmatrix, microphone


def set_bit_rate_to_unsigned_8():
    print("Setting bit rate to 8...")
    microphone.set_bit_rate_to_unsigned_8()


def set_bit_rate_to_signed_16():
    print("Setting bit rate to 16...")
    microphone.set_bit_rate_to_signed_16()


def set_sample_rate_to_16khz():
    print("Setting sample rate to 16KHz...")
    microphone.set_sample_rate_to_16khz()


def set_sample_rate_to_22khz():
    print("Setting sample rate to 22KHz...")
    microphone.set_sample_rate_to_22khz()


def pause(length):
    ledmatrix.off()
    sleep(length)


def record(record_time, output_file, pause_time=1):
    print("Recording audio for " + str(record_time) + "s...")
    ledmatrix.set_all(255, 0, 0)
    ledmatrix.show()
    microphone.record()
    sleep(record_time)
    microphone.stop()
    ledmatrix.off()
    microphone.save(output_file, True)
    print("Saved to " + output_file)
    print("")
    pause(pause_time)


set_sample_rate_to_22khz()

set_bit_rate_to_unsigned_8()
record(5, "/tmp/test22-8.wav")

set_bit_rate_to_signed_16()
record(5, "/tmp/test22-16.wav")


set_sample_rate_to_16khz()

set_bit_rate_to_unsigned_8()
record(5, "/tmp/test16-8.wav")

set_bit_rate_to_signed_16()
record(5, "/tmp/test16-16.wav")

7.2.2. Using the pi-topPULSE’s LED matrix: Test colors

import time

from pitop.pulse import ledmatrix


def show_map(r, g, b):
    for x in range(0, 7):
        for y in range(0, 7):
            z = (float(y) + 7.0 * float(x)) / 49.0
            rr = int(z * r)
            gg = int(z * g)
            bb = int(z * b)
            ledmatrix.set_pixel(x, y, rr, gg, bb)
    ledmatrix.show()


ledmatrix.rotation(0)
ledmatrix.clear()

# Display 49 different color intensities
for r in range(0, 2):
    for g in range(0, 2):
        for b in range(2):
            if r + g + b > 0:
                rr = 255 * r
                gg = 255 * g
                bb = 255 * b
                print(rr, gg, bb)
                show_map(rr, gg, bb)
                time.sleep(5)

ledmatrix.clear()
ledmatrix.show()

7.2.3. Using the pi-topPULSE’s LED matrix: Fancy Light Show!

import colorsys
import math

from pitop.pulse import ledmatrix

s_width, s_height = ledmatrix.get_shape()


# twisty swirly goodness
def swirl(x, y, step):
    x -= s_width / 2
    y -= s_height / 2

    dist = math.sqrt(pow(x, 2) + pow(y, 2)) / 2.0
    angle = (step / 10.0) + (dist * 1.5)
    s = math.sin(angle)
    c = math.cos(angle)

    xs = x * c - y * s
    ys = x * s + y * c

    r = abs(xs + ys)
    r = r * 64.0
    r -= 20

    return (r, r + (s * 130), r + (c * 130))


# roto-zooming checker board


def checker(x, y, step):
    x -= s_width / 2
    y -= s_height / 2

    angle = step / 10.0
    s = math.sin(angle)
    c = math.cos(angle)

    xs = x * c - y * s
    ys = x * s + y * c

    xs -= math.sin(step / 200.0) * 40.0
    ys -= math.cos(step / 200.0) * 40.0

    scale = step % 20
    scale /= 20
    scale = (math.sin(step / 50.0) / 8.0) + 0.25

    xs *= scale
    ys *= scale

    xo = abs(xs) - int(abs(xs))
    yo = abs(ys) - int(abs(ys))
    val = (
        0
        if (math.floor(xs) + math.floor(ys)) % 2
        else 1 if xo > 0.1 and yo > 0.1 else 0.5
    )

    r, g, b = colorsys.hsv_to_rgb((step % 255) / 255.0, 1, val)

    return (r * 255, g * 255, b * 255)


# weeee waaaah


def blues_and_twos(x, y, step):
    x -= s_width / 2
    y -= s_height / 2

    scale = math.sin(step / 6.0) / 1.5
    r = math.sin((x * scale) / 1.0) + math.cos((y * scale) / 1.0)
    b = math.sin(x * scale / 2.0) + math.cos(y * scale / 2.0)
    g = r - 0.8
    g = 0 if g < 0 else g

    b -= r
    b /= 1.4

    return (r * 255, (b + g) * 255, g * 255)


# rainbow search spotlights


def rainbow_search(x, y, step):
    xs = math.sin((step) / 100.0) * 20.0
    ys = math.cos((step) / 100.0) * 20.0

    scale = ((math.sin(step / 60.0) + 1.0) / 5.0) + 0.2
    r = math.sin((x + xs) * scale) + math.cos((y + xs) * scale)
    g = math.sin((x + xs) * scale) + math.cos((y + ys) * scale)
    b = math.sin((x + ys) * scale) + math.cos((y + ys) * scale)

    return (r * 255, g * 255, b * 255)


# zoom tunnel


def tunnel(x, y, step):
    speed = step / 100.0
    x -= s_width / 2
    y -= s_height / 2

    xo = math.sin(step / 27.0) * 2
    yo = math.cos(step / 18.0) * 2

    x += xo
    y += yo

    if y == 0:
        if x < 0:
            angle = -(math.pi / 2)
        else:
            angle = math.pi / 2
    else:
        angle = math.atan(x / y)

    if y > 0:
        angle += math.pi

    angle /= 2 * math.pi  # convert angle to 0...1 range

    shade = math.sqrt(math.pow(x, 2) + math.pow(y, 2)) / 2.1
    shade = 1 if shade > 1 else shade

    angle += speed
    depth = speed + (math.sqrt(math.pow(x, 2) + math.pow(y, 2)) / 10)

    col1 = colorsys.hsv_to_rgb((step % 255) / 255.0, 1, 0.8)
    col2 = colorsys.hsv_to_rgb((step % 255) / 255.0, 1, 0.3)

    col = col1 if int(abs(angle * 6.0)) % 2 == 0 else col2

    td = 0.3 if int(abs(depth * 3.0)) % 2 == 0 else 0

    col = (col[0] + td, col[1] + td, col[2] + td)

    col = (col[0] * shade, col[1] * shade, col[2] * shade)

    return (col[0] * 255, col[1] * 255, col[2] * 255)


effects = [tunnel, rainbow_search, checker, swirl]

step = 0
while True:
    for i in range(500):
        for y in range(s_height):
            for x in range(s_width):
                r, g, b = effects[0](x, y, step)
                if i > 400:
                    r2, g2, b2 = effects[-1](x, y, step)

                    ratio = (500.00 - i) / 100.0
                    r = r * ratio + r2 * (1.0 - ratio)
                    g = g * ratio + g2 * (1.0 - ratio)
                    b = b * ratio + b2 * (1.0 - ratio)
                r = int(max(0, min(255, r)))
                g = int(max(0, min(255, g)))
                b = int(max(0, min(255, b)))
                ledmatrix.set_pixel(x, y, r, g, b)
        step += 1

        ledmatrix.show()

    effect = effects.pop()
    effects.insert(0, effect)

7.2.4. Using the pi-topPULSE’s LED matrix: Showing CPU temperature

import time

from pitop.pulse import ledmatrix


def getCpuTemperature():
    tempFile = open("/sys/class/thermal/thermal_zone0/temp")
    cpu_temp = tempFile.read()
    tempFile.close()
    return int(int(cpu_temp) / 1000)


OFFSET_LEFT = 0
OFFSET_TOP = 2


# fmt: off
NUMS = [1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1,  # 0
        0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,  # 1
        1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1,  # 2
        1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1,  # 3
        1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1,  # 4
        1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1,  # 5
        1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1,  # 6
        1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0,  # 7
        1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,  # 8
        1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1]  # 9
# fmt: on


# Displays a single digit (0-9)
def show_digit(val, xd, yd, r, g, b):
    offset = val * 15
    for p in range(offset, offset + 15):
        xt = p % 3
        yt = (p - offset) // 3
        ledmatrix.set_pixel(xt + xd, 7 - yt - yd, r * NUMS[p], g * NUMS[p], b * NUMS[p])
    ledmatrix.show()


# Displays a two-digits positive number (0-99)
def show_number(val, r, g, b):
    abs_val = abs(val)
    tens = abs_val // 10
    units = abs_val % 10
    if abs_val > 9:
        show_digit(tens, OFFSET_LEFT, OFFSET_TOP, r, g, b)
    show_digit(units, OFFSET_LEFT + 4, OFFSET_TOP, r, g, b)


###########################################################
# MAIN
###########################################################

ledmatrix.rotation(0)
ledmatrix.clear()

lastTemperature = -1

try:
    while True:
        temperature = getCpuTemperature()
        if temperature != lastTemperature:
            if temperature < 60:
                show_number(temperature, 0, 255, 0)
            elif temperature < 70:
                show_number(temperature, 255, 255, 0)
            else:
                show_number(temperature, 255, 0, 0)
            lastemperature = temperature
        time.sleep(2)

except KeyboardInterrupt:
    ledmatrix.clear()
    ledmatrix.show()

7.2.5. Using the pi-topPULSE’s LED matrix: Showing CPU usage

import time

from pitop.pulse import ledmatrix

last_work = [0, 0, 0, 0]
last_idle = [0, 0, 0, 0]


def get_cpu_rates():
    global last_work, last_idle
    rate = [0, 0, 0, 0]
    f = open("/proc/stat", "r")
    line = ""
    for i in range(0, 4):
        while not "cpu" + str(i) in line:
            line = f.readline()
        # print(line)
        splitline = line.split()
        work = int(splitline[1]) + int(splitline[2]) + int(splitline[3])
        idle = int(splitline[4])
        diff_work = work - last_work[i]
        diff_idle = idle - last_idle[i]
        rate[i] = float(diff_work) / float(diff_idle + diff_work)
        last_work[i] = work
        last_idle[i] = idle
    f.close()
    return rate


ledmatrix.rotation(0)

try:
    while True:
        rate = get_cpu_rates()
        ledmatrix.clear()
        for i in range(0, 4):
            level = int(6.99 * rate[i])
            if level < 4:
                r = 0
                g = 255
                b = 0
            elif level < 6:
                r = 255
                g = 255
                b = 6
            else:
                r = 255
                g = 0
                b = 0
            for y in range(0, level + 1):
                ledmatrix.set_pixel(2 * i, y, r, g, b)

        ledmatrix.show()
        time.sleep(1)

except KeyboardInterrupt:
    ledmatrix.clear()
    ledmatrix.show()

7.2.6. Module Reference: pi-topPULSE Configuration

pitop.pulse.configuration.reset_device_state(enable)[source]

reset_device_state: Deprecated

pitop.pulse.configuration.enable_device()[source]
pitop.pulse.configuration.disable_device()[source]
pitop.pulse.configuration.set_microphone_sample_rate_to_16khz()[source]

Set the appropriate I2C bits to enable 16,000Hz recording on the microphone.

pitop.pulse.configuration.set_microphone_sample_rate_to_22khz()[source]

Set the appropriate I2C bits to enable 22,050Hz recording on the microphone.

pitop.pulse.configuration.speaker_enabled()[source]

Get whether the speaker is enabled.

pitop.pulse.configuration.mcu_enabled()[source]

Get whether the onboard MCU is enabled.

pitop.pulse.configuration.eeprom_enabled()[source]

Get whether the eeprom is enabled.

pitop.pulse.configuration.microphone_sample_rate_is_16khz()[source]

Get whether the microphone is set to record at a sample rate of 16,000Hz.

pitop.pulse.configuration.microphone_sample_rate_is_22khz()[source]

Get whether the microphone is set to record at a sample rate of 22,050Hz.

7.2.7. Module Reference: pi-topPULSE LED Matrix

pitop.pulse.ledmatrix.set_debug_print_state(debug_enable)[source]

Enable/disable debug prints.

pitop.pulse.ledmatrix.brightness(new_brightness)[source]

Set the display brightness between 0.0 and 1.0.

Parameters:

new_brightness – Brightness from 0.0 to 1.0 (default 1.0)

pitop.pulse.ledmatrix.get_brightness()[source]

Get the display brightness value.

Returns a float between 0.0 and 1.0.

pitop.pulse.ledmatrix.rotation(new_rotation=0)[source]

Set the display rotation.

Parameters:

new_rotation – Specify the rotation in degrees: 0, 90, 180 or 270

pitop.pulse.ledmatrix.flip_h()[source]

Flips the grid horizontally.

pitop.pulse.ledmatrix.flip_v()[source]

Flips the grid vertically.

pitop.pulse.ledmatrix.get_shape()[source]

Returns the shape (width, height) of the display.

pitop.pulse.ledmatrix.get_pixel(x, y)[source]

Get the RGB value of a single pixel.

Parameters:
  • x – Horizontal position from 0 to 7

  • y – Veritcal position from 0 to 7

pitop.pulse.ledmatrix.set_pixel(x, y, r, g, b)[source]

Set a single pixel to RGB color.

Parameters:
  • x – Horizontal position from 0 to 7

  • y – Veritcal position from 0 to 7

  • r – Amount of red from 0 to 255

  • g – Amount of green from 0 to 255

  • b – Amount of blue from 0 to 255

pitop.pulse.ledmatrix.set_all(r, g, b)[source]

Set all pixels to a specific color.

pitop.pulse.ledmatrix.show()[source]

Update pi-topPULSE with the contents of the display buffer.

pitop.pulse.ledmatrix.clear()[source]

Clear the buffer.

pitop.pulse.ledmatrix.off()[source]

Clear the buffer and immediately update pi-topPULSE.

pitop.pulse.ledmatrix.run_tests()[source]

Runs a series of tests to check the LED board is working as expected.

pitop.pulse.ledmatrix.start(new_update_rate=0.1)[source]

Starts a timer to automatically refresh the LEDs.

pitop.pulse.ledmatrix.stop()[source]

Stops the timer that automatically refreshes the LEDs.

7.2.8. Module Reference: pi-topPULSE Microphone

pitop.pulse.microphone.record()[source]

Start recording on the pi-topPULSE microphone.

pitop.pulse.microphone.is_recording()[source]

Returns recording state of the pi-topPULSE microphone.

pitop.pulse.microphone.stop()[source]

Stops recording audio.

pitop.pulse.microphone.save(file_path, overwrite=False)[source]

Saves recorded audio to a file.

pitop.pulse.microphone.set_sample_rate_to_16khz()[source]

Set the appropriate I2C bits to enable 16,000Hz recording on the microphone.

pitop.pulse.microphone.set_sample_rate_to_22khz()[source]

Set the appropriate I2C bits to enable 22,050Hz recording on the microphone.

pitop.pulse.microphone.set_bit_rate_to_unsigned_8()[source]

Set bitrate to device default.

pitop.pulse.microphone.set_bit_rate_to_signed_16()[source]

Set bitrate to double that of device default by scaling the signal.

7.2.9. Advanced: EEPROM

The pi-topPULSE contains an EEPROM which was programmed using this settings file. during factory production.

See the Raspberry Pi Foundation’s HAT Github repository for more information.