بنقرة واحدة
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."