LuxLibre › Documentation › Testing a flashlight
On this page: Overview · Equipment · Bring-up of a new board · Firmware tests · Output and runtime · Intensity and beam distance · Thermal and touch temperature · Battery and charging · Flicker · Durability · Optical safety · Writing the report
This guide takes a LuxLibre light from the first power-up of a new board to the numbers you publish. Every procedure works with a small budget. Each section ends with a short note on what a professional lab does differently, so you know where your numbers stop being exact.
Rule IDs such as THM-1 point to the design rules. Numbers from standards carry their source. Numbers marked “LuxLibre rule”, “LuxLibre default” or “LuxLibre suggestion” are project choices, not standards.
Safety while testing
- Li-ion cells can burn. A shorted, punctured, crushed or overheated cell can vent flames. Never short a cell, never pierce or bend one, and do not test with damaged cells.
- Charge on a non-flammable surface (stone, metal tray, ceramic tile), not on a bed or a desk covered in paper, and stay nearby during the first charges of a new board.
- Eyes. Do not look into a high-output LED or a laser, not even “just to check”. Point the light at a matte wall or into the lumen tube. Never look into a laser beam or its reflection.
- Burns. A head in turbo gets hot enough to burn within seconds. Let it cool before you touch it and keep it away from plastics and paper.
Read SAFETY.md before you start.
A light is tested in six stages. Stages (a) to (c) happen for every new board. Stages (d) and (e) happen for every hardware release. Stage (f) collects the results.
The times below are rough LuxLibre estimates for a first pass by one person.
| Test | What it proves | Rule IDs | Equipment | Time needed |
|---|---|---|---|---|
| Bench bring-up | Board assembled right, outputs off by default, readings calibrated, standby drain known | DRV-7, DRV-9, FW-1, BAT-9, BAT-6, DRV-2, REQ-4 | Multimeter, current-limited supply, programmer | 2-4 h |
| Firmware in the simulator | Code and board parameters behave as intended | FW-8, FW-2, FW-5 | PC | Minutes (CI); 1 h for a new board header |
| Firmware on the board | Gestures and protections work on hardware | FW-3, FW-6, BAT-5, BAT-7, THM-5, DRV-8 | Supply, multimeter, USB console | 2-3 h |
| Output and runtime | Lumens at 30 s and 2 min, runtime to 10 %, sustained output | REQ-2 | Lumen tube, lux meter, reference light | Half a day to a day (one full runtime per mode) |
| Intensity and beam distance | Peak intensity (cd) and beam distance | REQ-2 | Lux meter, tape measure, dark corridor | 1 h |
| Thermal and touch temperature | Hottest touchable point stays within the burn limits | THM-1, THM-4, THM-6 | Thermocouple meter | 3-4 h |
| Battery and charging | Charge voltage and current, temperature window, USB-C, reversed cell | BAT-4, BAT-5, CHG-1, CHG-2, CHG-3, CHG-6 | USB power meter, multimeter, supply, cables | 3-5 h (one full charge) |
| Flicker | No visible flicker at any level | LED-6, FW-4 | Phone camera; photodiode + oscilloscope | 1 h |
| Durability | Survives drops, then water | MEC-2, MEC-3 | Concrete floor, water tube | 2 h |
| Optical safety | LED risk group known, laser class verified, interlock works | LED-5, LAS-1, LAS-2, LAS-3 | Datasheets; laser power meter | 1-2 h |
| Release test report | Every requirement has a result | REQ-1, REQ-4, FW-8 | Template | 1-2 h |
| Item | Used for | Notes |
|---|---|---|
| Multimeter with a µA range | Rail resistance, voltages, LED current, standby current | Note its accuracy on the voltage range: BAT-9 needs 1 %, so the meter must be better than that. |
| Bench power supply with current limit | First power-up, LVP test, reversed-cell test | Most cheap supplies cannot sink current: do not let a charger push current into them (see Battery and charging). |
| USB power meter (inline, USB-C) | Charge current, charge energy, termination | Measures on the USB side, so it includes the charger’s losses. |
| Thermocouple meter (type K) with thin-wire probes | Touch temperature, reference for the NTC calibration | Check it in ice water: it should read 0 °C. |
| Lux meter | Lumen tube, intensity at a distance | Check it against a second meter if you can. |
| Home-made lumen tube | Relative output and runtime | Calibrate it against a light with a published measured output (see Output and runtime). |
| Phone camera | Quick flicker check, photos for the report | A video at a fast shutter speed shows PWM as stripes. |
| Kitchen scale | Weight for the spec sheet | |
| Tape measure, foil or polyimide tape | Distances, fixing thermocouples | |
| Bucket or a capped tube taller than 1 m | IPX7 test | The lowest point of the light must be 1 m under water. |
| Programmer | Flashing the MCU | UPDI, WCH-LinkE (SWIO) or plain USB, see docs/firmware/README.md. |
| Tool | What it adds |
|---|---|
| µA logger (source-measure unit or power profiler) | Standby current with its wake-up spikes, without burden-voltage problems; a source-measure unit can also replace the cell and sink charge current. |
| Integrating sphere | Absolute lumens instead of relative tube readings. |
| Photodiode + oscilloscope | Flicker waveform, frequency and modulation depth. |
| Laser power meter | The real laser output for the class check (LAS-3). |
| Thermal camera | Finds the hottest touchable point in one look. |
| Climate chamber | A controlled 25 °C for thermal tests; cold and hot tests of the charge window. |
Do these steps in order. Stop at the first failure and fix it before you go on.
ver and status on boards with a console. ver must print the firmware
version and the board name, for example LuxLibre 0.5.0 / FlashKa Keychain v0.6
(REQ-4). Write it into the report.cell_mV from
status, with the light off. Set BAT_CAL to the current value plus
(multimeter - cell_mV) and save. Repeat at a low and a high voltage (for example
3.0 V and 4.2 V from the supply) to see whether the error is only an offset. Pass: within
1 % at both ends.level N for a set of
levels (for example 1, 30, 60, 90, 120, 150) and measure the LED current. For low levels
put the meter’s mA range in series with the LED. For high levels measure the voltage
across the sense resistor at its test point and divide by its value: a series ammeter
adds resistance and changes the result. Compare with the table in
docs/firmware/user-interface.md and your board header
(LX_MAIN_MAX_MA, LX_OUT_MIN_Q16). Keep high levels short when the LED is not yet in
its housing: a bare LED board overheats in seconds.On boards where the console runs over USB (the FlashKa), the USB cable is also a charger
connection. While it is plugged in the main LED is limited to CHG_MAXLVL
(CHG-6) and the light does not sleep. For the LED current test,
set CHG_MAXLVL 150 temporarily and put it back afterwards. Do not power such a board from a
bench supply in place of the cell while USB is connected unless the supply can sink current:
the charger would push current into it.
A multimeter on its µA range puts a shunt resistor in series. The voltage across it (the burden voltage) is shunt resistance times current. When the MCU wakes up, the current jumps, the burden voltage jumps with it, and the MCU can brown out and reset. The trick is to bypass the meter while the current is high.
Compare with BAT-6: at most 3 % of the capacity per month, which is 33 µA for 800 mAh and 123 µA for 3000 mAh (a month is about 730 h). For reference, the ESP32-C3-MINI-1 module alone needs 5 µA in deep sleep (Espressif), so the rest of the board has to stay well below the limit as well.
What a lab does differently: an X-ray of leadless parts instead of a visual check, a source-measure unit for standby current, and a calibrated reference for voltage.
make test in firmware/ runs the unit and behaviour tests on the PC. Every change must
pass it in CI (FW-8). The behaviour tests cover lockout across a
reboot, the stuck button, LVP, thermal regulation without flicker, sensor faults and the
charge window.
A new board header (FW-2) is first checked in the simulator. Run the scenarios from docs/firmware/simulator.md with the board’s limits, for example:
cd firmware
make sim
build/luxsim --preset 18650 --set THM_LIMIT=50 --csv turbo.csv "2C W600000"
Check that thermal regulation settles, turbo steps down after TURBO_S, and LVP ends in a
cut-off.
The button map is in docs/firmware/user-interface.md. Use the
layout your board sets with UI_STYLE.
| Gesture | Expected | Rule |
|---|---|---|
| 1C from off, 1C again | On at the remembered level, then off | FW-3 |
| Hold from off | Moon, then brighter (ramp layout) or the next mode (modes layout) | FW-3 |
| 2C | Turbo; steps down to TURBO_DOWN after TURBO_S; 2C again returns to the previous level |
FW-3 |
| 3C | Battery voltage as blinks (3.8 V = 3 blinks, pause, 8 blinks); compare with the multimeter | FW-3 |
| 4C | Lockout (3 blinks of the main LED, or the lock colour on boards with an indicator LED). Clicks give only a short flash; hold gives moon only if LOCK_MOON = 1. 4C unlocks. |
BAT-7 |
4C, then remove the cell (or reboot, or switch off the supply), reconnect |
Still locked | FW-6 |
| 9C | 5 blinks of the main LED (or the reset colour on boards with an indicator LED); all parameters back to defaults except the calibration (BAT_CAL, THM_OFFSET) |
FW-5 |
| Laser gesture (click, then click-and-hold) in lockout | No laser | LAS-2 |
The factory reset keeps the calibration values BAT_CAL and THM_OFFSET; they are also
stored in their own block, so they survive a firmware update that changes the parameter list.
The console command defaults all clears them as well.
get LVP_WARN, get LVP_CUT and get LVP_RESUME first. Switch on a middle level and
lower the voltage slowly; LuxLibre suggests 20 mV steps with at least 10 s per step,
because the firmware filters the reading. Expected: below LVP_WARN the light steps down
10 levels every 5 s; below LVP_CUT it switches off; a click is then refused. Raise the
voltage: the light stays off until the cell rests above LVP_RESUME or USB is connected.
The cut-off never goes below the floor for the chemistry (2700 mV per cell for Li-ion), even
if LVP_CUT is set lower, and the step-down always starts at least 200 mV above it.
On boards with a built-in cell, continue below LVP_CUT with the supply on the cell side
of the protection circuit and check that it cuts off at the threshold in its datasheet
(BAT-3).status:
temp_dC (tenths of a degree) rises, and thermal_cap falls as the reading approaches
THM_LIMIT. The output must settle, not oscillate. For the shutdown path, avoid high
temperatures: temporarily set THM_SHUTDN 40 (its lowest allowed value) and run turbo
until the light switches off; it must refuse to switch on until 5 °C cooler. Restore the
value and check with get. If you warm the head with a heat gun to test the sensor
response, keep it at a distance, heat the head only, never the cell, and stop well below
the cell’s maximum discharge temperature (see its datasheet).THM_FLOOR, no laser, and no charging.LOCK_MOON = 1), still locked after you release it. Then unlock,
switch off and clamp the button again: the light comes on and ramps (a hold is a normal
gesture), and after POCKET_S (default 30 s) it switches off and locks itself. A click
after the release must do nothing until 4C.reboot restarts the MCU: the
light must go dark during the restart and come back in its saved state (off or locked),
never on. wdtest switches the main LED to moon and stops the firmware on purpose: the
watchdog must restart the MCU within its time (1 s on the ATtiny1616, 4 s on the CH32V003,
3 s on the ESP32-C3) and the light must come back dark. If the moon stays on, the watchdog
does not work: remove the cell and fix the port before anything else. On boards without a
console, check the watchdog setup in the port by review.What a lab does differently: automated button actuators and a programmable supply run the same sequences hundreds of times and log every transition.
REQ-2 asks for ratings in the ANSI/PLATO FL 1 way. FL 1 measures the output in an integrating sphere between 30 s and 2 min after switch-on, and the runtime from the 30 s value until the output falls to 10 % of it (Lupine, Streamlight). LuxLibre adds the sustained output after 10 min.
Many lights start bright and step down within seconds. Measured examples from 1Lumen:
| Light | Claimed (lm) | At switch-on (lm) | At 30 s (lm) | 30 s as % of claim |
|---|---|---|---|---|
| TS10 | 1400 | 1454 | 129 | 9 % |
| SC31T Pro | 2210 | 1581 | 886 | 40 % |
| TS25 (50 °C limit) | 4000 | 3616 | 701 | 18 % |
A rating at switch-on hides this. Always publish the 30 s value.
The 2025 edition of FL 1 adds a test for short-duration elevated brightness (turbo), dust ratings and a stopwatch icon, and widens the scope to area lights and spotlights (Business Wire). The details of the turbo test are not public. Until they are, LuxLibre suggests publishing the output at switch-on and the time until turbo steps down, clearly labelled as not the FL 1 method.
A lumen tube is a light-tight tube, white inside, with a diffuser and a lux meter sensor at a fixed port. The lux reading is proportional to the light that enters the tube.
t_s,lumens,T_sensor_C. Fill T_sensor_C with
temp_dC / 10 from status, or, without a console, with a thermocouple reading on the
head (and say so in the report). Then plot it next to the simulator prediction with
firmware/tools/plot_sim.py (--title and --xlabel
change the labels for other kinds of runs):cd firmware
build/luxsim --preset 18650 --csv sim.csv "2C W7200000"
python3 tools/plot_sim.py turbo.png measured.csv:"Measured" sim.csv:"Simulator" --limit 50
A large difference between measurement and simulator means the thermal model or the board header is wrong (THM-3); fix the model before you publish.
What a lab does differently: an integrating sphere calibrated with standard lamps, a spectroradiometer for colour temperature and CRI, a controlled 25 °C, and several samples per model.
Peak intensity is the light per solid angle in the brightest part of the beam, in candela (cd). FL 1 measures the illuminance (lux) at 2, 10 or 30 m and computes cd = lux × d²; the beam distance is the distance at which the illuminance falls to 0.25 lx, which is 2 √cd metres (Lupine).
throw does
this arithmetic; run it with --help for its arguments.What a lab does differently: a goniophotometer measures the whole beam pattern, not only the peak, at the distances the standard sets.
This section verifies THM-1 with the procedure of THM-6 and calibrates the sensor (THM-4).
ISO 13732-1 burn thresholds for touching a hot surface, in °C:
| Contact time | Metal | Plastic |
|---|---|---|
| 1 s | 65 | 85 |
| 10 s | 55 | 70 |
| 1 min | 51 | 60 |
| 10 min | 48 | 48 |
| 8 h | 43 | 43 |
Sources: 1 min to 8 h from CENELEC Guide 29 Table A.1 (CENELEC); 1 s and 10 s from EN 13202 via IEEE PSTC slides (IEEE PSTC).
Pass criteria (THM-1): the hottest touchable surface stays at or below 48 °C in continuous use and never exceeds 51 °C (metal).
temp_dC and the level every 10 s.THM_OFFSET. Leave the light off (and not charging) for 1 h next to the
reference thermocouple so that everything is at room temperature. set THM_OFFSET 0,
read temp_dC, then set THM_OFFSET to the reference minus temp_dC / 10, rounded, and
save. The charge window uses the same reading, so the offset must make the sensor read
the true temperature.set TURBO_S 0 if you want to see the
thermal regulator alone) until the level and temperatures are steady.THM_LIMIT. At steady state, the sensor reads hotter than the surface by a
difference Δ = sensor - surface. Take the smallest Δ you measured and set
THM_LIMIT to 48 + Δ, rounded down (allowed range 30-70 °C). Repeat step 3 and check that the surface stays at or
below 48 °C and never above 51 °C, including the overshoot when turbo starts.TURBO_S back to its board default and save.What a lab does differently: a climate chamber at exactly 25 °C, several thermocouples logged at once, a thermal camera with a known emissivity setting, and the measurement conditions of the product safety standard.
CHG_TMIN and
CHG_TMAX with get; the LuxLibre default is 0-45 °C, but use the window in your cell’s
datasheet if it is narrower. To test without extreme temperatures, move the limits towards
room temperature: set CHG_TMAX 30 and warm the light gently (hand, warm air) until
temp_dC passes 30 °C: charging must pause and resume when it cools. Then set CHG_TMIN 20
and cool the light in a fridge, in a sealed bag against condensation: charging must pause
below 20 °C. Restore the values and check with get.CHG_MAXLVL (check level
in status).Never charge a light that failed the water test or has a damaged cell.
What a lab does differently: a battery cycler logs charge and discharge curves over many cycles, and a climate chamber tests the charge window at the real limits, cold and hot.
Flicker is the periodic change of light output, for example from PWM (pulse-width modulation: switching the LED on and off fast). LED-6 and FW-4 require constant current or PWM at 3 kHz or more (LuxLibre rule).
IEEE 1789-2015 limits (standard copy), f = flicker frequency in Hz:
| Region | Below 90 Hz | From 90 Hz up to the limit | No limit from |
|---|---|---|---|
| Low risk | Mod% < 0.025 f | Mod% < 0.08 f (up to 1250 Hz) | 1250 Hz |
| No observable effect (NOEL) | Mod% < 0.01 f | Mod% < 0.0333 f (up to 3000 Hz) | 3000 Hz |
Example: at 1000 Hz, NOEL allows Mod% < 33.3 %. IEEE has listed 1789 as “Inactive-Reserved” since 26 March 2026 (IEEE): it is no longer maintained, but it remains the common reference, and LuxLibre keeps its NOEL region as the target (LuxLibre choice).
What a lab does differently: a calibrated flicker meter that also reports the flicker index and stroboscopic visibility measures.
Do the drop test first and the water test after it, as FL 1 requires (Lupine).
What a lab does differently: a drop rig with a defined release and orientation, a pressure chamber for IPX8, and dust tests for the new FL 1 dust ratings.
IEC 62471 sorts light sources by blue-light hazard: Exempt (no hazard within 10 000 s), RG1 (no hazard within 100 s), RG2 (no hazard within 0.25 s, the eye’s aversion response), RG3 (hazardous even for a momentary exposure). Flashlights are not general lighting and are assessed at 200 mm. IEC TR 62778 gives a threshold distance; above RG1 at 200 mm, the hazard distance is marked on the product. IEC 62471-7:2023 is the newer part for visible products. (Secondary source; check the standard text before you claim a group.)
Without a lab, a maker can:
IEC 60825-1 classes for visible lasers: Class 2 ≤ 1 mW continuous; Class 3R ≤ 5 mW; EN 50689 allows only Class 1, 2 or restricted 3R in consumer products, and only Class 1 in products that appeal to children (UK government, UL).
LASER_S emission. The seller’s label is not a measurement.
The whole-beam value is at least as high as the value under the aperture conditions of
IEC 60825-1, so it is a conservative check.LASER_TMAX and below LASER_VMIN, and stops after LASER_S.What a lab does differently: a spectroradiometer and imaging radiometer for IEC 62471, and laser power and beam measurements under the exact IEC 60825-1 conditions.
ver, the board header (for example
firmware/boards/flashka-keychain-v05/board.h),
the git commit, the hardware revision on the silkscreen
(REQ-4), and every parameter you changed from the default
(list prints them all).BAT_CAL, THM_OFFSET, the lumen tube factor and its reference).