一键导入
hubitat-sandbox-pitfalls
Avoid Hubitat sandbox and HTTP client failures caused by cross-@Field initializers, blocked JDK APIs, and non-standard content types.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Avoid Hubitat sandbox and HTTP client failures caused by cross-@Field initializers, blocked JDK APIs, and non-standard content types.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Pattern for keeping a rolling temperature-trend sample buffer in Hubitat state, computing slope over a configurable window, and classifying rising/falling/steady/unknown.
Implement Tuya Local v3.3 Groovy drivers on Hubitat using rawSocket, AES-128-ECB, queued retries, and defensive frame parsing.
Use Hubitat async HTTP plus a request queue to authenticate with Cognito, cache tokens in state, refresh proactively, and replay a single 401-failed request.
When two agents produce overlapping skills in one session, consolidate by merging unique content into the highest-confidence existing skill.
Never let cached-state dedup bypass session validity in cloud-backed Hubitat drivers.
Standard guard pattern for async HTTP response callbacks in Hubitat drivers
| name | hubitat-sandbox-pitfalls |
| description | Avoid Hubitat sandbox and HTTP client failures caused by cross-@Field initializers, blocked JDK APIs, and non-standard content types. |
| domain | groovy |
| confidence | high |
| source | earned |
This skill applies when editing Hubitat drivers that use top-level @Field static final constants, JDK utility APIs, or Hubitat HTTP helpers that must talk to APIs with non-standard wire Content-Type requirements.
@Field static final initializers in Hubitat drivers MUST NOT reference any other @Field constant — not via GString ${X}, not via concatenation + X, not at all. Inline literals or compute the derived value inside a method body.System.*, Thread.*, Runtime.*, reflection helpers, and file I/O. Prefer Hubitat builtins such as now(), pauseExecution(ms), runIn, runEvery*, state, atomicState, http*, and log.*.application/json, application/x-www-form-urlencoded, and text/xml. If the target API requires another wire content type, pre-serialize the body to a String and set the real wire Content-Type in headers, while leaving contentType / requestContentType as application/json.Hubitat's asynchttpPost / asynchttpGet / httpPost only have body encoders for application/json, application/x-www-form-urlencoded, and text/xml. If your target API requires an unusual Content-Type (AWS services use application/x-amz-json-1.1 and similar), you MUST pre-serialize the body to a String yourself and pass it via body: jsonString. Then set the wire Content-Type via the headers map. Use contentType: "application/json" in the params solely to keep Hubitat's encoder check happy — it won't actually be used. Set requestContentType: "application/json" too for compatibility across Hubitat versions.
| Avoid | Use instead |
|---|---|
System.currentTimeMillis() | now() |
new Date() | new Date(now()) |
Thread.sleep(ms) | pauseExecution(ms) |
Thread.*, executors | runIn, runEvery1Minute, runEvery5Minutes, etc. |
System.out.*, System.err.* | log.info, log.warn, log.error, log.debug |
reflection / Class.forName / .getClass() tricks | direct type references or explicit branching |
File, Files, java.nio.* writes | state, atomicState, HTTP, or preferences |
UUID.randomUUID() when sandbox behavior is uncertain | a now()-based id helper |
non-standard wire Content-Type (for example AWS application/x-amz-json-1.1) | pre-serialize body to a JSON String, put the real header in headers, keep contentType / requestContentType at application/json |
System., Thread., Runtime., Class., .getClass(, Date.parse, new Date(), File(, Files., Eval., GroovyShell, GroovyClassLoader, MetaClass, and .eval(.drivers/gemstone-lights/gemstone-lights.groovy
@Field static final String USER_AGENT = "Hubitat Gemstone Lights/0.2.5"private Long currentEpochSeconds() { Math.round(now() / 1000.0d) as Long }return "hubitat-${now()}-${nextSequence}"body: JsonOutput.toJson(payload) with wire Content-Type set in headers and Hubitat contentType kept at application/json@Field static final String USER_AGENT = "Hubitat Gemstone Lights/${DRIVER_VERSION}"@Field static final String USER_AGENT = "Hubitat Gemstone Lights/" + DRIVER_VERSIONSystem.currentTimeMillis() in auth/session helpersUUID.randomUUID() in driver code when a now()-based id is sufficient