# Authoring HTTP Device Core parameter files with an AI assistant This document teaches an AI assistant (Claude, ChatGPT, etc.) everything it needs to **generate parameter files for the SKAARHOJ HTTP Device Core**. Paste this whole file into the assistant, then describe the HTTP request you want to control. The assistant returns one `.json` file per parameter that you **import directly** into the HTTP Core web UI — no hand-editing required. > **How to use it (copy/paste prompt):** > *"Here is the spec for SKAARHOJ HTTP Core parameter files. Using the API described > below, produce one importable parameter JSON file for each action I list. Follow the > schema and rules exactly and return each file in its own code block with the file name > it should be saved as. \ \ endpoints\>"* --- ## 1. What a parameter file is The HTTP Device Core connects a SKAARHOJ controller to **any device or service with an HTTP/REST API**. Each **parameter** describes a single HTTP request (method, path, body, headers) plus how to interpret the response. Parameters belong to a **Model**; every device assigned to that model exposes the same parameters in Reactor. A parameter file is a single JSON object. You create it in the web UI by exporting a parameter, and you load it again with **Import**. An AI assistant can produce the same JSON from scratch. ### The file name *is* the parameter label When you import a file, the core sets the parameter's label to the **file name with `.json` removed**. So save the file as the name you want the parameter to have, e.g. `Recall Preset.json` → a parameter called *Recall Preset*. The `Label` field inside the JSON is ignored on import (keep it in sync anyway for readability). ### Where to import In the HTTP Core web UI: - **New parameter from a file:** open a Model → **Import parameter** (the import icon at the top of the model page, or *Add parameter → Import from file…*). The file becomes a brand-new parameter. - **Overwrite an existing parameter:** open the parameter → **Import** (toolbar). The uploaded file replaces that parameter's configuration. You can select **multiple files at once** to import a whole batch of parameters. After importing you may be prompted to **Reload Core** to push the new structure to Reactor. Make all your changes first, then reload once. --- ## 2. File schema A parameter file is exactly this shape (top-level keys `Info`, `Headers`, `Variables`). Field names are **case-sensitive**. ```json { "Info": { "Label": "string", "Description": "string", "RequestType": "GET | POST | PUT | PATCH | DELETE | Variable", "DoNotUseBaseURL": false, "RequestPath": "string", "Body": "string", "Type": "Trigger | Toggle | String | Integer | Float", "StatusRegex": "string", "FeedbackType": "None | Confirm on status 2xx | Regex match value | Confirm on regex match", "Min": 0, "Max": 0, "OffVal": "string", "OnVal": "string" }, "Headers": { "Headers": [ { "Key": "string", "Value": "string" } ] }, "Variables": [ { "Label": "string", "Description": "string", "Tag": "string", "Type": "String | Int | Float | Binary", "Min": 0, "Max": 1 } ] } ``` ### 2.1 `Info` — the request and parameter behaviour | Field | Type | Meaning | |---|---|---| | `Label` | string | Display name. **Overwritten by the file name on import** — keep them matching. | | `Description` | string | Shown in Reactor and in the editor. Optional, but recommended. | | `RequestType` | enum | HTTP method: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, or `Variable`. `Variable` lets the Reactor user pick the method at runtime (adds a "Request Type" meta field). | | `DoNotUseBaseURL` | bool | `false` → `RequestPath` is appended to the device's BaseURL. `true` → `RequestPath` must be a full absolute URL (`https://…`). | | `RequestPath` | string | The path (or full URL). May contain `{value}` and `{tag}` placeholders. | | `Body` | string | Request body for POST/PUT/PATCH. Free text — usually JSON. May contain placeholders. Leave `""` for GET/DELETE. | | `Type` | enum | The control type Reactor presents (see §3). | | `StatusRegex` | string | Regular expression run against the response body. The **last capture group** of the match is used (see §5). Empty when unused. | | `FeedbackType` | enum | How the response is interpreted (see §5). | | `Min` / `Max` | number | Value range for `Integer`/`Float` types. `0,0` when unused. | | `OffVal` / `OnVal` | string | For `Toggle`: the literal text sent for off/on. Empty → `false`/`true` (see §3). | ### 2.2 `Headers` — per-parameter HTTP headers ```json "Headers": { "Headers": [ { "Key": "Content-Type", "Value": "application/json" } ] } ``` - Use `"Headers": { "Headers": null }` (or `[]`) when there are no parameter-specific headers. - These are merged on top of the Model's **Global Headers** and the device's **Header Overrides**. Precedence (highest wins): **parameter header → device override → model global**. - For `POST`/`PUT`/`PATCH` with a JSON body, set `Content-Type: application/json`. ### 2.3 `Variables` — `{tag}` placeholders Every `{tag}` you put in the path, body, or a header value becomes a runtime input the Reactor user can set. Declare each one here. | Field | Type | Meaning | |---|---|---| | `Label` | string | Display name of the input. | | `Description` | string | Shown in Reactor. Optional. | | `Tag` | string | The placeholder name **without braces**. `"id"` matches `{id}` in the path/body/header. Letters and digits only. | | `Type` | enum | `String`, `Int`, `Float`, or `Binary`. | | `Min` / `Max` | number | Range for `Int`/`Float`. For `String`/`Binary` use `0`/`1`. | The placeholder match is **case-insensitive**. Do **not** declare a variable for `{value}` — that one is built in (see §4). --- ## 3. Parameter types (`Info.Type`) | `Type` | Reactor control | Sends | Notes | |---|---|---|---| | `Trigger` | A button | One request when pressed | No `{value}`. Use for fire-and-forget actions (recall, reboot, next…). | | `Toggle` | An on/off switch | One request per state change | `{value}` becomes `OnVal` when on and `OffVal` when off. If `OnVal`/`OffVal` are empty, `{value}` is the literal `true`/`false`. | | `String` | A text field | A request carrying the typed text | `{value}` = the text. | | `Integer` | A number field | A request carrying the number | Requires `Min`/`Max`. `{value}` = the integer. | | `Float` | A number field | A request carrying the decimal | Requires `Min`/`Max`. `{value}` = the float. | **Rules / gotchas** - `Integer` and `Float` **must** have a non-zero `Min`/`Max` range. (`0,0` is rejected.) - `Trigger` ignores `Confirm on status 2xx`/`Confirm on regex match` feedback (a button has no value to confirm). A `Trigger` *can* return a string via `Regex match value` (see "Get Todo" example) — useful to surface a value on a button press. - `Toggle` with custom `OnVal`/`OffVal` is how you target APIs that expect e.g. `"on"`/`"off"`, `1`/`0`, or `enabled`/`disabled`. --- ## 4. Placeholders: `{value}` and `{tag}` - **`{value}`** — the parameter's own value (the text/number/toggle state). Available for every type **except `Trigger`**. Put it wherever the value belongs: - Path: `lights/{id}/brightness?level={value}` - Body: `{"bri": {value}}` - **`{tag}`** — a declared variable (see §2.3). Use as many as you need. - Matching is **case-insensitive** (`{ID}` == `{id}`). - **Literal braces:** to send a real `{` or `}` (not a placeholder), escape it as `\{` or `\}`. The backslash is removed before sending. In JSON that backslash itself must be escaped, so write `\\{` and `\\}` in the file. - The query string is URL-encoded automatically; you don't pre-encode placeholder values. --- ## 5. Feedback (`Info.FeedbackType` + `Info.StatusRegex`) Feedback decides whether/how the parameter reflects the device's real state back in Reactor. | `FeedbackType` | What happens | |---|---| | `None` | Fire-and-forget. The value is assumed applied; no response parsing. | | `Confirm on status 2xx` | The new value is confirmed only if the HTTP status is 200–299. (Ignored for `Trigger`.) | | `Regex match value` | `StatusRegex` is run on the response body; the **last capture group** becomes the parameter's value. Use to read state back from JSON/XML/text. | | `Confirm on regex match` | The value is confirmed if `StatusRegex` matches anything in the response. | **Regex notes** - Go (RE2) regex syntax. The value used is the **innermost / last capturing group** of the first match. Example: `"state"\s*:\s*(\d+)` → captures the number after `"state":`. - For `Regex match value` the captured text is coerced to the parameter `Type` (`true`/`false` for `Toggle`, parsed number for `Integer`/`Float`, raw text for `String`/`Trigger`). - Remember JSON escaping: a regex `"\d+"` is written `"\\d+"` in the file, and a literal `"` inside the regex becomes `\"`. --- ## 6. Worked examples (public API: `https://jsonplaceholder.typicode.com/`) These are real, importable files. The device BaseURL is `https://jsonplaceholder.typicode.com/`. ### 6.1 `Get Todo.json` — GET + variable + read a value back A button that fetches `todos/{id}` and surfaces the todo's `title` as the parameter value. ```json { "Info": { "Label": "Get Todo", "Description": "Fetches a todo item by ID and returns its title as the parameter value.", "RequestType": "GET", "DoNotUseBaseURL": false, "RequestPath": "todos/{id}", "Body": "", "Type": "Trigger", "StatusRegex": "\"title\":\\s*\"([^\"]*)\"", "FeedbackType": "Regex match value", "Min": 0, "Max": 0, "OffVal": "", "OnVal": "" }, "Headers": { "Headers": null }, "Variables": [ { "Label": "Todo ID", "Description": "Which todo to fetch (1-200)", "Tag": "id", "Type": "Int", "Min": 1, "Max": 200 } ] } ``` ### 6.2 `Create Post.json` — POST + JSON body + headers + variables ```json { "Info": { "Label": "Create Post", "Description": "Creates a new post from a title and body.", "RequestType": "POST", "DoNotUseBaseURL": false, "RequestPath": "posts", "Body": "{\"title\": \"{title}\", \"body\": \"{body}\", \"userId\": {userId}}", "Type": "Trigger", "StatusRegex": "", "FeedbackType": "None", "Min": 0, "Max": 0, "OffVal": "", "OnVal": "" }, "Headers": { "Headers": [ { "Key": "Content-Type", "Value": "application/json; charset=UTF-8" } ] }, "Variables": [ { "Label": "Title", "Description": "Post title", "Tag": "title", "Type": "String", "Min": 0, "Max": 1 }, { "Label": "Body", "Description": "Post body text", "Tag": "body", "Type": "String", "Min": 0, "Max": 1 }, { "Label": "User ID", "Description": "Author user ID (1-10)","Tag": "userId", "Type": "Int", "Min": 1, "Max": 10 } ] } ``` ### 6.3 `Set Post Title.json` — String value via PUT, confirmed on 2xx ```json { "Info": { "Label": "Set Post Title", "Description": "Updates the title of an existing post. The new title is the parameter value.", "RequestType": "PUT", "DoNotUseBaseURL": false, "RequestPath": "posts/{id}", "Body": "{\"title\": \"{value}\"}", "Type": "String", "StatusRegex": "", "FeedbackType": "Confirm on status 2xx", "Min": 0, "Max": 0, "OffVal": "", "OnVal": "" }, "Headers": { "Headers": [ { "Key": "Content-Type", "Value": "application/json; charset=UTF-8" } ] }, "Variables": [ { "Label": "Post ID", "Description": "Which post to update (1-100)", "Tag": "id", "Type": "Int", "Min": 1, "Max": 100 } ] } ``` ### 6.4 `Publish Post.json` — Toggle with custom on/off values ```json { "Info": { "Label": "Publish Post", "Description": "Toggles the published flag of a post. Sends true on, false off.", "RequestType": "PUT", "DoNotUseBaseURL": false, "RequestPath": "posts/{id}", "Body": "{\"id\": {id}, \"published\": {value}}", "Type": "Toggle", "StatusRegex": "", "FeedbackType": "Confirm on status 2xx", "Min": 0, "Max": 0, "OffVal": "false", "OnVal": "true" }, "Headers": { "Headers": [ { "Key": "Content-Type", "Value": "application/json; charset=UTF-8" } ] }, "Variables": [ { "Label": "Post ID", "Description": "Which post to publish (1-100)", "Tag": "id", "Type": "Int", "Min": 1, "Max": 100 } ] } ``` ### 6.5 `Delete Post.json` — DELETE trigger ```json { "Info": { "Label": "Delete Post", "Description": "Deletes a post by ID.", "RequestType": "DELETE", "DoNotUseBaseURL": false, "RequestPath": "posts/{id}", "Body": "", "Type": "Trigger", "StatusRegex": "", "FeedbackType": "None", "Min": 0, "Max": 0, "OffVal": "", "OnVal": "" }, "Headers": { "Headers": null }, "Variables": [ { "Label": "Post ID", "Description": "Which post to delete (1-100)", "Tag": "id", "Type": "Int", "Min": 1, "Max": 100 } ] } ``` --- ## 7. Checklist for the assistant before returning a file 1. **Valid JSON.** No trailing commas; all strings quoted; braces/brackets balanced. 2. **All keys present** with the exact names and casing from §2 (`Info`, `Headers`, `Variables`, and every `Info` sub-field). Missing fields default to empty/zero but it is safest to include them all. 3. **Enums are exact** (including spaces): `RequestType`, `Type`, `FeedbackType`, variable `Type`. e.g. `"Confirm on status 2xx"`, not `"confirm 2xx"`. 4. **Every `{tag}`** used in path/body/headers has a matching entry in `Variables` (except `{value}`). 5. **`{value}` is present** for non-`Trigger` types and absent for `Trigger`. 6. **`Integer`/`Float` have a real `Min`/`Max`** (not `0,0`). 7. **JSON-in-JSON is escaped**: bodies and regexes containing `"` and `\` use `\"` and `\\` inside the file's string. 8. **Body is empty** for `GET`/`DELETE`; `Content-Type` header set when a JSON body is sent. 9. **File name = intended parameter label**, ending in `.json`. State it clearly. 10. **One file per parameter.** Return each in its own code block, named. --- ## 8. Quick reference — allowed values - `Info.RequestType`: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `Variable` - `Info.Type`: `Trigger`, `Toggle`, `String`, `Integer`, `Float` - `Info.FeedbackType`: `None`, `Confirm on status 2xx`, `Regex match value`, `Confirm on regex match` - `Variables[].Type`: `String`, `Int`, `Float`, `Binary` - Built-in placeholder: `{value}` (all types except `Trigger`) - Escape literal braces: `\\{` and `\\}` (in the JSON file)