|=========================================| | ArtiRELAY API Protocol Version 1.00 | | Written by: Michel van Osenbruggen | | CopyRight 2026 ArtiLED B.V. | |=========================================| Firmware version : 1.00 Latest change : 20-03-2026 =============== | Description | =============== The ArtiLED Relay Controller HTTP REST API runs on port 80. All endpoints accept GET or POST parameters. All responses return JSON. See ArtiRELAY.txt for the TCP text protocol on port 1094. ======================= | Protocol Definition | ======================= Protocol : HTTP Port : 80 URL : http:///api DATA : GET or POST with variables Authentication : token= parameter on each request |=============| | Error Codes | |=============| 1 : Login Failed (invalid username or password) 2 : Token Invalid 3 : Incomplete data (not all data supplied) 4 : Invalid data (data value incorrect) 6 : Command Invalid 7 : Unauthorized IP address (firewall) 8 : Already Bound / Already Adopted |====================| | Response Structure | |====================| All responses return JSON: { "success": 1, "error": 0, "error_text": "Success", "execution_time": 5, "data": {} } success : 1 = success, 0 = error error : error code (0 = none) error_text : human readable error description execution_time : milliseconds data : response data (varies per endpoint) |=================================| | Management Endpoints | |=================================| > /api/alive Parameters : none (firewall check only) Response data : {"name":"RELC-001", "ident":"hje33knsjabdkrl"} Description : Health check — returns name and ident > /api/login Parameters : data={"username":"...","password":"..."} Response data : {"token":"..."} Description : Authenticate with username/password, returns token > /api/version Parameters : token= Response data : {"version":"1.00"} Description : Returns firmware version > /api/info Parameters : token= Response data : { "version": "1.00", "name": "RELC-001", "hub": "0.0.0.0", "master": "0.0.0.0", "controller": "0.0.0.0", "relays": 8, "delay": 1, "restore": 0, "uptime": 12345, "mac": "AA:BB:CC:DD:EE:FF", "serial": "ABCDEFGHIJ", "type": "RELC-001" } Description : Returns full device info > /api/reset Parameters : token= Description : Returns success then reboots the ESP32 > /api/adopt Parameters : token=, data={"ident":"...", "hub":""} Description : Sets the Hub IP address (adopted by Hub) Error 8 : Rejected if already adopted (HUB already set). Orphan first. > /api/orphan Parameters : token=, data={"ident":"..."} Description : Clears the Hub IP address (orphaned by Hub) > /api/bind Parameters : token=, data={"ident":"...", "master":""} Description : Sets the Master/Controller IP address (bound) Error 8 : Rejected if already bound (MASTER already set). Release first. > /api/release Parameters : token=, data={"ident":"..."} Description : Clears the Master/Controller IP address (released) |===============================| | Relay Command Endpoint | |===============================| Endpoint : /api Parameters : token=, data= All relay commands use the /api endpoint with a JSON data parameter. The JSON must contain a "command" field. |=================| | Relay Commands | |=================| --- SET (persistent on/off) --- $ Set single relay on: data={"command":"set", "relay":1, "state":1} $ Set single relay off: data={"command":"set", "relay":1, "state":0} relay : 1-8 (relay port number) state : 0 = LOW (off), 1 = HIGH (on) $ Set all relays on: data={"command":"all", "state":1} $ Set all relays off: data={"command":"all", "state":0} state : 0 = LOW (off), 1 = HIGH (on) Sets all configured relays to the same state. --- TOGGLE (flip current state) --- $ Toggle single relay: data={"command":"toggle", "relay":1} relay : 1-8 (relay port number) Reads current state and sets to opposite. No state parameter needed. $ Toggle all relays: data={"command":"toggle_all"} Flips every configured relay to its opposite state. --- PULSE (momentary) --- $ Pulse single relay: data={"command":"pulse", "relay":1, "state":1} data={"command":"pulse", "relay":1, "state":1, "duration":5} relay : 1-8 (relay port number) state : initial state before toggle duration : optional, seconds (overrides global RELAY_DELAY for this pulse) Sets relay to state, waits duration (or RELAY_DELAY) seconds, then sets to opposite state. State 1 = pulse HIGH then LOW. State 0 = pulse LOW then HIGH. --- SEQUENCE (sequential switching) --- $ Sequence up: data={"command":"sequence", "direction":"up", "state":1} data={"command":"sequence", "direction":"up", "state":1, "duration":3} $ Sequence down: data={"command":"sequence", "direction":"down", "state":0} data={"command":"sequence", "direction":"down", "state":0, "duration":3} direction : "up" = relay 1 through N, "down" = relay N through 1 state : 0 = LOW (off), 1 = HIGH (on) duration : optional, seconds between each relay (overrides global RELAY_DELAY) Sets relays sequentially with delay between each relay. --- TIMED (non-blocking auto-off timer) --- $ Timed relay: data={"command":"timed", "relay":1, "state":1, "duration":300} relay : 1-8 (relay port number) state : 0 = LOW (off), 1 = HIGH (on) — initial state duration : 1-86400 seconds (max 24 hours) Sets relay to state, then automatically restores to opposite after duration. Non-blocking — device remains fully responsive during the timer. A new timed command on the same relay replaces the previous timer. --- CUSTOM SEQUENCE (user-defined order and delays) --- $ Custom sequence: data={"command":"custom_sequence", "steps":[ {"relay":3, "state":1, "delay":2}, {"relay":1, "state":1, "delay":0}, {"relay":5, "state":1, "delay":5}, {"relay":2, "state":0, "delay":0} ]} steps : array of 1-8 step objects relay : 1-8 (relay port number) state : 0 = LOW (off), 1 = HIGH (on) delay : seconds to wait after this step (0 = no wait, last step delay ignored) --- STATUS (query output states) --- $ Get status of all relays: data={"command":"status"} Response data : {"command":"status", "relays":8, "relay_1":0, "relay_2":1, "relay_3":0, ...} Each relay_N value : 0 = LOW (off), 1 = HIGH (on) Uses digitalRead() to return actual pin state. --- INTERLOCK (mutual exclusion pairs) --- $ Set interlock pairs: data={"command":"interlock", "pairs":[[1,2],[3,4]]} pairs : array of up to 4 pairs, each pair = [relayA, relayB] When relayA goes HIGH, relayB is forced LOW (and vice versa). Each relay can only be in one pair. Replaces all existing pairs. Saved to EEPROM. $ Get interlock pairs: data={"command":"get_interlock"} Response data : {"command":"get_interlock", "pairs":[[1,2],[3,4]]} Only active pairs are returned. |==================| | Firewall | |==================| When FIREWALL_API=1, HTTP API endpoints only accept connections from: - Registered Hub IP - Registered Master IP - Registered Controller IP The /api/adopt, /api/bind, and /api/login endpoints bypass the firewall (they need to be reachable before registration).