Innerscene Developer API

Once an Innerscene fixture - Circadian Sky or Virtual Sun - is connected to your local Wi-Fi network, it exposes a small HTTP server on the LAN. You can read its status and drive its color and brightness from any device on the same network using ordinary GET and POST requests - no SDK, no cloud round-trip, no account.

This guide walks through the four prerequisites - updating the firmware, joining Wi-Fi, finding the IP address, and choosing a command - and then provides a complete reference for every publicly-supported endpoint along with copy-and-paste examples in Node.js and Python.

Who this guide is for

  • System integrators - AV/control installers, lighting designers, and building-management system vendors who need to drive fixtures from a Crestron, Lutron, Savant, or custom controller.
  • Home automation enthusiasts - Home Assistant, Node-RED, openHAB, and HomeKit-via-Homebridge users who want fixtures to participate in scenes, schedules, and routines beyond what Innerscene Studio provides natively.
  • Researchers - circadian-rhythm, vision-science, and chronobiology labs that need precise, scriptable control of color temperature, brightness, and individual color channels for stimulus delivery and spectral tuning.
  • Show-control and demo developers - anyone scripting time-lapse demos, retail experiences, or art installations from Python, JavaScript, TouchDesigner, or any other HTTP-capable environment.

The HTTP server is unauthenticated and LAN-only

Any device on the same network can issue commands - treat your fixtures the way you would treat any other smart-home device on your LAN. The fixture does not accept connections from the public internet, and Innerscene does not recommend exposing it through a port forward. Endpoints that could corrupt calibration data, network credentials, or other sensitive state are intentionally omitted from this guide.

1. Update the fixture firmware

The HTTP endpoints described in this guide require recent firmware. Before you start, update each fixture using Innerscene Studio (the iOS app):

  • Install Innerscene Studio from the iOS App Store.
  • Open Innerscene Studio within Bluetooth range of the fixture and tap it in the device list to connect.
  • Open Settings → Firmware Updates. If a newer build is available the app will prompt you to install it; the fixture reboots automatically when the update finishes.

You can confirm the running version at any time with GET /getVersion after Wi-Fi is configured.

Updating older fixtures (no Bluetooth)

If Innerscene Studio cannot find your fixture, it likely predates Bluetooth provisioning. From the app's device list, tap Have a device with older firmware? and follow the on-screen instructions:

  1. Open Settings → Wi-Fi on your phone and join the network whose name starts with Innerscene- - the password is innerscene.
  2. Important: if a captive-portal screen appears showing fixture controls, do not interact with it - close it (tap the X), then tap Use Without Internet when prompted, and return to Innerscene Studio. Tapping anything in the captive-portal sheet can interrupt the upgrade.
  3. The app reaches the fixture at 172.30.0.1, uploads the latest firmware, and reboots the device. Once the upgrade completes, the fixture will appear in the regular Bluetooth device list.

2. Connect the fixture to Wi-Fi

Wi-Fi is configured from the fixture's built-in web interface, which Innerscene Studio reaches over Bluetooth. The full step-by-step instructions - including SSID selection, password entry, and the captive-portal flow - are documented in the User Guide (the same guide applies to Virtual Sun - append ?product=virtual-sun to the URL).

Use a 2.4 GHz network

The fixture supports 2.4 GHz Wi-Fi only. If your router broadcasts both bands under one SSID with band-steering enabled, consider creating a 2.4 GHz-only SSID for the fixtures.

3. Find the fixture's IP address

Once joined to Wi-Fi, every fixture is assigned an IP address by your router. There are several ways to find it:

  • From Innerscene Studio. Connect to the fixture, open Settings → Wi-Fi. The current IP address is shown alongside the connected SSID. The fixture's MAC address is shown on the same screen and on the device-info page.
  • From your router's client list. Look it up by MAC address - copy the MAC from Innerscene Studio and match it against the connected-clients table in your router's admin UI. Each fixture also broadcasts its own Wi-Fi network with the SSID Innerscene-<type>-<mac> (for example Innerscene-pri-a4cf12ab34cd), where type reflects the fixture's role or daughterboard: pri (primary), sub (secondary), cas (Casambi), dmx, dali, 0-10, cal, hub. This SSID can be used to identify nearby fixtures from your phone's Wi-Fi scan.
  • By scanning your subnet. Every Circadian Sky fixture responds to /getVersion, so the quickest way to enumerate fixtures from a Mac, Linux, or Windows-with-WSL machine is:
bash
# Replace 192.168.1 with your subnet. Returns IPs that respond to /getVersion.
for n in $(seq 1 254); do
  ip="192.168.1.$n"
  curl -s -m 0.4 "http://$ip/getVersion" \
    | grep -q '"version"' && echo "$ip"
done

Once you have an IP, verify the fixture is reachable:

bash
$ curl http://192.168.1.42/getVersion
{"version": "2.4.1", "build_date": "Apr 30 2026", "build_time": "14:22:08", ...}

Open the fixture's built-in web UI

