cd /news/developer-tools/petlibro-polar-reverse-engineering-n… · home topics developer-tools article
[ARTICLE · art-112109] src=gist.github.com ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Petlibro Polar Reverse Engineering Notes

A developer reverse-engineered the Petlibro Polar (PLAF109/AF109) pet feeder firmware, mapping the ESP32-C3's GPIO and AW9523B I/O expander pins to their functions. The analysis, performed offline with GPT 5.6 Sol, provides a pin map for future replacement firmware, highlighting a GPIO9 conflict with the ROM download strap.

read11 min views10 publishedAug 24, 2026

note: these findings were done with GPT 5.6 Sol.

This document records static analysis of the stock PLAF109/AF109 application firmware on disk. It is intended as a starting point for a future replacement firmware, not as permission to energize actuators from an incomplete pin map. The analysis was offline; no device or Petlibro service was contacted.

File: firmware/PLAF109_OTA_020032.bin

  • File SHA-256: 9e73f904e7f6a09172b7384aa84fa38963ce75ef22bebec89f38ebef5c8dd53d

  • Target: ESP32-C3, revision 0.3 or newer

  • Application: AF109

version2.0.32

  • Build: 2025-04-22 09:46:39, ESP-IDF v4.4.6-dirty

  • Image size: 1,247,744 bytes

  • Entry point: 0x40380450

  • IROM: 0x42000020

through0x420ec8cf

  • DROM: 0x3c0f0020

through0x3c11bcc7

This is only an OTA application image. Values kept in NVS, including the unit's motor-current calibration and thresholds, are not in this file.

The ESP32-C3 directly handles ADC inputs, interrupts, one PWM output, and a one-wire sound interface. Most actuator outputs are provided by an AW9523B 16-bit I/O expander at I2C address 0x58

.

The central board initializer at 0x4200d726

calls these routines in order:

  • AW9523B and I2C initialization at 0x4200d94a

  • cooler/PTC output initialization at 0x4200d1c0

  • plate motor initialization at 0x4200d134

  • door motor initialization at 0x4200d17a

  • button initialization at 0x4200d09e

  • alarm/status LED initialization at 0x4200d0f4

  • sensor and 38 kHz LEDC initialization at 0x4200cdb6

  • ADC initialization at 0x4200d200

  • sound interface initialization at 0x4200d6ca

The AW9523 shadow-register bit writer is at 0x4200d838

. It updates a 16-bit RAM shadow and writes AW9523 output registers 0x02

and 0x03

through the I2C helper at 0x4200d816

.

Confidence in this table is high: the assignments come from immediate values passed to ESP-IDF GPIO, ADC, I2C, and LEDC functions, then were correlated with the firmware's retained log labels.

ESP GPIO Direction/peripheral Recovered purpose Evidence
0 digital input, any-edge DC/battery power-source detection polled by Power_Handle at 0x4200c692
1 ADC1 channel 1 NTC temperature divider read by Read_Ntc_Temp at 0x4200d41a
2 LEDC output 38 kHz optical/IR emitter, 8-bit timer, duty 127 or 0 LEDC setup under 0x4200cdb6
3 ADC1 channel 3 door motor current retained assertion names ADC1_CHAN3_MOTOR
4 ADC1 channel 4 battery voltage firmware converts calibrated mV and applies a 2:1 divider factor
5 ADC2 channel 0 plate motor current retained assertion names ADC2_CHAN0_MOTOR
6 digital output one-wire sound/voice IC data byte sender at 0x4200d77a
7 I2C0 SDA AW9523B data pull-up enabled
8 I2C0 SCL AW9523B clock pull-up enabled, 100 kHz bus
9 digital output AW9523B reset held low for 200 ms, then high
10 interrupt input, pull-up, any-edge rotating tray microswitch/index pulse Plate_Micro_Handle at 0x4200e332
18 interrupt input, any-edge user/reset button Key_init and Timer_KeyRestoreHandle
19 interrupt input, any-edge door/close-position signal retained label Close_SW_Interrupt
20 interrupt input, any-edge IR/pet-presence receiver Infrared_Handle at 0x4200c596

GPIO9 is an important board-specific conflict: it resets the AW9523B in the running application, but it is also the ESP32-C3 ROM download-mode strap. A replacement firmware must release it appropriately after boot.

The firmware treats AW9523 pins as one flat bit index from 0 through 15.

Bit AW9523 pin Recovered purpose Initial state
0, 1 P0.0, P0.1 hardware revision straps/inputs read during startup
4, 7 P0.4, P0.7 paired existence/optical sensing controls application controlled
5, 6 P0.5, P0.6 rotating plate motor H-bridge inputs high/high
8, 9 P1.0, P1.1 two-channel front/alarm status LED low/low
12 P1.4 cooler/PTC power control high
14, 15 P1.6, P1.7 feeding-door motor H-bridge inputs high/high

