The Anpiz IPC-D3B53W-S is a cheap Amazon dome camera that turns out to be a surprisingly capable piece of hardware once you replace the stock firmware with OpenIPC. Under the hood it runs a SigmaStar SSC377 (infinity6c) SoC with a SC4336P image sensor, capable of 2560×1440 at 30fps. Here’s everything you need to get it running.
What You’ll Need
- Anpiz IPC-D3B53W-S camera
- CH341A programmer and a flash chip clamp (SOIC-8)
- A PC with flashrom installed
- OpenIPC 16MB Lite image for SSC377 — download from openipc.org
- SSH client and a network cable
Step 1 — Flash the Firmware
The camera uses a GD25Q128C 16MB SPI NOR flash chip on the PCB. You do not need to desolder it — a SOIC-8 chip clamp works fine.
- Disassemble the camera and locate the flash chip on the main board
- Clip the CH341A clamp onto the chip (power the camera off first)
- Connect the CH341A to your PC and flash the OpenIPC image:
flashrom -p ch341a_spi -w openipc-ssc377-lite-16mb.bin
- Verify the write completes without errors
- Remove the clamp, reassemble, and power the camera on
The camera should come up on your network via DHCP within about 30 seconds. Set a root password in the Web UI, then ssh in as root.
Step 2 — Copy the IQ Tuning File
The stock firmware ships with a sensor-specific image quality binary (sc4336p_day.bin) that contains the color correction matrix, white balance tables, and gamma curves tuned for this exact sensor. Without it, colors look washed out and flat.
Extract the file from the original firmware (or download my copy here) and copy it to the camera. The easiest method if you only have SSH access (no SCP) is base64:
On your PC:
base64 sc4336p_day.bin
On the camera via SSH:
base64 -d > /etc/sensors/sc4336p.bin << 'EOF'
<paste base64 output here>
EOF
# Verify the file size (should be 111620 bytes)
wc -c /etc/sensors/sc4336p.bin
Then tell majestic to use it in /etc/majestic.yaml:
isp:
iqFile: /etc/sensors/sc4336p.bin
Step 3 — Fix the CMA Memory Allocation
Out of the box, OpenIPC only reserves 2MB of CMA memory for the video encoder. The SC4336P at 1920×1080 needs at least 6.2MB, which causes the encoder to fail silently and produce a solid pink image.
Increase the CMA reservation in the boot environment:
fw_setenv bootargs "console=ttyS0,115200 panic=20 root=/dev/mtdblock3 init=/init mtdparts=NOR_FLASH:256k(boot),64k(env),2048k(kernel),5120k(rootfs),-(rootfs_data) LX_MEM=0x4000000 mma_heap=mma_heap_name0,miu=0,sz=0x2000000 cma=8M"
Reboot and verify:
cat /proc/meminfo | grep -i cma
# CmaTotal: 8192 kB
Step 4 — Configure the GPIO Pins (IR Filter and Light)
This was the most involved part of the setup. The stock firmware doesn’t document its GPIO assignments anywhere obvious, so finding the right pins required extracting and analysing the firmware.
The key was finding ko.sh — the kernel module startup script embedded in the squashfs of the original firmware — which explicitly exports and tests the ICR motor pins at boot.
The complete pin map for this camera:
| Function | Interface | Pin/Channel |
|---|---|---|
| ICR filter — day coil | GPIO | 11 |
| ICR filter — night coil | GPIO | 80 |
| LED light | GPIO | 13 |
| IR LED (infrared light) | PWM | pwmchip0/pwm4 |
| White light | PWM | pwmchip0/pwm0 |
| Light sensor input | GPIO | 23 (input) |
| Alarm input | GPIO | 44 (input) |
| Alarm output | GPIO | 61 (output) |
The IR cut filter is a mechanical two-coil motor — it needs a brief pulse (~250ms) on one pin to switch to night position and a pulse on the other to return to day. Both pins sit at 0 between switches. The IR and white lights are PWM-controlled at a 50kHz period, not simple GPIO on/off.
Add the ICR pins to /etc/majestic.yaml:
nightMode:
irCutPin1: 11
irCutPin2: 80
irCutSingleInvert: false
lightMonitor: false # doesn't seem to work
lightSensorInvert: false
backlightPin: 13
To manually test the filter from the shell:
# Switch to day mode
echo 1 > /sys/class/gpio/gpio80/value
echo 0 > /sys/class/gpio/gpio11/value
usleep 250000
echo 0 > /sys/class/gpio/gpio11/value
echo 0 > /sys/class/gpio/gpio80/value
# Switch to night mode
echo 1 > /sys/class/gpio/gpio11/value
echo 0 > /sys/class/gpio/gpio80/value
usleep 250000
echo 0 > /sys/class/gpio/gpio11/value
echo 0 > /sys/class/gpio/gpio80/value
You should hear a faint click each time as the filter moves.
The Pink Screen Mystery
During setup we ran into a solid pink image with no visible picture at all. It turned out to be two separate issues that happened to occur at the same time:
- CMA too small — the encoder was failing silently (fixed by the
cma=8Mbootarg above) - Lens not fully seated — the lens barrel wasn’t screwed down flush to the sensor PCB, letting ambient light bleed in through the gap from behind and saturating the sensor pink
If you see a solid pink image, check both. The CMA fix is in the bootargs. The lens issue is mechanical — just unscrew the dome cover and tighten the lens down until it’s flush.
Step 5 — Automatic Day/Night Switching
OpenIPC’s built-in night mode appears to have a significant limitation on this camera: enabling lightMonitor: true (which uses image brightness to decide when to switch) disables all the night mode buttons in the web UI. And setting lightMonitor: false to get the buttons back means automatic switching stops working for some reason. You can’t have both at the same time. I hope I am wrong – if so, correct me!
But my workaround is to disable lightMonitor and handle automatic switching yourself with a cron script that uses sunrise/sunset times for your location. Save the following to /root/nightwatch.sh:
#!/bin/sh
LAT=40.0000
LON=-85.0000
STATE_FILE=/tmp/nightmode_state
CACHE=/tmp/sun_times
set_day() {
if [ "$(cat $STATE_FILE 2>/dev/null)" != "day" ]; then
echo "Switching to DAY mode"
curl -s "http://localhost/night?enabled=0" > /dev/null
echo 11 > /sys/class/gpio/export 2>/dev/null
echo 80 > /sys/class/gpio/export 2>/dev/null
echo out > /sys/class/gpio/gpio11/direction 2>/dev/null
echo out > /sys/class/gpio/gpio80/direction 2>/dev/null
echo 1 > /sys/class/gpio/gpio80/value
echo 0 > /sys/class/gpio/gpio11/value
usleep 250000
echo 0 > /sys/class/gpio/gpio11/value
echo 0 > /sys/class/gpio/gpio80/value
echo day > $STATE_FILE
else
echo "Already in DAY mode"
fi
}
set_night() {
if [ "$(cat $STATE_FILE 2>/dev/null)" != "night" ]; then
echo "Switching to NIGHT mode"
curl -s "http://localhost/night?enabled=1" > /dev/null
echo 11 > /sys/class/gpio/export 2>/dev/null
echo 80 > /sys/class/gpio/export 2>/dev/null
echo out > /sys/class/gpio/gpio11/direction 2>/dev/null
echo out > /sys/class/gpio/gpio80/direction 2>/dev/null
echo 1 > /sys/class/gpio/gpio11/value
echo 0 > /sys/class/gpio/gpio80/value
usleep 250000
echo 0 > /sys/class/gpio/gpio11/value
echo 0 > /sys/class/gpio/gpio80/value
echo night > $STATE_FILE
else
echo "Already in NIGHT mode"
fi
}
iso_to_ts() {
DT=$(echo $1 | sed 's/T/ /' | sed 's/+[0-9:]*$//' | sed 's/-[0-9][0-9]:[0-9][0-9]$//')
date -u -d "$DT" +%s
}
is_valid_ts() {
[ -n "$1" ] && echo "$1" | grep -q '^[0-9]*$'
}
CACHE_AGE=0
if [ -f $CACHE ]; then
CACHE_AGE=$(( $(date +%s) - $(date -r $CACHE +%s 2>/dev/null || echo 0) ))
fi
FORCE_FETCH=0
if [ ! -f $CACHE ] || [ $CACHE_AGE -gt 86400 ]; then
FORCE_FETCH=1
else
read SUNRISE_TS SUNSET_TS < $CACHE
if ! is_valid_ts "$SUNRISE_TS" || ! is_valid_ts "$SUNSET_TS"; then
echo "Bad cache detected, clearing"
rm -f $CACHE
FORCE_FETCH=1
else
echo "Cached: sunrise=$SUNRISE_TS sunset=$SUNSET_TS"
fi
fi
if [ "$FORCE_FETCH" = "1" ]; then
echo "Fetching sun times from API"
RESPONSE=$(curl -s "https://api.sunrise-sunset.org/json?lat=$LAT&lng=$LON&formatted=0")
SUNRISE=$(echo $RESPONSE | grep -o '"sunrise":"[^"]*"' | cut -d'"' -f4)
SUNSET=$(echo $RESPONSE | grep -o '"sunset":"[^"]*"' | cut -d'"' -f4)
SUNRISE_TS=$(iso_to_ts "$SUNRISE")
SUNSET_TS=$(iso_to_ts "$SUNSET")
if is_valid_ts "$SUNRISE_TS" && is_valid_ts "$SUNSET_TS"; then
echo "$SUNRISE_TS $SUNSET_TS" > $CACHE
echo "Fetched: sunrise=$SUNRISE_TS sunset=$SUNSET_TS"
else
echo "Failed to fetch valid sun times, defaulting to night"
set_night
exit 1
fi
fi
NOW=$(date +%s)
echo "Now=$NOW sunrise=$SUNRISE_TS sunset=$SUNSET_TS"
if [ "$NOW" -ge "$SUNRISE_TS" ] && [ "$NOW" -lt "$SUNSET_TS" ]; then
set_day
else
set_night
fi
Update LAT and LON for your location. Make it executable and add it to cron:
chmod +x /root/nightwatch.sh
echo "*/5 * * * * /root/nightwatch.sh >> /tmp/nightwatch.log 2>&1" >> /etc/crontabs/root
killall crond 2>/dev/null
crond
The script caches sunrise/sunset times for 24 hours (using the free sunrise-sunset.org API), only pulses the ICR motor when the state actually needs to change, and fails safely to night mode if the API is unreachable.
With this approach, set lightMonitor: false in majestic.yaml so the web UI buttons remain functional for manual overrides.
Final majestic.yaml
Here’s a working configuration for reference:
system:
webPort: 80
isp:
iqFile: /etc/sensors/sc4336p.bin
antiFlicker: disabled
image:
mirror: false
flip: false
rotate: 0
contrast: 50
hue: 50
saturation: 50
luminance: 50
video0:
enabled: true
codec: h264
size: 1920x1080
fps: 20
bitrate: 4096
rcMode: vbr
gopSize: 1
video1:
enabled: false
nightMode:
colorToGray: true
irCutPin1: 11
irCutPin2: 80
irCutSingleInvert: false
lightMonitor: false
lightSensorInvert: false
backlightPin: 0
rtsp:
enabled: true
port: 554
watchdog:
enabled: true
timeout: 300
Summary
The Anpiz IPC-D3B53W-S is a solid candidate for OpenIPC. The hardware is capable, the sensor driver is already supported upstream, and once the IQ file, CMA, and GPIO pins are sorted it runs well. The main gotchas are the CMA allocation (easy fix), finding the correct ICR GPIO pins (GPIO 11 and 80, not obvious without digging into the original firmware), and making sure the lens is properly seated after reassembly.