Pointing a browser at http://<fixture-ip>/ loads the same control interface that Innerscene Studio shows over Bluetooth. From any phone, tablet, or computer on the same network you can adjust CCT and brightness, edit the schedule, configure daughterboards, and view diagnostics - no app needed. It is also the quickest visual confirmation that you have the right IP.

If you plan to control a fixture from a long-running script, reserve its IP in your router's DHCP settings so it does not change.

4. Send your first command

Every fixture interaction is a single HTTP request. Most endpoints are GET requests with parameters in the query string and return JSON. The example below disables the circadian schedule and sets the fixture to 4500 K at 50% brightness:

bash
curl "http://192.168.1.42/setSchedule?mode=0"
curl "http://192.168.1.42/setCCT?cct=4500&i=0.5"

The first call exits the automatic schedule so manual commands are honored, and the second sets the color temperature and brightness. Skip ahead to Examples for full Node.js and Python programs.

API Reference

All endpoints are served from the fixture's IP on port 80. JSON is the default response format. Parameters are passed as URL query parameters (for both GET and POST requests).

Every write endpoint listed below takes effect immediately - no reboot is required. Configuration changes are applied to the running fixture and saved to non-volatile storage in the same call. The only way to reboot is the explicit /restart endpoint.

Status & Identity

Tap any endpoint to expand its parameters, example request, and example response.

GET/getVersionFirmware version, build date, and ESP-IDF SDK version.

Example request

curl http://192.168.1.42/getVersion

Example response

{
  "version": "2.4.1",
  "build_date": "Apr 30 2026",
  "build_time": "14:22:08",
  "build_timestamp": "6814a3e0",
  "sdk": "5.1.2"
}

Response fields

FieldDescription
versionApplication firmware version string.
build_dateCompile-time date in __DATE__ format.
build_timeCompile-time time in __TIME__ format.
build_timestampHex-encoded compile timestamp; useful for OTA freshness checks.
sdkESP-IDF version (major.minor.patch).
GET/getStatusCompact JSON snapshot of the fixture state. The recommended polling endpoint.

Returns a single flat JSON object containing time, CCT, lux, MAC, and a number of compact mode/state fields used by Innerscene Studio and the web UI. Field names are short to keep responses small.

Parameters

NameTypeDescription
hc0 | 1Optional. When set to 1, also includes a home-card bitmask (hc field) summarising peer/sensor presence.

Example request

curl "http://192.168.1.42/getStatus"

Example response

{
  "timezone": "America/Los_Angeles",
  "utc_time": "2026-05-07T18:42:12Z",
  "cct": 4500, "lux": 1280, "nlux": 0.45000000,
  "mac": "a4:cf:12:ab:34:cd",
  "cs": 0, "toff": 0.00, "flags": 1, "puc": 7, "ls": 1,
  "m": 0, "wx": 0,
  "ssc": 0, "msc": 0, "esc": 0,
  "as": 0, "dv1": 0.0, "dv2": 0.0,
  "gc": 0, "ir": -1, "sss": 0,
  "fr": 0, "ddb": 0, "rc": 6
}

Response fields

FieldDescription
timezoneIANA timezone string set on the fixture (or null).
utc_timeCurrent UTC time (ISO-8601).
cctCurrent target color temperature (Kelvin).
luxCurrent absolute target lux at the surface.
nluxNormalised intensity 0–1 (matches setCCT i parameter).
macFixture's AP MAC address.
csLast control source (0=schedule, 1=Web UI, 2=BLE, 3=peer, 4=preview, 5=external).
toffSchedule time offset in hours (used when previewing a schedule).
flagsBitmask: 1=primary, 2=internet OK, 4=primary search, 8=primary found, 16=reboot pending, 32=manufacturing, 256=calibrating.
pucPeer update counter; increments when peer set changes.
lsSchedule mode (1=schedule active, 0=manual).
mMessage count in the user-facing message buffer.
wxWeather modulation lux offset (cd offset percent).
ssc / msc / escCounters for SkySync, motion sensor, and EnOcean dimmer events.
gcWireless-group radio channel (0 if no group).
irIdle resume: ms until schedule resumes (-1 = not pending).
sssSkySync state (0=idle, 1=actively overriding).
frFixture role: 0=auto, 1=force primary, 2=force secondary.
ddbDetected daughterboard type (hardware).
rcActual Wi-Fi radio channel reported by esp_wifi_get_channel().
When a daughterboard is fitted, an extra di object is appended with type-specific fields (0–10 V, DALI, DMX, or Casambi). When SkySync is actively overriding, stc/stl (target CCT and lux) are also appended.
GET/getDeviceCapabilitiesMin/max CCT and lux supported by this fixture.

Use this when building a UI to clamp slider ranges to what the hardware actually supports.

Example request

curl http://192.168.1.42/getDeviceCapabilities

Example response

{
  "cct": { "min": 1800, "max": 20000 },
  "lux": { "min": 0,    "max": 4000 }
}
GET/getLuxCurvePer-CCT maximum lux output curve.

Sampled at ~30 points across the supported CCT range. Useful for plotting the fixture's photometric envelope or warning users when a target lux is unreachable at a given color temperature.

