Osvitová jednotka
pre výrobu plošných spojov fotocestou.
BananaPi jednodoskový minipočítač
Banana Pi is an open source hardwarový projekt spoločnosti GuangDong BiPai technology co., LTD.i technology co., LTD.
Monitor radiácie s BPI-M2 Zero.
Screenshot z interpretovaných dát monitora radiacie
Záťažovy regulátor otáčok mini vŕtačky
K základnej výbave každej dielne elektrotechnika, či modelára patrí mini vŕtačka
Záťažovy regulátor otáčok mini vŕtačky
pohľad na osadenú dosku plošných spojov
Spájkovacia pec
pre spájkovanie SMD dosiek plošných spojov
RC433 pre Home Assistant
ovládanie garážvej brány z HomeAssistenta
LK-20 napájací zdroj
laboratórny napájací zdroj
Internetový rádiobudík
Prehrávač médií Volumio s LCD displejom a automatickým riadením jasu

Riadenie jasu LCD displeja podľa okolitého osvetlenia

 

     Čoraz viac prístrojov a zariadení je vybavemých LCD displejmi, pre zobrazovanie hodnôt, či zadávanie vstupných parametrov. Jednou zo základných nevýhod je absencia automatického nastavenia jasu. Viacero obrazoviek v blízkosti pôsobí rušivo, ak nemajú približne rovnakú úroveň jasu. Navrhnuté riešenie pre RAspberry Pi 3b+ a 7" DSI displej je popísaný v nasledujúcom príspevku.

disp veml 1

 

 Riešenie vniklo pôvodne pre internetové rádio s VolumioOS , ale je vhodné pre akékoľvek zariadenie, kde beží Python. Algoritmus je jednoduchý. Snímač okolitého osvetlenia, sníma jeho intenzitu, na základe čoho sa riadi podsvietenie LCD dipleja. Ďalej bude popísané riešenie tak ako bolo realizované pre samoregulácia podsvietenia LCD pre Volumio, alebo iné podobné embedded systémysamoregulácia podsvietenia LCD pre Volumio, alebo iné podobné embedded systémy.

 

Požadované funkcie:

 Automatické nastavenie jasu podľa okolitého osvetlenia
 Logaritmická krivka jasu pre prirodzené vnímanie
 Plynulé prechody zabraňujúce blikaniu
 Konfigurovateľné parametre prostredníctvom externých súborov
 Automatický štart pri bootovaní prostredníctvom systemd služby
 Monitorovanie v reálnom čase s detailným zaznamenávaním

 

Hardvérové komponenty:

KomponentModel/TypPopis
Hlavná jednotka Raspberry Pi 3B+ Riadiaca jednotka
Displej 7" LCD DPI (OFI009) Dotykový displej pripojený cez DPI rozhranie
Enkodér KY-040 Otočný enkodér na ovládanie hlasitosti
Svetelný senzor VEML7700 (BH-014PA) 16-bit I2C senzor okolitého osvetlenia

 

poznámka: Pre správnu funkciu riadenia jasu nie je použitie enkodéra KY-040 potrebné, uvádzam ho pre lepšie pochopenie výberu gpio vstupov a z dôvodu komplexnosti implementácie.

 

Schéma zapojenia:

 

Pin 1 (3.3V) ──────── Pin 5 (+3.3V)
Pin 3 (GPIO 2) ──────── Pin 2 (SDA)
Pin 5 (GPIO 3) ──────── Pin 1 (SCL)
Pin 6 (GND) ──────── Pin 4 (GND)


Referencia GPIO pinov:

 

screenshot gpio readall


Otočný enkodér (KY-040):

CLK: GPIO pin (BCM číslovanie z gpio readall)
DT: GPIO pin (BCM číslovanie)
SW: GPIO pin (tlačidlo)
POWER+: 3.3V
GND: Zem
Poznámka: Nakonfigurujte piny enkodéra vo Volumio plugin-e Rotary Encoder pomocou BCM čísel pinov. Pre správnu funkciu riadenia jasu nie je použitie enkodéra KY-040 potrebné.

