element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
    About the element14 Community
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      •  Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
EZ-EV Challenge
  • Challenges & Projects
  • Design Challenges
  • EZ-EV Challenge
  • More
  • Cancel
EZ-EV Challenge
Projects Vape Cell EV - smart battery charging
  • News
  • Projects
  • Forum
  • DC
  • Leaderboard
  • Files
  • Members
  • More
  • Cancel
  • New
Join EZ-EV Challenge to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: saramic
  • Date Created: 16 Aug 2026 11:03 PM Date Created
  • Views 93 views
  • Likes 1 like
  • Comments 1 comment
  • bms
  • ina219
  • uno q
Related
Recommended

Vape Cell EV - smart battery charging

saramic
saramic
16 Aug 2026
Vape Cell EV - smart battery charging

shamelessly taking some extra time to complete the project as per the discussion in Challengers, Post your Projects!

TL;DR

A system for characterising salvaged lithium cells from disposable vapes — measuring capacity, internal resistance, and charge/discharge behaviour — built around an Arduino UNO Q, an INA219 current/power monitor, and a live web dashboard. The relay auto-cycling works. The AliExpress “18650” turned out to have ~484 mAh of actual capacity. The vape cell data is still being collected.


Introduction

Disposable vapes get thrown away by the tens of millions. Each one contains a lithium cell — usually 280–450 mAh, occasionally more. Most of them still work. The broader EZ-EV design challenge is about building an electric vehicle; the Vape Cell EV thread is could a variety of cells with unknown history be put together in a smart battery to power such an EV.

The project got as far as to measure the cycle of charging and discharging of a known 18650 cell vs a random vape cell.


System Architecture

            Charger+   Battery+
                │           │
                └───┐   ┌───┘
                    RELAY (SPDT × 2)
                      │
    ┌─────────────────┴────────────────────┐
    │              INA219                  │    0.1Ω shunt
    │              VIN+ → VIN−             │── 10.0Ω load ──── GND
    └─────────────────┬────────────────────┘
                      │ I2C (A4/A5 = Wire2 = i2c3)
    ┌─────────────────┴────────────────────┐
    │  Arduino UNO Q  (STM32 MCU side)     │
    │  Bridge.provide_safe("get_readings") │
    │  Bridge.provide_safe("relay_on/off") │
    │  D7 → relay signal pin               │
    └─────────────────┬────────────────────┘
                      │ RouterBridge IPC
    ┌─────────────────┴────────────────────┐
    │  Arduino UNO Q  (Linux MPU side)     │
    │  Python Flask :8080                  │
    │  Bridge.call("get_readings")         │
    │  SSE → browser   CSV → disk          │
    └──────────────────────────────────────┘

Key hardware:

Component Role Notes
Arduino UNO Q MCU + Linux MPU hub STM32 MCU + RouterBridge IPC
INA219 breakout Voltage, current, power I2C, 0.1 Ω shunt, 12-bit, ±3.2 A range
5 W / 10 Ω resistor Discharge load ~370–400 mA at 3.7–4.0 V
CC/CV power supply Charging source 4.15 V output

The Journey

Part I — What’s in a Vape

Cracking open disposable vapes. The cells are usually in a bare foil pouch, soldered directly to the vape mechanism with thin wires acting as a fuse for protection, any short or over current burns the wires out and that is it. Often the batteries have no markings and are of an unknown rating. The case for a proper characterisation rig started here.

image

Vape cell hookup wire acting as a fuse in the case of a short circuit

Part II — RS-485 Comms

As part of development kit was a pair of RS485 communications boards, I took a side step to see if they would come in handy at some point. This involved hooking up the RS485 board to the IO ports of the STM32 MCU which in turn connecst to the Linux MPU sdie of the UNO Q. The RouterBridge architecture means the STM32 is exposed as a set of named RPC endpoints — you Bridge.provide_safe("name", handler) on the MCU and Bridge.call("name") from Python. Every Bridge.call() must happen from a single thread; Flask routes set a pending flag, and the main poll loop picks it up. Although I did get communications working, and even did some speed tests, I ran out of time to actually make use of the comms as part of the solution.

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