Example request

curl http://192.168.1.42/getLuxCurve

Example response

{
  "curve": [
    [1800, 1200],
    [2400, 2400],
    [3000, 3200],
    [4000, 3900],
    [5000, 4000],
    [6500, 3800],
    [10000, 3100],
    [20000, 1900]
  ]
}

Response fields

FieldDescription
curveArray of [cct, maxLux] tuples. cct is in Kelvin; maxLux is the maximum surface lux deliverable at that CCT.
GET/getTempDriver-board internal temperature.

Example request

curl http://192.168.1.42/getTemp

Example response

{
  "adc_raw": 1843,
  "adc_cal": 1521,
  "degC": 42.18
}

Response fields

FieldDescription
adc_rawRaw ADC reading from the on-board thermistor.
adc_calCalibrated voltage in millivolts.
degCTemperature in degrees Celsius (typically 30–55 °C in normal operation).
GET/getUpTimeSeconds since the last boot.

Plain integer response (not JSON) representing whole seconds. Useful for detecting unexpected reboots in long-running automations.

Example request

curl http://192.168.1.42/getUpTime

Example response

84326
GET/getDBInfoDaughterboard type and live readings.

Reports which optional control daughterboard (if any) is installed: 0–10 V dimmer, DALI, DMX, or Casambi.

Example request

curl http://192.168.1.42/getDBInfo

Example response

{
  "type": 1,
  "longDescription": "Dual 0-10V",
  "wifiDescription": "0-10",
  "adc": 2147,
  "dbInt": 0
}

Response fields

FieldDescription
typeNumeric daughterboard type (e.g. 1 = 0–10 V, 2 = DALI, 3 = DMX, 4 = Casambi, 5 = Calibration). 0 indicates no daughterboard.
longDescriptionHuman-readable description shown in Innerscene Studio - e.g. Dual 0-10V, DALI DT8, Casambi, Secondary.
wifiDescriptionShort tag (≤4 chars) used inside the SoftAP SSID. One of pri, sub, cas, dmx, dali, 0-10, cal, hub, unk.
adcRaw ADC reading on the daughterboard detect pin.
dbIntOptional integer value reported by the daughterboard firmware.

Light Control

GET/getCCTCurrent target color temperature and brightness.

Example request

curl http://192.168.1.42/getCCT

Example response

{
  "cct": 4500,
  "i": 0.450000,
  "lux": 1280.000000
}

Response fields

FieldDescription
cctCurrent target color temperature in Kelvin.
iNormalised brightness (0–1) - same scale as the setCCT i parameter.
luxAbsolute target surface lux.
GET/setCCTSet color temperature and brightness. Exits the schedule.

Primary control endpoint. Calling this sets a new target and switches the fixture out of automatic schedule mode. Values outside the device's supported range are clamped silently.

Parameters

NameTypeDescription
cct*integer (Kelvin)Target color temperature. Pass -1 to keep the current CCT and only change brightness.
ifloat 0–1Normalised brightness. Required if lux is not supplied.-1 keeps current,0 turns the fixture off.
luxfloatAbsolute target lux. Use instead of i when you want a specific lux value.
pct0 | 1When 1, i is interpreted as a percentage of the per-CCT maximum (not the global max). Useful for keeping perceived brightness constant when changing CCT.
fade0 | 1Override fade for this call (0 = instant, 1 = fade as configured).

* required

Example request

# Set 4500 K at 50% brightness
curl "http://192.168.1.42/setCCT?cct=4500&i=0.5"

# Set 3000 K at an absolute 800 lux
curl "http://192.168.1.42/setCCT?cct=3000&lux=800"

Example response

1
The literal response is 1 on success, or a JSON-encoded string starting with error: if a required parameter is missing. Calls during an active calibration return {"error":"blocked - calibration active"}.
GET/previewCCTLike /setCCT, but auto-reverts to the schedule after a few seconds.

Drives the LEDs immediately without exiting schedule mode. The fixture returns to its scheduled output after a short timeout with no further preview commands. Use this when a user is dragging a slider and you do not want to permanently disable the schedule.

Parameters

NameTypeDescription
cct*integer (Kelvin)Target color temperature.
i*float 0–1Normalised brightness.

* required

Example request

curl "http://192.168.1.42/previewCCT?cct=2700&i=0.3"

Example response

1
GET/setScheduleEnable or disable the automatic circadian schedule.

Parameters

NameTypeDescription
mode*0 | 11 = enable schedule; 0 = disable (manual mode). Manual setCCT calls automatically set this to 0.
srcstringOptional. Set to ext when the call originates from an external source (0–10 V, DMX, DALI, Casambi) so that the external input is treated as the active control source.

* required

Example request

# Resume automatic schedule
curl "http://192.168.1.42/setSchedule?mode=1"

# Switch to manual control
curl "http://192.168.1.42/setSchedule?mode=0"

Example response

1
GET/setFadeEnable or disable LED fade transitions.

Parameters

