Two critical fixes for the voltage monitoring system when 4G is active
on battery power:
1. Desktop Notifications Now Working:
- Fixed D-Bus socket detection in voltage-alert-notify.sh
- Changed from non-existent 'dbus-session' file to correct socket
path /run/user/$USER_ID/bus
- Notifications now properly appear when voltage drops below 3.45V
- Added timestamp to notification message for better tracking
- Made notification message more compact and actionable
2. Voltage Monitor Stability Fixed:
- Added nohup when backgrounding monitor process in voltage-monitor-control.sh
- Prevents SIGHUP signal when parent script exits
- Monitor now remains stable and continuously detects low voltage
- Rate-limited alerts working correctly (every 30 seconds)
Testing confirmed:
- Notifications display correctly with timestamp
- Monitor survives AC connect/disconnect cycles
- Low voltage detection working (threshold: 3.45V)
- Alerts sent successfully during battery drain with 4G active
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The voltage monitoring system was detecting low battery voltage correctly
but desktop notifications were not appearing. The issue was in the D-Bus
session detection logic which searched for a non-existent "dbus-session"
file.
Changes:
- Use correct D-Bus socket path: /run/user/$USER_ID/bus
- Check socket existence with [ -S ] instead of searching for file
- Notifications now properly appear when voltage drops below 3.45V
This ensures users receive critical warnings when the 4G modem is active
on battery and voltage reaches dangerous levels that could cause system hangs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added blank lines between images and captions to ensure captions appear
on a new row below images instead of on the same line.
This follows Markdown best practices where a blank line creates a new
paragraph for the caption text.
Fixed in both STORY.md and STORY.zh-CN.md for all images.
Image optimizations:
- Converted all PNG screenshots to JPG format
- Resized all images to max 800px width
- Reduced quality to 80% (optimal for web)
- Maintained visual clarity while reducing file sizes
Size reductions:
- uconsole-debugging-4g.jpg: 265KB → 119KB (55% smaller)
- feb4000-battery-percentage: 46KB → 28KB (39% smaller)
- feb4000-voltage-current: 69KB → 40KB (42% smaller)
- feb4000-energy-output-with-threshold: 70KB → 41KB (41% smaller)
Total savings: ~185KB combined (185KB → 228KB for all 4 images)
Faster page load times with no noticeable quality loss
Updated image references in both STORY.md and STORY.zh-CN.md
- Converted original 3.6MB iPhone photo to 265KB web-optimized JPG (93% reduction)
- Resized to 1200px width with 85% quality for fast loading
- Added to both English and Chinese story files
- Placed after introduction section to show vibe coding in action
- Caption emphasizes building on the device experiencing the problem
Image location: story-assets/uconsole-debugging-4g.jpg
Major rewrite to match the voltage-focused narrative in STORY.md:
Content Changes:
- Removed outdated power budget calculations and theory
- Focused narrative on voltage drop discovery (not power delivery)
- Added voltage threshold analysis (3.45V minimum for 4G module)
- Included usable vs unusable capacity breakdown (54% vs 46%)
- Updated all component descriptions to unified power regulator
- Aligned power modes table and testing results
- Added event-driven AC detection mention
Technical Updates:
- Changed from 4G Power Manager to uConsole Smart Power Regulator
- Updated installation commands to install-uconsole-power-regulator.sh
- Added voltage monitoring system components description
- Included power modes table (AC/Battery+4G/Battery)
- Updated community impact section with AC detection
Structure:
- Now 250 lines (previously 397) - cleaner, more focused
- Matches English version structure and flow
- Removed redundant technical explanations
- Kept essential voltage discovery story
Both English and Chinese versions now tell the same story with proper alignment.
- Updated installation commands to use new install-uconsole-power-regulator.sh
- Changed references from '4G Power Manager' to 'uConsole Smart Power Regulator'
- Added power modes table showing AC/Battery+4G/Battery scenarios
- Updated feature list to include AC detection and voltage monitoring
- Clarified voltage-based issue vs power budget issue
- Added upgrade path mention
Both English and Chinese versions now aligned with unified system.
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
**STORY.md (Main Article):**
- Focused on the 4G voltage discovery and vibe coding workflow
- Emphasizes the problem-solving narrative and methodology
- Highlights voltage drop as root cause, not power budget
- Shorter, more engaging format for casual readers
- Links to TOOL-GUIDE.md for technical details
**TOOL-GUIDE.md (Technical Reference):**
- Comprehensive user manual for battery monitor tool
- Complete API reference and endpoints
- Battery testing methodology and interpretation
- 4G power manager installation and tuning
- Troubleshooting guide and advanced usage
- Database schema and CSV format documentation
This split allows readers to:
1. Get inspired by the vibe coding story (STORY.md)
2. Dive deep into tool usage when needed (TOOL-GUIDE.md)
Both documents cross-reference each other appropriately.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major story revision based on real-world testing and analysis:
**New Findings:**
- Root cause: Voltage drop below 3.45V (4G module minimum), not power budget
- SimTech SIM7600G-H operates at 3.4-4.2V; hangs below 3.45V threshold
- FEB-4000 battery test: 13.4 Wh usable (54%) above 3.45V threshold
**New Features:**
- Add 3.45V reference line to Energy Output vs. Voltage chart
- Visual indicator for 4G module minimum voltage threshold
- Real discharge curve analysis from 2h 48m FEB-4000 battery test
**Story Changes:**
- Focus shifted from power (watts) to voltage stability
- Include community discussion findings from ClockworkPi forums
- Add detailed FEB-4000 test results with screenshots
- Reframe 4G power manager as voltage-aware solution
- Add battery rating methodology based on usable capacity above 3.45V
**Screenshots Added:**
- feb4000-battery-percentage.png - Full discharge curve
- feb4000-voltage-current.png - Voltage/current trends
- feb4000-energy-output-with-threshold.png - Critical 3.45V analysis
This reflects the actual discovery: not insufficient wattage, but voltage sag under load causing 4G module brownout.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Energy output chart now displays correctly for saved sessions by using first reading's capacityNow as baseline
- Improve chart label layout with proper spacing (removed cut-off issue)
- Eliminate 1s+ lag when editing session names by switching to uncontrolled input pattern
- Add keyboard shortcuts for session editing (Enter to save, Escape to cancel)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add initialCapacityRef to track starting battery capacity
- Transform historical data to calculate energy output in mWh using direct capacity method
- Reorganize charts into 2x2 grid layout with consistent 200px heights
- Add new chart: Energy Output (mWh) vs Voltage (V)
- Shows discharge curve for determining usable capacity at different voltage cutoffs
- Uses hardware fuel gauge readings for accuracy (no accumulation errors)
- Format voltage with 2 decimal places (.xx) and energy with 1 decimal place (.x)
- Maintains power-saving compatibility (hidden in background mode)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Distinguishes between system/host uptime and monitoring session duration
for clearer metrics tracking.
System Uptime:
- Read from /proc/uptime (Linux system uptime)
- Shows how long the Raspberry Pi has been running
- Always visible in status card
- Format: Xh Ym Zs (e.g., "2h 15m 43s")
- Updates every 2 seconds with battery data
Session Time:
- Renamed from "Uptime" for clarity
- Tracks current monitoring session duration
- Only visible when monitoring is active
- Resets when Start Monitoring is clicked
- Independent of system uptime
Implementation:
- getSystemUptime() reads /proc/uptime first field (seconds)
- Added systemUptime to BatteryData interface
- Renamed uptime state to sessionTime
- Updated all references and UI labels
UI Layout:
Status card now shows (when monitoring):
├─ Battery metrics (6 cards)
├─ System Uptime (always visible)
├─ Session Time (monitoring only)
└─ Energy Consumed (monitoring only)
Benefits:
- System Uptime: Track system stability, detect unexpected reboots
- Session Time: Know exact monitoring duration for tests
- Clear distinction between host and application metrics
Implements real-time uptime and energy (Wh) tracking for monitoring
sessions, with live display and per-session historical calculations.
Real-Time Monitoring Display:
- Uptime counter updates every second (formatted as Xh Ym Zs)
- Energy consumed calculated using trapezoidal integration
- Formula: Energy += avg(Power[i-1], Power[i]) × time_delta
- Displays both Wh and mWh for precision
- Shows in status card when monitoring is active
Energy Calculation Algorithm:
- Uses trapezoidal rule for numerical integration
- Calculates average power between consecutive readings
- Accounts for variable time intervals
- Uses Math.abs() for absolute power consumption
- Accumulates energy from monitoring start
Per-Session Energy Display:
- calculateSessionEnergy() function in db.ts
- Processes all readings for a session
- Shows total Wh consumed during session
- Displays duration in human-readable format
- Updates session list with: "X readings • Xh Ym Zs • X.XXX Wh"
State Management:
- energyConsumed state tracks cumulative Wh
- uptime state tracks elapsed seconds
- lastPowerReadingRef stores previous reading for integration
- All reset on Start Monitoring
- All cleared on Stop Monitoring
Session Interface Updates:
- Added energy_wh?: number (optional for backward compatibility)
- Added duration_seconds?: number
- getMonitoringSessions() now calculates both automatically
UI Improvements:
- Two new cards in status grid during monitoring
- Uptime card with live seconds counter
- Energy card with Wh/mWh dual display
- Session list shows duration and energy per session
- formatUptime() helper for consistent time formatting
Performance:
- Energy calculation is O(n) over readings
- Cached in session query (no repeated calculations)
- Minimal overhead (~1ms per session)
Reverts the historicalData skip and adds multiple optimizations that
reduce power consumption without sacrificing data quality or reliability.
Data Preservation Changes:
- Revert: historicalData array now always updated (no data loss)
- Full granularity maintained in background mode
- Safe for power failure scenarios - last data point always preserved
- No changes to polling interval (still 2 seconds)
Power Optimizations (Applied to ALL modes):
1. Disable chart animations - isAnimationActive={false} on all charts
2. Remove CartesianGrid from all charts (~30% less SVG elements)
3. Lazy-load sessions list with Intersection Observer
- Sessions only fetched when card scrolls into view
- Eliminates initial load database query
Background Mode Benefits:
- Charts hidden (no rendering overhead)
- Same 2-second data collection
- historicalData array populated normally
- Database recording unchanged
- Combined optimizations save ~20-40% power
- Perfect for long-term monitoring and power testing
Live Mode Benefits:
- Full visualizations with cleaner, faster charts
- No animation overhead
- Simpler SVG rendering (no grid lines)
- Better performance on embedded systems
Technical Details:
- useEffect with IntersectionObserver for sessions lazy loading
- sessionsLoaded flag prevents multiple fetches
- threshold: 0.1 for early loading when user scrolls near
- All data arrays maintain full fidelity
- Monitoring buffer still caps at 1000 points
Documentation updates:
- Clarify full data granularity in background mode
- List all power optimizations with explanations
- Add note about power failure safety
Implements two display modes to reduce power consumption during monitoring
while maintaining consistent data collection quality.
Features:
- Live Mode: Full real-time charts with animations (default)
- Background Mode: Charts hidden, minimal UI updates (battery-saving)
- Same 2-second polling interval in both modes
- Database recording continues normally in both modes
- Mode toggle button appears when monitoring is active
Live Mode:
- All visualizations active (4 charts with animations)
- Real-time chart updates every 2 seconds
- Best for active monitoring and data analysis
- Higher power consumption from continuous SVG rendering
Background Mode:
- Charts completely hidden (no rendering overhead)
- Only current stats shown in status card
- Blue info card shows mode status
- Saves ~20-40% power by eliminating chart re-renders
- Best for long recording sessions
- historicalData state not updated (skips array manipulation)
UI improvements:
- Eye/EyeOff icons for mode toggle
- Background mode info card with status message
- Shows recording status in background mode message
- Charts still appear when viewing historical data
Technical optimizations:
- Skip setHistoricalData() updates in background mode
- Conditional chart rendering based on mode
- Buffer management continues in both modes
- No impact on data quality or database writes
Documentation updates:
- Add Display Modes section to CLAUDE.md
- Explain power savings and use cases for each mode
- Update feature list with two monitoring modes
When power dies during recording, all data is preserved but session
metadata is incomplete (end_time = start_time, reading_count = 0).
This adds automatic detection and repair of such sessions.
Features:
- Detect sessions where start_time equals end_time but has readings
- Visual indicators: yellow badge showing incomplete session count
- "Repair All" button in Recording Sessions card header
- Individual session badges showing "Incomplete" status
- Yellow highlighting for incomplete sessions in the list
- New API endpoint: /api/battery/sessions/repair
Database improvements:
- getIncompleteSessions() finds sessions needing repair
- repairSession() updates end_time to last reading timestamp
- repairAllIncompleteSessions() repairs all incomplete sessions
- Auto-calculates correct reading_count from actual data
UI improvements:
- AlertTriangle icon for incomplete session warnings
- RefreshCw icon for repair action
- Automatic incomplete session counting on session list load
- User-friendly repair confirmation with count of repaired sessions
Bug fix:
- Changed LEFT JOIN to INNER JOIN in incomplete detection query
- Use COUNT(r.id) instead of reading_count column for accuracy
When selecting "Record from start", the system now properly saves all
data points collected between clicking "Start Monitoring" and
"Start Recording".
Changes:
- Add new POST /api/battery/save endpoint for bulk saving readings
- Replace placeholder saveSingleReading with saveBufferedReadings
- Batch save all buffered readings in a single API call
- Log number of saved readings for verification
Previously, the saveSingleReading function was just a placeholder that
didn't actually save data to the database, causing data loss when users
selected "from start" option.
Extends battery monitoring to include energy capacity metrics:
- Read energy_full_design, energy_full, and energy_now from sysfs
- Convert µWh values to Wh for display and storage
- Add capacity columns to database with migration support
- Update UI to show current, full, and design capacity values
- Include capacity data in CSV exports
This provides better insight into actual battery health and remaining
energy beyond just percentage, useful for calculating runtime estimates.
Remove Math.abs() from power value display in battery status section.
Power should be negative when discharging and positive when charging
to accurately reflect energy flow direction.
Changes to STORY.md:
- Reframe as part of 'Vibe Coding for Work/Life' series
- More conversational and engaging tone throughout
- Emphasize the joy and freedom of portable development
- Update title: 'Vibe Coding Chronicles: Solving uConsole's Power Crisis...'
- Add series context and hashtag #VibeCodingChronicles
- Rewrite sections to be more relatable and less technical-only
- Add call-to-action for community building
Add STORY.zh-CN.md:
- Complete Chinese translation of the updated story
- Maintains same structure, tone, and technical accuracy
- Localized for Chinese-speaking audience
- All screenshots, code blocks, and technical details preserved
This post chronicles the development journey of solving the uConsole CM5's 4G
power management issue through battery monitoring and automatic power scaling.
Key sections:
- Research phase: AXP228 PMIC power limits and battery configuration
- Solution design: Real-time monitoring with Next.js + automatic power management
- Implementation details: React 19, TypeScript, SQLite, systemd, udev
- Screenshots showcasing the battery monitor UI and features
- Technical appendix with power budget analysis and API documentation
The story emphasizes "vibe coding" - rapid development directly on the target
device, enabling fast iteration and immediate feedback loops.
Includes targeted screenshots of:
- Full battery monitoring interface
- Real-time status dashboard with live metrics
- Interactive charts (percentage, power, voltage, current)
- Recording session management with edit/export functionality
- Custom time range export interface
Major UX improvements:
- Separate 'Start Monitoring' (display only) from 'Start Recording' (save to DB)
- Merge recording options into single combined button: 'Start Recording [from now/from start]'
- Buffer monitoring data in memory (up to 1000 readings) for retroactive recording
- Move CSV export to individual session rows and custom time range card
- Add visual indicators: Live badge (monitoring) and Recording badge (saving)
- Restore original 3-chart layout with proper styling and grid layout
- Make charts always visible (not hidden when monitoring stops)
- Add subtle blue highlighting for selected sessions
- Improve real-time status display with always-updated current data
Benefits:
- Users can observe battery behavior before deciding to record
- No wasted database space for exploratory monitoring
- Export exactly what you need (per session or custom range)
- Cleaner, more intuitive UI with better visual feedback
- Clearer separation of concerns improves UX
Documentation updates:
- Updated README.md with new monitoring/recording workflow
- Updated CLAUDE.md with detailed data flow explanation
- Added per-session export documentation
- Clarified the purpose of separating monitoring from recording
- Extended install-4g-power-manager.sh with comprehensive uninstall command
- Uninstall stops/disables service, removes all files, cleans temp files
- Restores CPU settings to default (ondemand governor, 2.4GHz)
- Prompts user whether to keep or remove log files
- Supports selective uninstall (daemon only or udev only)
- Updated documentation with uninstall instructions
- Improved usage examples and help text
- Enhanced README.md with 4G power management feature overview
- Added quick install instructions and link to full documentation
- Updated CLAUDE.md with detailed 4G power management architecture
- Documented hardware context, power limits, and AXP228 behavior
- Added integration notes for battery monitor app usage
This is a Next.js 16 web application for Raspberry Pi uConsole CM5 that:
- Monitors battery metrics in real-time from AXP20x power supply
- Visualizes battery data with charts (Recharts)
- Stores historical data in SQLite database
- Exports data to CSV
- Manages monitoring sessions
New Feature: 4G Power Manager
- Automatically detects 4G modem state changes
- Reduces CM5 CPU frequency when 4G is active to prevent hangs
- Uses udev rules + systemd service for reliable monitoring
- Solves battery power delivery limitation (18-20W max from AXP228)
Hardware: Raspberry Pi CM5 with AXP228 power management IC
Tech Stack: Next.js 16, React 19, TypeScript, Tailwind CSS 4, shadcn/ui