tech explorers, welcome!

Tag: python

Raspberry Pi 5 fan setup in Ubuntu and status indicator

The heat arrived once again and I was feeling that my Raspberry Pi was too warm considering that it has the official built-in fan, with temperatures easily rising above 60ºC.

Since I installed Ubuntu on it, the fan didn’t seem to work right, but that’s something that has been solved in the recent versions of the kernel.

So here’s how you can set it up in Ubuntu and display it’s status.

Fan check

First of all let's check that our fan is working correctly by managing it manually.

Update your system so you can get the latest fixes that affect the fan. My latest version is Ubuntu Linux 24.04.2.

Now you should be able to turn on the fan manually by typing the following command in the terminal:

echo 4 | sudo tee /sys/class/thermal/cooling_device0/cur_state

A value of 4 will turn on the fan in it's maximum revolutions. You can change this value from 0 to 4.

If the above worked correctly you will hear significant noise from your fan. Now you can turn it off again by echoing a value of 0:

echo 0 | sudo tee /sys/class/thermal/cooling_device0/cur_state

So you see that altering the value in the cur_sate file manually changes the fan speed. That's exactly what the fan daemon does once it's configured, so we will monitor this value later to find out if our fan is working (returned value != 0):

cat /sys/class/thermal/cooling_device0/cur_state

Fan setup

The fan wasn't preconfigured in the earlier versions of the Ubuntu kernel for the Raspberry Pi. I'm not sure if it is now by default, but just check it by editing the config.txt file located in /boot/firmware and find out some lines similar to the following:

dtparam=fan_temp0=58000
dtparam=fan_temp0_hyst=10000
dtparam=fan_temp0_speed=200

If you cannot find them, just add them at the end of the file.

You may also adjust these values freely, considering:

fan_temp0=58000 indicates the trigger temperature that will turn on the fan

fan_temp0_hyst means the temperature reduction that turns off the fun (10000 below 58000 = 48000)

fan_temp0_speed indicates the fan speed, from 0 to 255

So that's our fan setup to run at 200rpm if the temperature is above 58ºC and turn off if it reduces 10ºC (~48ºC).

Now apply these changes by rebooting the system.

Fan monitoring

I was already monitoring a series of variables from my Raspberry Pi 5 using an OLED screen, as it's explained in this other post:

https://theroamingworkshop.cloud/b/en/2655/case-oled-display-for-raspberry-pi-with-status-panel/

Let's now add an indicator with the status of the fan!

I've included a couple of lines to the python script to retreive the fan status executing the command that we saw above:

#Fan ON/OFF
cmd = "cat /sys/class/thermal/cooling_device0/cur_state"
Fan = subprocess.check_output(cmd, shell=True).decode("utf-8")

Somewhere below I am reading a .png file for the fan:

fan_img=Image.open("~/Documents/OLED/fan-icon.png")
fan_img = fan_img.resize((30, 30), Image.BICUBIC)
fan-icon.png

And right at the display stage, I would show it if the value of Fan is different to cero (fan is ON):

if int(Fan)!=0:
    bg.paste(fan_img,(90,55))

All these changes have been updated in the Github repository for my previous display script:

https://github.com/TheRoam/RaspberryPi-SSD1351-OLED

So that's a very nice looking fan indicator for your display!

See you next time!👋

🐦 @RoamingWorkshop

Case + OLED display for Raspberry Pi with status panel

I was tempted to just switch cases from my Raspberry Pi 4 to the Raspberry Pi 5, but look at it…

  • 16×2 LCD display from an Arduino Starter Kit
  • C++ program with the WiringPi library
  • DIY case

I was really proud of it at the time and it was good learning back in 2020, but surely I could do better. Surely I could do a cool status panel!!

Components

  • Raspberry Pi (probably compatible with any of them)
  • OLED display (RGB 1.5 inch size is ideal)
  • PCB prototype board
  • Jumper cables
  • Soldering iron
(courtesy of epiCRealism model in ComfyUI)
  • Casing (3D printed or handcrafted)

Software config

I'll configure the Raspberry to interact with this display using python, with the Adafruit Circuitpython library for the SSD1351 display controller:
https://learn.adafruit.com/adafruit-1-5-color-oled-breakout-board/python-wiring-and-setup#setup-3042417

It's as simple as installing Circuitpython with the following command:

sudo pip3 install --upgrade click setuptools adafruit-python-shell build adafruit-circuitpython-rgb-display

