feat: catalog sync — Weather Station, Lock Vision, Lock Vision Pro, Smart Lock Pro Wifi, AI Art Frame uploadImage#47
Merged
Conversation
added 7 commits
May 15, 2026 22:38
- Weather Station (deviceType WeatherStation) — outdoor sensor with atmosphericPressure, temperature, humidity, battery, version - Lock Vision and Lock Vision Pro — video smart locks with the same destructive unlock guard as Smart Lock Pro; Pro variant adds deadbolt - Smart Lock Pro Wifi alias on the existing Smart Lock entry — Matter- enabled Lock Pro reports a different deviceType but identical control surface, so an alias avoids a parallel duplicate entry - AI Art Frame uploadImage <imageUrl> command — single https URL parameter, idempotent; documented assumption noted in CHANGELOG
LLM conditions now enforce per-rule and global budgets across three dimensions: hourly call count (existing), hourly token count (new), and daily USD cost (new). Costs are computed from a per-model pricing table; calls to models not in the table silently skip the cost dimension while still enforcing calls and tokens. - DecideResult.usage carries provider-reported tokensIn / tokensOut and a calculated costUsd. OpenAI and Anthropic providers populate this from their respective response shapes. - Schema v0.2 accepts max_tokens_per_hour and max_cost_per_day_usd on both per-rule budget and global automation.llm_budget. - Audit kind llm-condition now records llmUsage; llm-budget-exceeded records the dimension that tripped (calls | tokens | cost). - Two new lints: condition-llm-tokens-budget-zero (token cap of 0 always trips on_error) and condition-llm-cost-without-known-model (USD cap with provider:auto silently skips models without pricing). - The evaluator keeps backward compatibility: callers passing a single number still mean "global max_calls_per_hour".
Cross-event aggregation backed by the per-device history JSONL ring at
~/.switchbot/device-history/<deviceId>.jsonl. New helper queryEventWindow()
in src/devices/history-window.ts walks rotated files newest-first, applies
optional eventFilter, and bails when timestamps fall below sinceMs.
Two consumers share the same EventWindowFetcher abstraction in matcher.ts:
1. event_count condition (new oneOf branch in v0.2 schema):
conditions:
- event_count:
device: front-door
event: motion.detected
window: "5m"
min: 3
max: 10
Resolves alias to deviceId, parses duration, counts records inside
[now - window, now], fails when count is outside [min, max].
2. LLM recent_events hook (declared in v0.2 schema since Track kappa but
not wired): now populates context.recent_events with up to N latest
matching events on the trigger device.
LlmConditionEvaluator is finally wired into RulesEngine (previously only
simulate had it).
New lints: condition-event-count-bad-window, condition-event-count-max-below-min.
…allback
Many users want to keep LLM conditions on-device (privacy, latency, no
per-token cost, air-gapped). This adds first-class support for any
OpenAI-compatible /v1/chat/completions endpoint — Ollama, llama.cpp
server, vLLM, LM Studio.
Default behavior: assume the endpoint does NOT support OpenAI-style
tool use (the common reality for local models). decide() routes through
a structured-output prompt that asks the model for a JSON object
{"pass": bool, "reason": str} and parses it with a lenient extractor
that handles fenced code blocks and prose-wrapped JSON. If the first
response is not parseable, one repair retry is performed before failing.
Operators on tool-use-capable local endpoints can opt in via YAML
tool_use: true or SWITCHBOT_LOCAL_LLM_TOOL_USE=1.
Surface area:
- New LLMProvider.capabilities.toolUse flag (true for openai/anthropic,
configurable for local).
- New SWITCHBOT_LOCAL_LLM_URL / SWITCHBOT_LOCAL_LLM_MODEL /
SWITCHBOT_LOCAL_LLM_API_KEY env vars (defaults: ollama at
localhost:11434, llama3.2, no auth).
- New doctor check `local-llm-reachable` — only fires when policy uses
provider:local; probes the endpoint with a 3s GET and reports latency.
createLLMProvider('local', ...) now constructs LocalProvider rather
than reusing OpenAIProvider — this fixes the (already documented as a
gap) case where a local endpoint doesn't speak tool use.
… pipe
Closes the last Track kappa follow-up: long-running clients (notably
`mcp serve`) currently pay a Node.js cold-start cost on every invocation
because the rules daemon has no way to accept commands in-process. This
adds a minimal newline-delimited JSON-RPC 2.0 endpoint:
- POSIX: ~/.switchbot/daemon.sock, mode 0600
- Windows: \.\pipe\switchbot-daemon-<user> (per-user DACL)
The path helper, server, and client all live under src/daemon/. The
server binds when `switchbot rules run` finishes engine.start() and
unbinds on stop(). v1 methods exposed:
- daemon.status — pid, startedAt, rulesActive, globalDryRun
- daemon.ping — { ok: true, t }
- daemon.reload — drives the same path SIGHUP / sentinel use today
Wire protocol is one JSON message per line — trivial to speak from any
language without a Content-Length parser. The single-shot client opens
a connection per call, which keeps both sides stateless; pooling can be
added later for hot paths.
New doctor check `daemon-ipc` probes the socket when the daemon is
running and reports round-trip latency. When the daemon is stopped the
check is silently skipped (status: ok, applicable: false), so users
without a long-running daemon see no warnings.
mcp.<toolName> proxying via the daemon (for `mcp serve --via-daemon`)
is intentionally deferred — the transport itself is the load-bearing
piece, and routing MCP traffic through it is a separable layer that
can land in a follow-up without changing this surface.
…licy reference Updates docs to match the five MVPs already landed on this branch: - roadmap.md: refresh status header to 2026-05-15, add Track κ (already shipped on main) under "Completed tracks", and add the five in-flight MVPs (Track μ catalog sync + Track λ.1-λ.4 budget/aggregation/local-provider/IPC) under a new "In-flight" section. Replace the now-completed "Daemon mode" item in the next-execution queue with the follow-up "mcp serve --via-daemon". - policy-reference.md: add `event_count` row to the conditions table and a fields block describing window/min/max + the two lints that guard it. Expand the LLM condition block with `provider: local`, the new budget dimensions (max_tokens_per_hour, max_cost_per_day_usd), guidance for the SWITCHBOT_LOCAL_LLM_* env vars, the structured-output fallback for non-tool-use models, and the corresponding lints + audit records. Add the matching global llm_budget fields. agent-guide.md unchanged — these MVPs add no new MCP tools or plan/CLI surface; catalog additions are auto-discovered through schema export, and the daemon JSON-RPC surface is internal until the upcoming `mcp serve --via-daemon` proxy lands.
Brings README in line with the five MVPs already landed on this branch and documented in CHANGELOG / docs/policy-reference.md: - Conditions list adds event_count alongside time_between / device_state / llm. - LLM condition block now shows provider: local, the new max_tokens_per_hour and max_cost_per_day_usd budget dimensions, and the SWITCHBOT_LOCAL_LLM_URL / _MODEL / _TOOL_USE env vars (with structured-output fallback note for non-tool-use models). - Doctor check list adds daemon-ipc and local-llm-reachable, with a one-liner about when each fires. - Test count refreshed to 2465 in both the Features bullet and the Development section.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Catch up to upstream SwitchBot OpenAPI device additions:
lock/unlock(destructive,safetyReasonset)deadboltSmart LockaliasuploadImage <imageUrl>command (https-only)Catalog data only — no
CATALOG_SCHEMA_VERSIONbump.Branch also includes follow-up engine work landed as separate commits (USD/token budget for
llmconditions,event_countcondition +recent_eventshook, local / non-tool-use LLM provider, daemon JSON-RPC IPC). See individual commits for details.Test plan
npm test— 2465 passednpm run build— greennode dist/cli.js schema export --type "Weather Station"round-tripsnode dist/cli.js devices commands "AI Art Frame"showsuploadImageunlockstill requires--yes/confirm:true