NameTypeDescription
on*0 | 11 = fade between values smoothly; 0 = jump instantly on every setCCT call.

* required

Example request

curl "http://192.168.1.42/setFade?on=1"

Example response

1
GET/identifyBlink the fixture so you can identify it visually.

Calling without parameters causes this fixture to blink. Optionally, pass a target MAC and the call broadcasts an identify command to that fixture instead, which is useful when you have multiple fixtures on the same network.

Parameters

NameTypeDescription
mac12-char hexOptional. Lowercase hex MAC (no separators) of a target fixture, e.g. a4cf12ab34cd.
wgintegerOptional. Wireless group number to scope the broadcast (defaults to this fixture's group).

Example request

# Blink this fixture
curl http://192.168.1.42/identify

# Blink a different fixture by MAC
curl "http://192.168.1.42/identify?mac=a4cf12ab34cd"

Example response

1
GET/restartSoft-reboot the fixture.

Parameters

NameTypeDescription
delayinteger (ms)Delay before rebooting. Defaults to 1000 ms.

Example request

curl "http://192.168.1.42/restart?delay=2000"

Example response

true
The fixture will be unreachable for ~30 seconds while it reboots and rejoins Wi-Fi. The response is sent before the reboot timer fires.

Direct Channel Control

Circadian Sky only - for research and calibration use.

The endpoints in this section are supported on Circadian Sky fixtures only. Virtual Sun does not expose direct PWM channel control.

These endpoints write raw 12-bit PWM duty values to each LED channel and bypass the fixture's photometric calibration. Output spectrum and luminous flux will not match the factory CCT/lux mapping, channel-specific maxima are not enforced beyond the 0–4095 range, and excessive duty on any channel may exceed thermal limits over long runs. Use /setCCT for normal control. Use these endpoints when you need bench control of individual channels for spectral research or sensor calibration.

The fixture exposes four PWM-driven channels, addressed as c0 through c3. Each accepts a 12-bit duty value (0–4095). The spectral mapping of each channel is product-specific and not published — if you need precise spectral control, characterise the output with a spectrometer.

ParamChannel
c0Channel 1
c1Channel 2
c2Channel 3
c3Channel 4
GET/getChannelsRead the raw PWM duty for every LED channel. Circadian Sky only.

Returns a JSON array of the current 12-bit duty values (0–4095) for each channel in the order shown above: [c0, c1, c2, c3]. Useful for verifying the result of a /setChannels call or capturing the channel mix produced by the standard CCT calibration at a given operating point.

Example request

curl http://192.168.1.42/getChannels

Example response

[1820, 1145, 0, 312]
On hub-mode units (no LED daughterboard) all channels report0.
GET/setChannelsWrite raw PWM duty per channel. Circadian Sky only - bypasses photometric calibration.

Sets one or more LED channels to a 12-bit PWM duty value. Only the parameters you pass are changed; channels you omit retain their current value. The fixture leaves schedule mode but does not apply any color or brightness correction - what you write is what is driven to the LED driver.

Parameters

NameTypeDescription
c0integer 0–4095Channel 1 duty.
c1integer 0–4095Channel 2 duty.
c2integer 0–4095Channel 3 duty.
c3integer 0–4095Channel 4 duty.
bypass0 | 1When 1, the call is permitted even while the fixture's calibration LED-lock is active (used by external sensor-calibration tools). Defaults to 0.

Example request

# Drive only c3 at ~25%, all others off
curl "http://192.168.1.42/setChannels?c0=0&c1=0&c2=0&c3=1024"

# Tune just one channel without touching the others
curl "http://192.168.1.42/setChannels?c2=512"

Example response

0

The fixture will not protect itself against unsafe channel mixes. Sustained operation at full duty across multiple channels can exceed the thermal envelope - monitor /getTemp during long runs.

Returns the literal string 0 (ESP_OK) on success or a non-zero error code if any value was outside 0–4095. Use /getChannels to verify what the driver actually applied.

Time & Schedule

GET/setTimezoneSet the IANA timezone used by the schedule.

The fixture computes sunrise and sunset locally and runs the circadian schedule against the configured timezone.

Parameters

NameTypeDescription
tz*string (IANA)IANA timezone identifier such as America/Los_Angeles or Europe/London.
spacestringOptional. Set to persistent to keep the timezone across factory reset (defaults to the resettable key space).

* required

Example request

curl "http://192.168.1.42/setTimezone?tz=America/Los_Angeles"

Example response

1
GET/readClockRead the on-board real-time clock and battery health.

Example request

curl http://192.168.1.42/readClock

Example response

{
  "time": "2026-05-07T18:42:12Z",
  "bat": 1
}

Response fields

FieldDescription
timeCurrent RTC time as ISO-8601 (assumed UTC).
batRTC coin-cell battery health: 1 = OK, 0 = depleted/missing.
Returns the literal string 0 if the RTC chip cannot be read.

External Inputs (Daughterboards)

These endpoints are only meaningful on fixtures fitted with a 0–10 V, DALI, DMX, or Casambi daughterboard. Use /getDBInfo to detect what is installed before calling them.

GET/read010VRead 0–10 V input voltages and current 0–10 V configuration.

Returns the live voltage on both 0–10 V channels along with the calibrated output values and the saved daughterboard configuration.

Example request

curl http://192.168.1.42/read010V

Example response

{
  "vCCT": 7.42, "vDIM": 5.10,
  "aCCT": 1834, "aDIM": 1265,
  "nCCT": 0.74, "nDIM": 0.51,
  "oCCT": 4500, "oDIM": 0.50,
  "cct_min": 0.5, "cct_max": 9.5,
  "dim_min": 0.5, "dim_max": 9.5,
  "dim_pow": 2.0,
  "mode": 0, "filter": 0,
  "cctSource": 0, "fixedCCT": 4500,
  "schedExitV": 9.0,
  "refCCT": 7.40, "refDIM": 5.05
}

Response fields

FieldDescription
vCCT / vDIMLive measured voltages on the CCT and dim inputs.
aCCT / aDIMRaw ADC counts on each input.
nCCT / nDIMNormalised 0–1 inputs after calibration.
oCCT / oDIMMapped output CCT (Kelvin) and dim (0–1).
cct_min / cct_maxVoltages mapping to lowest / highest CCT.
dim_min / dim_maxVoltages mapping to off / full brightness.
dim_powExponent applied to dim input (1 = linear, 2 = squared).
mode0–10 V mode (0 = dual normal, 1 = swapped, etc.).
filterInput filter mode index.
cctSourceWhen dim-only modes are active, where CCT comes from.
fixedCCTCCT to use in fixed-CCT modes.
schedExitVVoltage threshold that exits schedule mode.
GET/set010VParamsConfigure 0–10 V calibration and behaviour.

All parameters are optional - only the keys you pass are changed. Values are written to the resettable key space by default; pass persistent=1 to make them survive a factory reset.

Parameters

NameTypeDescription
cct_minfloat (V)Voltage that maps to the lowest CCT.
cct_maxfloat (V)Voltage that maps to the highest CCT.
dim_minfloat (V)Voltage that maps to off (0%).
dim_maxfloat (V)Voltage that maps to full brightness.
dim_powfloatPower curve exponent applied to the dim input (1 = linear).
modeinteger0–10 V mode index. See Innerscene Studio for human-readable names.
filterintegerInput filter mode index.
cctSourceintegerCCT source for dim-only modes.
fixedCCTinteger (Kelvin)CCT used when in fixed-CCT mode.
schedExitfloat 0.05–10 VVoltage delta required to exit schedule mode.
persistent0 | 11 = save to persistent key space (kept across factory reset).

Example request

# Linear-dim calibration with full range 0.5–9.5 V
curl "http://192.168.1.42/set010VParams?dim_min=0.5&dim_max=9.5&dim_pow=1&persistent=1"

Example response

1
GET/setDaliParamsConfigure DALI CCT mapping.

Parameters

NameTypeDescription
cct_mininteger (Kelvin)DALI level 0 maps to this CCT.
cct_maxinteger (Kelvin)DALI level 254 maps to this CCT.
persistent0 | 11 = save to persistent key space.

Example request

curl "http://192.168.1.42/setDaliParams?cct_min=2700&cct_max=6500&persistent=1"

Example response

1
GET/setDMXParamsSet the DMX base address and mode flags.

Parameters

NameTypeDescription
modeinteger (bitmask)DMX mode flags. Refer to Innerscene Studio for bit definitions; sent verbatim to the daughterboard.
baseAddressinteger 0–511DMX base address. Set to -1 to disable DMX control.
persistent0 | 11 = save to persistent key space.

Example request

curl "http://192.168.1.42/setDMXParams?baseAddress=24&mode=1&persistent=1"

Example response

1
GET/read_DMXLive DMX channel values and recent change record.

Example request

curl http://192.168.1.42/read_DMX

Example response

{
  "baseAddress": 24,
  "dip_addr": 24,
  "mode_flags": 1,
  "changeTime": 142,
  "index": 1,
  "oldValue": 128,
  "newValue": 200,
  "cct": [180, 4500],
  "dim": [200, 0.78],
  "schedule": 0,
  "inSchedule": 0
}

Response fields

FieldDescription
baseAddressConfigured DMX base address.
dip_addrAddress read from the on-board DIP switches.
mode_flagsActive mode bitmask.
changeTimeMilliseconds since the most recent DMX change.
index / oldValue / newValueChannel index and old/new values from the most recent change.
cct[raw DMX value, mapped CCT in Kelvin].
dim[raw DMX value, normalised dim 0–1].
scheduleCurrent value of the schedule channel.
inSchedule1 if the fixture is currently in schedule mode.
GET/casambiInfoCasambi daughterboard state and live readings.

Example request

curl http://192.168.1.42/casambiInfo

Example response

{
  "ua": "AA:BB:CC:DD:EE:FF",
  "nu": "11:22:33:44:55:66",
  "fid": 12345,
  "fwv": "37.20",
  "uid": 12, "sm": 0, "smn": "Idle", "ir": 1,
  "cmin": 2200, "cmax": 6500,
  "fmin": 1800, "fmax": 20000,
  "lon": -118.2437, "lat": 34.0522, "tzo": -480,
  "rt": "2026-05-07T11:42:12",
  "d": 0.500, "k": 4500, "y": 1
}

Response fields

FieldDescription
uaCasambi unit MAC address.
nuCasambi network UUID (first 6 bytes).
fidNumeric fixture ID assigned by Casambi.
fwvCasambi module firmware version (major.minor).
uid / sm / smnUnit ID, state-mode integer, and state-mode name.
ir1 once the Casambi network init has been received.
cmin / cmaxCasambi-configured CCT range.
fmin / fmaxFixture's hardware CCT range (for clamping).
lon / lat / tzoGeo-position and timezone offset (minutes) reported by Casambi.
rtReal-time clock from the Casambi network.
dCurrent dim level (0–1).
kCurrent CCT (Kelvin).
y1 if Casambi is actively driving the fixture.

Network & Peers

GET/getIPsAll network interface addresses, plus MAC and SoftAP SSID.

Returns one entry per active esp_netif (typically the station and the SoftAP), followed by the AP MAC address and the fixture's SoftAP SSID.

Example request

curl http://192.168.1.42/getIPs

Example response

[
  ["sta", "WIFI_STA_DEF",
   "192.168.1.42", "255.255.255.0", "192.168.1.1"],
  ["ap", "WIFI_AP_DEF",
   "172.30.0.1",   "255.255.255.0", "172.30.0.1"],
  "a4:cf:12:ab:34:cd",
  "Innerscene-pri-a4cf12ab34cd"
]

Response fields

FieldDescription
Each interface entry[description, key, ip, netmask, gateway].
Trailing string 1Fixture's AP MAC address.
Trailing string 2SoftAP SSID currently being broadcast.
GET/getAPInfoConnected Wi-Fi station details and SoftAP configuration.

Example request

curl http://192.168.1.42/getAPInfo

Example response

{
  "sta": {
    "ssid": "MyHomeNetwork",
    "passwd": "********",
    "bssid": "f0:9f:c2:11:22:33",
    "channel": 6,
    "authmode": 3,
    "rssi": -54
  },
  "ap": {
    "ssid": "Innerscene-pri-a4cf12ab34cd",
    "passwd": "innerscene",
    "channel": 6,
    "authmode": 3,
    "ssid_hidden": 0,
    "max_connection": 4,
    "beacon_interval": 1000
  }
}

Response fields

FieldDescription
sta.ssid / sta.bssidConnected Wi-Fi network details.
sta.rssi / sta.channelSignal strength (dBm) and Wi-Fi channel.
sta.authmodeAuth mode (3 = WPA2-PSK).
ap.ssidThe fixture's own SoftAP SSID.
ap.ssid_hidden1 if the SoftAP is hidden during startup channel scan.
The sta.passwd field is included in the response - be careful where you log it.
GET/getPeerInfoOther Innerscene fixtures discovered on the local network.

Each fixture in a wireless group periodically beacons its state to the others over ESP-NOW. This endpoint returns the most recent record this fixture is holding for every peer in its group.

The response is a single JSON object containing a peer-update counter and an array p of strings - one string per peer, with nine comma-separated fields per string. The fields appear in fixed order:

apMac,ipv4,buildTimestamp,flags,wirelessGroup,channel,tempScaled,upTime,rssi

Example request

curl http://192.168.1.42/getPeerInfo

Example response

{
  "puc": 7,
  "p": [
    "a4cf12ab34cd,2a01a8c0,68142b00,1,3,6,33825,84326,-46",
    "a4cf12ab35ef,2b01a8c0,68142b00,0,3,6,33279,84102,-58"
  ]
}

Response fields

FieldDescription
pucPeer update counter - increments each time the local peer table changes. Matches the puc field in /getStatus, so you can detect changes without re-fetching the full list.
p[i] field 1 - apMac12-character lowercase hex of the peer's SoftAP MAC, with no separators. Example: a4cf12ab34cd a4:cf:12:ab:34:cd.
p[i] field 2 - ipv432-bit IPv4 address printed as lowercase hex with no leading zeros, in the order ESP-IDF stores it (octet 4 first). To reconstruct the dotted address, read the value as a uint32 and extract bytes LSB-first. Example: 2a01a8c0 bytes 0xc0,0xa8,0x01,0x2a 192.168.1.42.
p[i] field 3 - buildTimestampLowercase hex of the peer's firmware build Unix timestamp (the same value returned in the build_timestamp field of /getVersion). Useful for detecting peers that need an OTA update.
p[i] field 4 - flagsDecimal bitmask. bit 0 (value 1) = peer is the wireless-group primary. Other bits are reserved.
p[i] field 5 - wirelessGroupDecimal 0–255. The wireless group this peer belongs to. Always matches the local fixture's group, since cross-group peers are filtered out of the table.
p[i] field 6 - channelDecimal Wi-Fi channel the peer is operating on (1–13 for 2.4 GHz). The whole group converges on the primary's channel.
p[i] field 7 - tempScaledDecimal 0–65535. Temperature mapped linearly so that 0 = -20 °C and 65535 = +100 °C (120 °C span). Decode with degC = -20 + (tempScaled / 65535) * 120. Example: 33825 → ~42 °C.
p[i] field 8 - upTimeDecimal seconds since the peer last booted. Resets to 0 on every reboot.
p[i] field 9 - rssiSigned dBm (typically -30 to -90). 0 indicates ESP-NOW has not yet measured the link. Lower (more negative) values mean weaker signal.

Because the format is positional, peers must be parsed by splitting on the comma. Example Python:

for s in r.json()["p"]:
    mac, ipv4_hex, build, flags, group, ch, t, up, rssi = s.split(",")
    n = int(ipv4_hex, 16)
    ip = f"{n & 0xff}.{(n>>8) & 0xff}.{(n>>16) & 0xff}.{(n>>24) & 0xff}"
    degC = -20 + (int(t) / 65535) * 120
    is_primary = (int(flags) & 1) == 1

Messages

GET/getMessagesUser-facing event messages (mode changes, schedule transitions, errors).

Mirrors the Messages view in Innerscene Studio. Each message is encoded as a single string with three comma-separated fields: type, age in seconds, and the human text.

Example request

curl http://192.168.1.42/getMessages

Example response

[
  "12,-15,Schedule mode turned on via WebUI",
  "5,-94,Power on : Last CCT, DIM = 4500K, 50%"
]

Response fields

FieldDescription
Each entrytype,seconds_ago,message - type is the numeric MESSAGE_TYPE enum, seconds_ago is negative (relative to now), and the rest is the rendered message.
GET/clearMessagesClear messages of a given numeric type.

Parameters

NameTypeDescription
type*integerMESSAGE_TYPE enum value to clear. Match this against the first field returned by /getMessages.

* required

Example request

curl "http://192.168.1.42/clearMessages?type=12"

Example response

{"status":"success"}
Returns {"status":"failed"} if no message of that type was found.

Examples

The fixture is just an HTTP server

Anything that can issue HTTP requests can drive a fixture. The examples below cover Node.js, Python, and Home Assistant because those are the most common, but the same calls work from a shell script with curl, an Arduino with WiFiClient, or any other language that can issue HTTP requests.

Node.js

Discover capabilities, read state, and adjust the fixture:

javascript
// fixture.mjs - control an Innerscene fixture from Node.js
//   npm install node-fetch
//   node fixture.mjs 192.168.1.42

import fetch from "node-fetch";

const ip = process.argv[2];
if (!ip) throw new Error("Usage: node fixture.mjs <fixture-ip>");

const base = `http://${ip}`;

async function get(path) {
  const res = await fetch(`${base}${path}`);
  if (!res.ok) throw new Error(`${path} -> HTTP ${res.status}`);
  const text = await res.text();
  try { return JSON.parse(text); } catch { return text; }
}

// 1. Discover what the fixture supports
const caps = await get("/getDeviceCapabilities");
console.log("CCT range :", caps.cct);
console.log("Lux range :", caps.lux);

// 2. Read its current state
const status = await get("/getStatus");
console.log("Now      :", status.cct, "K  ", status.lux, "lux");

// 3. Disable the schedule and set 4500 K at 50% brightness
await get("/setSchedule?mode=0");
await get("/setCCT?cct=4500&i=0.5");

// 4. Blink it to confirm which physical fixture you just controlled
await get("/identify");

A simple sunset routine that fades the fixture from daylight to warm dim over ten minutes:

javascript
// Sunset routine: drop from 5000 K / 100% to 2700 K / 10% over 10 minutes.
// Each fade takes ~2 seconds on the fixture; we issue 30 steps over 600 seconds.
import fetch from "node-fetch";

const ip = "192.168.1.42";
const steps = 30;
const totalSeconds = 600;
const startCCT = 5000, endCCT = 2700;
const startI = 1.0,  endI = 0.10;

await fetch(`http://${ip}/setSchedule?mode=0`);

for (let i = 0; i <= steps; i++) {
  const t = i / steps;
  const cct = Math.round(startCCT + (endCCT - startCCT) * t);
  const intensity = (startI + (endI - startI) * t).toFixed(3);
  await fetch(`http://${ip}/setCCT?cct=${cct}&i=${intensity}`);
  await new Promise(r => setTimeout(r, (totalSeconds * 1000) / steps));
}

Python

Same flow as the Node.js example, using requests:

python
# fixture.py - control an Innerscene fixture from Python
#   pip install requests
#   python fixture.py 192.168.1.42

import sys, json, requests

if len(sys.argv) < 2:
    raise SystemExit("Usage: python fixture.py <fixture-ip>")

base = f"http://{sys.argv[1]}"

def get(path):
    r = requests.get(base + path, timeout=5)
    r.raise_for_status()
    try:
        return r.json()
    except ValueError:
        return r.text

# 1. Discover what the fixture supports
caps = get("/getDeviceCapabilities")
print("CCT range :", caps["cct"])
print("Lux range :", caps["lux"])

# 2. Read its current state
status = get("/getStatus")
print("Now       :", status["cct"], "K  ", status["lux"], "lux")

# 3. Disable the schedule and set 4500 K at 50% brightness
get("/setSchedule?mode=0")
get("/setCCT?cct=4500&i=0.5")

# 4. Blink it to confirm which physical fixture you just controlled
get("/identify")

Continuously print the fixture's state once per second - useful for logging or driving a dashboard:

python
# Poll the fixture once per second and print CCT + lux
import time, requests

ip = "192.168.1.42"
while True:
    s = requests.get(f"http://{ip}/getStatus", timeout=2).json()
    print(f"{s['utc_time']}  {s['cct']:>5} K  {s['lux']:>5} lux  flags={s['flags']}")
    time.sleep(1)

Home Assistant

Home Assistant can talk to the fixture using its built-in rest_command and rest sensor integrations - no custom integration is required. Add the snippets below to your Home Assistant configuration to expose the fixture as both a callable service and a live sensor.

How a Home Assistant Lovelace dashboard might render the fixture once the YAML above is in place - sensor tiles wired to /getStatus and /getTemp, action buttons bound to rest_command services.

Outbound commands (set CCT, switch modes, identify, restart):

yaml
# configuration.yaml - define outbound commands
rest_command:
  fixture_set_cct:
    url: "http://192.168.1.42/setCCT?cct={{ cct }}&i={{ intensity }}"
    method: GET
  fixture_preview_cct:
    url: "http://192.168.1.42/previewCCT?cct={{ cct }}&i={{ intensity }}"
    method: GET
  fixture_schedule:
    url: "http://192.168.1.42/setSchedule?mode={{ mode }}"
    method: GET
  fixture_identify:
    url: "http://192.168.1.42/identify"
    method: GET
  fixture_restart:
    url: "http://192.168.1.42/restart"
    method: GET

Once defined, call them from automations, scripts, or dashboards:

yaml
- service: rest_command.fixture_set_cct
  data: { cct: 4500, intensity: 0.5 }

Pull live state into Home Assistant entities so you can graph CCT, lux, and temperature over time, or use them as automation triggers:

yaml
# configuration.yaml - pull live state into Home Assistant
sensor:
  - platform: rest
    name: Office Fixture
    resource: "http://192.168.1.42/getStatus"
    scan_interval: 10
    value_template: "{{ value_json.cct }}"
    unit_of_measurement: "K"
    json_attributes:
      - cct
      - lux
      - nlux
      - flags
      - ls         # 1 = schedule active, 0 = manual
      - utc_time
      - mac

  - platform: rest
    name: Office Fixture Temperature
    resource: "http://192.168.1.42/getTemp"
    scan_interval: 60
    value_template: "{{ value_json.degC }}"
    unit_of_measurement: "°C"
    device_class: temperature

Example automations - a sunset fade and an auto-resume on motion:

yaml
# automations.yaml - fade to warm dim 30 min before sunset
- alias: Office fixture sunset fade
  trigger:
    - platform: sun
      event: sunset
      offset: "-00:30:00"
  action:
    - service: rest_command.fixture_schedule
      data: { mode: 0 }                    # exit automatic schedule
    - service: rest_command.fixture_set_cct
      data: { cct: 2700, intensity: 0.15 }

# Resume the schedule when motion is detected after a manual override
- alias: Office fixture resume schedule on motion
  trigger:
    - platform: state
      entity_id: binary_sensor.office_motion
      to: "on"
  condition:
    - condition: state
      entity_id: sensor.office_fixture
      attribute: ls
      state: 0
  action:
    - service: rest_command.fixture_schedule
      data: { mode: 1 }

Reserve a static IP

Hard-coding the fixture's IP in your Home Assistant config means the integration breaks if DHCP reassigns the address. Bind the fixture's MAC to a fixed IP in your router's DHCP reservation table, or use a hostname your DNS resolves consistently.

Notes & Caveats

  • Manual overrides exit the schedule. Calling /setCCT takes the fixture out of automatic mode. Re-enable the schedule with /setSchedule?mode=1 when you are done.
  • Use previewCCT for sliders. If a user is dragging a UI control, previewCCT avoids permanently disabling the schedule and self-clears after a few seconds of inactivity.
  • Poll at most a few times per second. /getStatus is cheap, but the fixture is a small embedded device. One poll every 1–2 seconds is plenty for a dashboard.
  • Reserve the IP in your router. Long-running automations break if DHCP reassigns the address. Most routers support binding an IP to a MAC.
  • Endpoints not in this guide are private. The fixture exposes additional URIs used internally by Innerscene Studio for provisioning, calibration, and OTA updates. They are not part of the supported API and may change between firmware releases. Calling them can corrupt the fixture's calibration state.

Need an endpoint that is not listed? Have a question about integrating with a building-management system? Email [email protected].