BalenaOS, RPI and HAT (OLED, RGB and FAN)

I’m trying to get a Yahboom RGB Cooling HAT to work with my rpi4B with balenaOS.
I have tested this HAT with Raspbian OS 64-bit (here) and it works but I cannot seem to get it to work on balenaOS.
I asked for help in another thread here but nothing.
Doing a little research, it looks like I could do this if I can prepare it for use with balena CLI.
Using the balena python hello world sample, I copied my script over into the project and pushed the change.
I had a look at balena’s documentation and I gather that i2c is enabled by default with balenaOS (from here), so I don’t need to do anything to get that part functioning.
Just trying to get the fan script to work, I keep hitting an error:

Restarting service 'balena-hello-world sha256:944ea72ca402c28d953331a66cc9ead117e43ea8e57bd3e98c53956e3959cbd9'
[balena-hello-world] Traceback (most recent call last):
[balena-hello-world]   File "/usr/src/app/src/app.py", line 1, in <module>
[balena-hello-world]     import smbus2
[balena-hello-world] ModuleNotFoundError: No module named 'smbus2'
Service exited 'balena-hello-world sha256:944ea72ca402c28d953331a66cc9ead117e43ea8e57bd3e98c53956e3959cbd9'

My Dockerfile.template looks like this:

FROM balenalib/%%BALENA_ARCH%%-python:latest-run
RUN install_packages apt-utils
RUN install_packages i2c-tools
RUN install_packages python3-smbus
WORKDIR /usr/src/app
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . ./
CMD ["python","-u","src/app.py"]

requirements.txt is empty at the moment.
app.py looks like this:

import smbus2
import time
bus = smbus.SMBus(1)

addr = 0x0d
fan_reg = 0x08

while True:
    bus.write_byte_data(addr, fan_reg, 0x01)
    time.sleep(1)

Has anyone got experience getting HATs to work over i2c with BalenaOS on 64-bit?
Is there an RPI4B base image I can use instead of whatever this is so I can just do it like on my working RPI4Bs?
Also, does anyone else experience about ~18-30seconds of lag with balenaSound? My devices are overheating and I suspect that to be the main issue.

1 Like

@casehighway I’d guess this is due to the way you’re installing smbus - try adding smbus2 to the requirements.txt file instead of installing the python3-smbus package.

1 Like

Hi, thank you for your advice.
I made the change and realized I had to make a few other changes too, but after that, success!

So to sumarize, here’s what I needed to change to get the fan and RGB scripts to work:

  1. add the two lines mentioned in the balenaOS i2c documentation to my docker-compose
  2. add ‘smbus2’ to requirements
  3. adjust the app.py script to call smbus2 instead of smbus

Moving on to the OLED.
EDIT2: made adjustments to adafruit like the previous issue and tried a few things. I’m still hitting an error in the logs:

Restarting service 'balena-hello-world sha256:be63159d5bfe0e3da7e1b58f6f0921af445ec19e86b549dc76b6297d6f66b77a'
 balena-hello-world  Traceback (most recent call last):
 balena-hello-world      import adafruit_ssd1306
 balena-hello-world    File "/usr/src/app/src/app.py", line 3, in <module>
 balena-hello-world    File "/usr/local/lib/python3.11/site-packages/adafruit_ssd1306.py", line 17, in <module>
 balena-hello-world    File "/usr/local/lib/python3.11/site-packages/adafruit_bus_device/spi_device.py", line 29, in <module>
 balena-hello-world      from adafruit_bus_device import i2c_device, spi_device
 balena-hello-world    File "/usr/local/lib/python3.11/site-packages/adafruit_bus_device/spi_device.py", line 76, in SPIDevice
 balena-hello-world      class SPIDevice:
 balena-hello-world      chip_select: Optional[DigitalInOut] = None,
 balena-hello-world                            ^^^^^^^^^^^^
 balena-hello-world  NameError: name 'DigitalInOut' is not defined
