
Battery Selector
- 77 installs
- 19 repo stars
- Updated May 26, 2026
- wedsamuel1230/arduino-skills
Helps with ai & agent building tasks.
About
battery-selector is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- battery-selector
- AI & Agent Building
- AI-coding skill
Battery Selector by the numbers
- 77 all-time installs (skills.sh)
- +6 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #5,386 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 1, 2026 (Skillselion catalog sync)
npx skills add https://github.com/wedsamuel1230/arduino-skills --skill battery-selectorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 77 |
|---|---|
| repo stars | ★ 19 |
| Last updated | May 26, 2026 |
| Repository | wedsamuel1230/arduino-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Battery Selector
Guides battery chemistry and charging circuit selection for embedded projects.
Resources
This skill includes bundled tools and references:
- scripts/compare_batteries.py - Battery comparison calculator with 15+ battery types
- references/safety-guidelines.md - Comprehensive safety guide for all chemistries
Quick Start
Interactive selection:
uv run --no-project scripts/compare_batteries.py --interactiveCommand line:
# Find battery for 50mA project, 24h runtime
uv run --no-project scripts/compare_batteries.py --current 50 --hours 24
# Require rechargeable
uv run --no-project scripts/compare_batteries.py --current 100 --hours 12 --rechargeable
# List all batteries in database
uv run --no-project scripts/compare_batteries.py --listWhen to Use
- "What battery should I use?"
- "How do I charge this project?"
- "Lithium vs alkaline?"
- "Is this battery safe?"
- Planning portable/battery-powered projects
Decision Flowchart
START
│
▼
Is project rechargeable? ──No──► Alkaline/Lithium Primary
│ (Disposable batteries)
Yes
│
▼
What voltage does MCU need?
│
├── 5V ──► LiPo + Boost converter
│ OR 3x/4x NiMH
│
├── 3.3V ──► Single LiPo (3.0-4.2V)
│ Directly compatible!
│
└── 12V+ ──► Multi-cell LiPo pack
OR Lead-acid
│
▼
How much current?
│
├── <50mA ──► Small LiPo (500-1000mAh)
│ OR Coin cell (CR2032)
│
├── 50-500mA ──► Standard LiPo (1000-3000mAh)
│ OR 18650 cells
│
└── >500mA ──► Large LiPo (3000mAh+)
OR Multiple 18650s
External power recommendedBattery Chemistry Comparison
Quick Reference
| Chemistry | Voltage | Rechargeable | Energy Density | Cost | Safety |
|---|---|---|---|---|---|
| Alkaline | 1.5V/cell | No | Medium | Low | Very safe |
| Lithium Primary | 3V | No | High | Medium | Safe |
| NiMH | 1.2V/cell | Yes | Medium | Medium | Safe |
| LiPo/Li-ion | 3.7V | Yes | Very High | Medium | ⚠️ Needs care |
| LiFePO4 | 3.2V | Yes | High | High | Safer than LiPo |
| Lead-acid | 2V/cell | Yes | Low | Low | ⚠️ Acid hazard |
Alkaline (AA/AAA/9V)
Pros:
- Cheap, available everywhere
- No charging circuit needed
- Very safe
- Long shelf life (5-10 years)
Cons:
- Not rechargeable (e-waste!)
- Voltage drops as discharged
- Poor at high current
- Heavy for capacity
Best For:
- Low-power projects (<20mA average)
- Beginner projects
- Remote/deployment where charging impractical
- Backup power
Voltage Configurations:
Cells Voltage Use With
────────────────────────────
2x AA 3.0V 3.3V MCUs (with LDO)
3x AA 4.5V 5V MCUs (direct or LDO)
4x AA 6.0V 5V MCUs (with regulator)
9V 9.0V With 5V/3.3V regulator---
NiMH (AA/AAA Rechargeable)
Pros:
- Rechargeable (500-1000 cycles)
- Same size as alkaline
- Safer than lithium
- No memory effect
Cons:
- Lower voltage (1.2V vs 1.5V)
- Self-discharge (~20%/month)
- Need proper charger
- Heavier than LiPo
Best For:
- Projects replacing disposable batteries
- Educational settings
- Where LiPo is too risky
- Budget rechargeable solution
Charging:
- Use dedicated NiMH charger
- Don't mix brands/capacities
- Eneloop/Eneloop Pro recommended
---
LiPo / Li-ion (3.7V)
Pros:
- High energy density (light + powerful)
- Rechargeable (300-500 cycles)
- Flat discharge curve
- Many form factors
Cons:
- ⚠️ Fire risk if abused
- Needs protection circuit
- Temperature sensitive
- Ages even unused
Best For:
- Most portable projects
- Weight-sensitive applications
- When you need runtime
- Professional builds
Critical Safety Rules:
✅ DO:
- Use protected cells with BMS
- Store at 40-60% charge
- Use proper TP4056/similar charger
- Monitor temperature during charge
- Use battery with JST-PH connector (prevents polarity swap)
❌ DON'T:
- Puncture, crush, or bend
- Charge below 0°C
- Discharge below 3.0V
- Leave charging unattended (first few times)
- Use damaged/puffy batteries---
LiFePO4 (3.2V)
Pros:
- Much safer than LiPo (no thermal runaway)
- Longer cycle life (2000+ cycles)
- Flat discharge curve
- Tolerates abuse better
Cons:
- Lower energy density
- Lower voltage (may need boost)
- More expensive
- Less common in small sizes
Best For:
- Safety-critical applications
- Outdoor/rugged deployments
- Long-term installations
- When LiPo risk unacceptable
---
CR2032 / Coin Cells
Pros:
- Tiny and light
- Long shelf life
- 3V output (direct to 3.3V MCU)
Cons:
- Very low capacity (220mAh)
- Poor high-current performance
- Not rechargeable
- ⚠️ Danger if swallowed
Best For:
- Ultra-low power only (<10µA average)
- RTC backup
- Tiny sensors
- Keyfobs, beacons
Current Limits:
Continuous: <2mA
Pulse: <15mA (brief)
DON'T use for: WiFi, Bluetooth, motors, LEDs---
Voltage Regulation
3.3V Systems (ESP32, RP2040)
Single LiPo → 3.3V:
LiPo outputs 3.0-4.2V
Most 3.3V MCUs tolerate this range directly!
Option 1: Direct connection (if MCU allows)
LiPo(+) → 3.3V/VIN pin
Option 2: LDO for clean 3.3V
LiPo(+) → [AMS1117-3.3] → 3.3V pin
(Need 4V min input for AMS1117)
Better: Use HT7333 LDO (low dropout, low quiescent)
Works from 3.3V input!5V Systems (Arduino UNO/Nano)
LiPo → 5V:
Option 1: Boost converter
LiPo(+) → [MT3608] → 5V → VIN pin
Option 2: PowerBoost module (Adafruit)
Includes charging + boost + protection
Option 3: USB power bank
Already regulated 5V + charging built-in---
Charging Solutions
TP4056 Module (Most Popular)
┌─────────────────────────────┐
│ TP4056 with Protection │
│ │
│ [USB-C] ─► [TP4056] ─► [DW01+FS8205] ─► [B+/B-]
│ IN Charger Protection To Battery
│ │
│ Features: │
│ - 1A max charge current │
│ - Overcharge protection │
│ - Overdischarge protect │
│ - Short circuit protect │
│ - LED charge indicator │
└─────────────────────────────┘
Wiring:
B+ → LiPo positive
B- → LiPo negative
OUT+ → Load/MCU positive
OUT- → Load/MCU negative⚠️ Get module WITH protection (6 pins, not 4 pins)
Adafruit PowerBoost 500C/1000C
Premium solution with:
- LiPo charging via USB
- 5V boost output (500mA or 1A)
- Low battery indicator
- Load sharing (charge while running)
DIY Charging Don'ts
❌ Never charge LiPo with a constant voltage supply
❌ Never charge LiPo with a phone charger directly
❌ Never charge at >1C rate (e.g., 1000mAh → max 1A)
❌ Never charge frozen batteries---
Battery Sizing Calculator
Step 1: Determine average current (from power-budget-calculator)
I_avg = _____ mA
Step 2: Determine required runtime
T_required = _____ hours
Step 3: Calculate minimum capacity
C_min = I_avg × T_required × 1.25 (safety factor)
C_min = _____ × _____ × 1.25
C_min = _____ mAh
Step 4: Select battery
Choose capacity ≥ C_min
Consider: size, weight, form factorExample:
Project: Weather station
I_avg: 15mA
T_required: 48 hours (2 days between charges)
C_min = 15 × 48 × 1.25 = 900mAh
Selection: 1000mAh LiPo (gives ~67 hours actual)---
Common Mistakes
1. Using Wrong Charger
❌ "My 9V adapter should work"
LiPo needs CC-CV charging at 4.2V max!
✅ Use TP4056 or dedicated LiPo charger2. No Low-Voltage Cutoff
❌ Draining LiPo below 3.0V
Permanently damages the cell!
✅ Use protection module OR monitor in code:
if (batteryVoltage < 3.2) {
enterDeepSleep(); // Protect battery
}3. Ignoring Inrush Current
❌ Battery can't handle WiFi TX spike (500mA)
Causes brownout/reset
✅ Add 100-470µF capacitor near MCU
✅ Size battery for peak current, not just average4. No Reverse Polarity Protection
❌ Swapping battery wires = magic smoke
✅ Use JST-PH connectors (keyed)
✅ Add protection diode or P-FET---
Recommended Setups by Project Type
Low-Power Sensor Node
Battery: 18650 (3000mAh) or LiPo 2000mAh
MCU: ESP32 with deep sleep
Charger: TP4056 with protection
Runtime: Weeks to monthsHandheld Device
Battery: LiPo 1000-2000mAh flat pack
MCU: Any
Charger: PowerBoost or TP4056 + boost
Runtime: Hours to daysRobot/High Current
Battery: 2S or 3S LiPo pack (7.4V or 11.1V)
Regulator: Buck converter to 5V
Charger: Balance charger (external)
Runtime: Minutes to hoursUltra-Low Power Beacon
Battery: CR2032 or 2x AA
MCU: ESP32-C3 or ATtiny with deep sleep
No charger needed
Runtime: Months to yearsQuick Selection Table
| Project Type | Best Battery | Capacity | Charger |
|---|---|---|---|
| Simple Arduino | 4x AA | 2500mAh | None |
| ESP32 portable | 18650 | 2600mAh | TP4056 |
| Wearable | Small LiPo | 500mAh | TP4056 |
| Robot | 2S LiPo | 2200mAh | Balance |
| Ultra-low power | CR2032 | 220mAh | None |
| Solar project | LiFePO4 | 3200mAh | MPPT |
{
"name": "battery-selector",
"metadata": {
"description": "Helps choose the right battery type and charging solution for Arduino/ESP32/RP2040 projects. Use when user asks about battery options, charging circuits, power source selection, or says \"what battery should I use\". Covers chemistry selection, safety, voltage regulation, and charging circuits.",
"version": "0.8.0",
"license": "MIT",
"author": "arduino-skills contributors",
"tags": ["battery-selection", "power-management", "embedded-systems", "maker", "electronics"],
"category": "maker-tools"
},
"plugins": [
{
"name": "battery-selector",
"description": "Guide for selecting the right battery type and charging solution for embedded projects",
"enabled": true
}
]
}
Battery Safety Guidelines for Makers
Chemistry-Specific Safety
Lithium Polymer (LiPo)
Risk Level: HIGH - Handle with care
1. Never puncture, crush, or deform the pouch 2. Never charge above 4.2V per cell 3. Never discharge below 3.0V per cell (3.2V recommended) 4. Never charge unattended or overnight 5. Always use a proper balance charger 6. Store at ~3.8V (storage voltage) if not using for weeks 7. Dispose of puffy/swollen batteries immediately (fire hazard)
Charging Requirements:
- CC/CV (Constant Current / Constant Voltage) charger required
- Charge rate: 0.5C to 1C maximum (1C = capacity in mAh as current)
- Example: 1000mAh battery → max 1A charge current
- Recommended ICs: TP4056, MCP73831, BQ24072
Lithium-Ion (18650, etc.)
Risk Level: MEDIUM-HIGH
1. Use cells with built-in protection circuit (PCB/BMS) 2. Never short-circuit terminals 3. Respect temperature limits during charging (0-45°C typical) 4. Use battery holder with proper polarity protection 5. Protected cells are ~2-3mm longer than unprotected
Charging Requirements:
- Similar to LiPo: CC/CV at 4.2V cutoff
- Charge rate: 0.5C standard, 1C fast charge
- Same charger ICs work: TP4056, MCP73831
LiFePO4 (Lithium Iron Phosphate)
Risk Level: LOW-MEDIUM - Safest lithium chemistry
1. Different voltage: 3.2V nominal, 3.6V max, 2.5V cutoff 2. More tolerant of abuse than Li-ion/LiPo 3. No thermal runaway risk 4. Requires LiFePO4-specific charger (NOT Li-ion charger!) 5. Excellent cycle life (2000+ cycles)
Charging Requirements:
- CC/CV at 3.6V cutoff (not 4.2V!)
- Dedicated IC: CN3058E or similar LiFePO4 charger
- Can use TP5000 with proper configuration
NiMH (Nickel Metal Hydride)
Risk Level: LOW
1. Can handle overcharge better than lithium 2. Use -ΔV detection chargers for fast charge 3. Trickle charge at C/10 to C/20 4. Self-discharge varies by type (Eneloop = low, standard = high) 5. No fire/explosion risk
Charging Requirements:
- Delta-V detection for fast charge
- Timer backup recommended
- Simple trickle charge at C/10 acceptable
- Can parallel cells directly
Alkaline (Non-rechargeable)
Risk Level: VERY LOW
1. Do NOT attempt to recharge (can leak/burst) 2. Remove from device if not using for extended period 3. Check for leaks before handling old batteries 4. Dispose properly - some recycling programs accept
Protection Circuit Design
Essential Components for Lithium:
Battery Protection PCB Functions:
├── Overcharge Protection (OVP)
│ └── Disconnect at 4.25V-4.35V
├── Overdischarge Protection (UVP)
│ └── Disconnect at 2.4V-3.0V
├── Overcurrent Protection (OCP)
│ └── Disconnect at defined current limit
├── Short Circuit Protection (SCP)
│ └── Immediate disconnect
└── Temperature Protection (OTP)
└── Optional but recommendedRecommended Protection ICs:
| IC | Features | Cost |
|---|---|---|
| DW01A | OVP, UVP, OCP, SCP | $0.05 |
| FS312F-G | Same + better UVP threshold | $0.08 |
| S8261 | Higher current capability | $0.10 |
| BQ2970 | Integrated with balancing | $0.50 |
Schematic Pattern:
[Battery +] ─── [Protection IC] ─── [MOSFET] ─── [Output +]
│
[Battery -] ─────────┴──────────────────────── [Output -]Charging System Design
Single Cell LiPo/Li-ion (TP4056):
USB 5V ──► TP4056 Module ──► LiPo Battery
│ │
[CHRG LED] [Protection]
[DONE LED]TP4056 Module Pinout:
- IN+, IN-: 5V input
- BAT+, BAT-: Battery connection
- OUT+, OUT-: Load output (with protection)
Solar Charging:
Solar Panel ──► CN3065 ──► LiPo ──► Load
│ │
[MPPT] [CC/CV]Key Parameters:
- Panel voltage: ~6V for 5V charging
- CN3065 handles MPPT and charging
- Add blocking diode for reverse protection
Temperature Considerations
Charging Temperature Limits:
| Chemistry | Min Charge | Max Charge |
|---|---|---|
| LiPo | 0°C | 45°C |
| Li-ion | 0°C | 45°C |
| LiFePO4 | 0°C | 45°C |
| NiMH | 0°C | 40°C |
Discharge Temperature Limits:
| Chemistry | Min Discharge | Max Discharge |
|---|---|---|
| LiPo | -20°C | 60°C |
| Li-ion | -20°C | 60°C |
| LiFePO4 | -20°C | 60°C |
| NiMH | -20°C | 50°C |
Cold Weather Charging:
- NEVER charge lithium batteries below 0°C
- Internal damage causes lithium plating
- Pre-warm battery before charging in cold
Storage Guidelines
Long-term Storage:
| Chemistry | Storage Voltage | Storage State |
|---|---|---|
| LiPo/Li-ion | 3.7-3.8V | ~40% charge |
| LiFePO4 | 3.2-3.3V | ~50% charge |
| NiMH | Any | Periodic top-up |
| Alkaline | N/A | Cool, dry place |
Storage Environment:
- Temperature: 15-25°C ideal
- Humidity: <50% RH
- Away from metal objects
- In fireproof container for LiPo
- Check monthly for swelling/damage
Emergency Procedures
LiPo Fire:
1. Do NOT use water 2. Use sand or dry chemical extinguisher (Class D) 3. Ventilate area (toxic fumes) 4. Let battery burn out if safe to do so 5. Cool surrounding area to prevent spread
Battery Leak (Alkaline/NiMH):
1. Wear gloves - alkaline electrolyte is caustic 2. Neutralize with vinegar (for alkaline) 3. Clean area thoroughly 4. Dispose of battery properly
Swollen LiPo:
1. Do NOT puncture 2. Place in fireproof container outdoors 3. Discharge to 0V using resistor (if safe) 4. Take to battery recycling center 5. Never dispose in regular trash
Quick Reference Card
┌─────────────────────────────────────────────────────────┐
│ BATTERY QUICK REFERENCE │
├─────────────────────────────────────────────────────────┤
│ LiPo/Li-ion: 3.7V nom, 4.2V max, 3.0V min, CC/CV │
│ LiFePO4: 3.2V nom, 3.6V max, 2.5V min, CC/CV │
│ NiMH: 1.2V nom, 1.4V max, 1.0V min, -ΔV │
│ Alkaline: 1.5V nom, (non-rechargeable) │
├─────────────────────────────────────────────────────────┤
│ ⚠️ Never charge lithium below 0°C │
│ ⚠️ Never leave lithium charging unattended │
│ ⚠️ Dispose of puffy batteries immediately │
│ ⚠️ Use protection circuits on all lithium cells │
└─────────────────────────────────────────────────────────┘#!/usr/bin/env python3
"""
Battery Selector - Compare battery chemistries and find optimal choice
Analyzes project requirements and recommends suitable batteries based on:
- Capacity and runtime
- Size/weight constraints
- Temperature range
- Rechargeability requirements
- Cost optimization
Usage:
uv run --no-project scripts/compare_batteries.py --interactive
uv run --no-project scripts/compare_batteries.py --current 50 --hours 24 --rechargeable
uv run --no-project scripts/compare_batteries.py --project weather_station
"""
import argparse
import json
from dataclasses import dataclass
from typing import List, Optional
# =============================================================================
# Battery Database
# =============================================================================
BATTERY_DATABASE = {
# Alkaline Primary Cells
"AA_Alkaline": {
"chemistry": "Alkaline",
"voltage_nominal": 1.5,
"voltage_cutoff": 0.9,
"capacity_mah": 2500,
"energy_wh": 3.75,
"weight_g": 23,
"dimensions_mm": {"diameter": 14.5, "length": 50.5},
"temp_range_c": (-20, 55),
"rechargeable": False,
"cycle_life": 1,
"self_discharge_monthly_pct": 2,
"cost_usd": 0.50,
"pros": ["Widely available", "Long shelf life", "Low cost"],
"cons": ["Not rechargeable", "Voltage drops under load", "Poor at cold temps"]
},
"AAA_Alkaline": {
"chemistry": "Alkaline",
"voltage_nominal": 1.5,
"voltage_cutoff": 0.9,
"capacity_mah": 1000,
"energy_wh": 1.5,
"weight_g": 11.5,
"dimensions_mm": {"diameter": 10.5, "length": 44.5},
"temp_range_c": (-20, 55),
"rechargeable": False,
"cycle_life": 1,
"self_discharge_monthly_pct": 2,
"cost_usd": 0.40,
"pros": ["Compact", "Cheap"],
"cons": ["Limited capacity", "Not rechargeable"]
},
"9V_Alkaline": {
"chemistry": "Alkaline",
"voltage_nominal": 9.0,
"voltage_cutoff": 6.0,
"capacity_mah": 550,
"energy_wh": 4.95,
"weight_g": 46,
"dimensions_mm": {"width": 26.5, "height": 48.5, "depth": 17.5},
"temp_range_c": (-20, 55),
"rechargeable": False,
"cycle_life": 1,
"self_discharge_monthly_pct": 2,
"cost_usd": 3.00,
"pros": ["High voltage, simple power design"],
"cons": ["Very low capacity", "Expensive per Wh"]
},
"CR2032": {
"chemistry": "Lithium Primary",
"voltage_nominal": 3.0,
"voltage_cutoff": 2.0,
"capacity_mah": 220,
"energy_wh": 0.66,
"weight_g": 3,
"dimensions_mm": {"diameter": 20, "height": 3.2},
"temp_range_c": (-30, 60),
"rechargeable": False,
"cycle_life": 1,
"self_discharge_monthly_pct": 1,
"cost_usd": 0.30,
"pros": ["Very compact", "Long shelf life", "Wide temp range"],
"cons": ["Very low capacity", "Max ~3mA continuous"]
},
# NiMH Rechargeable
"AA_NiMH_2000": {
"chemistry": "NiMH",
"voltage_nominal": 1.2,
"voltage_cutoff": 1.0,
"capacity_mah": 2000,
"energy_wh": 2.4,
"weight_g": 28,
"dimensions_mm": {"diameter": 14.5, "length": 50.5},
"temp_range_c": (0, 40),
"rechargeable": True,
"cycle_life": 500,
"self_discharge_monthly_pct": 20,
"cost_usd": 3.00,
"pros": ["Rechargeable", "High discharge rate", "No memory effect"],
"cons": ["High self-discharge", "Lower voltage than alkaline"]
},
"AA_NiMH_Eneloop": {
"chemistry": "NiMH Low Self-Discharge",
"voltage_nominal": 1.2,
"voltage_cutoff": 1.0,
"capacity_mah": 1900,
"energy_wh": 2.28,
"weight_g": 27,
"dimensions_mm": {"diameter": 14.5, "length": 50.5},
"temp_range_c": (-20, 50),
"rechargeable": True,
"cycle_life": 2100,
"self_discharge_monthly_pct": 1,
"cost_usd": 4.00,
"pros": ["Low self-discharge", "Long cycle life", "Good cold performance"],
"cons": ["Premium price", "Slightly lower capacity"]
},
# Lithium-ion / LiPo
"18650_3000": {
"chemistry": "Li-ion",
"voltage_nominal": 3.7,
"voltage_cutoff": 3.0,
"capacity_mah": 3000,
"energy_wh": 11.1,
"weight_g": 48,
"dimensions_mm": {"diameter": 18.6, "length": 65.2},
"temp_range_c": (-20, 60),
"rechargeable": True,
"cycle_life": 500,
"self_discharge_monthly_pct": 3,
"cost_usd": 5.00,
"pros": ["High energy density", "High discharge rate", "Common"],
"cons": ["Requires protection circuit", "Needs proper charger"]
},
"18650_3500": {
"chemistry": "Li-ion",
"voltage_nominal": 3.7,
"voltage_cutoff": 3.0,
"capacity_mah": 3500,
"energy_wh": 12.95,
"weight_g": 50,
"dimensions_mm": {"diameter": 18.6, "length": 65.2},
"temp_range_c": (-20, 60),
"rechargeable": True,
"cycle_life": 500,
"self_discharge_monthly_pct": 3,
"cost_usd": 8.00,
"pros": ["Highest capacity 18650", "High energy density"],
"cons": ["Lower max discharge than 3000mAh", "More expensive"]
},
"LiPo_500": {
"chemistry": "LiPo",
"voltage_nominal": 3.7,
"voltage_cutoff": 3.2,
"capacity_mah": 500,
"energy_wh": 1.85,
"weight_g": 12,
"dimensions_mm": {"width": 30, "height": 40, "thickness": 4},
"temp_range_c": (0, 45),
"rechargeable": True,
"cycle_life": 300,
"self_discharge_monthly_pct": 3,
"cost_usd": 4.00,
"pros": ["Very thin", "Flexible form factor", "Light"],
"cons": ["Fragile", "Fire risk if punctured", "Puff with age"]
},
"LiPo_1000": {
"chemistry": "LiPo",
"voltage_nominal": 3.7,
"voltage_cutoff": 3.2,
"capacity_mah": 1000,
"energy_wh": 3.7,
"weight_g": 22,
"dimensions_mm": {"width": 34, "height": 50, "thickness": 5},
"temp_range_c": (0, 45),
"rechargeable": True,
"cycle_life": 300,
"self_discharge_monthly_pct": 3,
"cost_usd": 6.00,
"pros": ["Good balance of capacity and size"],
"cons": ["Requires careful handling"]
},
"LiPo_2000": {
"chemistry": "LiPo",
"voltage_nominal": 3.7,
"voltage_cutoff": 3.2,
"capacity_mah": 2000,
"energy_wh": 7.4,
"weight_g": 40,
"dimensions_mm": {"width": 40, "height": 60, "thickness": 7},
"temp_range_c": (0, 45),
"rechargeable": True,
"cycle_life": 300,
"self_discharge_monthly_pct": 3,
"cost_usd": 10.00,
"pros": ["Good capacity for wearables/portables"],
"cons": ["More expensive"]
},
# LiFePO4
"LiFePO4_1500": {
"chemistry": "LiFePO4",
"voltage_nominal": 3.2,
"voltage_cutoff": 2.5,
"capacity_mah": 1500,
"energy_wh": 4.8,
"weight_g": 42,
"dimensions_mm": {"diameter": 18.5, "length": 65},
"temp_range_c": (-20, 60),
"rechargeable": True,
"cycle_life": 2000,
"self_discharge_monthly_pct": 2,
"cost_usd": 8.00,
"pros": ["Very long cycle life", "Safer than Li-ion", "Wide temp range"],
"cons": ["Lower energy density", "3.2V may need boost converter"]
},
"LiFePO4_3000": {
"chemistry": "LiFePO4",
"voltage_nominal": 3.2,
"voltage_cutoff": 2.5,
"capacity_mah": 3000,
"energy_wh": 9.6,
"weight_g": 80,
"dimensions_mm": {"diameter": 26, "length": 65},
"temp_range_c": (-20, 60),
"rechargeable": True,
"cycle_life": 2000,
"self_discharge_monthly_pct": 2,
"cost_usd": 12.00,
"pros": ["High capacity + long life", "Safe chemistry"],
"cons": ["Larger form factor"]
}
}
@dataclass
class ProjectRequirements:
"""Project power requirements"""
average_current_ma: float
peak_current_ma: Optional[float] = None
target_runtime_hours: float = 24
min_voltage: float = 3.0
max_voltage: float = 5.0
rechargeable_required: bool = False
max_weight_g: Optional[float] = None
max_volume_cc: Optional[float] = None
min_temp_c: float = 0
max_temp_c: float = 40
max_cost_usd: Optional[float] = None
cycle_count_target: int = 1
def calculate_runtime(battery: dict, current_ma: float) -> float:
"""Calculate runtime in hours, accounting for Peukert effect"""
capacity = battery["capacity_mah"]
# Simple Peukert approximation
c_rate = current_ma / capacity
if c_rate > 1.0:
effective_capacity = capacity * 0.6 # High drain penalty
elif c_rate > 0.5:
effective_capacity = capacity * 0.8
elif c_rate > 0.2:
effective_capacity = capacity * 0.9
else:
effective_capacity = capacity * 0.95
return effective_capacity / current_ma if current_ma > 0 else float('inf')
def calculate_volume(dims: dict) -> float:
"""Calculate volume in cc from dimensions"""
if "diameter" in dims:
# Cylindrical
r = dims["diameter"] / 2 / 10 # mm to cm
h = dims.get("length", dims.get("height", 0)) / 10
return 3.14159 * r * r * h
else:
# Rectangular
w = dims.get("width", 0) / 10
h = dims.get("height", 0) / 10
d = dims.get("depth", dims.get("thickness", 0)) / 10
return w * h * d
def evaluate_battery(battery_name: str, battery: dict, req: ProjectRequirements) -> dict:
"""Evaluate a battery against requirements"""
result = {
"name": battery_name,
"chemistry": battery["chemistry"],
"voltage": battery["voltage_nominal"],
"capacity_mah": battery["capacity_mah"],
"energy_wh": battery["energy_wh"],
"score": 100,
"issues": [],
"suitable": True
}
# Voltage check
if battery["voltage_nominal"] < req.min_voltage:
result["issues"].append(f"Voltage too low ({battery['voltage_nominal']}V < {req.min_voltage}V)")
result["score"] -= 50
if battery["voltage_nominal"] > req.max_voltage:
result["issues"].append(f"Voltage too high ({battery['voltage_nominal']}V > {req.max_voltage}V)")
result["score"] -= 30
# Runtime check
runtime = calculate_runtime(battery, req.average_current_ma)
result["runtime_hours"] = round(runtime, 2)
if runtime < req.target_runtime_hours:
deficit_pct = (1 - runtime / req.target_runtime_hours) * 100
result["issues"].append(f"Runtime {runtime:.1f}h < target {req.target_runtime_hours}h ({deficit_pct:.0f}% short)")
result["score"] -= min(50, deficit_pct / 2)
else:
bonus = min(20, (runtime / req.target_runtime_hours - 1) * 10)
result["score"] += bonus
# Rechargeable check
if req.rechargeable_required and not battery["rechargeable"]:
result["issues"].append("Not rechargeable (required)")
result["score"] -= 100
result["suitable"] = False
# Cycle life check
if battery["cycle_life"] < req.cycle_count_target:
result["issues"].append(f"Cycle life {battery['cycle_life']} < required {req.cycle_count_target}")
result["score"] -= 30
# Weight check
if req.max_weight_g and battery["weight_g"] > req.max_weight_g:
result["issues"].append(f"Too heavy ({battery['weight_g']}g > {req.max_weight_g}g)")
result["score"] -= 20
# Volume check
volume = calculate_volume(battery["dimensions_mm"])
result["volume_cc"] = round(volume, 2)
if req.max_volume_cc and volume > req.max_volume_cc:
result["issues"].append(f"Too large ({volume:.1f}cc > {req.max_volume_cc}cc)")
result["score"] -= 20
# Temperature check
temp_range = battery["temp_range_c"]
if req.min_temp_c < temp_range[0]:
result["issues"].append(f"Cold temp limit {temp_range[0]}°C > required {req.min_temp_c}°C")
result["score"] -= 20
if req.max_temp_c > temp_range[1]:
result["issues"].append(f"Hot temp limit {temp_range[1]}°C < required {req.max_temp_c}°C")
result["score"] -= 20
# Cost check
if req.max_cost_usd and battery["cost_usd"] > req.max_cost_usd:
result["issues"].append(f"Cost ${battery['cost_usd']:.2f} > budget ${req.max_cost_usd:.2f}")
result["score"] -= 15
# Peak current check (LiPo/Li-ion can handle high peaks, coin cells cannot)
if req.peak_current_ma:
if battery["chemistry"] == "Lithium Primary" and req.peak_current_ma > 5:
result["issues"].append(f"Coin cell can't handle {req.peak_current_ma}mA peaks")
result["score"] -= 40
result["cost_per_wh"] = round(battery["cost_usd"] / battery["energy_wh"], 3)
result["wh_per_g"] = round(battery["energy_wh"] / battery["weight_g"], 4)
if result["score"] < 0:
result["suitable"] = False
return result
def find_best_batteries(req: ProjectRequirements, top_n: int = 5) -> List[dict]:
"""Find the best batteries for the requirements"""
results = []
for name, battery in BATTERY_DATABASE.items():
result = evaluate_battery(name, battery, req)
results.append(result)
# Sort by score descending
results.sort(key=lambda x: x["score"], reverse=True)
return results[:top_n]
def generate_comparison_table(results: List[dict]) -> str:
"""Generate markdown comparison table"""
lines = [
"| Battery | Chemistry | Voltage | Runtime (h) | Score | Issues |",
"|---------|-----------|---------|-------------|-------|--------|"
]
for r in results:
issues = "; ".join(r["issues"][:2]) if r["issues"] else "✓ Meets requirements"
status = "✓" if r["suitable"] else "✗"
lines.append(
f"| {r['name']} | {r['chemistry']} | {r['voltage']}V | "
f"{r['runtime_hours']:.1f} | {r['score']:.0f} {status} | {issues} |"
)
return "\n".join(lines)
def generate_report(req: ProjectRequirements, results: List[dict]) -> str:
"""Generate full battery selection report"""
lines = [
"# Battery Selection Report",
"",
"## Requirements",
f"- Average Current: {req.average_current_ma} mA",
f"- Target Runtime: {req.target_runtime_hours} hours",
f"- Voltage Range: {req.min_voltage}V - {req.max_voltage}V",
f"- Rechargeable: {'Required' if req.rechargeable_required else 'Optional'}",
f"- Temperature Range: {req.min_temp_c}°C to {req.max_temp_c}°C",
"",
"## Top Recommendations",
"",
generate_comparison_table(results),
""
]
# Detailed analysis of top choice
if results and results[0]["suitable"]:
top = results[0]
battery = BATTERY_DATABASE[top["name"]]
lines.extend([
f"## Recommended: {top['name']}",
"",
f"**Chemistry:** {top['chemistry']}",
f"**Nominal Voltage:** {top['voltage']}V",
f"**Capacity:** {top['capacity_mah']} mAh ({battery['energy_wh']} Wh)",
f"**Expected Runtime:** {top['runtime_hours']:.1f} hours",
f"**Weight:** {battery['weight_g']}g",
f"**Cost:** ${battery['cost_usd']:.2f}",
"",
"**Pros:**",
])
for pro in battery.get("pros", []):
lines.append(f"- {pro}")
lines.append("")
lines.append("**Cons:**")
for con in battery.get("cons", []):
lines.append(f"- {con}")
return "\n".join(lines)
def interactive_mode():
"""Run battery selector interactively"""
print("=" * 60)
print("Battery Selector - Interactive Mode")
print("=" * 60)
print()
current = float(input("Average current draw (mA): "))
peak = input("Peak current (mA) [optional]: ").strip()
peak = float(peak) if peak else None
runtime = float(input("Target runtime (hours) [24]: ").strip() or "24")
min_v = float(input("Minimum voltage required (V) [3.0]: ").strip() or "3.0")
max_v = float(input("Maximum voltage (V) [5.0]: ").strip() or "5.0")
rechargeable = input("Rechargeable required? (y/n) [n]: ").strip().lower() == 'y'
weight = input("Max weight (g) [optional]: ").strip()
weight = float(weight) if weight else None
min_temp = float(input("Min operating temp (°C) [0]: ").strip() or "0")
max_temp = float(input("Max operating temp (°C) [40]: ").strip() or "40")
budget = input("Max cost ($) [optional]: ").strip()
budget = float(budget) if budget else None
req = ProjectRequirements(
average_current_ma=current,
peak_current_ma=peak,
target_runtime_hours=runtime,
min_voltage=min_v,
max_voltage=max_v,
rechargeable_required=rechargeable,
max_weight_g=weight,
min_temp_c=min_temp,
max_temp_c=max_temp,
max_cost_usd=budget
)
results = find_best_batteries(req)
report = generate_report(req, results)
print("\n" + "=" * 60)
print(report)
# Save option
save = input("\nSave report? (y/n) [n]: ").strip().lower()
if save == 'y':
filename = "battery_selection_report.md"
with open(filename, 'w') as f:
f.write(report)
print(f"Saved to: {filename}")
def main():
parser = argparse.ArgumentParser(description="Battery Selector for Embedded Projects")
parser.add_argument("--interactive", "-i", action="store_true", help="Interactive mode")
parser.add_argument("--current", "-c", type=float, help="Average current (mA)")
parser.add_argument("--hours", "-t", type=float, default=24, help="Target runtime (hours)")
parser.add_argument("--rechargeable", "-r", action="store_true", help="Require rechargeable")
parser.add_argument("--min-voltage", type=float, default=3.0, help="Min voltage")
parser.add_argument("--max-voltage", type=float, default=5.0, help="Max voltage")
parser.add_argument("--list", "-l", action="store_true", help="List all batteries")
parser.add_argument("--json", "-j", action="store_true", help="Output as JSON")
args = parser.parse_args()
if args.list:
print("Battery Database:")
print("-" * 80)
for name, b in BATTERY_DATABASE.items():
print(f"{name:20} {b['chemistry']:15} {b['voltage_nominal']}V "
f"{b['capacity_mah']:5}mAh ${b['cost_usd']:.2f}")
return
if args.interactive:
interactive_mode()
return
if args.current:
req = ProjectRequirements(
average_current_ma=args.current,
target_runtime_hours=args.hours,
min_voltage=args.min_voltage,
max_voltage=args.max_voltage,
rechargeable_required=args.rechargeable
)
results = find_best_batteries(req)
if args.json:
print(json.dumps(results, indent=2))
else:
print(generate_report(req, results))
return
parser.print_help()
if __name__ == "__main__":
main()