Pripojenie displeja:

Napájanie: +5V a GND z konektora X1
DPI signály: Pripojené podľa konfigurácie DPI v /boot/config.txt

Snímač osvetlenia VEML7700 som namontoval na plastový držiak vytlačený na 3D tlačiarni zo zadnej strany displeja. V prednej sklennej maske displeja som odstránil farebný nástrek v mieste, kde je za sklom snímač VEML7700, tak ako je to zrejmé z obrázku.
disp veml

 

Softvérové požiadavky:

Operačný systém: Linuxový systém ako Raspi, Armbian, VolumioOS...
Python: 3.x
popis programu a jeho možnosti môžete nájsť aj na GITHUB-e.

 

Inštalácia:

príklad inštalácie s VolumioOS, pre iné OS je postup podobný a sotva potrebuje komentár pre užívateľa so základnými znalosťami. Pre bežiaci Linux systém môžete použiť pripravený inštalačný (prípadne odištalačný ) skript install.sh (uninstall.sh), ktorý najdete v sekcii na stiahnutie.

Krok 1: Príprava SD karty

Použite Balena Etcher na nahratie Volumio image, alebo iného napr.:

Volumio-3.832-2025-07-26-pi.zip
Krok 2: Konfigurácia APT repozitára

Po prvom spustení upravte APT zdroje:

sudo nano /etc/apt/sources.list

Nahraďte obsah:

deb http://archive.raspbian.org/raspbian/ buster main contrib non-free rpi
Povoľte SSH: http://volumio.local/dev
Krok 3: Inštalácia systémových závislostí
sudo apt update
sudo apt upgrade
sudo apt install python3-pip i2c-tools
Krok 4: Inštalácia Python knižníc
sudo pip3 install adafruit-circuitpython-veml7700
sudo pip3 install RPi.GPIO
sudo pip3 install smbus
Krok 5: Overenie I2C senzora
sudo i2cdetect -y 1

Očakávaný výstup (senzor na adrese 0x10):

veml7700 addr

 

Krok 6: Vytvorenie Python skriptu

Vytvorte súbor /home/volumio/backlight_control.py:

nano /home/volumio/backlight_control.py

Vložte obsah skriptu (pozri backlight_control.py v tomto repozitár backlight LCD).