Part III — INA219 Power Monitor

Although I had some ideas of OpAmp circuits and keeping to steady known discharge rates over a resistor, I came across the INA219 which was going to simplify this. Well simplify this after I got it working with the dual brain architecture of the UNO Q and some wiring issues.

Wire2.begin() isn’t optional. On arduino:zephyr, the I2C hardware peripheral uses lazy initialisation. Without an explicit Wire2.begin() in setup(), every transfer returns error 1 and nothing about the error messages hints why.

void setup() {
    Bridge.begin();
    Wire2.begin();   // i2c3: A4=SDA(PC1), A5=SCL(PC0) — without this, all I2C fails
    ...
}

Bus voltage needs a GND reference. The INA219 measures bus voltage at VIN− relative to GND. Current measurement is differential and works regardless, but voltage read 0.012 V until a wire ran from the battery’s negative terminal to the INA219’s GND pin. The cell was sitting at 3.87 V the whole time.

JSON truncation is silent. The config handler packed the I2C address into a fixed buffer:

char addrStr[6];
snprintf(addrStr, sizeof(addrStr), "\"0x%02X\"", sensors[i].addr);
// "0x40" = 6 chars + null = 7 bytes → snprintf silently drops the closing "
// result: ["0x40,"rShunt":...] → JSON parse error at char 28

Bumping to char addrStr[8] fixed it. The Python side was receiving the truncated string without complaint until json.loads() rejected it.

With readings flowing, a live web dashboard served from the UNO Q’s MPU: per-sensor cards (bus voltage, current, power), dual-axis sparklines with fixed scales (0–6 V amber / 0–500 mA green), session mWh tracking, time-window selector (1m → 10h), and CSV logging.

image

potentially up to 4 INA219 could be hooked up

Part IV — On Battery Charging

Although I didn’t get as far as building a fully automated, AI powered, smart battery charging solution, I did learn a bunch about battery charging and ran some of my own charge/discharge experiments.

Expanding the initial INA219 power monitor with a few relays, allowed me to cycle through charge and discharge cycles. Of course I ran into a few issues to get this working:

  • The INA219 calibration register resets on power glitches. Switching the relay caused a brief voltage dip on the rail that reset the INA219 — which cleared the calibration register and made the current register read zero permanently (shunt voltage still showed correctly, since it doesn’t need calibration). The fix: re-write the calibration register on every poll cycle, not just at startup.
    for (int i = 0; i < numSensors; i++) {
        // re-arm after any reset/glitch
        inaWrite16(sensors[i].addr, REG_CALIB, INA219_CALIB);
        if (inaRead(sensors[i])) sensors[i].reads++;
        else sensors[i].errors++;
    }
  • Auto-cycling logic has a 500 ms reset bug. The first implementation reset the 30-second countdown timer inside updateRelay(), which was called on every SSE message (every 500 ms). The countdown never accumulated past 500 ms. The fix was one line: only reset the timer when the relay state actually changes.
    function updateRelay(on) {
      // only on actual state change
      if (relayState !== on) autoConditionStart = null;
      relayState = on;
      ...
    }

Finally I got a neat dashboard to watch the auto-cycling between Battery CHARGE / DISCHARGE with a live [29s] countdown timer before the change over, battery percentage bars (❚❚❚White medium square 75%), and configurable thresholds (≥4.1 V and ≤150 mA held for 30 s to end charge; <3.0 V held for 30 s to end discharge).

Part V — 18650 vs Vape Cell

Finally it was time to use the auto-cycling charge discharge setup to gather some real data.

Data collection in progress. First characterisation run on an AliExpress “18650”:

