Skip to content

HTTP API

RapierXbox edited this page Jul 13, 2026 · 2 revisions

HTTP API

ShellyElevate runs a small HTTP server on port 8080. It's on by default and there's no authentication, so this is a LAN-only thing. The port isn't configurable.

All responses are JSON. Most of them include a success boolean. POST bodies are JSON unless noted.

Quick sanity check:

curl http://<device-ip>:8080/

If you get a JSON blob back, you're good.

Device info

GET /

Returns the basics: package, version, detected model, and how many buttons/inputs the model has.

{
  "name": "me.rapierxbox.shellyelevatev2",
  "version": "3.0.0",
  "modelName": "BLAKE",
  "proximity": "true",
  "numOfButtons": 4,
  "numOfInputs": 1
}

modelName matches the internal name in Supported Devices.

Settings management

GET /settings

Dump every setting key as a flat JSON object. Useful for backups.

curl http://<device-ip>:8080/settings

POST /settings

Write one or more settings. Include only the keys you want to change, or include everything to restore a backup.

curl -X POST http://<device-ip>:8080/settings \
  -H "Content-Type: application/json" \
  -d '{
    "mqttEnabled": true,
    "mqttBroker": "tcp://192.168.1.50",
    "mqttPort": 1883,
    "mqttUsername": "homeassistant",
    "mqttPassword": "yourpassword"
  }'

Every valid key is in Configuration Reference.

A few details worth knowing:

  • Sending null for a key removes it.
  • Types are inferred from JSON, but an existing key keeps the type it's already stored as: if a key is already an int, a value like 50.5 is rounded and written back as int rather than switching the type (this avoids crashing readers that expect an int). New keys follow the JSON: a whole number in int range becomes int, a decimal becomes float. dynamicTempOffsetBaseline and dynamicTempOffsetK are always float.
  • A JSON array of strings becomes a StringSet. Mixed-type arrays are silently ignored.
  • After the write, the settings change is broadcast internally. Running components react immediately, you don't need to reboot.

Device control

Relays

# read
curl 'http://<device-ip>:8080/device/relay?num=0'
# returns {"success": true, "state": true}

# write
curl -X POST http://<device-ip>:8080/device/relay \
  -H "Content-Type: application/json" \
  -d '{"num": 0, "state": true}'

On the write, num can also be passed as a query param. Returns the resulting state.

Sensors

Endpoint Returns
GET /device/getTemperature {"temperature": 23.5}
GET /device/getHumidity {"humidity": 45.2}
GET /device/getLux {"lux": 120.5}
GET /device/getProximity {"distance": 5.0} (fails on models without proximity)

Screen

curl -X POST http://<device-ip>:8080/device/wake     # wake the screen
curl -X POST http://<device-ip>:8080/device/sleep    # start screensaver
curl -X POST http://<device-ip>:8080/device/reboot   # reboot the device

reboot has a 20-second cooldown after startup. If you call it too early it silently refuses (returns success: false and shows a toast). This stops the device entering a reboot loop on a crashing boot.

Night mode

curl 'http://<device-ip>:8080/device/night_mode'                 # read -> {"success": true, "state": false}
curl -X POST http://<device-ip>:8080/device/night_mode \
  -H "Content-Type: application/json" -d '{"state": true}'       # set

Open settings / exit

curl -X POST http://<device-ip>:8080/device/settings   # open the settings screen on the device
curl -X POST http://<device-ip>:8080/device/close      # exit the app (System.exit) ~100ms after replying

close is mostly useful for scripted restarts (the app is relaunched by the kiosk watchdog / on boot). It's a hard exit, not a graceful one.

Dimmer

If you have a Shelly Dimmer backplate wired up over UART:

# status (also reports power if measured)
curl http://<device-ip>:8080/device/dimmer
{
  "success": true,
  "on": true,
  "brightness": 75,
  "not_dimmable": false,
  "not_calibrated": false,
  "overheat": false,
  "overcurrent": false,
  "power": 31.2,
  "voltage": 230,
  "current": 0.135
}

Set on/off or brightness (0 to 100):

curl -X POST http://<device-ip>:8080/device/dimmer \
  -H "Content-Type: application/json" -d '{"brightness": 50}'

curl -X POST http://<device-ip>:8080/device/dimmer \
  -H "Content-Type: application/json" -d '{"on": false}'

Returns 404 if no dimmer is detected on the UART bus.

Memory

curl http://<device-ip>:8080/device/free

Returns the parsed output of free -m. Useful for diagnosing weird crashes; these are constrained devices.

WebView control

GET /webview/refresh

Reload the page. No body needed.

POST /webview/inject

Execute arbitrary JS in the WebView.

curl -X POST http://<device-ip>:8080/webview/inject \
  -H "Content-Type: application/json" \
  -d '{"javascript": "document.body.style.background=\"red\""}'

This is the same channel the JavaScript Interface uses, in reverse.

Media

Media playback is gated behind mediaEnabled: true in settings. Until that's on, every /media/* endpoint returns 400.

POST /media/play

curl -X POST http://<device-ip>:8080/media/play \
  -H "Content-Type: application/json" \
  -d '{
    "url": "http://example.com/sound.mp3",
    "music": true,
    "volume": 0.5
  }'
  • music: true: uses the "music" player. Loops, can be paused/resumed.
  • music: false: "effect" player. One-shot. Pauses music while it plays.
  • volume is 0.0 to 1.0.

Pause / resume / stop / volume

curl -X POST http://<device-ip>:8080/media/pause
curl -X POST http://<device-ip>:8080/media/resume
curl -X POST http://<device-ip>:8080/media/stop

curl http://<device-ip>:8080/media/volume
curl -X POST http://<device-ip>:8080/media/volume \
  -H "Content-Type: application/json" -d '{"volume": 0.8}'

Pause/resume only affect the music player, not effects.

Error responses

  • Wrong HTTP method on an endpoint returns 500 with {"success": false}.
  • Bad inputs (missing query param, malformed body) return 400 with an error message.
  • Media-disabled returns 400 with {"error": "Media disabled"}.
  • Dimmer-missing returns 404 with {"error": "Dimmer not attached"}.

Notes on running this from outside the LAN

Don't. There's no authentication. If you need remote access, put the device behind a VPN or use MQTT over a TLS-enabled broker.

Clone this wiki locally