Remove obsolete audio and buzzer control documentation files, including detailed guides and HTML interfaces, to streamline the repository and eliminate redundancy. This cleanup enhances maintainability and focuses on essential resources for the reTerminal DM4 audio and buzzer functionalities.
This commit is contained in:
577
archive/chromium-setup-legacy/LED-CONTROL-GUIDE.md
Normal file
577
archive/chromium-setup-legacy/LED-CONTROL-GUIDE.md
Normal file
@@ -0,0 +1,577 @@
|
||||
# reTerminal DM4 LED Control Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The reTerminal DM4 has a user-controllable LED (`usr-led`) that can be used for status indicators, notifications, and visual feedback. The LED is controlled via the Linux LED subsystem, similar to the buzzer.
|
||||
|
||||
**⚠️ Important Note**: While the LED control interface exists and responds to commands, the physical LED may not be visible or installed on all reTerminal DM4 units. The control interface will accept commands and report correct values (0 for off, 255 for on), but if the LED doesn't appear to turn on physically, it may not be present on your specific model. Always verify with Seeed Studio documentation for your specific unit.
|
||||
|
||||
## LED Device Information
|
||||
|
||||
- **Device Path**: `/sys/class/leds/usr-led`
|
||||
- **Control Method**: Brightness control (0 = off, 1 = on)
|
||||
- **Type**: Simple on/off LED (max brightness = 1)
|
||||
- **Location**: User-controllable status LED
|
||||
- **Hardware**: Controlled via PCA9535 GPIO expander (I2C address 0x21)
|
||||
- **Note**: When setting brightness to 1, the system may report 255 (this is normal - it represents max brightness)
|
||||
|
||||
## Available LEDs on reTerminal DM4
|
||||
|
||||
The device has multiple LEDs, but the user-controllable one is:
|
||||
|
||||
- **`usr-led`**: User-controllable LED (primary LED for applications)
|
||||
- **`usr-buzzer`**: Buzzer (not an LED, but controlled similarly)
|
||||
- **`ACT`**: Activity LED (system-controlled, shows SD card activity)
|
||||
- **`PWR`**: Power LED (system-controlled)
|
||||
- **`lcd-pwr`**: LCD power LED (system-controlled)
|
||||
- **`audio-pwr`**: Audio power LED (system-controlled)
|
||||
|
||||
## Basic LED Control
|
||||
|
||||
### Simple On/Off
|
||||
|
||||
```bash
|
||||
# Turn LED ON
|
||||
echo 1 | sudo tee /sys/class/leds/usr-led/brightness
|
||||
|
||||
# Turn LED OFF
|
||||
echo 0 | sudo tee /sys/class/leds/usr-led/brightness
|
||||
```
|
||||
|
||||
### Check LED Status
|
||||
|
||||
```bash
|
||||
# Check current brightness (0 = off, 1 = on)
|
||||
cat /sys/class/leds/usr-led/brightness
|
||||
|
||||
# Check max brightness
|
||||
cat /sys/class/leds/usr-led/max_brightness
|
||||
```
|
||||
|
||||
## Python Control
|
||||
|
||||
### Simple Python Functions
|
||||
|
||||
```python
|
||||
import subprocess
|
||||
|
||||
LED_PATH = '/sys/class/leds/usr-led/brightness'
|
||||
|
||||
def led_on():
|
||||
"""Turn LED ON"""
|
||||
subprocess.run(['sudo', 'tee', LED_PATH],
|
||||
input='1', text=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL)
|
||||
|
||||
def led_off():
|
||||
"""Turn LED OFF"""
|
||||
subprocess.run(['sudo', 'tee', LED_PATH],
|
||||
input='0', text=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL)
|
||||
|
||||
def led_toggle():
|
||||
"""Toggle LED state"""
|
||||
with open(LED_PATH, 'r') as f:
|
||||
current = f.read().strip()
|
||||
new_state = '0' if current == '1' else '1'
|
||||
subprocess.run(['sudo', 'tee', LED_PATH],
|
||||
input=new_state, text=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL)
|
||||
|
||||
def led_status():
|
||||
"""Get LED status"""
|
||||
with open(LED_PATH, 'r') as f:
|
||||
return 'ON' if f.read().strip() == '1' else 'OFF'
|
||||
```
|
||||
|
||||
### Blinking Pattern
|
||||
|
||||
```python
|
||||
import time
|
||||
import subprocess
|
||||
|
||||
LED_PATH = '/sys/class/leds/usr-led/brightness'
|
||||
|
||||
def led_blink(count=5, on_time=0.2, off_time=0.2):
|
||||
"""Blink LED specified number of times"""
|
||||
for _ in range(count):
|
||||
subprocess.run(['sudo', 'tee', LED_PATH],
|
||||
input='1', text=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL)
|
||||
time.sleep(on_time)
|
||||
subprocess.run(['sudo', 'tee', LED_PATH],
|
||||
input='0', text=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL)
|
||||
time.sleep(off_time)
|
||||
|
||||
def led_pulse(duration=2, interval=0.1):
|
||||
"""Pulse LED (rapid on/off) for specified duration"""
|
||||
end_time = time.time() + duration
|
||||
while time.time() < end_time:
|
||||
subprocess.run(['sudo', 'tee', LED_PATH],
|
||||
input='1', text=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL)
|
||||
time.sleep(interval)
|
||||
subprocess.run(['sudo', 'tee', LED_PATH],
|
||||
input='0', text=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL)
|
||||
time.sleep(interval)
|
||||
```
|
||||
|
||||
## Using LED Triggers
|
||||
|
||||
The LED supports various triggers for automatic control:
|
||||
|
||||
### Available Triggers
|
||||
|
||||
```bash
|
||||
# List available triggers
|
||||
cat /sys/class/leds/usr-led/trigger
|
||||
```
|
||||
|
||||
Common triggers:
|
||||
- `none` - Manual control (default)
|
||||
- `timer` - Blink at specified intervals
|
||||
- `heartbeat` - Blink in heartbeat pattern
|
||||
- `default-on` - Always on
|
||||
- `cpu` - Blink based on CPU activity
|
||||
- `mmc0` - Blink on SD card activity
|
||||
|
||||
### Timer Trigger (Blinking)
|
||||
|
||||
```bash
|
||||
# Set timer trigger
|
||||
echo timer | sudo tee /sys/class/leds/usr-led/trigger
|
||||
|
||||
# Set delay_on (time LED is ON in milliseconds)
|
||||
echo 500 | sudo tee /sys/class/leds/usr-led/delay_on
|
||||
|
||||
# Set delay_off (time LED is OFF in milliseconds)
|
||||
echo 500 | sudo tee /sys/class/leds/usr-led/delay_off
|
||||
|
||||
# Disable timer (return to manual control)
|
||||
echo none | sudo tee /sys/class/leds/usr-led/trigger
|
||||
```
|
||||
|
||||
### Heartbeat Trigger
|
||||
|
||||
```bash
|
||||
# Set heartbeat pattern
|
||||
echo heartbeat | sudo tee /sys/class/leds/usr-led/trigger
|
||||
|
||||
# Return to manual control
|
||||
echo none | sudo tee /sys/class/leds/usr-led/trigger
|
||||
```
|
||||
|
||||
### CPU Activity Trigger
|
||||
|
||||
```bash
|
||||
# Blink based on CPU activity
|
||||
echo cpu | sudo tee /sys/class/leds/usr-led/trigger
|
||||
|
||||
# Return to manual control
|
||||
echo none | sudo tee /sys/class/leds/usr-led/trigger
|
||||
```
|
||||
|
||||
## Bash Script Examples
|
||||
|
||||
### Simple LED Control Script
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# LED control script
|
||||
|
||||
LED_PATH='/sys/class/leds/usr-led/brightness'
|
||||
|
||||
case "$1" in
|
||||
on)
|
||||
echo 1 | sudo tee $LED_PATH > /dev/null
|
||||
echo "LED ON"
|
||||
;;
|
||||
off)
|
||||
echo 0 | sudo tee $LED_PATH > /dev/null
|
||||
echo "LED OFF"
|
||||
;;
|
||||
toggle)
|
||||
current=$(cat $LED_PATH)
|
||||
if [ "$current" = "1" ]; then
|
||||
echo 0 | sudo tee $LED_PATH > /dev/null
|
||||
echo "LED OFF"
|
||||
else
|
||||
echo 1 | sudo tee $LED_PATH > /dev/null
|
||||
echo "LED ON"
|
||||
fi
|
||||
;;
|
||||
blink)
|
||||
count=${2:-5}
|
||||
for i in $(seq 1 $count); do
|
||||
echo 1 | sudo tee $LED_PATH > /dev/null
|
||||
sleep 0.2
|
||||
echo 0 | sudo tee $LED_PATH > /dev/null
|
||||
sleep 0.2
|
||||
done
|
||||
;;
|
||||
status)
|
||||
current=$(cat $LED_PATH)
|
||||
echo "LED is: $([ $current -eq 1 ] && echo 'ON' || echo 'OFF')"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {on|off|toggle|blink [count]|status}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
```
|
||||
|
||||
## Flask Integration
|
||||
|
||||
### Add LED Control to Flask App
|
||||
|
||||
```python
|
||||
from flask import Flask, jsonify, request
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
|
||||
app = Flask(__name__)
|
||||
LED_PATH = '/sys/class/leds/usr-led/brightness'
|
||||
|
||||
class LEDController:
|
||||
def __init__(self):
|
||||
self.is_blinking = False
|
||||
self.blink_thread = None
|
||||
|
||||
def _write_led(self, value):
|
||||
"""Internal method to write to LED"""
|
||||
try:
|
||||
subprocess.run(['sudo', 'tee', LED_PATH],
|
||||
input=str(value), text=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
check=True)
|
||||
return True
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
||||
def on(self):
|
||||
"""Turn LED ON"""
|
||||
return self._write_led(1)
|
||||
|
||||
def off(self):
|
||||
"""Turn LED OFF"""
|
||||
return self._write_led(0)
|
||||
|
||||
def toggle(self):
|
||||
"""Toggle LED state"""
|
||||
try:
|
||||
result = subprocess.run(['cat', LED_PATH],
|
||||
capture_output=True, text=True, check=True)
|
||||
current = result.stdout.strip()
|
||||
new_state = '0' if current == '1' else '1'
|
||||
return self._write_led(new_state)
|
||||
except:
|
||||
return False
|
||||
|
||||
def blink(self, count=5, on_time=0.2, off_time=0.2):
|
||||
"""Blink LED specified number of times"""
|
||||
if self.is_blinking:
|
||||
return False
|
||||
|
||||
def _blink():
|
||||
self.is_blinking = True
|
||||
for _ in range(count):
|
||||
self.on()
|
||||
time.sleep(on_time)
|
||||
self.off()
|
||||
time.sleep(off_time)
|
||||
self.is_blinking = False
|
||||
|
||||
self.blink_thread = threading.Thread(target=_blink, daemon=True)
|
||||
self.blink_thread.start()
|
||||
return True
|
||||
|
||||
def pulse(self, duration=2, interval=0.1):
|
||||
"""Pulse LED for specified duration"""
|
||||
if self.is_blinking:
|
||||
return False
|
||||
|
||||
def _pulse():
|
||||
self.is_blinking = True
|
||||
end_time = time.time() + duration
|
||||
while time.time() < end_time:
|
||||
self.on()
|
||||
time.sleep(interval)
|
||||
self.off()
|
||||
time.sleep(interval)
|
||||
self.is_blinking = False
|
||||
|
||||
self.blink_thread = threading.Thread(target=_pulse, daemon=True)
|
||||
self.blink_thread.start()
|
||||
return True
|
||||
|
||||
def status(self):
|
||||
"""Get LED status"""
|
||||
try:
|
||||
result = subprocess.run(['cat', LED_PATH],
|
||||
capture_output=True, text=True, check=True)
|
||||
state = result.stdout.strip()
|
||||
return 'ON' if state == '1' else 'OFF'
|
||||
except:
|
||||
return 'UNKNOWN'
|
||||
|
||||
led = LEDController()
|
||||
|
||||
@app.route('/led/on', methods=['POST', 'GET'])
|
||||
def led_on():
|
||||
if led.on():
|
||||
return jsonify({'status': 'success', 'message': 'LED turned ON'})
|
||||
return jsonify({'status': 'error', 'message': 'Failed to turn LED ON'}), 500
|
||||
|
||||
@app.route('/led/off', methods=['POST', 'GET'])
|
||||
def led_off():
|
||||
if led.off():
|
||||
return jsonify({'status': 'success', 'message': 'LED turned OFF'})
|
||||
return jsonify({'status': 'error', 'message': 'Failed to turn LED OFF'}), 500
|
||||
|
||||
@app.route('/led/toggle', methods=['POST', 'GET'])
|
||||
def led_toggle():
|
||||
if led.toggle():
|
||||
return jsonify({'status': 'success', 'message': 'LED toggled'})
|
||||
return jsonify({'status': 'error', 'message': 'Failed to toggle LED'}), 500
|
||||
|
||||
@app.route('/led/blink', methods=['POST', 'GET'])
|
||||
def led_blink():
|
||||
count = int(request.args.get('count', 5))
|
||||
on_time = float(request.args.get('on_time', 0.2))
|
||||
off_time = float(request.args.get('off_time', 0.2))
|
||||
|
||||
if led.blink(count, on_time, off_time):
|
||||
return jsonify({
|
||||
'status': 'success',
|
||||
'message': f'LED blinking {count} times'
|
||||
})
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'message': 'LED is already blinking'
|
||||
}), 409
|
||||
|
||||
@app.route('/led/pulse', methods=['POST', 'GET'])
|
||||
def led_pulse():
|
||||
duration = float(request.args.get('duration', 2))
|
||||
interval = float(request.args.get('interval', 0.1))
|
||||
|
||||
if led.pulse(duration, interval):
|
||||
return jsonify({
|
||||
'status': 'success',
|
||||
'message': f'LED pulsing for {duration} seconds'
|
||||
})
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'message': 'LED is already active'
|
||||
}), 409
|
||||
|
||||
@app.route('/led/status', methods=['GET'])
|
||||
def led_status():
|
||||
state = led.status()
|
||||
return jsonify({
|
||||
'status': 'success',
|
||||
'led': state,
|
||||
'is_blinking': led.is_blinking
|
||||
})
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=5000, debug=True)
|
||||
```
|
||||
|
||||
## Permission Setup
|
||||
|
||||
Same as buzzer control - see `FLASK-BUZZER-CONTROL.md` for detailed permission setup options.
|
||||
|
||||
### Quick Setup (sudoers method)
|
||||
|
||||
Create `/etc/sudoers.d/led-control`:
|
||||
|
||||
```
|
||||
# Allow LED control without password
|
||||
pi ALL=(ALL) NOPASSWD: /usr/bin/tee /sys/class/leds/usr-led/brightness
|
||||
```
|
||||
|
||||
### Udev Rules Method
|
||||
|
||||
Create `/etc/udev/rules.d/99-led.rules`:
|
||||
|
||||
```
|
||||
SUBSYSTEM=="leds", KERNEL=="usr-led", MODE="0666", GROUP="audio"
|
||||
```
|
||||
|
||||
Then add user to audio group and reload udev:
|
||||
```bash
|
||||
sudo usermod -a -G audio pi
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
### Status Indicator
|
||||
|
||||
```python
|
||||
def show_status(status):
|
||||
"""Show status with LED"""
|
||||
if status == 'success':
|
||||
led.on()
|
||||
time.sleep(0.5)
|
||||
led.off()
|
||||
elif status == 'error':
|
||||
led.blink(3, 0.1, 0.1) # Fast blink 3 times
|
||||
elif status == 'warning':
|
||||
led.blink(2, 0.3, 0.3) # Slow blink 2 times
|
||||
```
|
||||
|
||||
### Notification System
|
||||
|
||||
```python
|
||||
def notify(message_type):
|
||||
"""Notify user with LED patterns"""
|
||||
patterns = {
|
||||
'info': (1, 0.2, 0.2), # 1 blink, 0.2s on/off
|
||||
'success': (2, 0.1, 0.1), # 2 fast blinks
|
||||
'error': (3, 0.05, 0.05), # 3 very fast blinks
|
||||
'warning': (2, 0.3, 0.3), # 2 slow blinks
|
||||
}
|
||||
|
||||
count, on_time, off_time = patterns.get(message_type, (1, 0.2, 0.2))
|
||||
led.blink(count, on_time, off_time)
|
||||
```
|
||||
|
||||
### System Monitoring
|
||||
|
||||
```python
|
||||
import psutil
|
||||
|
||||
def monitor_system():
|
||||
"""Use LED to indicate system load"""
|
||||
cpu_percent = psutil.cpu_percent(interval=1)
|
||||
|
||||
if cpu_percent > 80:
|
||||
led.pulse(1, 0.05) # Fast pulse for high load
|
||||
elif cpu_percent > 50:
|
||||
led.pulse(1, 0.1) # Medium pulse
|
||||
else:
|
||||
led.off() # Off for low load
|
||||
```
|
||||
|
||||
## Combined LED and Buzzer Control
|
||||
|
||||
You can combine LED and buzzer for multi-modal notifications:
|
||||
|
||||
```python
|
||||
def alert(message_type):
|
||||
"""Alert with both LED and buzzer"""
|
||||
if message_type == 'critical':
|
||||
# Fast LED blink + buzzer beep
|
||||
threading.Thread(target=led.blink, args=(5, 0.1, 0.1), daemon=True).start()
|
||||
buzzer.beep(0.3)
|
||||
elif message_type == 'notification':
|
||||
# Slow LED blink
|
||||
threading.Thread(target=led.blink, args=(2, 0.3, 0.3), daemon=True).start()
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### LED Not Responding / Not Visible
|
||||
|
||||
**Important**: The LED control interface accepts commands, but the LED may not be physically visible or may be in a location that's not easily observable. Here are troubleshooting steps:
|
||||
|
||||
1. **Verify LED device exists:**
|
||||
```bash
|
||||
ls -la /sys/class/leds/usr-led/
|
||||
cat /sys/class/leds/usr-led/brightness
|
||||
```
|
||||
|
||||
2. **Ensure trigger is set to 'none' for manual control:**
|
||||
```bash
|
||||
# Check current trigger
|
||||
cat /sys/class/leds/usr-led/trigger
|
||||
|
||||
# Set to 'none' for manual control
|
||||
echo none | sudo tee /sys/class/leds/usr-led/trigger
|
||||
```
|
||||
|
||||
3. **Test with different values:**
|
||||
```bash
|
||||
# Turn OFF
|
||||
echo 0 | sudo tee /sys/class/leds/usr-led/brightness
|
||||
sleep 1
|
||||
|
||||
# Turn ON (may show as 255, which is normal)
|
||||
echo 1 | sudo tee /sys/class/leds/usr-led/brightness
|
||||
sleep 1
|
||||
|
||||
# Check what value was actually set
|
||||
cat /sys/class/leds/usr-led/brightness
|
||||
```
|
||||
|
||||
4. **Check if LED responds to trigger modes:**
|
||||
```bash
|
||||
# Try default-on trigger
|
||||
echo default-on | sudo tee /sys/class/leds/usr-led/trigger
|
||||
sleep 2
|
||||
|
||||
# Return to manual control
|
||||
echo none | sudo tee /sys/class/leds/usr-led/trigger
|
||||
```
|
||||
|
||||
5. **Physical verification:**
|
||||
- The LED may be located in a position that's not easily visible
|
||||
- Check around the screen bezel, especially near the buzzer location
|
||||
- The LED might be very dim or require specific viewing angle
|
||||
- Some reTerminal DM units may not have a physical LED installed
|
||||
|
||||
6. **Check GPIO control (alternative method):**
|
||||
```bash
|
||||
# The LED is controlled via PCA9535 GPIO expander
|
||||
# Base GPIO: 578
|
||||
# You can try controlling via GPIO directly if LED subsystem doesn't work
|
||||
```
|
||||
|
||||
### LED Always On/Off
|
||||
|
||||
- Check if a trigger is active: `cat /sys/class/leds/usr-led/trigger`
|
||||
- Set trigger to 'none' for manual control: `echo none | sudo tee /sys/class/leds/usr-led/trigger`
|
||||
- Verify brightness value: `cat /sys/class/leds/usr-led/brightness` (should be 0 for off, 255 for on)
|
||||
|
||||
### Brightness Shows 255 Instead of 1
|
||||
|
||||
**This is normal behavior!** When you set brightness to 1 (on), the system may report it as 255. This is because:
|
||||
- The LED subsystem internally uses 0-255 range
|
||||
- Setting 1 maps to maximum brightness (255)
|
||||
- This is expected behavior and doesn't indicate a problem
|
||||
|
||||
### LED Not Physically Visible
|
||||
|
||||
According to official documentation, the reTerminal DM may not have a user-controllable LED indicator in all models. If the LED doesn't appear to turn on:
|
||||
|
||||
1. **Verify your model**: Check if your specific reTerminal DM4 unit includes a user LED
|
||||
2. **Check documentation**: Refer to Seeed Studio's official documentation for your specific model
|
||||
3. **Contact support**: If LED control is required, contact Seeed Studio support for model-specific information
|
||||
|
||||
### Alternative: Use System LEDs
|
||||
|
||||
If `usr-led` is not available or not visible, you can use system LEDs for status indication:
|
||||
- **ACT LED**: Shows SD card activity (system-controlled)
|
||||
- **PWR LED**: Power indicator (system-controlled)
|
||||
|
||||
Note: System LEDs are typically read-only and controlled by the system.
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- See `FLASK-BUZZER-CONTROL.md` for Flask integration examples
|
||||
- See `BUZZER-TEST-GUIDE.md` for buzzer control
|
||||
- See `AUDIO-CONFIGURATION-REPORT.md` for complete hardware info
|
||||
Reference in New Issue
Block a user