Service exited 'balena-hello-world sha256:be63159d5bfe0e3da7e1b58f6f0921af445ec19e86b549dc76b6297d6f66b77a'

no change to my docker compose file.

requirements:

adafruit-circuitpython-ssd1306

dockerfile.template:

FROM balenalib/%%BALENA_ARCH%%-python:latest-run
RUN pip install vcgencmd 
RUN pip install smbus2
WORKDIR /usr/src/app
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . ./
CMD ["python","-u","src/app.py"]

the app.py file has been updated to match the oled script (i’ll only include the first 14 lines here):

import time
import os
import adafruit_ssd1306
import subprocess
import busio
from PIL import Image, ImageDraw, ImageFont
from board import SCL, SDA
i2c = busio.I2C(SCL, SDA)
disp = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
...

any advice on this one?
please and thank you!

EDIT: Looking ahead, it looks like i’ll need some way to determine the temperature (and later, other system details like network adapter in-use, RAM and disk usage). Is there some way that i can call balenaos system info? skipping the oled specific script stuff (using the fan temp script), I get errors like this:

error log:

Restarting service 'balena-hello-world sha256:44cc131b2db05ae6792ece6a457aaa0996be1b86b00436a9ab190ce0a0b2933f'
 balena-hello-world  /bin/sh: 1: vcgencmd: not found
 balena-hello-world  
 balena-hello-world  Traceback (most recent call last):
 balena-hello-world    File "/usr/src/app/src/app.py", line 16, in <module>
 balena-hello-world      temp = float(CPU_TEMP)
 balena-hello-world             ^^^^^^^^^^^^^^^
 balena-hello-world  ValueError: could not convert string to float: ''
Service exited 'balena-hello-world sha256:44cc131b2db05ae6792ece6a457aaa0996be1b86b00436a9ab190ce0a0b2933f'

OK, so I think I made some progress.

requirements:

adafruit-circuitpython-ssd1306
Pillow

dockertemplate (removed the commented lines for shorter post):

FROM balenalib/%%BALENA_ARCH%%-python:latest-run
RUN install_packages python3-rpi.gpio
WORKDIR /usr/src/app
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . ./
CMD ["python","-u","src/app.py"]

app.py (decided to reduce it to 10 lines until all modules can be imported with no issues)

import time
import os
import subprocess
import busio
from PIL import Image, ImageDraw, ImageFont
from board import SCL, SDA
from digitalio import DigitalInOut
import adafruit_ssd1306

log now shows this:

Traceback (most recent call last):
  File "/usr/src/app/src/app.py", line 7, in <module>
    from board import SCL, SDA
  File "/usr/local/lib/python3.11/site-packages/board.py", line 48, in <module>
    from adafruit_blinka.board.raspberrypi.raspi_4b import *
  File "/usr/local/lib/python3.11/site-packages/adafruit_blinka/board/raspberrypi/raspi_4b.py", line 6, in <module>
    from adafruit_blinka.microcontroller.bcm2711 import pin
  File "/usr/local/lib/python3.11/site-packages/adafruit_blinka/microcontroller/bcm2711/pin.py", line 5, in <module>
    from RPi import GPIO
  File "/usr/lib/python3/dist-packages/RPi/GPIO/__init__.py", line 23, in <module>
    from RPi._GPIO import *
ModuleNotFoundError: No module named 'RPi._GPIO'

any thoughts or advice would be greatly appreciated.

1 Like

more progress!

did some research here and here.
I followed the first link’s thread, asked for help and followed the advice - didn’t work.
the second link’s thread suggested success, so I tried to replicate as much as I could… and finally figured it out.
putting everything together:

dockertemplate:

FROM balenalib/%%BALENA_MACHINE_NAME%%-debian-python:3.11-build
RUN pip3 install Pillow adafruit-circuitpython-ssd1306 RPi.GPIO smbus
WORKDIR /usr/src/app
COPY . ./
CMD ["python3","-u","src/app.py"]

app.py (the source oled, fan and rgb scripts now ‘function’ without modification)

so to summarize:

  1. adjust the balena base image
  2. install all the required modules either using requirements or RUN pip3 install
  3. have the correct script loaded into app.py

moving on, the temperature and network details on the oled are not correct.

temp data problem
the original temp method uses ‘vcgencmd
with or without it installed, it doesn’t seem to work.
this also means the fan temp script won’t work as intended.

the oled script code:

    cmd = os.popen('vcgencmd measure_temp').readline()
    CPU_TEMP = cmd.replace("temp=","Temp:").replace("'C\n","C")

returns logs:

CPU_TEMP: Can't open device file: /dev/vcio

I tried to add /dev/vcio to the dockercompose file but that didn’t change anything.

network data problem
using balena scan, I know what the target device’s local network address is (192.168.A.B). the oled, however, shows a different address. since the device is not physically connected to the network, we know the network adapter data is wrong too. the oled shows “etho0: 172.17.0.2”, but it should be “wlan:192.168.A.B”. I assume this means it’s retrieving the containers details and not the hosts? how do I go about getting the hosts details?

I have a few more ideas to try but in the mean time, as usual, any advice or thoughts?
please and thanks!

figured it out!

the temp data problem can be solved with the third method (check temp without 3rd party util) from here

and the network data problem can be solved by setting the container’s network mode to ‘host’. like this:

version: "2"

services:
  hello-world:
    build: .
    network_mode: host
    devices:
      - "/dev/i2c-1:/dev/i2c-1"

so to summarize everything so far:

  1. set the right balena base image in the docker template
    (e.g. %%BALENA_MACHINE_NAME%%-debian-python:3.11-build)
  2. install the relevant modules in the docker template
    (e.g. Pillow adafruit-circuitpython-ssd1306 RPi.GPIO smbus)
  3. configure docker compose for i2c and network mode
    (see above)

everything is functional now but there is one remaining problem, which is the oled screen doesn’t seem to be scaling correctly.
the screen resolution should be 128x32 and is set to this in the script.
the code:

    draw.rectangle((0,0,128,32), outline=0, fill=0)
    draw.rectangle((0,10,128,32), outline=0, fill=255)
    draw.rectangle((0,20,128,32), outline=0, fill=0)
    draw.rectangle((0,30,128,32), outline=0, fill=255)

what the oled shows (this)

when it’s running the ‘right’ script, it’s supposed to look like is this (source: yahboom official rgb cooling hat repo)

any idea why this happens?
EDIT: tbh, not sure if this is an actual problem. looking at it again, it doesn’t look that far off.

other than this, everything works so, now to put everything together

I’m still missing a few HATs so this is not a report about how that’s solved all my balena sound problems.

Just came back to update on the lag issue.
My four balena sound devices haven’t rebooted in 3 days (how long they’ve been online for).
I’ve currently got lag across the whole system by about 25 seconds.
Devices are running between 46 and 55 degrees.

If I stream to a multi-room-client ONLY device (48C), it will play almost lag free.

I’ve got HATs on all of my RPI4Bs and the devices are running between 45C and 47C.
The lag across the system is about 19 seconds (time from clicking ‘next song’ to waiting for the next song to play on all devices).
Sometimes something will be playing and then eveyrthing will stop playing across all the devices. somehow, it seems to be able to finish a song before this happens - it’s not clear to me why this happens.

I’m getting IO errors thrown every now and then that restarts the HAT service. The logs look like this:

rpi-hat Traceback (most recent call last):
rpi-hat File “/usr/src/core/main.py”, line 135, in
rpi-hat setRGB(Max_LED, 0, 0, 0)
rpi-hat File “/usr/src/core/main.py”, line 129, in setRGB
rpi-hat bus.write_byte_data(hat_addr, 0x02, g&0xff)
rpi-hat OSError: [Errno 121] Remote I/O error

I did some research before that suggested that the script was running too quickly and that added some breaks/sleeps would resolve this issue - it hasn’t or the sleep isn’t long enough but there’s no evidence that suggests extending the sleep would resolve this issue (or the previous issue) so i’m taking no action.