If you find issues with your python version not finding a compatible circuit python version, include --break-system-packages at the end. (It wont break anything today, but don't get used to it...)

sudo pip3 install --upgrade click setuptools adafruit-python-shell build adafruit-circuitpython-rgb-display --break-system-packages

Wiring

Now wire your display according to the manufacturer guidance. Mine is this one from BuyDisplay:

https://www.buydisplay.com/full-color-1-5-inch-arduino-raspberry-pi-oled-display-module-128x128

OLED DisplayRaspberry Pi (pin #)
GNDGND (20)
VCC3V3 (17)
SCLSPI0 SCLK (23)
SDASPI0 MOSI (19)
RESGPIO25 (22)
DCGPIO 24 (18)
CSSPI0 CE0 (24)

Use a site like pinout.xyz to find a suitable wiring configuration.

You're ready to do some tests before making your final move to the PCB.

Script config

You can try Adafruit's demo script. Just make sure that you choose the right display and update any changes to the ping assignment (use IO numbers/names rather than physical pin numbers):

# Configuration for CS and DC pins (adjust to your wiring):
cs_pin = digitalio.DigitalInOut(board.CE0)
dc_pin = digitalio.DigitalInOut(board.D24)
reset_pin = digitalio.DigitalInOut(board.D25)

# Setup SPI bus using hardware SPI:
spi = board.SPI()

disp = ssd1351.SSD1351(spi, rotation=270,                         # 1.5" SSD1351
    cs=cs_pin,
    dc=dc_pin,
    rst=reset_pin,
    baudrate=BAUDRATE
)

Assembly

Here are the STL 3D files for this case design:

Now let's put it all together:

  1. Screw the frame to the display
  2. Solder the 7 pins of the display to 7 jumper cables across the PCB
  3. Wire all connections to the Raspberry Pi
  4. Screw the top and bottom pieces together
  5. Place the display on the support

Final result

I've shared the script you see on the images via github:

https://github.com/TheRoam/RaspberryPi-SSD1351-OLED

It currently displays:

  • Time and date
  • System stats (OS, disk usage and CPU temperature)
  • Local weather from World Meteorological Organization (updated hourly)

And this is how it ends up looking. Much better right?

As always, enjoy your tinkering, and let me know any comments or issues on Twitter!

🐦 @RoamingWorkshop

UNIHIKER-PAL: open-source python home assistant simplified

PAL is a simplified version of my python home assistant that I’m running in the DFRobot UNIHIKER which I’m releasing as free open-source.

This is just a demonstration for voice-recognition command-triggering simplicity using python and hopefully will serve as a guide for your own assistant.

Current version: v0.2.0 (updated september 2024)

Features

Current version includes the following:

  • Voice recognition: using open-source SpeechRecognition python library, returns an array of all the recognised audio strings.
  • Weather forecast: using World Meteorological Organization API data, provides today's weather and the forecast for the 3 coming days. Includes WMO weather icons.
  • Local temperature: reads local BMP-280 temperature sensor to provide a room temperature indicator.
  • IoT HTTP commands: basic workflow to control IoT smart home devices using HTTP commands. Currently turns ON and OFF a Shelly2.5 smart switch.
  • Power-save mode: controls brightness to lower power consumption.
  • Connection manager: regularly checks wifi and pings to the internet to restore connection when it's lost.
  • PAL voice samples: cloned voice of PAL from "The Mitchells vs. The Machines" using the AI voice model CoquiAI-TTS v2.
  • UNIHIKER buttons: button A enables a simple menu (this is thought to enable a more complex menu in the future).
  • Touchscreen controls: restore brightness (center), switch program (left) and close program (right), when touching different areas of the screen.

Installation

  1. Install dependencies :
    pip install SpeechRecognition pyyaml
  2. Download the github repo:
    https://github.com/TheRoam/UNIHIKER-PAL
  3. Upload the files and folders to the UNIHIKER in /root/upload/PAL/
  4. Configure the PAL_config.yaml WIFI credentials, IoT devices, theme, etc.
  5. Run the python script python /root/upload/PAL/PAL_v020.py from the Mind+ terminal or from the UNIHIKER touch interface.

If you enable Auto boot from the Service Toggle menu , the script will run every time the UNIHIKER is restarted.

https://www.unihiker.com/wiki/faq#Error:%20python3:%20can't%20open%20file…

Configuration

Version 0.2.0 includes configuration using a yaml file that is read when the program starts.

CREDENTIALS:
    ssid: "WIFI_SSID"
    pwd: "WIFI_PASSWORD"

DEVICES:
    light1:
        brand: "Shelly25"
        ip: "192.168.1.44"
        channel: 0

    light2:
        brand: "Shelly25"
        ip: "192.168.1.44"
        channel: 1

    light3:
        brand: "Shelly1"
        ip: "192.168.1.42"
        channel: 0

PAL:
    power_save_mode: 0
    temperature_sensor: 0
    wmo_city_id: "195"

Location

The variable "CityID" is used by the WMO API to provide more accurate weather forecast for your location. Define it with the parameter wmo_city_id

You can choose one of the available locations from the official WMO list:

https://worldweather.wmo.int/en/json/full_city_list.txt

IoT devices

At the moment, PAL v0.2.0 only includes functionality for Shelly2.5 for demonstration purposes.

Use variables lampBrand, lampChannel and lampIP to suit your Shelly2.5 configuration.

This is just as an example to show how different devices could be configured. These variables should be used to change the particularities of the HTTP command that is sent to different IoT devices.

More devices will be added in future releases, like Shelly1, ShellyDimmer, Sonoff D1, etc.

Power save mode

Power saving reduces the brightness of the device in order to reduce the power consumption of the UNIHIKER. This is done using the system command "brightness".

Change "ps_mode" variable to enable ("1") or disable ("0") the power-save mode.

Room temperature

Change "room_temp" variable to enable ("1") or disable ("0") the local temperature reading module. This requires a BMP-280 sensor to be installed using the I2C connector.

Check this other post for details on sensor installation:

https://theroamingworkshop.cloud/b/en/2490/

Other configurations in the source code:

Theme

Some theme configuration has been enabled by allowing to choose between different eyes as a background image.

Use the variables "eyesA" and "eyesB" specify one of the following values to change the background image expression of PAL:

  • "happy"
  • "angry"
  • "surprised"
  • "sad"

"eyesA" is used as the default background and "eyesB" will be used as a transition when voice recognition is activated and PAL is talking.

The default value for "eyesA" is "surprised" and it will change to "happy" when a command is recognized.

Customizable commands

Adding your own commands to PAL is simple using the "comandos" function.

Every audio recognized by SpeechRecognition is sent as a string to the "comandos" function, which then filters the content and triggers one or another matching command.

Just define all the possible strings that could be recognized to trigger your command (note that sometimes SpeechRecognition provides wrong or inaccurate transcriptions).

Then define the command that is triggered if the string is matched.

def comandos(msg):
    # LAMP ON
    if any(keyword in msg for keyword in ["turn on the lamp", "turn the lights on","turn the light on", "turn on the light", "turn on the lights"]):
        turnLAMP("on")
        os.system("aplay '/root/upload/PAL/mp3/Turn_ON_lights.wav'")

Activation keyword

You can customize the keywords or strings that will activate command functions. If any of the keywords in the list is recognized, the whole sentence is sent to the "comandos" function to find any specific command to be triggered.

For the case of PAL v0.2, these are the keywords that activate it (90% it's Paypal):

activate=[
    "hey pal",
    "hey PAL",
    "pal",
    "pall",
    "Pall",
    "hey Pall",
    "Paul",
    "hey Paul",
    "pol",
    "Pol",
    "hey Pol",
    "poll",
    "pause",
    "paypal",
    "PayPal",
    "hey paypal",
    "hey PayPal"
]

You can change this to any other sentence or name, so PAL is activated when you call it by these strings.

PAL voice

Use the sample audio file "PAL_full" below (also in the github repo in /mp3) as a reference audio for CoquiAI-TTS v2 voice cloning and produce your personalized voices:

https://huggingface.co/spaces/coqui/xtts

TIP!
You can check this other post for voice cloning with CoquiAI-XTTS:
https://theroamingworkshop.cloud/b/en/2425

Demo

Below are a few examples of queries and replies from PAL:

"Hey PAL, turn on the lights!"
"Hey PAL, turn the lights off"

Future releases (To-Do list)

I will be developing these features in my personal assistant, and will be updating the open-source release every now and then. Get in touch via github if you have special interest in any of them:

  • Advanced menu: allow configuration and manually triggering commands.
  • IoT devices: include all Shelly and Sonoff HTTP API commands.
  • Time query: requires cloning all number combinations...
  • Wikipedia/browser query: requires real-time voice generation...
  • Improved animations / themes.

Any thoughts, issues or improvements, I'll be happy to read them via github or Twitter!

🐦 @RoamingWorkshop