I got myself a Petzl NAO RL for (ultra-)trailrunning, wich is equipped with a USB C connetor for the battery. My first thougt: Nice, I could run it on a bigger powerbank in my backpack.
This kind of works, when using a extention cord with 5 kOhm "OTG" resistors on CC pins to enable power output. But this only enables the "normal" operation mode, the reactive lighting is not working. So lets find out why.
When the USB plug is connected, the Naos battery outputs 5.1V to the headlamp. The headlamp then uses the sidebanduse (SBU, B8) pin to talk back to the battery. This happens as 1-wire bus running at 19200 baud and a level of 2.7V. The headlamp acts as the master.
The headlamp authentificates with the battery with a challenge by sending a seed, which the battery has to reply to. If correct, a second seed is send. Then some yet unknown messages are send.
Handshake example:
--> 40 01 A8 9F AE (request) <-- 60 01 9B 2D 9C (response) --> 41 01 09 1C 17 <-- 61 01 09 5E 38 --> 42 05 00 00 5F <-- 62 05 32 2A 19 --> 03 04 00 00 62 <-- 23 04 0B 86 D4 --> 04 12 00 00 F1 (VCC is lowered to 3.9V) --> 24 12 0B 86 47 <-- 05 0C 00 00 39 ...
When authentification was sucessful, the voltage on VCC lowers to ~3.9V (probably Li-Ion passthru) as long as the SBU is pulled high. Even when completly "off", as long as you dont disconnect the battery.
General protocol information:
example:
03 0A 00 00 95 23 0A 90 18 52
Structure: SID+SN PID data[...] Checksum
SID read request: 0x0X
SID write request: 0x4X
SID response: request + 0x20 where X = Sequence number in range 0 to 7 starting at 0 incrementing after each message.
Checksum is calculated with these parameters (thanks to this):
width=8 poly=0x31 init=0xff refin=false refout=false xorout=0x00 check=0xf7 residue=0x00 name="CRC-8/NRSC-5"
Authentification
To understand the authentification I made a circuit to power the headlamp and capture the handshake with an Arduino, then power the headlamp off, waiting 4 second (required as cooldown for the battery) and then apply power again. The serial recording and analysis was done in python with pandas. In this way I collected ~2000 samples within a few hours to work with. The first to check if a response to a challenge is constant (so same result for each time requested). With this approach I found out, that the challenges are nestet, so the first request ist answered last and the other one in between. The second thing to check was, if the challenges are dependent on each other. For this I compared the results of the same challenge, one time as the inner one, one time as the outer one: They are the same. Yea, much less complexity.
So we got a function mapping 2 Byte on 2 Byte. Checking the data revealed, that there are several inputs (challenges) for the same output (response) and he first byte of the resonse is alway below 16. The second byte of the response differs a lot when only one bit of the input is changed.
After a few hours of manual search and the attempt of getting something out of ChatGPT (did not work at all, it just provided incorrect FAKE answers preteending to be the solution) it was clear: The first byte is the "sum of set bits" (like Brian Kernighan Algorithm) and the second one is the same as the checksum calculation (again found with reveng.exe)
The authentification is done in 2 steps:
--> 40 01 A8 9F AE Challenge (outer) from headlamp: A8 9F <-- 60 01 9B 2D 9C Challenge (inner) from Battery: 9B 2D --> 41 01 09 1C 17 Response to battery (inner): 09 1C <-- 61 01 09 5E 38 Response to headlamp (outer): 09 5E
Known commands:
These commands can be decoded easily by knowing the environment (voltage, current, temperature, power state)
4X 0D 00 0Y CRC: Set default value of red backlight without enabeling it. Y= 0: off, 1: constant, 2: blinking 4X 0E 00 0Y CRC: Set red backlight. Y= 0: off, 1: constant, 2: blinking 0X 0D 00 00 CRC: Request current state of backlight 2X 0D 00 0Y CRC: Y=[0|1|2] see above 0X 0A 00 00 CRC: Request energy counter 2X 0A 8B 18 CRC: energy counter, signed or not, maybe mAh? 0X 80 00 00 CRC: Request batter info 2X 80 0F 3E : VCC output voltage 3902 mV FF A6 : battery current: -90 mA 8B 18 : energy counter (same as 0A message) 01 06 : battery temperature 262 = 26.2°C Other commands running once when connecting the battery. Currently unknown: 4X 05 00 00 CRC --> 6X 05 32 2A CRC 0X 04 00 00 CRC --> 2X 04 0B 86 CRC 0X 12 00 00 CRC --> 2X 12 0B 86 CRC 0X 0C 00 00 CRC --> 2X 0C 00 00 CRC 0X 11 00 00 CRC --> 2X 11 01 10 CRC 0X 82 00 00 CRC --> 2X 82 EC F6 00 0A 12 3C 7F 7F CRC 0X 83 00 00 CRC --> 2X 83 0C 10 18 22 32 32 FF FF CRC 0X 07 00 00 CRC --> 2X 07 0A D2 CRC 0X 84 00 00 CRC --> 2X 84 00 1E 00 64 00 00 00 00 CRC
While running the headlamp constantly requests A0, 80 and D0 every 200ms. Message spacing is ~20ms. My only question is FOR WHAT?
Replicating the battery
All I want to have is a bigger battery. So I need a device that does the communication to enable reactive lighting mode. I took a Seed XIAO (5$ SAMD21 Cortex M0), implemented the things I found out above and added low power mode with wakeup on UART activity. USB C VCC is directly connected to a (BMS protected) 1S 18650 stack. Annnd, it works.
I dont get constant communication while the lamp is running, but that does not affect the usability.
Hardware
To make a 1 wire serial bus, connect TX with a diode to RX (just google it). For deepsleep wakeup i connected pin 5 to RX for CHANGE monitoring. With this the serial pheriphial dont need to be startet on wakeup (switching from interrupt). Connect RX to USB C B8. Thats it.
I added a 40M (megaohm!) pulldown to PIN 6 to avoid wakeup when no lamp is connected. With lower values the communication does not work.
Current draw of the XIAO is 55µA in deepsleep (LowPower.deepSleep();) without lamp connected, with the headlamp 85µA. So no need for a hardware switch while not in use. Remove the "Power" LED.
As someone asked for the wiring. (I did not use this USB C breakout board)
Quick & ugly, but works.
As an cable extention a normal USB 3.2 cable probably does not work, because SBU pins are not connected. Take a thunderbolt capable (not tested) one or make it yourself. Also the direction or the connector does matter. Connect all 4 GND and VCC pins due to the high currents on full power.
To PETZL
If you are planning to sell a bigger battery soon, sorry, too late. If you are afraid that counterfeit batteries will join the market: Maybe your own fault, you could have made it secure and not just "security by obscurity". If you want me to "review" some other of your products, please contact me, I'm highly interested. Not just electonical stuff, I also like your other products. And I highly recommend this headlamp, it is soooo nice and lightweight (but also expensive)