ArtiLED Video Processor API v1.3 ================================= Base URL: http:///api/ Authentication: Token parameter (GET or POST) Response format: JSON { success, error, error_text, execution_time, data } Shared node commands: /alive, /version, /info, /config, /light -> see ArtiNodeAPI.txt /api/video — Video Processor Commands ====================================== GET /api/video?token=&data={} Returns current video processor state. Response data: { input, switch, input_count } GET /api/video?token=&data= Control video processor. Switch input: data: {"input": 1} Input 1 data: {"input": 2} Input 2 data: {"input": 3} Input 3 data: {"input": 4} Input 4 Response data: { input, action: "switch" } /api/hdmi — HDMI Processor (DIVA) Commands ============================================ GET /api/hdmi?token=&data={} Returns current HDMI processor state. Response data: { enabled, input, hdr, osd, autosw, audio, audio_mute0, audio_mute1, oled, oledrev, oledrot, oledfade } GET /api/hdmi?token=&data= Control HDMI processor. Multiple commands can be sent in one request. Input switching: data: {"input": 1} HDMI Input 1 data: {"input": 2} HDMI Input 2 data: {"input": 3} HDMI Input 3 data: {"input": 4} HDMI Input 4 HDR profile: data: {"hdr": 0} HDR Off data: {"hdr": 1} HDR Profile 1 ... data: {"hdr": 13} HDR Profile 13 OSD (On-Screen Display): data: {"osd": 1} OSD On data: {"osd": 0} OSD Off Auto switch: data: {"autosw": 1} Auto-switch On data: {"autosw": 0} Auto-switch Off Audio profile: data: {"audio": 0} Full data: {"audio": 1} Native data: {"audio": 2} 5.1 data: {"audio": 3} Stereo data: {"audio": 4} TX1 Audio mute TX0: data: {"audio_mute0": 1} Mute TX0 On data: {"audio_mute0": 0} Mute TX0 Off Audio mute TX1: data: {"audio_mute1": 1} Mute TX1 On data: {"audio_mute1": 0} Mute TX1 Off OLED display: data: {"oled": 1} OLED On data: {"oled": 0} OLED Off Hotplug: data: {"hotplug": 1} Issue a hot-plug event to the sources (links renegotiate, no reboot) Response data: { hotplug: { outcome, sent, acknowledged, took_s, error } } outcome: acknowledged | unknown | failed sent once, never repeated; unknown/failed => success 0, error 6 Reboot: data: {"reboot": 1} Reboot HDMI processor (returns at once) data: {"reboot": 1, "wait": 1} Reboot, return when the unit answers on RS232 again (up to 90 s) data: {"reboot": 1, "min_idle_hours": 4} Reboot only when the capture has had no signal for 4 hours (0 = always) data: {"reboot": 1, "dry_run": 1} Decide and report, send nothing Response data with wait, min_idle_hours or dry_run: { reboot: { outcome, skipped, reason, signal, shm_signal, idle_s, min_idle_hours, dry_run, alive_before, sent, acknowledged, ready, took_s, error } } outcome: rebooted | skipped | dry_run | unknown | failed sent once, never repeated; unknown/failed => success 0, error 6 ready: the unit answers on RS232 again (picture not verified) min_idle_hours needs a fresh /api/video_status snapshot from a running grabber: idle counts from the later of signal.since and grabber.observed_since Older processors (before /api/video_status) accept {"reboot": 1} and ignore wait, min_idle_hours and dry_run: an unguarded reboot at once. Callers must check that /api/video_status answers before sending a guarded reboot. Combined example: data: {"input": 2, "hdr": 7, "osd": 0} Switches to input 2, sets HDR profile 7, turns OSD off. Response data: { input: 2, hdr: 7, osd: 0 } /api/modes — Modes (list) ========================== GET /api/modes?token=&data={} Returns the modes of the Video Processor (the Hub lists them as Advanced Modes). Response data: { modes: [ { id, name, image } ] } /api/mode — Mode (start / stop) ================================ GET /api/mode?token=&data={"mode": "Cinema"} Starts the mode by name: switches its video input (when set) and loads its presets (force 0: only settings that differ are pushed), then marks it the running mode. Response data: the request ({ mode } or { mode, running }) GET /api/mode?token=&data={"mode": "Cinema", "running": 0} Stops the mode (clears its running state; nothing is restored). Names match case-insensitively. Starts and stops are applied in the order they arrive; the newest request wins. Errors: 4 Invalid Data, 5 Mode not found / Mode already running (a scripted mode), 6 Control service unreachable /api/presets — Presets (list) ============================== Sections: grabber, input, main, ambi, matrix, panel, hdmi GET /api/presets?token=&data={} Returns all presets. Response data: { presets: [ { id, name, section, active, saved_at, count } ] } GET /api/presets?token=&data={"section": "grabber"} Returns the presets of one section. /api/preset — Preset (load / manage) ===================================== GET /api/preset?token=&data={} Returns the active preset per section. Response data: { active: [ { section, label, id, name } ] } id 0 = none GET /api/preset?token=&data= "preset" is an id or a name. "section" is required. Load: data: {"section": "grabber", "preset": 3} data: {"section": "grabber", "preset": "Movie"} data: {"section": "grabber", "preset": 3, "force": 0} Skipped when its values already run (force: 0 or 1) Response data: { section, id, name, result: "applied" | "skipped", changed } changed = settings that differed and were pushed (only those are written / sent to the device) Get: data: {"section": "grabber", "preset": 3, "action": "get"} Response data: { section, preset: { name, section, saved_at, created_at, values } } Save (from the live settings): data: {"section": "grabber", "action": "save", "name": "Movie"} New preset data: {"section": "grabber", "preset": 3, "action": "save"} Overwrite Response data: { section, id, name, count } Copy: data: {"section": "grabber", "preset": 3, "action": "copy", "name": "Movie B"} Response data: { section, id, name, count } Rename: data: {"section": "grabber", "preset": 3, "action": "rename", "name": "Movie"} Response data: { section, id, name } Delete: data: {"section": "grabber", "preset": 3, "action": "delete"} Response data: { section, id } Errors: 4 Invalid Data, 5 Unknown section, 6 Preset Not Found, 7 rejected (error_text) /api/video_status — Capture Status (read only) ============================================== GET /api/video_status?token= Response data: { timestamp, age_s, fresh, grabber: { running, pid, heartbeat_age_ms, observed_since, observed_pid }, running: writer pid alive and heartbeat present, not from the future and at most 5 s old observed_since: the live grabber continuously seen since; a new writer pid restarts it signal: { state, since }, state: present | lost | disabled source: { width, height }, effective: { width, height }, after black-bar removal display: { aspect, ratio }, Screen Format: the shape of the screen the signal is made for (data/video_display_aspect: 16:9 | 16:10 | 4:3 | 1.85:1 | 2.00:1 | 21:9 | 2.35:1 | 2.39:1 | 2.40:1, default 16:9) bars: { enabled, unknown, horizontal, vertical, horizontal_pct, vertical_pct, orientation }, horizontal: rows above and below the picture (each), vertical: columns left and right (each), capture pixels *_pct: share of the frame height / width orientation: full | letterbox (bars above and below) | pillarbox (bars left and right) | windowbox aspect: { state, ratio, label, orientation, reason, since, hold_s, pending }, ratio: the picture inside the bars, on the display (bars relative to the frame, scaled by display.ratio) state: ok | source | unknown label: 4:3 | 1.66:1 | 16:9 | 1.85:1 | 2.00:1 | 2.20:1 | 2.35:1 | 2.39:1 (scope) | 2.55:1 | 2.76:1 | :1 held: a new shape is reported after hold_s seconds (data/video_aspect_hold, default 10) hdr: { setting, applied } } sdr | hdr | auto /api/hdmi_status — HDMI Processor (DIVA) Live Signal (read only) ================================================================ GET /api/hdmi_status?token= Response data: { enabled, ipaddr, updated, age_s, interval_s, reachable, input, interval_s: the daemon's poll cadence (3 while the Dashboard is being watched, 60 otherwise); reachable = info present and age_s <= interval_s * 2 + 5 rx, tx0, tx1: { raw, resolution, refresh, chroma, colorimetry, range, bit_depth, hdr, converted_to_sdr, pixel_clock_mhz, hdcp } | null, format, e.g. "4K59.94 4:2:2 12-bit" dynamic_range, SDR | HDR | HDR10 | HLG | Dolby Vision | null (HDR page not fetched) sink0, sink1, source_name, audio: { rx, out }, counters: { tx0hpd, tx0rs, tx0tmds, tx0ns, tx0scerr, tx1hpd, tx1rs, tx1tmds, tx1ns, tx1scerr, rx0in5v, rx1in5v, rx2in5v, rx3in5v }, raw, hdr_raw } input: 1..4 | follow Error Codes ============ 0 = No error 2 = Token Invalid 3 = Incomplete Data 4 = Invalid Data 5 = /video_status, /hdmi_status: Status not available (status service not running) /presets, /preset: Unknown section 6 = /hdmi: HDMI controller command not cleanly successful (outcome unknown or failed; detail in data) /preset: Preset Not Found 7 = /preset: Rejected (error_text says why: incomplete or invalid preset, write or device failure, name rule)