Gerber Prime 6000

July 15, 2026 · View on GitHub

Reverse-engineered from the device's web UI (js/global.js, code v2.0.21). All requests use HTTP Basic auth (admin / 888888 by default) against the controller's IP.


/sdk.cgi — device control & status

Request: POST /sdk.cgi, body = one form field json, whose value is the command object serialized as JSON then encodeURIComponent(encodeURI(<json>)) (double-encoded, as the UI does it).

Command object shape:

{"control":{"cmd":"<command>","uid":<int>,"chid":<int>,"val":<int|array>,"home_id":"<id>"}}

Only cmd is always required; the rest depend on the command.

Response: a URI-encoded JSON string — URI-decode it, then parse. Success is respcode: 100, respmsg: "OK".

Commands

cmdFieldsPurpose
get_all_deviceFull inventory: every device + channel + state (read-only).
getdeviceuidOne device.
getinterfaceGateway/interface info.
switchuid, chid, val (0/255 for relays), home_idSet a channel.
switch_color_setuid, valRGB colour set.
configuration_set / configuration_getuid, valDevice config parameters.
include / exclude / abortuidZ-Wave pairing (variants with a Z-Wave dongle).
deldeviceuidRemove a device.
zwnosecureuidZ-Wave security setting.

The UI helper is Switch(uid, chid, val, home_id){"control":{"cmd":"switch", ...}}.

get_all_device response (shape)

{
  "control": {"cmd":"get_all_device","respcode":100,"respmsg":"OK"},
  "device": [{
    "uid": 257,
    "home_id": "PAN27",
    "version": "PAN27",
    "channel": [
      {"chid":1,"name":"Wall Switch 0-1","ctrltype":23,"functype":23,"basicvalue":0, ...},
      {"chid":7,"name":"Roller Shutter 0-7","ctrltype":26,"functype":26,"basicvalue":0, ...}
    ],
    "pan27_info": {
      "curtain_sec": [0,0,0,0,0,0,20,0],   // shutter travel time (s) per channel
      "key_type":    [1,1,1,1,2,1,1,1],
      "modbus_addr": 1,
      "modbus_is_slave": 0                  // 0 = master, 1 = slave
    }
  }]
}
  • basicvalue: 0 = off, 255 = on (for relay channels).
  • ctrltype / functype: 23 = on/off relay, 26 = roller shutter. (Dimmer TBD.)

/network.cgi — network / Wi-Fi config

Request: POST /network.cgi?, body = the raw command string (not JSON). For setters the form is name=value. Response is URI-encoded text ending ...<br><cmd> done.

CommandPurpose
getwifimodeReturns AP, STA, or OFF.
setwifimode=AP | STA | OFFSet Wi-Fi mode (no AP+STA coexistence).
getssidlistScan — returns visible SSIDs (<br>-separated).
getstassid / setstassid=<ssid>Station (client) SSID to join.
setstapwd=<pwd>Station password (empty for open networks).
getapssid / setapssid=<ssid>This unit's own AP SSID.
setappwd=<pwd>This unit's own AP password.
wificommitApply Wi-Fi changes — reboots the unit.
jsongetall / jsongetuserdataApp/user data blobs.

Save sequence the UI uses (order matters):

STA:  setstassid=<ssid> → setstapwd=<pwd> → setwifimode=STA → wificommit
AP:   setapssid=<ssid>  → setappwd=<pwd>  → setwifimode=AP  → wificommit
OFF:  setwifimode=OFF   → wificommit

⚠️ In testing, driving the STA switch purely through these calls did not complete a join (the security type of the target SSID isn't set this way). Doing the STA switch from the web UI (selecting the network from the scanned list) and then power-cycling did work. See the README "gotchas". PRs with a working pure-API STA method welcome.


Request encoding reference

import urllib.parse
# JavaScript encodeURI / encodeURIComponent equivalents:
def encodeURI(s):          return urllib.parse.quote(s, safe="!#$&'()*+,-./:;=?@_~")
def encodeURIComponent(s): return urllib.parse.quote(s, safe="!'()*-._~")

# /sdk.cgi body:
body = "json=" + encodeURIComponent(encodeURI(json_string))
# /network.cgi body is just the raw command string, e.g. "getwifimode"