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)