ワンクリックで
hubitat-log-hygiene
Avoid flooding Hubitat's live-log view by curating catalog dumps, large lists, and error messages.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Avoid flooding Hubitat's live-log view by curating catalog dumps, large lists, and error messages.
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-log-hygiene |
| description | Avoid flooding Hubitat's live-log view by curating catalog dumps, large lists, and error messages. |
| domain | hubitat-drivers |
| confidence | high |
| source | earned |
Hubitat's live-log view has limited visible rows. A driver that emits a large list (dozens of preset/effect names) on every named-effect call floods the view, hiding useful diagnostic output.
log.debugWhen a driver loads or refreshes a lookup table (effect catalog, preset list, device inventory), emit only the count at log.debug. Never join() a collection of unknown size into a single log line — even at debug level, 1457 names is multi-KB of noise that floods the live log:
// BAD — even behind log.debug this is KBs of noise with 1457 entries
log.debug "[Gemstone] Other patterns (${otherNames.size()}): ${otherNames.join(', ')}"
// GOOD — count only; names are still discoverable via the warn-on-miss path
log.debug "[Gemstone] Other patterns: ${otherCount} non-favorite patterns available by name."
Small, curated sets (e.g. favorites — typically < 20) may still enumerate by name at log.debug:
// gemstone-lights.groovy — favorites line (small list, kept as-is)
log.debug "[Gemstone] Loaded ${count} effects. Favorites (${favoriteNames.size()}): ${favoriteNames ? favoriteNames.join(', ') : '(none)'}"
Also demote the "available effects" helper used in startup/refresh callbacks:
// gemstone-lights.groovy line 1818
log.debug "[Gemstone] Available effects: ${names ? names.join(', ') : '(none loaded)'}"
log.infoOn a successful lookup, emit a single concise info line — never the full catalog list.
// gemstone-lights.groovy line 900 (activateEffectByPattern)
infoLog "${device.displayName} effect → ${displayEffectName(resolvedName)}"
log.warn with cap at 20When a lookup fails, keep showing suggestions but:
log.info to log.warn… (N more) if truncated// gemstone-lights.groovy lines 1821–1828
private void warnAvailableEffectNames() {
List names = orderedEffectDisplayNames().sort()
Integer total = names.size()
List shown = total > 20 ? names.take(20) : names
String suffix = total > 20 ? ", … (${total - 20} more)" : ""
log.warn "[Gemstone] Available effects: ${shown ? shown.join(', ') + suffix : '(none loaded)'}"
}
Also clean up the error log line itself — don't embed the full inline join in the log.error string:
// gemstone-lights.groovy line 854 (activateEffectByName miss)
log.error "[Gemstone] No effect named '${requestedName}'."
warnAvailableEffectNames()
| Situation | Level | List? | Notes |
|---|---|---|---|
| Catalog loaded / large collection | log.debug | Count only | Even at debug, joining 1000+ names is multi-KB noise |
| Catalog loaded / small curated set | log.debug | Full join OK | Only when size is known-small (e.g. favorites < 20) |
| Effect found by name | log.info | None | One line: name → patternId |
| Effect NOT found by name | log.error + log.warn | Capped (20) | error = "not found"; warn = "available: …" |
| Index not found | log.error + log.warn | Capped (20) | Same pattern |
Confidence: medium
When a device API exposes 50+ items but the user only cares about a curated subset, filter the Hubitat capability attribute (e.g., lightEffects) to the curated subset. Keep the full set accessible via name-based commands so power users can still address everything.
lightEffects, numeric index), one for full name lookup (effectCatalog, effectPatterns).nextIndex for curated items (e.g., favorites). Non-curated items are still accessible by name via on-demand catalog fetch, but do NOT get persisted to state.effectCatalog or state.effectPatterns.setEffect(String), playEffectByName) resolve from the favorites cache first; on a cache miss, trigger an on-demand full catalog fetch (see hubitat-state-hygiene skill).setEffect(NUMBER) stay clean and short.// Favorites get a numeric slot (UI dropdown + setEffect(NUMBER)) AND are cached in state
favorites.each { displayName, patternId ->
effectCatalog[displayName] = patternId
effectPatterns[patternId] = ...
lightEffects[nextIndex.toString()] = displayEffectName(displayName)
effectIndex[nextIndex.toString()] = patternId
nextIndex++
}
// Non-favorites: count only — NOT written to state, NOT joined into a log line
Integer otherCount = 0
otherEntries.each { entry ->
if (safeString(entry.displayName)) {
otherCount++
}
}
log.debug "[Gemstone] Other patterns: ${otherCount} non-favorite patterns available by name."