The startup strap decode masks the low two AW9523 input bits. Static control flow maps value 2

to hardware 5.1.0

, value 1

to 5.2.0

, and other values to 5.0.0

. This agrees with the observed unit reporting hardware 5.1.0

, but the electrical pull-up/pull-down arrangement is not present in the OTA image.

The plate motor is a bidirectional DC motor behind two H-bridge inputs on AW bits 5 and 6. The stock firmware uses:

  • high/high as GPIO_MOTOR_BRAKE

  • high/low and low/high for the two directions

  • motor-current feedback on ESP GPIO5 / ADC2 channel 0

  • a tray index microswitch on ESP GPIO10

The direction combinations should initially be called direction A and direction B. Static analysis does not establish which is clockwise at the physical tray without a board observation.

Plate_Micro_Handle

at 0x4200e332

advances the current position on each accepted switch event, wrapping through positions 1, 2, and 3. When the current position equals the requested position, the routine writes high/high to AW bits 5 and 6 and changes the plate motor state to the stopped/braked state. The retained logs include F1

, F2

, PLATE_READY_SET_POS

, PLATE_READY_BACK_POS

, and SET_PLATE_POS_SERVICE

, showing that normal positioning and return/reposition behavior are separate state-machine paths.

The plate controller does not rely on time alone. It watches motor current and uses retained attributes named plateStuckCurrent

and plateStuckTimeout

. On a detected stall it enters MOTOR_STUCK

, brakes the motor, and inhibits normal cooling/feeding transitions. The actual current and timeout values are loaded from persistent device attributes and cannot be recovered from this OTA application alone.

The door motor is another bidirectional DC motor behind AW bits 14 and 15. Like the plate motor, high/high is its initialized stopped/braked state and the two asymmetric combinations select opposite directions. Firmware logs name the directions GPIO_DOOR_MOTOR_FORWARD

and GPIO_DOOR_MOTOR_BACK

; higher level paths associate them with closing and opening respectively. Verify that physical mapping before using it in replacement firmware because the motor or wiring orientation may vary by board revision.

Door movement uses both:

  • a position/close signal on ESP GPIO19
  • motor-current feedback on ESP GPIO3 / ADC1 channel 3

The state machine has DOOR_READY_OPEN

, DOOR_MOTOR_OPEN_OVER

, DOOR_READY_CLOSE

, DOOR_MOTOR_CLOSING

, DOOR_MOTOR_CLOSE_OVER

, and MOTOR_STUCK

states. A door-reset/recovery path samples at approximately 100 ms intervals with a roughly 50-sample bound, about five seconds total. Retained attributes doorStuckCurrent

, doorStuckTimeout

, doorCheckSignalTime

, and doorNotcheckSignalTime

show that both current and the position signal participate in protection. Their per-unit values are in NVS, not this image.

The feeding sequence is explicitly staged as plate movement/thaw, door open, feeding duration, and door close. It is not safe to expose independent raw motor buttons without preserving those interlocks and recovery states.

The only identified refrigeration output is AW bit 12, called PTC

by the firmware. No separate fan output was identified. The temperature input is an NTC divider on ESP GPIO1 / ADC1 channel 1.

Read_Ntc_Temp

at 0x4200d41a

averages ten ADC readings and applies a standard 10 kOhm, B3950 thermistor calculation using 3.3 V, 1 / 298.15

, and -273.15

. A retained tempCoeff

permits unit calibration. Temperature publication is held off during a 60-cycle stabilization period.

The cooler controller at 0x4200e672

contains exact double constants 12.0 and 13.0 degrees C at DROM addresses 0x3c0fae38

and 0x3c0fae30

, providing a 1 degree hysteresis band. It also has a 600-call dwell counter and guards for power source, feeding/plate activity, motor-stuck state, and explicit cool switch state. Logs include start cool

, NOT_COOL

, DL_COOL_STOP_STATUS

, switch plate make cool

, and GPIO_PTC_ON

.

Do not assume the electrical polarity of AW bit 12 yet. Initialization sets it high, while runtime paths explicitly write both high and low around the temperature comparisons and guard states. The retained GPIO_PTC_ON

log is not enough by itself to prove whether the expander output or a downstream transistor is active-low. Confirm polarity with an unpowered continuity check and then a current-limited measurement before enabling refrigeration.

The ESP32-C3 does not synthesize audio with I2S, DAC, or PWM. GPIO6 drives an external one-wire sound or voice IC using the byte sender at 0x4200d77a

. The recovered waveform is:

  • idle high
  • 5 ms low start pulse
  • eight data bits, least-significant bit first
  • bit 0: 1 ms high, then 3 ms low
  • bit 1: 3 ms high, then 1 ms low
  • return high after the eighth bit

The MQTT/application AUDIO

command path at 0x42018988

sends byte 0x01

, which is therefore the stock one-shot feeding bell command. Other internal paths also send 0xef