Metric This cell Genuine 18650 (2500 mAh)
Measured capacity ~484 mAh 2000–3600 mAh
Discharge time @ 340 mA 47 min ~430 min
Voltage sag rate 15 mV/min ~3 mV/min
Avg discharge voltage 3.50 V ~3.60 V

The discharge curve has no flat plateau — voltage drops steadily from 3.64 V to 2.92 V in under an hour. High internal resistance, re-wrapped smaller cell, or a counterfeit casing around an 18350. All three are consistent with the data. Vape cell data will follow once a full charge/discharge cycle completes.


What shipped

  • INA219 multi-sensor scanner — up to 4 sensors at 0x40/0x41/0x44/0x45 White check mark
  • Live dashboard: voltage, current, power, mWh, sparklines, CSV download White check mark
  • Time-window selector (1 m → 10 h) with server-side 10-hour history White check mark
  • Session tracking with real-time mWh accumulation White check mark
  • Relay auto-cycling with configurable charge/discharge thresholds White check mark
  • Battery percentage bars and Battery/ mode indicators White check mark
  • Auto-mode countdown display ([29s] until switch) White check mark
  • First cell characterisation — AliExpress “18650” measured at ~484 mAh White check mark
  • Mobile-responsive dashboard White check mark

What didn’t

  • Vape cell comparison data — auto-cycling still running, Part V incomplete Wrench
  • Temperature monitoring — 10 k thermistors acquired, not yet wired ✗
  • Multi-station cycling — TP4056 modules ordered, not yet integrated ✗
  • Controllable current source — proper CC charging beyond the bench supply ✗

Lessons Learned

Read the datasheet’s measurement model, not just the register map. The INA219 has two separate measurement paths — a differential shunt measurement and a ground-referenced bus voltage measurement. Understanding that distinction immediately explained why current worked and voltage read zero: no GND reference. Guessing at register settings would have taken hours.

Platform constraints are load-bearing. The UNO Q’s arduino:zephyr lazy I2C initialisation, the RouterBridge single-thread constraint for Bridge.call(), the Serial alias that hijacks the UART — none of these are obvious until you hit them. Finding each one was a day of confusion; writing it down in the post means the next person hits it for minutes.

The 30-second timer reset was invisible. The auto-cycling countdown logic looked correct in isolation. The bug only appeared because updateRelay() was called on every SSE message — something that wasn’t visible from reading updateRelay() alone. Reading call sites is as important as reading the function.

Cheap cells are genuinely small. The AliExpress “18650” at ~484 mAh isn’t a degraded cell — it’s a correctly functioning cell that was never 2000+ mAh. The discharge curve, sag rate, and total energy are all self-consistent. You cannot trust the label; you have to measure it. - with the caveat that my measuring rig still needs some calibration on a known good cell

Hardware takes twice as long as the electronics. The relay driver circuit went through three iterations over two sessions. Each one was a 10-minute change that needed 30 minutes of debugging. The lesson isn’t to get the circuit right first time — it’s to build in the debugging time.


Next

nothing blue up, and I have a bunch of vape cells that I don't know what to do. I have a test rig so I will probably run it on each cell, maybe if I get around to it I could also look at adding

  • a proper baseline for a quality 18650 - and also fine tune the charging and discharging current
  • Add NTC thermistor monitoring (Steinhart-Hart, temperature cutoff in auto mode)
  • TP4056 modules for multi-station parallel cycling
  • Cell passport scoring — a single number summarising a cell’s health for safe pack assembly

Source & Links

Resource Link
GitHub saramic/vape-cell-EV
Design challenge EZ-EV Challenge
Part I — What’s in a Vape element14 forum
Part II — RS-485 Comms element14 forum
Part III — INA219 Power Monitor element14 forum
Part IV — On Battery Charging element14 forum
Part V — 18650 vs Vape Cell element14 forum
  • Sign in to reply
  • stanto
    stanto 21 days ago

    ... There's a 'save as draft' button you know?

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2026 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube