- Python 100%
| .gitignore | ||
| LICENSE | ||
| README.md | ||
| tpi06.py | ||
tpi06
A small Python client and CLI for the local web API of the TRENDnet TPI-06 6-outlet managed PDU, plus notes on the API itself.
TRENDnet does not document this API. It is the same JSON API the device's web admin UI uses. Everything here was reverse-engineered from a browser capture and the UI's JavaScript bundle on firmware 1.1.0.27. A firmware update can change or break any of it.
Status
| Area | State |
|---|---|
| Login / bearer token auth | Confirmed |
| Outlet on/off | Confirmed |
| Outlet reboot | Confirmed |
| Status reads (switchview, dashboard, outlet config) | Confirmed |
| Token refresh, logout | Endpoint known from the UI source, request shape inferred, not yet captured |
| Everything else in the route table | Endpoint and method from the UI source only. Payloads unknown. |
Requirements
- Python 3.8+
requests
pip install requests
Quick start
export TPI06_HOST=192.168.0.80
export TPI06_USER=admin
export TPI06_PASS='...'
./tpi06.py status # table of outlets: name, on/off, W, A
./tpi06.py off 4 # turn outlet 4 off
./tpi06.py on 4 # turn outlet 4 on
./tpi06.py reboot 4 # power-cycle outlet 4
./tpi06.py raw GET /outlet/config/general
./tpi06.py raw PUT /some/path '{"json":"body"}'
raw paths are relative to /api.
As a library:
from tpi06 import TPI06
with TPI06("192.168.0.80", "admin", "secret") as pdu: # logs in, logs out on exit
for n, o in pdu.outlets().items():
print(n, o["name"], o["on"], o["watts"])
pdu.reboot_outlet(4)
TLS
The device serves HTTPS with a self-signed certificate. The client disables verification by default. To pin the certificate, export it and pass the path:
TPI06(host, user, pw, verify="/path/to/tpi06.pem")
Cloud mode
According to TRENDnet's user guide, when the unit is registered with TRENDnet Hive, all configuration is locked to the cloud. Leave cloud mode disabled if you want to manage the unit locally through this API.
API reference
Base URL: https://<device>/api
Conventions
-
Auth: every request carries
Authorization: bearer <token>. Unauthenticated calls from the UI send the header with an empty token (bearer). -
Request bodies: JSON, but the UI sends them with
Content-Type: text/plain;charset=UTF-8. The client copies this in case the server checks it. -
Responses: JSON. Every response observed includes this envelope:
{ "errCode": 0, "message": "OK", "status": "0", "msg": "success" }errCode: 0means success. The client raisesTPI06Errorfor any other value. -
Numbers as strings: many readings come back as padded strings, e.g.
"outlet1_power": " 68.9". Parse them withfloat(). -
Server: lighttpd 1.4.54. The
X-Rate-Limit: 5000response header is present, but its meaning is unknown.
Authentication
POST /sys/login
The UI sends an empty bearer token on this request.
{ "userLogin": { "usr": "admin", "pwd": "<password>" } }
Response:
{
"token": "<JWT>",
"first_login": false,
"timeout": 3600,
"errCode": 0, "message": "OK", "status": "0", "msg": "success"
}
timeoutis the session lifetime in seconds.- The JWT is HS256. Its
iatandexpclaims are the device's uptime in seconds, not Unix time, so don't compare them to the wall clock. Usetimeoutinstead.
GET /sys/token_refresh
The UI calls this at 80% of timeout with the current token and replaces its stored token with token from the response. The response also carries a fresh timeout.
POST /sys/logout
Ends the session.
Outlet control (confirmed)
Outlet IDs are 1–6. The always-on bypass outlet cannot be controlled.
PUT /overview/outlet/enable
Turn an outlet on or off.
{ "outletEnConfs": { "outlet_id": 4, "outlet_enable": 0 } }
outlet_enable: 0 = off, 1 = on.
The change is not instant. Each outlet's configured power-on and power-off delay (/outlet/config/general) applies. In the capture, outlet 4 had a 4 s delay, and switchview reported the new state about 4 s after the request. If you poll to confirm a change, wait at least that long.
PUT /overview/outlet/reboot
Power-cycle one outlet.
{ "outletRBConfs": { "outlet_id": 4 } }
While the outlet is cycling, outlet_N_switch_enable in /outlet/config/outletswitchenable goes false. This appears to be the UI's "toggle locked" flag, not the power state.
The UI's Power Cycle button cycles all outlets. Its payload has not been captured. It probably uses this endpoint with a sentinel outlet_id, but that is untested. Do not guess at it on a PDU that is powering anything you care about.
Status reads (confirmed)
GET /dashboard/switchview
Per-outlet live state. Response object switchOutletStatus, with these keys repeated for N = 1–6:
| Key | Example | Meaning |
|---|---|---|
outletN_id |
4 |
Outlet number |
outletN_name |
"outlet4" |
User-assigned name |
outletN_enable |
true |
Current power state |
outletN_isconnected |
false |
Unclear. It was false on outlets drawing 60–90 W. |
outletN_power |
" 68.9" |
Watts |
outletN_voltage |
" 120" |
Volts |
outletN_current |
" 0.6" |
Amps |
outletN_powrb_btn_en |
true |
Reboot button enabled in the UI |
The object also has one top-level key, outlet_power_reboot_en (bool).
GET /dashboard/agent
System overview. Response objects:
dashSwitchInfo:uptime(human-readable string),fw_versiondashSystemStatus:voltage,total_current,frequency,temperature. The temperature string includes the unit, e.g."107.6 ℉".dashAdminInfo:system_name,system_location,system_contact,serial_nodashEtherInfo: IPv4 and IPv6 addressing, DHCP flags, MACdashPowerConsumption:total_max_watts,total_used_watts,total_available_watts,out1_watts…out6_watts
GET /sys/top_banner
Header-bar data. Fields include user_id, device_model, device_name, location_name, fw_version, devCurrentTime, max_safe_vol, min_safe_vol, max_temp, cloud_mode, cloud_online_status, language_type, and system message slots message1…message5.
This endpoint answered with an empty bearer token. See Security notes.
GET /outlet/config/outletswitchenable
outletswitchenableConfs.outlet_N_switch_enable (bool, N = 1–6). This appears to be whether each outlet's toggle is usable, and it goes false during a reboot. It is not the power state; use switchview for that.
GET /outlet/config/general
outletGenConfs, with these keys for each outlet N:
outlet_N_idoutlet_N_nameoutlet_N_pow_del_en: power-delay enabledoutlet_N_pow_on_del: power-on delay, secondsoutlet_N_pow_off_del: power-off delay, seconds
There is also a global outlet_pow_del_en.
GET /outlet/config/safe
outletSafeConfs: outlet_safe_max_vol, outlet_safe_min_vol, and outlet_safe_vol_en (default range 95–130 V).
GET /outlet/config/remoterebootdelay
remoterebootdelayConfs.outlet_N_remote_reboot_delay (integer, N = 1–6).
Full route table
The UI source (apiURL map in the JS bundle) lists the routes below. ✅ means the route was exercised in a capture. Everything else is the method and path only. Request payloads are unknown for any write without ✅. To learn a payload, perform the action in the web UI with the browser's network tab open.
Write routes are marked ⚠️ where a wrong payload or a misfire could knock the device or its loads offline.
Session and system messages
| Method | Path | Purpose | |
|---|---|---|---|
| POST | /sys/login |
Log in, get token | ✅ |
| POST | /sys/logout |
Log out | |
| GET | /sys/token_refresh |
Renew token | |
| GET | /sys/top_banner |
Header-bar info | ✅ |
| POST | /sys/confirm_message |
Clear or ack a system message |
Dashboard and outlet control
| Method | Path | Purpose | |
|---|---|---|---|
| GET | /dashboard/agent |
System overview | ✅ |
| GET | /dashboard/switchview |
Per-outlet state and power | ✅ |
| PUT | /overview/outlet/enable |
Outlet on/off | ✅ |
| PUT | /overview/outlet/reboot |
Power-cycle outlet | ✅ |
Outlet configuration
| Method | Path | Purpose | |
|---|---|---|---|
| GET | /outlet/config/outletswitchenable |
Per-outlet toggle-enabled flags | ✅ |
| GET | /outlet/config/general |
Names and power on/off delays | ✅ |
| PUT | /outlet/config/general |
Set names and delays | |
| GET | /outlet/config/safe |
Safe-voltage range | ✅ |
| PUT | /outlet/config/safe |
Set safe-voltage range | |
| GET | /outlet/config/remoterebootdelay |
Remote reboot delay | ✅ |
| PUT | /outlet/config/remoterebootdelay |
Set remote reboot delay |
Schedules
| Method | Path | Purpose | |
|---|---|---|---|
| GET | /outlet/schedule/config |
List schedule profiles | |
| POST | /outlet/schedule/config |
Add schedule profile | |
| PUT | /outlet/schedule/config |
Modify schedule profile | |
| DELETE | /outlet/schedule/config |
Delete schedule profile | |
| PUT | /outlet/schedule/enable |
Enable/disable a schedule |
Ping auto-reboot (watchdog)
| Method | Path | Purpose | |
|---|---|---|---|
| POST | /tools/confirm_IPSite |
Test whether a host or IP answers a ping | |
| POST | /outlet/ping_reboot/pinghostsetting |
Add a ping host | |
| DELETE | /outlet/ping_reboot/pinghostsetting |
Delete a ping host | |
| GET | /outlet/ping_reboot/outletrebootsetting |
Get per-outlet watchdog rules | |
| PUT | /outlet/ping_reboot/outletrebootsetting |
Set per-outlet watchdog rules | ⚠️ |
| PUT | /outlet/ping_reboot/outletpingenable |
Enable/disable watchdog for an outlet | ⚠️ |
| PUT | /outlet/ping_reboot/outletpingenableall |
Enable/disable watchdog for all outlets | ⚠️ |
Network, system, time
| Method | Path | Purpose | |
|---|---|---|---|
| GET | /ethernet/info |
IPv4 settings | |
| PUT | /ethernet/info |
Set IPv4 settings | ⚠️ |
| GET | /sys/sys_setting |
Device name, location, contact, account | |
| PUT | /sys/sys_setting |
Set the above (includes username/password change) | ⚠️ |
| PUT | /sys/confirm_password |
Verify current password | |
| GET | /sys/https_enable |
HTTPS state | |
| PUT | /sys/check_httpsport |
Check whether an HTTPS port is in use | |
| GET | /sys/time_date_setting |
Time, date, time zone | |
| PUT | /sys/time_date_setting |
Set time, date, time zone | |
| GET | /sys/cloud_setting |
TRENDnet Hive settings | |
| PUT | /sys/cloud_setting |
Enable/disable Hive (locks local config when enabled) | ⚠️ |
Logging and alerts
| Method | Path | Purpose | |
|---|---|---|---|
| GET | /sys/log |
Remote log server settings and log entries | |
| GET | /sys/email_alert |
Email alert settings | |
| PUT | /sys/email_alert |
Set email alert settings | |
| POST | /sys/send_test_mail |
Send a test email |
Maintenance
| Method | Path | Purpose | |
|---|---|---|---|
| POST | /sys/config_backup |
Download configuration | |
| POST | /sys/config_restore |
Upload configuration | ⚠️ |
| POST | /sys/reboot |
Reboot the PDU controller | ⚠️ |
| POST | /sys/factory_reset |
Factory reset | ⚠️ |
| POST | /sys/firmware/check |
Upload and validate a firmware image | ⚠️ |
| POST | /sys/firmware/do_upgrade_manual |
Apply uploaded firmware | ⚠️ |
It is not yet confirmed whether /sys/reboot drops power to the outlets or only restarts the controller. Assume it may drop power until tested on a unit with nothing important plugged in.
Security notes
-
Unauthenticated reads.
/sys/top_bannerreturns the admin username, model, and firmware version with no token. Whether other GET routes also skip auth has not been tested. To check from the management network:curl -sk -H 'Authorization: bearer' https://<device>/api/dashboard/switchviewIf that returns outlet data, anyone who can reach the device can read it.
-
Isolate the device. Put the PDU on a management VLAN or otherwise firewall it. Defaults out of the box are
admin/adminat192.168.10.80. -
HAR captures contain secrets. A browser capture of the login includes the admin password in cleartext and a live session token. Treat HAR files from this device as credentials: don't commit them, and rotate the password if one has been shared.
-
Credentials in this client come from environment variables. Don't hard-code them.
Firmware compatibility
| Firmware | Status |
|---|---|
| 1.1.0.27 | Routes and payloads above were captured on this version |
| Newer | Untested |
After a firmware upgrade, re-check before relying on the client:
- Load the web UI and save the main
*.bundle.min.js. - Search it for
apiURLand diff the route map against the table above. - Re-capture one on/off and one reboot to confirm the payload shapes.
Contributing findings
The highest-value gaps, in order:
- The Power Cycle (all outlets) payload.
- The
PUT /outlet/config/generalpayload, so outlet names and delays can be set. - Schedule and ping-watchdog payloads.
- Which GET routes skip auth.
- Whether
/sys/rebootinterrupts outlet power.
Capture each one by performing the action in the UI with the network tab open. Then redact the Authorization header and any pwd fields before sharing.
License and disclaimer
This is not affiliated with or endorsed by TRENDnet. Use at your own risk: this tool switches mains power to real equipment.
See LICENSE