|====================================| | ArtiAPI Protocol Version 1.69 | | Written by: Michel van Osenbruggen | | CopyRight 2026 ArtiLED B.V. | |====================================| Hub version : 1.81 Latest change : 05-10-2026 ======================= | Protocol Definition | ======================= Protocol : HTTP(S) Port : 80/443 URL : http(s)://hub_ip/api DATA : POST with variables |=============| | Definitions | |=============| House : All lights are located in a House Room : Every light can be located in only one Room Zone : Every light can be located in multiple Zones Strip : Whole led strip -> All leds (Number of leds) Multi Strip : Multiple led strips with channel -> All leds Segment : Part of a led strip -> Start, End -> Start and End (0-1000) Part : Part of a led strip -> Start, End -> Start and End (0-1000) (Used for different scaling with Palette Part) Multi Segment : Multiple Parts of a led strip -> Array of n x (Start, End) -> Start and End (0-1000) Pixel : Single pixel of a led strip -> Pixel number -> Pixel numbers (0-1000) Multi Pixel : Multiple pixels of a led strip -> Array of Pixel Numbers -> Pixel numbers (0-1000) Pixel String : Multiple pixels of a led strip with a start (msb, lsb) then followed by an Array of Pixel Numbers (0-1000) Palette : Collection of Colors -> Max 16 colors |===================| | Channel Structure | |===================| 0 : 0 = All Channels 1 : 1 = Channel 1 2 : 2 = Channel 2 3 : 3 = Channel 3 4 : 4 = Channel 4 12 : 12 = Channel 1 + 2 13 : 13 = Channel 1 + 3 14 : 14 = Channel 1 + 4 23 : 23 = Channel 2 + 3 24 : 24 = Channel 2 + 4 34 : 34 = Channel 3 + 4 123 : 123 = Channel 1 + 2 + 3 124 : 124 = Channel 1 + 2 + 4 134 : 134 = Channel 1 + 3 + 4 234 : 234 = Channel 2 + 3 + 4 |===================| | Command Structure | |===================| > Command : /command + Token + Data -> example http://hub_ip/api/rooms # Privileged Command : /command + Token + Data (requires admin rights) $ Data : Depends on Command -> Send Data as json variable -> example: {"zone":1} or {"room":2} $ Token : Send as variable with each request token="Token" (Token is case sensitive) $ Text values : Taken exactly as sent (Hub 1.81). Until Hub 1.80 every value was HTML escaped on arrival, so a : text holding & < > " or ' reached the device changed: an announcement was spoken wrongly and a : name with & was not found. A caller that sent & to work around that must now send the plain & $ By name : A scene, mode, flow or profile addressed by name is found whether that name was typed through this : API or stored by the Hub's own forms. Where one name exists in two spellings, the spelling asked : for is the one that runs; the same name in several rooms or zones still runs in each of them ! Future Command : Command not done yet, coming soon |=============| | Error Codes | |=============| 1 : Login Failed (invalid username or password) 2 : Token Invalid (request new token) 3 : Incomplete data (not all data supplied) 4 : Invalid data (data value incorrect) 5 : Invalid item (id does not exist) 6 : Command Invalid 7 : Command Execution Failed ====================== | Response Structure | ====================== $ response : Command Response => { "success":1/0, "error":error Number, "error_text":"Error Text", "data": { data } } $ success : 1 = Command Successful, 0 = Error (See Error) $ error : Error Number (See List) $ error_text : Error Text $ execution_time : Time in milliseconds it took to execute the Command $ data : See Data Structure ================== | Data Structure | ================== $ name : {"name":"name"} -> Node Name $ ident : {"ident":"ident"} -> Node Ident $ version : {"version":"version"} -> Node Software Version $ state : {"state":state} -> State 0=Off, 1=On $ online : {"online":online} -> Node/Light Status 0=Offline, 1=Online $ active : {"active":active} -> Active 0=Not Active, 1=Active $ channel : {"channel":channel} -> See Channel Structure $ brightness : {"brightness":brightness} -> Brightness Value (0-255) $ hue : {"hue":hue} -> Hue Value (0-255) $ saturation : {"saturation":saturation} -> Saturation Value (0-255) $ color : {"color":"rgb(red,green,blue)"} $ colors : {"colors":["rgb(red,green,blue)","rgb(red,green,blue)", ....]} $ color_rgbw : {"red":red,"green":green,"blue":blue,"white":white} -> Values (0-255) $ color_rgb : {"red":red,"green":green,"blue":blue} -> Values (0-255) $ color_hsv : {"hue":hue,"saturation":saturation,"value":value} -> Values (0-255) $ color_w : {"temperature":temperature,"intensity":intensity} -> Values (0-255) $ segment : {"start":start,"end":end} -> Values (0-1000) $ part : {"start":start,"end":end} -> Values (0-1000) $ clear : {"clear":clear,"commit":commit} -> Values (0-1) $ house : {"power":power,"state":state,"capabilities":{capabilities}} -> power/state aggregated across all rooms+zones (OR semantics) $ room : {"id":id,"name":"name","icon":"icon","status":"status","state":state,"power":power,"brightness":brightness,"colors":["rgb(red,green,blue)", "rgb(red,green,blue)", ...],"running":{"type":"scene/mode","name":"name"} OR null,"capabilities":{capabilities}} $ zone : {"id":id,"name":"name","icon":"icon","channel":channel,"status":"status","state":state,"power":power,"brightness":brightness,"colors":["rgb(red,green,blue)", "rgb(red,green,blue)", ...],"running":{"type":"scene/mode","name":"name"} OR null,"capabilities":{capabilities}} $ scene : {"id":id,"name":"name","image":"image","running":0/1,"type":type} -> Running 0=Done, 1=Running : type 1=White 2=RGB 3=Multi 4=Gradient 5=Advanced 6=RGBW 7=Code 8=HTTP 9=Hue 10=Flow 11=HSV 12=Custom $ custom_scene : {"scene_id":id,"scene_name":"name","scene_image":"image","scene_rooms":"csv","scene_zones":"csv","scene_flow_id":id,"members":[{member1, member2, ....}]} $ brightness_fade : {"mode":mode,"curve":curve,"start":start,"end":end,"time":ms,"step":step} -> Controller-run brightness ramp (0xa5) : mode 0=From current brightness, 1=From start. curve See Curves List (0-10). start/end 0-255 : time 1-65535 MILLISECONDS (two bytes). step 1-255. Brightness only; colour is not changed $ member : {"selection":"room/zone/light","target":id,"action":"action"} and the fields that action uses : action : on,off,white,warm_white,normal_white,cool_white,rgb,rgbw,hsv,brightness,palette,effect_rgb,effect_rgbw,software_fade,software_transition,software_fade_transition,hardware_fade,clear : optional per action : "channel","value","brightness","red","green","blue","hue","saturation","hsv_value","white","temperature","intensity","color_array","palette_scale","palette_alternate","palette_blend","palette_start_index","palette_end_index","effect_id","effect_clear","effect_step","effect_start_delay","effect_end_delay","fade_type","start","end","duration","curve","step" : software fade axes : "red_start","red_end","green_start","green_end","blue_start","blue_end","white_start","white_end","hue_start","hue_end","saturation_start","saturation_end","value_start","value_end","temperature_start","temperature_end","intensity_start","intensity_end","palette_start","palette_end","brightness_start","brightness_end","fade_brightness" : hardware_fade adds "fade_mode" 0/1 and reuses "curve","start","end","step" and "duration" : hardware_fade "duration" is SECONDS but caps at 65 -> the controller time field is two bytes of ms : "delay" seconds, float, 0-3600 -> runs this member that long after the scene starts : "selection" and "target" are required; an absent "action" is stored as "rgb" $ mode : {"id":id,"name":"name","image":"image","running":0/1} -> Running 0=Done, 1=Running $ light : {"id":id,"name":"name","icon":"icon","disabled":disabled,"down":down,"status":"status","power":power,"state":state,"brightness":brightness,"colors":["rgb(red,green,blue)", ...],"channels":{"1":["rgb(...)"],"2":["rgb(...)"],"3":["rgb(...)"],"4":["rgb(...)"]},"running":{"type":"scene/mode","name":"name"} OR null,"capabilities":{capabilities}} : room/zone/light "status" reflects what was last set: - "Off" (state=0) - "Red"/"Green"/"Blue"/"Yellow"/"Orange"/"Cyan"/"Purple"/"Pink"/"White"/"Black" (color set) - "Cold White"/"Normal White"/"Warm White" (color_w set) - "Palette" (palette set) - "" (scene running) - "" (mode running) : room/zone "power" is OR of member lights' power (PSU on for nodes; always 0 for Hue, Fibaro, Homey, Home Assistant and slave lights). : light "channels" is always present with keys "1","2","3","4". Each channel either has its own per-channel colors (set via zone_channel-scoped zones or /light SET with channel parameter), or falls back to the whole-light colors. : light "colors" is the whole-light view: bare :colors if no per-channel SETs have happened, else the bare :colors concatenated with each diverged channel (channel 1 red + channel 2 blue -> ["rgb(red)","rgb(red)","rgb(blue)","rgb(blue)"]). : room/zone/light "running" reports the live scene or mode currently executing on the affected node(s) via ArtiMONITOR (UDP unicast Node -> Hub, port 1096). Null when nothing is running. For room/zone, the value aggregates across the member lights' nodes (most-common-wins). Hue and standalone slave lights never run scenes/modes and always return null. $ node : {"id":id,"ident":"ident","name":"name","ip":"ip","type":"type","disabled":disabled,"down":down,"fail_count":fail_count} $ slave : {"id":id,"ident":"ident","name":"name","ip":"ip","type":"type","disabled":disabled,"down":down,"fail_count":fail_count} $ relay : {"id":id,"ident":"ident","name":"name","ip":"ip","type":"type","ports":ports,"disabled":disabled,"down":down,"fail_count":fail_count} $ palette : {"palette":{"palette":palette_id,"blend":blend,"scale":scale,"alternate":alternate,"start_index":start_index,"end_index":end_index}} $ custom_palette : {"custom_palette":{"start_color":{"red":red,"green":green,"blue":blue},"end_color":{"red":red,"green":green,"blue":blue},"blend":blend,"scale":scale,"alternate":alternate,"start_index":start_index,"end_index":end_index}} $ advanced_palette : {"advanced_palette":{"color_array":[[pos,red,green,blue],[pos,red,green,blue],...],"blend":blend,"scale":scale,"alternate":alternate,"start_index":start_index,"end_index":end_index}} $ effect_rgb : {"effect_rgb":{"effect":effect_id,"clear":0/1,"step":step,"start_delay":start_delay,"end_delay":end_delay,"red":red,"green":green,"blue":blue}} $ effect_rgbw : {"effect_rgbw":{"effect":effect_id,"clear":0/1,"step":step,"start_delay":start_delay,"end_delay":end_delay,"red":red,"green":green,"blue":blue,"white":white}} Effect IDs : 1=Forward Fill, 2=Reverse Fill, 3=Forward Clear, 4=Reverse Clear, 5=Outward Fill, 6=Center Fill, 7=Outward Clear, 8=Center Clear, 9=Strobe Even, 10=Strobe Vari, 11=Random Fill, 12=Fade In, 13=Fade Out, 14=Forward Gradient In, 15=Reverse Gradient In, 16=Forward Gradient Out, 17=Reverse Gradient Out, 18=Outward Gradient In, 19=Outward Gradient Out, 20=Center Gradient In, 21=Center Gradient Out, 22=Forward Pixel Run, 23=Reverse Pixel Run, 24=Outward Pixel Run, 25=Center Pixel Run, 26=Cross Pixel Run, 27=Smart Forward Fill, 28=Smart Reverse Fill, 29=Smart Alt Forward Fill, 30=Smart Alt Reverse Fill, 31=Smart Forward Clear, 32=Smart Reverse Clear, 33=Smart Alt Forward Clear, 34=Smart Alt Reverse Clear Effect Parameters : effect=Effect ID (1-34), clear=Clear strip first (0/1), step=Step/Repeat/Pixels (0-65000), start_delay=Start delay (0-255), end_delay=End delay/Segments (0-255), Colors (0-255) Effect State Tracking : The Hub API and the Master state tracker derive a light's on/off state and colour from effect commands, based on the colour the effect LEAVES on the strip (black = off). Classification lives in TWO places that must stay in sync with the firmware: - Hub API : api/includes/functions.php -> effect_implied_state() - Master : artiled_state.py -> LIT/DARK/STROBE_EFFECT_IDS + effect_ends_lit() !! When ADDING A NEW EFFECT to the firmware, add its end-state to BOTH. State Semantics : Brightness NEVER RAISES state — a {"brightness":>0} does not turn a light on (state=1 only on an actual draw that lights non-zero pixels; mirrors firmware calculate_power_actual — brightness alone lights nothing). Brightness = 0 LOWERS state to 0 (zero brightness = all pixels dark = off; firmware emits State:0, Master artiled_state.py mirrors it). So dragging a dimmer never toggles power ON, but dimming fully to 0 turns the light OFF. Brightness aggregation differs BY LAYER, by design (do not "unify"): - Master per-node (aggregate_brightness): keeps the last-set brightness even while off (slider memory); reads 0 only when every slave is explicitly 0. - Hub /room /zone (aggregate_lights_for): averages only lights that are ON (state=1); 0 when the room/zone is off. $ notification : {"id":id, "priority":priority,"ident":"ident","name":"name","datetime":"datetime","text":"text"} $ holiday : {"id":id,"name":"name","start_date":"YYYY-MM-DD","end_date":"YYYY-MM-DD","recurring":0/1,"profile_id":id|null,"end_profile_id":id|null,"start_time":"HH:MM:SS"|null,"end_time":"HH:MM:SS"|null,"deactivate_start_at_end":0/1,"last_start_fired":"datetime"|null,"last_end_fired":"datetime"|null} $ event : {"id":id,"name":"name","type":type,"enable":0/1,"icon":"icon","date":"YYYY-MM-DD"|"","time":"HH:MM"|"","sun":"SunRise/SunSet"|"","sun_offset":minutes,"days":["Monday", ...],"months":["January", ...],"seasons":["Winter", ...],"profiles":["profile_name", ...],"daylight":"Daylight/Darkness"|"","randomize":0/1,"randomize_minutes":minutes,"scene_id":id,"scene_selection":0-3,"room_id":id,"zone_id":id,"light_id":id,"flow_id":id,"profile_id":id,"profile_action":"activate/deactivate","control_node_id":id,"control_action":"action","control_target":id,"last_fired":"datetime"|null} Event Types : 1=Scene, 2=HTTP, 3=Code, 4=Flow, 5=Profile, 6=Control Event Selection : scene_selection -> 0=House, 1=Room (room_id), 2=Zone (zone_id), 3=Light (light_id) Event Fields : "date" empty means it repeats; a date in the PAST is disabled by the Hub the next time it runs, because it can never fire again. "time" empty AND no "sun" means it fires at midnight. "days"/"months"/"seasons" are AND filters - empty means "no restriction". "profiles" is a GATE holding profile NAMES, not ids: the event only fires while at least one of them is active. Empty means "always". "sun_offset" is minutes, negative for before. ⚠ "url", "data" and "code" are NOT returned. An HTTP event's configuration can hold credentials, and a Code event's body is a python program the Hub runs - neither belongs in a list of what is scheduled. $ magic : {"type":"wakeup","id":id,"name":"name","enable":0/1,"icon":"icon","wake_time":"HH:MM","start_time":"HH:MM","duration":minutes,"days":["Monday", ...],"start_date":"YYYY-MM-DD"|null,"end_date":"YYYY-MM-DD"|null,"selection":0-3,"room_id":id,"zone_id":id,"light_id":id,"channel":channel,"curve":0-10,"brightness":0/1,"brightness_start":0-255,"brightness_end":0-255,"color_mode":"white/rgb/rgbw/hsv/palette","color_start":{...},"color_end":{...},"running":0/1,"next_run":"YYYY-MM-DD HH:MM"|"","last_fired":"datetime"|null,"last_result":"text"|null} Magic Types : "wakeup", "sleep", "daylight" Magic Selection : 0=House, 1=Room (room_id), 2=Zone (zone_id), 3=Light (light_id) Magic Colors : white {"temperature":0-255,"intensity":0-255} rgb {"red","green","blue"} 0-255 rgbw {"red","green","blue","white"} 0-255 hsv {"hue","saturation","value"} 0-255 palette [[position,r,g,b], ...] $ capabilities : light: {"state":1/0,"brightness":1/0,"white":1/0,"rgb":1/0,"rgbw":1/0,"hsv":1/0,"palette":1/0,"segments":1/0,"channels":N/null,"leds":[N,...],"scenes":N,"modes":N} : room/zone/house: the same without "leds" : Returned by /lights, /rooms, /zones and /house (2026-10). New response metadata: every other field and its type is unchanged. Replaces an earlier draft of this definition that no endpoint returned. : "state","brightness" on/off and dimming : "white" white by temperature and intensity (color_w) : "rgb","rgbw","hsv" colour by RGB, RGBW and HSV : "palette" a palette: several colours along the strip (palette, custom_palette, advanced_palette) : "segments" parts of a strip can be addressed on their own (1/0) : "channels" the NUMBER of output channels, 1-4. 0 = not supported (Hue). null = not known: the light's node has not reported it yet, the report expired, or it was outside 1-4. Never 0 for unknown. : "leds" LEDs per channel, 1-1000, one entry per channel ([120,120,120,120] = 4 channels of 120). [] when the light is not addressable (Hue) or the count is not known (not reported, expired, or outside 1-1000). : The 1/0 features come from the light's type: ArtiLED lights (types 1/2/3/6/10/11/13) report all of them; Hue lights/rooms/zones (21/22/23) report state, brightness, white and rgb only. Fibaro lights (31 switch, 32 dimmer, 33 RGBW) and Homey lights (41 switch, 42 dimmer, 43 white, 44 colour, 45 colour and white) report what their class can do: state always; brightness from 32/33 and 42-45; white (temperature) on 43/45; rgb on 33/44/45; rgbw on 33; hsv on 44/45; never palette or segments; channels 0, leds []. The class is fixed when the light is added to the Hub. Home Assistant lights (51 switch, 52 dimmer, 53 white, 54 colour, 55 colour and white, 56 RGBW, 57 RGBW and white) likewise: brightness from 52; white on 53/55/57; rgb and hsv on 54-57; rgbw on 56/57. Channels and LEDs come from what each node reports, refreshed hourly by the Hub; a slave light reports null / []. : room/zone/house: a feature is 1 when ANY member light has it (a light that cannot do something ignores that part of a command). "channels" is the highest KNOWN member count - not a promise that every member has that many: known 2 + unknown = 2, Hue 0 + unknown = null, no lights = 0. Members: room = lights in that room, zone = lights listed in that zone, house = all lights. : "scenes","modes" how many scenes / modes the Hub OFFERS there, as /scenes and /modes list them: - room/zone: the scene's rooms/zones list holds that id or 0 (everywhere); a light: its room's list; house: the scene's ROOMS list holds 0 (a zones list never makes a scene house-wide). - and at least one member light takes part: a light that does not respond to room (house) commands only counts for a scene/mode in its room (house) exception list; zone and light commands are explicit and are not filtered. - an Advanced scene (type 5) or a mode is started on the node by its broadcast name: it counts only for an ArtiLED light whose node has that name, or whose node has not reported its list yet. It never counts for Hue, Fibaro, Homey, Home Assistant or slave lights. An Advanced scene or mode WITHOUT a broadcast name is not counted. - every other scene type counts for any member that takes part. - a light that is down or disabled still counts: that is availability, shown by "down"/"disabled". : A count is what is offered, NOT a guarantee of the effect on that target: a Hue scene (9) starts its configured Hue scene, an HTTP (8), Code (7) or Flow (10) scene runs its configured action, whatever light, room or zone it was started for. {"light":id} does not confine those. : A single light runs scenes and modes too: /scene and /mode take {"light":light_id}. $ running : {"running":[{"ident":"ident","node":"node_name","type":"scene/mode/idle","name":"scene_or_mode_name","image_url":"/images/scenes/...","light_id":N|null,"room_id":N|null,"zone_id":N|null,"last_seen_ago_sec":N,"light_ids":[N,...],"room_ids":[N,...],"zone_ids":[N,...]},...],"count":N,"scenes_running":["name",...],"modes_running":["name",...],"fires":[{fire}],"fires_count":N} : Live cross-node ArtiMONITOR snapshot. Per-node entries include idle nodes that are heartbeating; absence from the list means the node has no heartbeat (silent/offline). last_seen_ago_sec = seconds since the last heartbeat (heartbeat interval is 15s, key TTL is 45s). Per-node "name" is the canonical Hub display name when a matching Hub scene/mode exists, else the Node-reported name verbatim. : "scenes_running" / "modes_running" are de-duplicated Hub display name arrays — useful for "is X playing anywhere?" checks. Same canonical-name resolution as per-node "name". : "fires" is the Hub-side per-fire view (added 1.45). One entry per Hub fire still active — see Data Structure 'fire'. Use this for scope-aware UIs (e.g. show "Music in zone Hifi" as a tile with a Stop button that targets only that zone) and for differentiating concurrent fires of the same scene/mode into different scopes. Per-node "running" is still present for backwards compatibility and for entries no Hub fire claims (Locally-started scenes/modes, or fires the Hub doesn't know about). $ fire : {"uuid":"","type":"scene/mode","hub_id":N,"name":"hub_display_name","broadcast_name":"node_side_name","image_url":"/images/scenes/...","scope_type":"house/room/zone/light","scope_id":N,"scope_label":"","target_nodes":["ident",...] OR ["*"],"confirming_nodes":["ident",...],"confirming_count":N,"confirmed":0/1,"fired_at":epoch,"last_seen":epoch} : One entry per active Hub fire (added 1.45). Lifecycle: - written on /scene or /mode with running:1 - cleared on /scene or /mode with running:0 (matching scope) - cleared automatically when a newer fire fully supersedes its targets - auto-expires ~10s after the last confirming heartbeat, or ~60s from fired_at if never confirmed (also expires by record TTL). : scope_type forces 'house' when the scene/mode uses LAN broadcast regardless of the room/zone the Hub was asked to fire into, because broadcast hits every node on the segment. : target_nodes is the unicast target set, or ["*"] for broadcast fires. confirming_nodes is the subset currently reporting the matching broadcast_name in the cross-node monitor stream. : Stable order: oldest fire first. ============ | Commands | ============ ----------------- | Alive Command | ----------------- > /Alive : No Data -> Returns Hub Name and Ident -> See Data Structure 'name' and 'ident' ----------------- | Login Command | ----------------- > /login : Data -> username and password -> Returns Token -> User Authenticates once with login screen ----------------- | Info Commands | ----------------- > /version : No Data -> Returns Hub Version -> See Data Structure 'version' ---------------- | Get Commands | ---------------- > /house : Empty Data {} -> Returns House -> {"house":{house}} See Data Structure 'house' > /rooms : No Data or {"room":room_id} or {"room":"room_name"} and {"order":"id"} or {"order":"name"} or {"select":"visible/invisible/all"} -> Returns Rooms -> {"rooms":[{room1, room2, ....}]} See Data Structure 'room' > /zones : No Data or {"zone":zone_id} or {"zone":"zone_name"} or {"room":room_id} or {"room":"room_name"} or {"select":"visible/invisible/all"} and {"order":"id"} or {"order":"name"} -> Returns Zones -> {"zones":[{zone1, zone2, ....}]} See Data Structure 'zone' > /scenes : No Data or {"zone":zone_id} or {"zone":"zone_name"} or {"room":room_id} or {"room":"room_name"} or {"select":"visible/invisible/all"} and {"order":"id"} or {"order":"name"} -> Returns Scenes -> {"scenes":[{scene1, scene2, ....}]} See Data Structure 'scene' > /custom_scenes : No Data -> Returns Custom Scenes (scene_type 12 only), by name -> {"scenes":[{scene1, scene2, ....}]} : {"custom_scene":scene_id} -> Returns that one custom scene WITH its members, as a list of one : See Data Structure 'custom_scene'. A scene_id of any other type returns error 4 "Scene Not Found" > /modes : No Data or {"zone":zone_id} or {"zone":"zone_name"} or {"room":room_id} or {"room":"room_name"} and {"order":"id"} or {"order":"name"} -> Returns Modes -> {"modes":[{mode1, mode2, ....}]} See Data Structure 'mode' > /lights : No Data or {"zone":zone_id} or {"zone":"zone_name"} or {"room":room_id} or {"room":"room_name"} or {"light":light_id} or {"light":"light_name"} -> Returns Lights -> {"lights":[{light1, light2, ....}]} See Data Structure 'light' > /notifications : No Data or {"order":id} or {"order":"date"}, {"limit":limit} -> Returns Notifications -> {"notifications":[{notification1, notification2, ....}]} See Data Structure 'notification' > /holidays : Empty Data {} -> Returns Holidays, earliest start first -> {"holidays":[{holiday1, holiday2, ....}]} See Data Structure 'holiday' > /events : Empty Data {} -> Returns Events, by name -> {"events":[{event1, event2, ....}]} See Data Structure 'event' > /magics : Empty Data {} or {"type":"wakeup"} -> Returns Magic entries -> {"magic":[{magic1, magic2, ....}]} See Data Structure 'magic' > /running : No Data -> Returns cross-node ArtiMONITOR snapshot of currently-running scenes and modes -> See Data Structure 'running' > /nodes : No Data -> Returns Nodes -> {"nodes":[{node1, node2, ....}]} See Data Structure 'node' > /slaves : No Data -> Returns Slaves -> {"slaves":[{slave1, slave2, ....}]} See Data Structure 'slave' > /relays : No Data -> Returns Relays -> {"relays":[{relay1, relay2, ....}]} See Data Structure 'relay' ! /strips : ! /segments : ---------------- | Set Commands | ---------------- > /house : Data {"channel":channel},{"state":state},{"brightness":brightness},{"color_w"},{"color_rgb"},{"color_rgbw"},{"color_hsv"},{"palette*"},{"effect_rgb"},{"effect_rgbw"},{"brightness_fade"} -> Sets House -> Returns Response See Data structure 'response' > /room : Data {"room":room_id} or {"room":"room_name"} and {"channel":channel},{"state":state},{"brightness":brightness},{"color_w"},{"color_rgb"},{"color_rgbw"},{"color_hsv"},{"palette*"},{"effect_rgb"},{"effect_rgbw"},{"brightness_fade"} -> Sets Room -> Returns Response See Data structure 'response' > /zone : Data {"zone":zone_id} or {"zone":"zone_name"} and {"channel":channel},{"state":state},{"brightness":brightness},{"color_w"},{"color_rgb"},{"color_rgbw"},{"color_hsv"},{"palette*"},{"effect_rgb"},{"effect_rgbw"},{"brightness_fade"} -> Sets Zone -> Returns Response See Data structure 'response' > /light : Data {"light":light_id} or {"light":"light_name"} and {"channel":channel},{"state":state},{"clear":clear},{"brightness":brightness},{"color_w"},{"color_rgb"},{"color_rgbw"},{"color_hsv"},{"palette*"},{"effect_rgb"},{"effect_rgbw"},{"brightness_fade"},{"segment"} -> Sets Light -> Returns Response See Data structure 'response' : You can add {"hue":1} if you also want to control added or associated Philips Hue Lights, and Fibaro, Homey and Home Assistant lights added to the Hub (Please note you cannot update them as often as ArtiLED lights). : Fibaro, Homey and Home Assistant lights take "state", "brightness" and one colour as far as their class can (see 'capabilities'); palette, effects and brightness_fade are ignored for them. A colour turns such a light on. The reply's success is 0 (error 7) when such a light refused a part it can do. : A Fibaro, Homey or Home Assistant light is "down" when its Home Center / Homey / server is down, or when the Hub has not seen a valid report from that device in the last 60 seconds (unavailable, deleted, or not answering). A down light is not commanded; rooms, zones and the house aggregate without it. A light that answers but has not reported a value yet (or no longer reports it) is NOT down: it is commanded, and that value reads false ("state": false) until it reports one. : ⚠ "state" semantics: state=1 sends a RESTORE to each light (wake + reload the controller's last SAVED output), state=0 sends SLEEP. Restore on a light that is already lit reloads the saved frame — which may be the off/dark frame — and visibly kills its output. Therefore: NEVER combine {"state"} with {"brightness"} or a color field. Send brightness/color alone — color commands turn lights on by themselves. Use {"state"} alone, and only for plain on/off. ------------------ | Scene Commands | ------------------ > /scene : Data {"scene":scene_id} or {"scene":"scene_name"} and {"room":room_id} or {"room":"room_name"} or {"zone":zone_id} or {"zone":"zone_name"} or {"light":light_id} or {"light":"light_name"} and optional {"running":0/1} -> Starts (default, or running:1) or Stops (running:0) the scene in the selected scope -> Returns Response See Data structure 'response' : EXACTLY ONE of "room"/"zone"/"light" — the "or" above is exclusive. Naming two is refused (error 5) : A name that does not resolve is REFUSED, never widened to house-wide. A NUMERIC "room":0 is the house-wide shortcut : "running":0 stops the named scene across the selected scope. The stop dispatch mirrors the start dispatch path (UDP unicast / TCP unicast / UDP broadcast per the scene's advanced flags), changing the protocol command to "Stop Scene" (UDP command code 2, TCP "Stop Scene "). Backwards-compatible: callers that omit "running" still get the previous start-only behavior. : Fibaro, Homey and Home Assistant lights in the scope automatically take the part of a started White (1), RGB (2), RGBW (6) or HSV (11) scene their class can show: a scene that sends "off", or sends brightness 0, switches them off; otherwise, in a White scene, a switch is switched on, a dimmer on with the scene's brightness (when the scene sends one) and a white light on with the brightness and its white; a colour light takes the scene's colour, and from a White scene its white. In an RGB, RGBW or HSV scene a switch, dimmer or white light follows the Behaviour option "In a Colour Scene" (the light's own, else the Hub's; default: switch off): switch off, stay as it is, or on with its own white (on, the scene's brightness). Other scene types (Multi colour, Gradient, Advanced, Code, HTTP, Hue, Flow, Custom) send them nothing; stopping a scene sends them nothing. They are sent after the ArtiLED lights; their result never changes the reply (a light that fails is logged in the Hub's scenes log). > /custom_scene : Data {"action":"add"} and fields -> Creates a custom scene -> Returns {"id":new_id} See Data structure 'response' : Data {"custom_scene":scene_id},{"action":"edit"} and fields -> Updates it -> Returns {"id":id} : Data {"custom_scene":scene_id},{"action":"delete"} -> Deletes it -> Returns {"id":id} : Fields: "name","image","members",["rooms"],["zones"],["scene_app_color"],["scene_sort"],["scene_stop_running_scenes"],["scene_stop_running_modes"] : "rooms"/"zones" omitted are derived from the members; sent empty means offered nowhere : Custom scenes only (scene_type 12). Any other scene_id returns error 4 "Scene Not Found" : A delete refused because the scene is in use returns {"uses":[...]} ----------------- | Mode Commands | ----------------- > /mode : Data {"mode":mode_id} or {"mode":"mode_name"} and {"room":room_id} or {"room":"room_name"} or {"zone":zone_id} or {"zone":"zone_name"} or {"light":light_id} or {"light":"light_name"} and optional {"running":0/1} -> Starts (default, or running:1) or Stops (running:0) the mode in the selected scope -> Returns Response See Data structure 'response' : EXACTLY ONE of "room"/"zone"/"light" — the "or" above is exclusive. Naming two is refused (error 5) : A name that does not resolve is REFUSED, never widened to house-wide. A NUMERIC "room":0 is the house-wide shortcut : "running":0 stops the named mode across the selected scope. Same dispatch semantics as /scene above (command code 2 / "Stop Mode "). ----------------- | Flow Commands | ----------------- > /flow : Data {"flow":flow_id} or {"flow":"flow_name"} and {"action":"start"} or {"action":"stop"} -> Starts or stops flow -> Returns Response See Data structure 'response' > /flows : No Data -> Returns Flows -> {"flows":[{flow1, flow2, ....}]} See Data Structure 'flow' $ flow : {"id":id,"name":"name","icon":"icon","enable":0/1,"running":true/false,"last_run":"datetime"} -------------------- | Profile Commands | -------------------- > /profile : Data {"profile":profile_id} or {"profile":"profile_name"} and {"action":"activate"} or {"action":"deactivate"} and optional {"source":"trigger"} -> Activates or deactivates profile -> Returns Response See Data structure 'response' > /profiles : No Data -> Returns Profiles -> {"profiles":[{profile1, profile2, ....}]} See Data Structure 'profile' $ profile : {"id":id,"name":"name","icon":"icon","active":0/1,"protected":0/1,"role_id":role_id} ------------------------- | Notification Commands | ------------------------- > /notification : Data {"notification":notification_id} or {"notifications":[id, id, ....]} -> Deletes one or more notifications -> Returns {"deleted":deleted,"failed":0,"requested":requested,"mode":"ids"} See Data structure 'response' : Data {"older_than_days":days} -> Deletes every notification older than that many days -> Returns {"deleted":deleted,"failed":0,"requested":deleted,"mode":"older_than_days","days":days} : Data {"delete_all":"ALL"} -> Deletes every notification -> Returns {"deleted":deleted,"failed":0,"requested":deleted,"mode":"all"} "notification" id, 1..2147483647 "notifications" array of ids, max 500 "older_than_days" 1..3650 "delete_all" "ALL" > /notifications : See Get Commands - reading the list is a Get. ---------------------- | Holiday Commands | ---------------------- > /holiday : Data {"action":"add"} and fields -> Creates a holiday -> Returns {"id":new_id} See Data structure 'response' : Data {"holiday":holiday_id},{"action":"edit"} and fields -> Updates it -> Returns {"id":id} : Data {"holiday":holiday_id},{"action":"delete"} -> Deletes it -> Returns {"id":id,"deleted":0/1} : Fields for add and edit: "name" required, 1..100 characters "start_date" required, "YYYY-MM-DD", a real calendar date "end_date" required, "YYYY-MM-DD", NOT before start_date "recurring" optional 0/1, default 0 "profile_id" optional, activated at the start; 0/""/null = none "end_profile_id" optional, activated at the end; 0/""/null = none "start_time" optional "HH:MM" or "HH:MM:SS"; none = start of day "end_time" optional "HH:MM" or "HH:MM:SS" "deactivate_start_at_end" optional 0/1, default 0 - turn the start profile off again when the holiday ends -------------------- | Event Commands | -------------------- > /event : Data {"action":"add"} and fields -> Creates an event -> Returns {"id":new_id} See Data structure 'response' : Data {"event":event_id},{"action":"edit"} and fields -> Updates it -> Returns {"id":id} : Data {"event":event_id},{"action":"delete"} -> Deletes it -> Returns {"id":id,"deleted":0/1} : Data {"event":event_id},{"action":"enable"} or {"action":"disable"} -> Returns {"id":id,"enable":0/1} : Data {"event":event_id},{"action":"test"} -> Runs it now -> Returns {"id":id} : add and edit accept "type" 1 (Scene), 4 (Flow) and 5 (Profile) only. Types 2 (HTTP), 3 (Code) and 6 (Control) can be read, enabled, disabled and deleted; edit or test on one returns error 6. : Fields for add and edit: "name" required, 1..50 characters "type" 1=Scene (default), 4=Flow, 5=Profile "enable" optional 0/1, default 1 "icon" optional, Font Awesome classes, max 30 characters, [A-Za-z0-9 _-] only; default "fas fa-couch" "date" optional "YYYY-MM-DD" one-off date; "" = it repeats "time" optional "HH:MM" or "HH:MM:SS" "sun" optional "SunRise" or "SunSet" "sun_offset" optional minutes, one of 0, +/-5, 10, 15, 20, 25, 30, 45, 60, 90, 120 "days" optional ["Monday", ...] or a comma string "months" optional ["January", ...] or a comma string "seasons" optional ["Winter","Spring","Summer","Autumn"] "profiles" optional ["profile_name", ...] - the gate, by NAME "daylight" optional "Daylight" or "Darkness" "randomize" optional 0/1, default 0 "randomize_minutes" optional, one of 5, 10, 15, 30, 45, 60; default 15 type 1 only: "scene_id" required "scene_selection" optional 0=House (default), 1=Room, 2=Zone, 3=Light "room_id" required when scene_selection is 1 "zone_id" required when scene_selection is 2 "light_id" required when scene_selection is 3 type 4 only: "flow_id" required type 5 only: "profile_id" required "profile_action" optional "activate" (default) or "deactivate" : "time" and "sun" are mutually exclusive; neither = midnight. > /magic : Data {"type":"wakeup","action":"add"} and fields -> Creates a wake-up -> Returns {"id":new_id} : Data {"type":"wakeup","magic":id},{"action":"edit"} and fields -> Updates it -> Returns {"id":id} : Data {"type":"wakeup","magic":id},{"action":"delete"} -> Deletes it -> Returns {"id":id,"deleted":0/1} : Data {"type":"wakeup","magic":id},{"action":"enable"} or {"action":"disable"} -> Returns {"id":id,"enable":0/1} : Data {"type":"wakeup","magic":id},{"action":"test"} -> Runs it now -> Returns {"id":id} : Data {"type":"wakeup","magic":id},{"action":"stop"} -> Cancels a running ramp -> Returns {"id":id} > /magics : See Get Commands - reading the list is a Get. > /events : See Get Commands - reading the list is a Get.