; its sound or control meaning is unresolved. Persistent fields include enableAudio

and audioTimes

, so scheduled feeding sounds can be suppressed or repeated independently of the one-shot command.

The external sound IC model and its complete command table cannot be derived from this application image. Identify the package marking or capture GPIO6 while exercising stock firmware before assuming commands other than 0x01

.

The front indicator uses AW bits 8 and 9. AlarmLed_init

at 0x4200d0f4

initializes both low. A dl_led

task drives combinations of the two outputs to represent states and honors retained settings including lightSwitch

, enableLight

, led_enable

, led_mode

, and start/end hour and minute fields.

The OTA image establishes that this is a two-channel indicator, but not which bit maps to which physical color or whether either channel is active-low. Observe the AW outputs alongside visible stock patterns before naming colors in custom firmware.

  • GPIO0 distinguishes external DC and battery operation. Stock logic disables or restricts cooling and networking behavior in battery mode.
  • GPIO4 measures battery voltage through a divider; firmware doubles the calibrated millivolt result before estimating charge state.
  • GPIO2 generates a 38 kHz, 50-percent-duty carrier and GPIO20 handles an infrared/presence event. This strongly indicates a modulated optical sensing pair used for pet/existence detection.
  • AW bits 4 and 7 are toggled together in related existence-detection paths. Their exact external circuits are not identifiable from the OTA image.
  • GPIO18 is the user button. The stock code uses debounce/restore timers and includes network/reset behavior, so a custom build should distinguish short and long presses before assigning destructive actions.

Before driving the motors or cooler, a replacement should preserve at least:

  • AW9523 reset, I2C shadowing, and stopped output states before task startup.
  • high/high motor brake behavior verified against the actual H-bridge.
  • tray microswitch debounce and modulo-3 position tracking.
  • an explicit homing/reposition procedure for unknown startup position.
  • current-based plate and door stall cutoffs, plus hard movement timeouts.
  • door position-signal validation while closing.
  • motor inhibition after a stall until an attended recovery action.
  • cooler hysteresis, minimum dwell time, battery-mode inhibition, and inhibition during motor movement or feeding transitions.
  • conservative startup defaults for both LED channels and the sound line.
  • retained calibration storage with bounds checking and recoverable defaults.

Do not copy unknown stock NVS values blindly between units. First obtain the full flash backup described in CUSTOM_FIRMWARE.md

, identify the relevant NVS keys, and correlate them with current-limited bench measurements.

Inspect the image header and segment map:

py -3.10 -m esptool image-info firmware\PLAF109_OTA_020032.bin

Resolve direct references to retained board-support labels:

py -3.10 analysis\esp32c3-xrefs.py `
  firmware\PLAF109_OTA_020032.bin `
  Motor_init Door_Motor_init Ptc_init AlarmLed_init Adc_init `
  Read_Ntc_Temp BSP_aduioInit AW9523B_i2cInit

High-value virtual addresses:

Address Meaning
0x4200c596
infrared input handler
0x4200c692
power-source input handler
0x4200cdb6
GPIO2 LEDC and sensor setup
0x4200d0f4
two-channel status LED initialization
0x4200d134
plate motor initialization
0x4200d17a
door motor initialization
0x4200d1c0
PTC/cooler output initialization
0x4200d200
ADC setup
0x4200d41a
NTC conversion
0x4200d6ca
sound GPIO initialization
0x4200d77a
one-wire sound byte sender
0x4200d816
AW9523 register write helper
0x4200d838
AW9523 bit shadow/write helper
0x4200d94a
I2C and AW9523 initialization
0x4200e332
tray microswitch and position handler
0x4200e672
cooler controller
0x42018988
one-shot AUDIO command dispatch

Useful retained strings include GPIO_MOTOR_BRAKE

, plateStuckCurrent

, doorStuckCurrent

, Close_SW_Interrupt

, MicroSw_DebounceHandle

, GPIO_PTC_ON

, Infrared_Handle

, AUDIO

, lightSwitch

, and audioTimes

.

  • cooler output polarity and downstream power-driver topology

  • AW bits 8/9 physical LED colors and polarity

  • plate direction A versus physical clockwise/counterclockwise movement

  • exact door switch active level and motor orientation on each board revision

  • per-unit plate and door stall-current thresholds from NVS

  • external sound IC model and commands other than confirmed bell byte 0x01

  • exact circuits controlled by AW bits 4 and 7

  • absolute tray position after startup when no trusted retained position exists

Resolve these with the full flash backup, board photographs and part markings, continuity checks while unpowered, and current-limited logic measurements of stock firmware. Do not begin by connecting normal actuator power to an untested replacement build.

── more in #developer-tools 4 stories · sorted by recency
consumerrights.wiki · · #developer-tools
Petlibro
── more on @petlibro 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/petlibro-polar-rever…] indexed:0 read:11min 2026-08-24 ·