#!/usr/bin/env python3
"""
LCD Backlight Control based on Ambient Light Sensor (VEML7700)
Automatically adjusts display brightness based on surrounding light conditions
"""import smbus
import time
import os
import glob
from typing import Optional# ==================== DEFAULT CONFIGURATION ====================
INT_TIME = 1 # Interval for light measurement in seconds
MIN_BACKLIGHT = 12 # Minimum backlight value (0-255)
MAX_BACKLIGHT = 255 # Maximum backlight value
SMOOTHING_FACTOR = 0.3 # Smoothing factor for brightness changes (0.0-1.0)
LUX_MULTIPLIER = 0.75 # For gain=1/8, IT=100ms# I2C Configuration
I2C_BUS = 1
VEML7700_ADDR = 0x10# VEML7700 Registers
REG_ALS_CONF = 0x00
REG_ALS_WH = 0x01
REG_ALS_WL = 0x02
REG_POW_SAV = 0x03
REG_ALS = 0x04
REG_WHITE = 0x05
REG_INTERRUPT = 0x06# Sensor configuration for max range (0-120Klx), lowest precision
CONF_VALUES = [0x00, 0x00] # Max gain, 100ms integration time
INTERRUPT_HIGH = [0x00, 0x00]
INTERRUPT_LOW = [0x00, 0x00]
POWER_SAVE_MODE = [0x00, 0x00]# Configuration directory
CONFIG_DIR = "/etc/lcd_backlight/"
class BacklightController:
def __init__(self):
try:
print("=== Initializing Backlight Controller ===")# Initialize basic attributes
self.current_brightness = MIN_BACKLIGHT
self.file_handle = None
self.config_mtime = 0 # Track config file modification time
self.enabled = True # Service enabled/disabled flag
self.config_exists = os.path.exists(CONFIG_DIR)# Find backlight sysfs path
print("Searching for backlight device...")
backlight_paths = glob.glob("/sys/class/backlight/*/brightness")
if not backlight_paths:
raise FileNotFoundError("No backlight device found in /sys/class/backlight/")
self.backlight_path = backlight_paths[0]
print(f"Found backlight: {self.backlight_path}")# Initialize I2C bus
print("Initializing I2C bus...")
self.bus = smbus.SMBus(I2C_BUS)# Load configuration
print("Loading configuration...")
self._load_configuration()print(f"Backlight control initialized - {time.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"Config source: {'FILES' if self.config_exists else 'DEFAULT VALUES'}")
print(f"Config: ENABLED={self.enabled}, MIN={self.min_backlight}, MAX={self.max_backlight}, INT_TIME={self.int_time}")# Initialize sensor
self._init_sensor()# Set initial brightness only if enabled
if self.enabled:
print("Setting initial brightness...")
self._update_brightness(force=True)
else:
print("Service is disabled, skipping initial brightness setup")print("=== Backlight Controller Initialized Successfully ===")except Exception as e:
print(f"Error during initialization: {e}")
raisedef _get_config_mtime(self) -> float:
"""Get the latest modification time of all config files"""
try:
if not os.path.exists(CONFIG_DIR):
return 0files = [
'lcd_enabled',
'lcd_min_backlight',
'lcd_max_backlight',
'lcd_int_time',
'lcd_lux_multiplier',
'lcd_smoothing_factor'
]mtimes = []
for filename in files:
filepath = os.path.join(CONFIG_DIR, filename)
if os.path.exists(filepath):
mtimes.append(os.path.getmtime(filepath))return max(mtimes) if mtimes else 0except Exception as e:
print(f"Error getting config mtime: {e}")
return 0def _check_config_changed(self) -> bool:
"""Check if configuration files have been modified or appeared/disappeared"""
try:
# Check if config directory existence changed
config_exists_now = os.path.exists(CONFIG_DIR)if config_exists_now != self.config_exists:
# Config directory appeared or disappeared
self.config_exists = config_exists_now
if config_exists_now:
print(f"\n[{time.strftime('%H:%M:%S')}] Configuration directory appeared, loading from files...")
else:
print(f"\n[{time.strftime('%H:%M:%S')}] Configuration directory removed, using default values...")
return True# If config exists, check for file modifications
if config_exists_now:
current_mtime = self._get_config_mtime()
if current_mtime > self.config_mtime:
print(f"\n[{time.strftime('%H:%M:%S')}] Configuration files changed, reloading...")
self.config_mtime = current_mtime
return Truereturn Falseexcept Exception as e:
print(f"Error checking config changes: {e}")
return Falsedef _read_config_value(self, filename: str, default_value, value_type=str):
"""Read a single config value from file or return default"""
try:
if not os.path.exists(CONFIG_DIR):
return default_valuefilepath = os.path.join(CONFIG_DIR, filename)
if not os.path.exists(filepath):
return default_valuewith open(filepath, "r") as f:
value = f.read().strip()if value_type == bool:
return bool(int(value))
elif value_type == int:
return int(value)
elif value_type == float:
return float(value)
else:
return valueexcept Exception as e:
print(f"Error reading {filename}, using default: {e}")
return default_valuedef _load_configuration(self):
"""Load configuration from files if they exist, otherwise use defaults"""if os.path.exists(CONFIG_DIR):
print(f"Loading configuration from: {CONFIG_DIR}")
self.config_mtime = self._get_config_mtime()# Read all config values from files
self.enabled = self._read_config_value('lcd_enabled', True, bool)
self.min_backlight = self._read_config_value('lcd_min_backlight', MIN_BACKLIGHT, int)
self.max_backlight = self._read_config_value('lcd_max_backlight', MAX_BACKLIGHT, int)
self.int_time = self._read_config_value('lcd_int_time', INT_TIME, int)
self.lux_multiplier = self._read_config_value('lcd_lux_multiplier', LUX_MULTIPLIER, float)
self.smoothing_factor = self._read_config_value('lcd_smoothing_factor', SMOOTHING_FACTOR, float)print(f"Loaded from files: enabled={self.enabled}, min={self.min_backlight}, max={self.max_backlight}")
print(f" int_time={self.int_time}, lux_mult={self.lux_multiplier}, smooth={self.smoothing_factor}")
else:
# Use default values from constants
print(f"Config directory not found, using default values")
self.config_mtime = 0
self.enabled = True
self.min_backlight = MIN_BACKLIGHT
self.max_backlight = MAX_BACKLIGHT
self.int_time = INT_TIME
self.lux_multiplier = LUX_MULTIPLIER
self.smoothing_factor = SMOOTHING_FACTORprint(f"Defaults: enabled={self.enabled}, min={self.min_backlight}, max={self.max_backlight}")
print(f" int_time={self.int_time}, lux_mult={self.lux_multiplier}, smooth={self.smoothing_factor}")def _init_sensor(self):
"""Initialize VEML7700 sensor with configuration"""
try:
self.bus.write_i2c_block_data(VEML7700_ADDR, REG_ALS_CONF, CONF_VALUES)
self.bus.write_i2c_block_data(VEML7700_ADDR, REG_ALS_WH, INTERRUPT_HIGH)
self.bus.write_i2c_block_data(VEML7700_ADDR, REG_ALS_WL, INTERRUPT_LOW)
self.bus.write_i2c_block_data(VEML7700_ADDR, REG_POW_SAV, POWER_SAVE_MODE)
time.sleep(0.1) # Wait for sensor to stabilize
print("VEML7700 sensor initialized successfully")
except Exception as e:
print(f"Error initializing sensor: {e}")
raisedef _read_lux(self) -> Optional[float]:
"""Read ambient light value from sensor in lux"""
try:
raw_value = self.bus.read_word_data(VEML7700_ADDR, REG_ALS)
lux = raw_value * self.lux_multiplier
return lux
except Exception as e:
print(f"Error reading sensor data: {e}")
return Nonedef _lux_to_brightness(self, lux: float) -> int:
"""
Convert lux value to brightness level (min_backlight to max_backlight)
Uses logarithmic curve for more natural perception
"""
if lux <= 0:
return self.min_backlight# Logarithmic mapping: 0-10000 lux -> min_backlight-max_backlight
import math
max_lux = 10000 # Maximum expected lux# Logarithmic scale feels more natural to human perception
brightness = self.min_backlight + (self.max_backlight - self.min_backlight) * (
math.log10(lux + 1) / math.log10(max_lux + 1)
)return int(max(self.min_backlight, min(self.max_backlight, brightness)))def _write_brightness(self, value: int) -> bool:
"""Write brightness value to sysfs with optimized file handling"""
try:
if self.file_handle is None:
self.file_handle = os.open(self.backlight_path, os.O_WRONLY)os.lseek(self.file_handle, 0, os.SEEK_SET)
os.write(self.file_handle, str(value).encode())
return Trueexcept OSError as e:
print(f"Error writing brightness to {self.backlight_path}: {e}")
self._close_file_handle()
return Falsedef _close_file_handle(self):
"""Safely close file handle"""
if self.file_handle is not None:
try:
os.close(self.file_handle)
except:
pass
self.file_handle = Nonedef _update_brightness(self, force: bool = False):
"""Read sensor and update backlight brightness"""
# Skip if disabled
if not self.enabled:
returnlux = self._read_lux()if lux is None:
return # Skip update on sensor errortarget_brightness = self._lux_to_brightness(lux)# Smooth brightness changes to avoid flickering
if not force:
self.current_brightness = int(
self.current_brightness * (1 - self.smoothing_factor) +
target_brightness * self.smoothing_factor
)
else:
self.current_brightness = target_brightnesssuccess = self._write_brightness(self.current_brightness)# Uncomment for debug
# if success:
# print(f"[{time.strftime('%H:%M:%S')}] Lux: {lux:6.1f} | Brightness: {self.current_brightness:3d}/{self.max_backlight}")def run(self):
"""Main control loop"""
try:
print("\n=== Starting main control loop ===")
print("Monitoring for configuration changes...")while True:
# Check for configuration changes
if self._check_config_changed():
self._load_configuration()
print(f"Active config: ENABLED={self.enabled}, MIN={self.min_backlight}, MAX={self.max_backlight}, INT_TIME={self.int_time}")# Update brightness if enabled
if self.enabled:
self._update_brightness()
time.sleep(self.int_time)
else:
# Check for config changes more frequently when disabled
time.sleep(1)except KeyboardInterrupt:
print(f"\n\nBacklight control stopped - {time.strftime('%Y-%m-%d %H:%M:%S')}")
finally:
self.cleanup()def cleanup(self):
"""Cleanup resources"""
print("Cleaning up resources...")
self._close_file_handle()
try:
self.bus.close()
except:
pass
if __name__ == "__main__":
try:
controller = BacklightController()
controller.run()
except Exception as e:
print(f"Fatal error: {e}")
import traceback
traceback.print_exc()

Nastavte oprávnenia:

chmod +x /home/volumio/backlight_control.py
 
Krok 7: Vytvorenie Systemd služby
sudo nano /etc/systemd/system/backlight.service

Obsah:

[Unit]
Description=Služba kontroly podsvietenia
After=multi-user.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /home/volumio/backlight_control.py
WorkingDirectory=/home/volumio
User=volumio
Group=volumio
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

 

Krok 8: Povolenie a spustenie služby
sudo systemctl daemon-reload
sudo systemctl enable backlight.service
sudo systemctl start backlight.service

 

Krok 9: Overenie stavu služby
sudo systemctl status backlight.service

Sledovanie logov v reálnom čase:

sudo journalctl -u backlight.service -f

 

Konfigurácia:

Umiestnenie konfiguračných súborov

Vytvorte konfiguračný adresár:

sudo mkdir -p /etc/lcd_backlight
 

Dostupné konfiguračné parametre:

Minimálny jas (0-255)
echo "12" | sudo tee /etc/lcd_backlight/lcd_min_backlight
Maximálny jas (0-255)
echo "255" | sudo tee /etc/lcd_backlight/lcd_max_backlight
Interval merania (sekundy)
echo "1" | sudo tee /etc/lcd_backlight/lcd_int_time
Lux multiplikátor (kalibrácia)
echo "0.75" | sudo tee /etc/lcd_backlight/lcd_lux_multiplier
Faktor vyhladenia (0.0-1.0)

Nižšie hodnoty = plynulejšie prechody

echo "0.3" | sudo tee /etc/lcd_backlight/lcd_smoothing_factor
Aplikovanie zmien konfigurácie
sudo systemctl restart backlight.service

 

Predvolené hodnoty:

ParameterPredvolená hodnotaPopis
MIN_BACKLIGHT 12 Minimálny jas (tma)
MAX_BACKLIGHT 255 Maximálny jas (svetlo)
INT_TIME 1 Interval merania (s)
LUX_MULTIPLIER 0.75 Kalibračný koeficient luxov
SMOOTHING_FACTOR 0.3 Vyhladenie prechodov

 

Používanie:

Automatický režim

Služba sa automaticky spustí pri štarte systému a beží nepretržite.

Manuálne ovládanie služby
# Stav služby
sudo systemctl status backlight.service

# Zastavenie služby
sudo systemctl stop backlight.service

# Spustenie služby
sudo systemctl start backlight.service

# Reštart služby
sudo systemctl restart backlight.service

# Zakázanie automatického štartu
sudo systemctl disable backlight.service

# Povolenie automatického štartu
sudo systemctl enable backlight.service
Zobrazenie logov
# Posledných 50 záznamov
sudo journalctl -u backlight.service -n 50

# Sledovanie v reálnom čase
sudo journalctl -u backlight.service -f

# Iba dnešné logy
sudo journalctl -u backlight.service --since today
Príklad výstupu logov
[12:34:56] Lux:  245.3 | Brightness: 145/255
[12:34:57] Lux:  248.1 | Brightness: 147/255
[12:34:58] Lux:  251.7 | Brightness: 149/255

 

Riešenie problémov:

Senzor nie je detekovaný
i2cdetect -y 1

Povoľte I2C rozhranie:

sudo nano /boot/config.txt
# Pridajte alebo odkomentujte:
dtparam=i2c_arm=on

Reštartujte po zmene.

Služba sa nespustí
sudo journalctl -u backlight.service -n 50 --no-pager

Overte Python závislosti:

python3 -c "import adafruit_veml7700; print('VEML7700: OK')"
python3 -c "import RPi.GPIO; print('GPIO: OK')"
python3 -c "import smbus; print('SMBus: OK')"

Skontrolujte syntax skriptu:

python3 -m py_compile /home/volumio/backlight_control.py
Jas displeja sa nemení
ls -la /sys/class/backlight/*/brightness

Test manuálnej kontroly jasu:

echo 128 | sudo tee /sys/class/backlight/*/brightness
echo 255 | sudo tee /sys/class/backlight/*/brightness

Skontrolujte oprávnenia súborov:

ls -la /home/volumio/backlight_control.py
# Malo by byť: -rwxr-xr-x (spustiteľný)
Zmena jasu je príliš citlivá
echo "0.5" | sudo tee /etc/lcd_backlight/lcd_smoothing_factor
sudo systemctl restart backlight.service
Displej príliš tmavý/svetlý
# Upravte minimálny jas
echo "5" | sudo tee /etc/lcd_backlight/lcd_min_backlight

# Upravte maximálny jas
echo "200" | sudo tee /etc/lcd_backlight/lcd_max_backlight

# Aplikujte zmeny
sudo systemctl restart backlight.service
Nesprávne hodnoty senzora
# Pre vyššiu citlivosť
echo "1.0" | sudo tee /etc/lcd_backlight/lcd_lux_multiplier

# Pre nižšiu citlivosť
echo "0.5" | sudo tee /etc/lcd_backlight/lcd_lux_multiplier

sudo systemctl restart backlight.service

 

Monitorovanie:

Monitorovanie v reálnom čase
# Sledovanie zmien jasu
sudo journalctl -u backlight.service -f
Štatistiky výkonu
# Čas behu a stav služby
sudo systemctl status backlight.service

# Nedávne logy s časovými pečiatkami
sudo journalctl -u backlight.service -n 100 --no-pager

 

Pokročilá konfigurácia:

Vlastná krivka jasu

Upravte /home/volumio/backlight_control.py a modifikujte metódu _lux_to_brightness() pre implementáciu vlastných kriviek jasu.

Viaceré senzory

Skript je možné rozšíriť pre podporu viacerých VEML7700 senzorov pre rôzne zóny.

 

Štruktúra súborov:

/home/volumio/
└── backlight_control.py          # Hlavný Python skript

/etc/systemd/system/
└── backlight.service              # Systemd služba

/etc/lcd_backlight/
├── lcd_min_backlight              # Minimálna hodnota jasu
├── lcd_max_backlight              # Maximálna hodnota jasu
├── lcd_int_time                   # Interval merania
├── lcd_lux_multiplier             # Kalibrácia luxov
└── lcd_smoothing_factor           # Faktor vyhladenia

/usr/local/bin/ └── backlight_control.py # Hlavný Python skript

Related Articles

Copyright © Free Joomla! 4 templates / Design by Galusso Themes