Major overhaul of power management system to address voltage-induced 4G module hangs through intelligent, event-driven power regulation. Key Features: - Unified power regulation based on AC power + 4G modem state - Event-driven AC detection via udev (power_supply subsystem) - Three optimized power modes for different scenarios - Automatic voltage monitoring with multi-method alerts Power Modes: - AC Connected: 2.4GHz (ondemand) - full performance - Battery + 4G: 1.8GHz (powersave) - voltage monitoring enabled - Battery Only: 2.0GHz (ondemand) - balanced performance Technical Improvements: - AC power state detection via udev events (not polling) - Edge case handling (service starts with AC connected) - Unified logging to /var/log/uconsole-power-regulator.log - Upgrade path from old 4G Power Manager - State tracking to avoid redundant regulator triggers Components: - uconsole-power-regulator.sh: Main power orchestrator - uconsole-power-daemon.sh: Background state monitoring (5s interval) - voltage-monitor.sh: Voltage checker (Battery + 4G only) - voltage-alert-notify.sh: Multi-method alerts (desktop/audio/log/LED) - voltage-monitor-control.sh: Monitor lifecycle controller - 99-uconsole-power-regulator.rules: udev event triggers - install-uconsole-power-regulator.sh: Installation + upgrade script Documentation: - Updated README.md with new system overview - Created README_CN.md (Chinese translation) - Updated TOOL-GUIDE.md with new architecture details - Updated CLAUDE.md with unified system documentation Breaking Changes: - Replaces 4G Power Manager with unified regulator - New service name: uconsole-power-regulator.service - New log file: /var/log/uconsole-power-regulator.log - Use upgrade script to migrate from old system Installation: - Fresh: sudo ./install-uconsole-power-regulator.sh install - Upgrade: sudo ./install-uconsole-power-regulator.sh upgrade - Uninstall: sudo ./install-uconsole-power-regulator.sh uninstall
13 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Battery Monitor is a Next.js 16 web application designed to run on Raspberry Pi uConsole CM5 hardware. It monitors and visualizes battery metrics in real-time by reading from Linux sysfs power supply interfaces specific to AXP20x/AXP22x power management chips commonly found in embedded systems.
Key Features
- Real-time battery monitoring with interactive charts
- Two Monitoring Modes: Live mode (real-time charts) and Background mode (battery-saving)
- Historical data storage and session management (SQLite)
- CSV export functionality
- Incomplete session detection and repair
- 4G Power Management: Automatic CPU frequency scaling to prevent system hangs when 4G module is active on battery
Development Commands
# Install dependencies
npm install
# Run development server (http://localhost:3000)
npm run dev
# Build for production
npm build
# Run production server
npm start
# Run linter
npm run lint
Hardware-Specific Context
This application is designed to run on Raspberry Pi or similar embedded Linux systems with AXP20x battery management hardware. The API reads from these sysfs paths:
- Battery data:
/sys/class/power_supply/axp20x-battery/* - AC adapter:
/sys/class/power_supply/axp22x-ac/online
Important: The application will fail to read battery data on systems without these hardware interfaces. When testing on non-Pi hardware, the API will return 500 errors.
Architecture
Frontend (Client-Side)
- Main Component:
src/components/BatteryMonitor.tsxis a client component that polls the battery API every 2 seconds when monitoring is active - State Management: Uses React hooks to maintain current battery data and historical readings (last 100 data points)
- Visualization: Uses Recharts for real-time line and area charts showing battery percentage, power consumption, voltage, and current trends
- Data Export: CSV export functionality for historical battery data
Backend (Server-Side)
- API Route:
src/app/api/battery/route.tsprovides a GET endpoint at/api/battery- Add
?save=truequery parameter to save readings to database
- Add
- Hardware Interface: Reads directly from Linux sysfs using Node.js
fs.readFileSync() - Data Transformation: Converts raw values from microvolts (µV) and microamps (µA) to volts and amps
- Database: SQLite database (
battery-data.db) stores historical readingssrc/lib/db.tscontains database utilities and schema/api/battery/history- Query historical data by time range/api/battery/sessions- Get monitoring session summaries
UI Components
Located in src/components/ui/, these are shadcn/ui components customized for this project:
- Card, Button, Badge, Progress, Table components
- Chart components for Recharts integration
- All use the
cn()utility fromsrc/lib/utils.tsfor Tailwind class merging
Path Aliases
The project uses @/* to reference src/*:
import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';
Key Dependencies
- Next.js 16: App Router architecture with React 19
- Recharts: Charts and data visualization
- shadcn/ui: UI component library (Radix UI primitives)
- Tailwind CSS 4: Styling with PostCSS
- date-fns: Date formatting
- lucide-react: Icons
- better-sqlite3: SQLite database for persistent data storage
TypeScript Configuration
- Strict mode enabled
- JSX mode:
react-jsx(React 19 automatic runtime) - Module resolution:
bundler - Path alias
@/*maps to./src/*
Data Flow
Monitoring vs Recording
The application separates monitoring (display only) from recording (database writes), and offers two display modes for power optimization:
Monitoring Mode (No Database Writes):
- User clicks "Start Monitoring" button
BatteryMonitorcomponent sets up 2-second polling interval- Each poll hits
/api/batteryendpoint (NO database save) - API reads raw battery values from sysfs
- API converts and calculates derived values (voltage, current, power)
- Frontend updates state, appends to
historicalData(max 100 points in memory) - Data is also buffered in
monitoringDataBufferRef(max 1000 points) - Charts automatically re-render with new data
- User can start recording at any point
Recording Mode (With Database Writes):
- While monitoring is active, user selects recording start point:
- "Record from now": New data only
- "Record from monitoring start": Saves buffered data since monitoring began
- User clicks "Start Recording"
- Creates new session in database with selected start time
- If "from monitoring start", sends buffered data via
/api/battery/saveendpoint - Each subsequent poll hits
/api/battery?save=true&sessionId=X - Readings are saved to database immediately with session association
- User can stop recording (monitoring continues) or stop both
- Session
end_timeandreading_countupdated on stop
Power Failure Resilience:
- All readings are saved to SQLite database immediately (synchronous commits)
- If power dies during recording, all data up to that point IS preserved
- Session metadata may be incomplete:
end_timeequalsstart_time,reading_countmay be 0 - UI automatically detects incomplete sessions (yellow warning badge)
- "Repair All" button updates incomplete sessions to correct end_time and reading_count
- Repair endpoint:
/api/battery/sessions/repair(POST withrepairAll: trueor specificsessionId)
Display Modes (Battery Optimization):
Live Mode (Default):
- Full real-time chart rendering with animations
- All visualizations active (percentage, power, voltage, current charts)
- Higher power consumption due to continuous SVG rendering
- Best for active monitoring and data analysis
Background Mode (Battery Saving):
- Charts hidden completely (no rendering overhead)
- Only current stats displayed in the status card
- Same 2-second polling interval (consistent data quality)
- Full data granularity maintained - historicalData array still updated
- Database recording continues normally
- Saves ~20-40% power through multiple optimizations:
- No chart SVG rendering (biggest win)
- Disabled chart animations globally
- Removed CartesianGrid (reduces SVG elements)
- Lazy-loaded sessions list (Intersection Observer)
- Best for long recording sessions where visualization isn't needed
- Safe for power failure testing - no data loss
Toggle between modes with the "Live Mode" / "Background Mode" button when monitoring is active.
Power Optimizations Applied:
- Charts hidden in background mode (eliminates 4 Recharts re-renders every 2s)
- Chart animations disabled (
isAnimationActive={false}on all Line/Area components) - CartesianGrid removed from all charts (reduces SVG complexity by ~30%)
- Sessions list lazy-loaded only when scrolled into view (Intersection Observer)
- Data granularity preserved - no polling changes, historicalData always updated
Historical Data Mode
- User selects start/end date/time in "Export Custom Time Range" card
- Frontend queries
/api/battery/history?start=<ISO>&end=<ISO> - Database returns all readings within the time range
- User can view data in charts or export directly to CSV
- User can click "Back to Live View" to resume real-time monitoring
Per-Session Export
- User clicks download button on specific session
- Frontend fetches
/api/battery/sessions/:id - All readings for that session are retrieved
- Data is exported to CSV with session name in filename
Working with Battery Data
The BatteryData interface is shared between API and frontend:
interface BatteryData {
timestamp: string; // ISO 8601 format
percentage: number; // 0-100
voltage: number; // volts (converted from µV)
current: number; // amps (converted from µA, positive=charging, negative=discharging)
power: number; // watts (voltage * current, positive=charging, negative=discharging)
status: string; // e.g., "Charging", "Discharging", "Full"
health: string; // e.g., "Good", "Unknown"
acConnected: boolean; // true if AC adapter is connected
}
Database Schema
The SQLite database (battery-data.db) contains two tables:
monitoring_sessions table - Tracks monitoring sessions:
id: Auto-incrementing primary keyname: Custom session name (nullable, editable by user)start_time: ISO 8601 timestamp when monitoring startedend_time: ISO 8601 timestamp when monitoring stoppedreading_count: Number of readings in this sessioncreated_at: Database insertion timestamp
battery_readings table - Stores individual battery readings:
id: Auto-incrementing primary keysession_id: Foreign key tomonitoring_sessions(nullable)timestamp: ISO 8601 timestamp from battery readingpercentage,voltage,current,power,status,health: Battery metricsac_connected: Boolean (stored as 0/1)created_at: Database insertion timestamp
Indexes on timestamp, created_at, and session_id for efficient queries.
Session Management
- When "Start Monitoring" is clicked, a new session is created
- All readings during monitoring are linked to that session via
session_id - When "Stop Monitoring" is clicked, the session's
end_timeandreading_countare updated - Users can select sessions from a dropdown or edit session names inline for easier identification
- Default session name:
Session [start timestamp](can be customized) - Users can delete sessions with a confirmation dialog - this removes the session and all associated readings
Error Handling
- If sysfs files cannot be read, API returns 500 error with
{ error: 'Unable to read battery data' } - Frontend displays error state in a red error card
- Missing or null values from sysfs are handled gracefully in
getBatteryData()
uConsole Smart Power Regulator
Located in scripts/ directory. See STORY.md and TOOL-GUIDE.md for full documentation.
Problem
The 4G modem (SimTech SIM7600G-H) requires minimum 3.45V to operate reliably. When battery voltage drops below this threshold, the modem can hang the entire system, requiring physical battery removal to restart. The issue is voltage-related, not power budget.
Solution: Unified Event-Driven Power Regulation
Key Components:
-
uconsole-power-regulator.sh - Main orchestrator
- Determines power state based on AC and 4G status
- Applies appropriate CPU settings for each state
- Controls voltage monitoring
- Logs to
/var/log/uconsole-power-regulator.log
-
uconsole-power-daemon.sh - Background daemon
- Monitors AC power and 4G modem state every 5 seconds
- Triggers regulator only when state changes
- Handles edge cases (e.g., service starts with AC already connected)
-
Voltage Monitoring System:
voltage-monitor.sh- Checks voltage every 5 seconds when Battery + 4G activevoltage-alert-notify.sh- Multi-method alerts (desktop notification, audio, log, LED)voltage-monitor-control.sh- Start/stop controller- Alerts when voltage < 3.45V, rate-limited to every 30 seconds
-
udev Rules:
scripts/99-uconsole-power-regulator.rules- Triggers on AC power connect/disconnect (power_supply subsystem)
- Triggers on 4G modem USB device changes (vendor:product = 1e0e:9001)
- Monitors wwan0 interface state changes
- Responds to ttyUSB and cdc-wdm device events
-
Power Modes:
State AC 4G Governor Max Freq Voltage Monitoring AC_POWER Connected Any ondemand 2.4GHz Off BATTERY_4G Disconnected Active powersave 1.8GHz On BATTERY_ONLY Disconnected Inactive ondemand 2.0GHz Off -
Installation:
scripts/install-uconsole-power-regulator.sh- Fresh install:
sudo ./install-uconsole-power-regulator.sh install - Upgrade from old system:
sudo ./install-uconsole-power-regulator.sh upgrade - Uninstall:
sudo ./install-uconsole-power-regulator.sh uninstall
- Fresh install:
Hardware Context
- AXP228 PMIC: Has IPS™ (Intelligent Power Select) that manages USB, AC, and battery inputs
- Power Limits: Battery discharge path limited to ~18-20W sustained
- Battery Config: Two 18650 cells in parallel (not series, no switching)
- USB Supplementation: When on USB power, can combine USB + battery for ~25W total
- 4G Modem: SimTech SIM7600G-H (Qualcomm), creates ttyUSB0-4 and wwan0 interface
Integration with Battery Monitor
The battery monitor app can display real-time power consumption, helping users:
- Monitor if power stays below 18-20W threshold
- Verify 4G power manager is working (power should drop when 4G activates)
- Track battery voltage under load (should stay above 3.3V)
Tuning
Edit scripts/4g-power-manager.sh configuration:
MAX_FREQ_POWERSAVE="1800000" # Lower for more power saving (try 1500000)
POWERSAVE_GOVERNOR="powersave" # Or try "conservative"
Commit Messages
- Do not mention Claude Code or AI assistance in commit messages
- Focus on technical changes and benefits to users
- do not mention claude in git commit