Device: Synaccess netBooter NP-0501DU Test Date: 2025-10-15 Status: ✅ COMPLETE - Device working correctly after factory reset Firmware: Unknown (check web interface)
After factory reset, the NP-0501DU works perfectly:
- ✅ No inverted logic - Status matches reality
- ✅ LEDs match power state - Visual indicators are accurate
- ✅ Explicit ON/OFF control - Full API support
- ✅ All commands work - Status, control, and toggle all functional
Critical Discovery: The manual documentation is incorrect. HTTP commands use SPACES, not commas.
http://{device_ip}/cmd.cgi?{command}
- Type: HTTP Basic Auth
- Username: admin (default)
- Password: admin (default, should be changed)
Query status of all outlets
GET http://192.168.1.100/cmd.cgi?$A5Response Format:
$A0,XXXXX,C.CC,TT\r\n\r\n\r\n
Fields:
$A0- Success codeXXXXX- 5-character outlet state string- Each character:
1= ON,0= OFF - Position mapping (RIGHT to LEFT):
- Position 4 (rightmost): Outlet 1
- Position 3: Outlet 2
- Position 2: Outlet 3
- Position 1: Outlet 4
- Position 0 (leftmost): Outlet 5
- Each character:
C.CC- Total current draw in AmpsTT- Temperature (may showXXif not available)
Examples:
$A0,00000,0.06,XX → All outlets OFF, 0.06A draw
$A0,00001,0.15,XX → Outlet 1 ON, others OFF, 0.15A
$A0,11111,0.85,XX → All outlets ON, 0.85A
$A0,10001,0.25,XX → Outlets 1 and 5 ON
Parsing Status String:
def parse_status(status_str: str) -> dict:
parts = status_str.strip().split(",")
return {
"code": parts[0], # $A0 = success, $AF = fail
"outlets": parts[1], # 5-char string
"current_amps": float(parts[2]),
"temperature": parts[3],
}
def get_outlet_state(outlets_str: str, outlet_num: int) -> bool:
"""Get state of specific outlet (1-5)"""
position = 5 - outlet_num # Outlet 1 → pos 4, outlet 5 → pos 0
return outlets_str[position] == '1'Turn outlet explicitly ON or OFF
# Turn outlet 1 ON
GET http://192.168.1.100/cmd.cgi?$A3 1 1
# Turn outlet 1 OFF
GET http://192.168.1.100/cmd.cgi?$A3 1 0
# Turn outlet 5 ON
GET http://192.168.1.100/cmd.cgi?$A3 5 1Parameters:
port- Outlet number (1-5)value- State (1= ON,0= OFF)
Response:
$A0\r\n\r\n → Success
$AF\r\n\r\n → Failed
Note: The manual documents this as $A3,port,value (with commas), but the HTTP interface requires SPACES.
Toggle outlet state (ON→OFF or OFF→ON)
# Toggle outlet 1
GET http://192.168.1.100/cmd.cgi?rly=0
# Toggle outlet 5
GET http://192.168.1.100/cmd.cgi?rly=4Parameters:
X- Relay index (0-4)rly=0→ Outlet 1rly=1→ Outlet 2rly=2→ Outlet 3rly=3→ Outlet 4rly=4→ Outlet 5
Response:
$A0\r\n\r\n → Success
Note: Toggle is useful but requires checking current state first. Use $A3 for explicit control.
| Physical Outlet | Status Position | Status Bit Mask | Control ($A3) | Toggle (rly) |
|---|---|---|---|---|
| 1 | 4 (rightmost) | 0b00001 |
$A3 1 X |
rly=0 |
| 2 | 3 | 0b00010 |
$A3 2 X |
rly=1 |
| 3 | 2 | 0b00100 |
$A3 3 X |
rly=2 |
| 4 | 1 | 0b01000 |
$A3 4 X |
rly=3 |
| 5 | 0 (leftmost) | 0b10000 |
$A3 5 X |
rly=4 |
These commands are documented in the manual but return $AF (failed) via HTTP:
- ❌
$A3,port,value- Explicit control with commas (use spaces instead!) - ❌
$A7,value- Set all outlets ON/OFF - ❌
/pset n x- Serial-style command - ❌
$A1,user,pass- Login (authentication is HTTP Basic only)
These may work via Telnet (port 23) but are not supported via HTTP.
| Code | Meaning |
|---|---|
$A0 |
Success |
$AF |
Failed / Unknown command |
import requests
from typing import Optional
class NetCommanderClient:
def __init__(self, host: str, username: str, password: str):
self.base_url = f"http://{host}/cmd.cgi"
self.auth = (username, password)
def get_status(self) -> dict:
"""Get outlet status and metrics."""
response = requests.get(f"{self.base_url}?$A5", auth=self.auth)
parts = response.text.strip().split(",")
return {
"outlets": {
1: parts[1][4] == '1', # Position 4
2: parts[1][3] == '1', # Position 3
3: parts[1][2] == '1', # Position 2
4: parts[1][1] == '1', # Position 1
5: parts[1][0] == '1', # Position 0
},
"total_current_amps": float(parts[2]),
"temperature": parts[3],
}
def set_outlet(self, outlet: int, state: bool) -> bool:
"""Set outlet explicitly ON (True) or OFF (False)."""
value = 1 if state else 0
# IMPORTANT: Use space between arguments!
url = f"{self.base_url}?$A3 {outlet} {value}"
response = requests.get(url, auth=self.auth)
return response.text.strip().startswith("$A0")
def toggle_outlet(self, outlet: int) -> bool:
"""Toggle outlet state."""
rly_index = outlet - 1
url = f"{self.base_url}?rly={rly_index}"
response = requests.get(url, auth=self.auth)
return response.text.strip().startswith("$A0")
# Usage
client = NetCommanderClient("192.168.1.100", "admin", "admin")
# Turn on outlet 1
client.set_outlet(1, True)
# Get status
status = client.get_status()
print(f"Outlet 1 is {'ON' if status['outlets'][1] else 'OFF'}")
print(f"Total current: {status['total_current_amps']}A")
# Turn off all outlets
for outlet in range(1, 6):
client.set_outlet(outlet, False)- All outlets: OFF
- IP:
192.168.1.100 - User/Pass:
admin/admin - Status:
$A0,00000,0.06,XX(or similar low current)
- LED indicators match outlet state ✓
- Status bits match physical power ✓
- No inverted logic ✓
- Explicit commands work ✓
- Base consumption: ~0.06-0.10A (device itself)
- Per-outlet load: Varies by connected device
- Monitoring current can help detect:
- Power loss (sudden drop)
- Short circuits (sudden spike)
- Equipment failure (unexpected change)
- Change default password immediately after setup
- Use HTTPS if device supports it (check model variant)
- Isolate on management network - PDUs shouldn't be on public internet
- Use strong passwords - Default
admin/adminis insecure - Disable unused protocols - Check if Telnet/SNMP can be disabled
- Monitor access logs - If available in web interface
- URL:
http://{device_ip}/ - Default Login: admin / admin
- Features:
- Outlet control (ON/OFF/Reboot)
- Network configuration
- User management
- Outlet naming/grouping
- AutoPing configuration
- Firmware upgrade
Check web interface for:
- Current firmware version
- Serial number
- Model information
- Advanced configuration options
- ❌ Manual shows
$A3,port,value(commas) - WRONG - ✅ Actual syntax:
$A3 port value(spaces) - CORRECT
- Cannot set all outlets at once via
$A7 - Must use individual
$A3commands for each outlet - Login command
$A1doesn't work (use HTTP Basic Auth)
- May show
XXinstead of actual temperature - Check firmware/hardware version
- May require calibration or not be present
All tests performed: 2025-10-15
- ✅ Status query ($A5)
- ✅ Explicit ON ($A3 port 1)
- ✅ Explicit OFF ($A3 port 0)
- ✅ Toggle (rly=X)
- ✅ All outlets (1-5)
- ✅ LED verification
- ✅ Power verification
- ✅ Status accuracy
Test files:
test_device_discovery.py- Initial discoverytest_command_formats.py- Command syntax testingtest_correct_syntax.py- Explicit control verification
- Device Manual:
1291_NPCStartup_v13.pdf - Test Results:
outlet_mapping_results_*.json - Factory Reset Guide:
FACTORY_RESET_GUIDE.md - Old (broken) mapping:
OUTLET_MAPPING.md(pre-reset)
Last Updated: 2025-10-15 Status: Complete and verified Device State: Working correctly after factory reset