Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Switchbot Frame Laravel Package

spaanproductions/laravel-switchbot-frame

A self-contained Laravel + Livewire admin page for the SwitchBot AI Art Frame: upload photos, optimize them for the E Ink Spectra 6 panel, push them to the frame, read real battery levels via webhook, and optionally generate art with AI.

View on GitHub
Deep Wiki
Context7

Getting Started

This package wires a Laravel app to a SwitchBot Frame (the e-ink style display) and adds an "AI Studio" layer on top of laravel/ai so you can generate or improve images with a prompt and push the result to the device.

composer require spaanproductions/laravel-switchbot-frame
php artisan vendor:publish --tag="switchbot-frame-config"

Then set the credentials it expects — SwitchBot API token/secret plus whatever laravel/ai provider keys you already use — and run any published migrations if your install persists generated images or usage records.

Where to look first, in order:

  1. config/switchbot-frame.php — device identifiers, storage disk, AI defaults (model, image size), and the usage/cost knobs.
  2. The service provider / facade — this is the surface you actually call from controllers and jobs.
  3. The AI Studio classes — the generation, prompt-improvement, and usage-recording pipeline lives here; read it before assuming how errors propagate (see Gotchas).
  4. composer.json of the package — check which laravel/ai major you're resolving, because 1.4.0 supports both ^0.11 and ^1.0 and the internals branch on it.

First use case worth shipping: a queued job that takes a prompt, generates an image, and pushes it to the frame. Do this on a queue from day one — generation is slow, and you want retries and timeouts under your control rather than inside a web request.

GenerateFrameImage::dispatch($prompt, $frameId);

If you only want to push existing artwork to the device, skip the AI Studio entirely and use the upload/send path directly — it's the smaller surface and has fewer moving parts.

Implementation Patterns

Treat generation as a job, not a request. Image generation + upload routinely exceeds sensible HTTP timeouts. Dispatch a job, return a placeholder record, and let the frame update land asynchronously. Give the job $timeout and $tries that reflect real provider latency, and use WithoutOverlapping keyed on the frame ID so two jobs can't fight over the same device.

Separate "prompt improvement" from "image generation". The package applies an improved prompt as a distinct step (and 1.4.0 explicitly guarantees that an improved prompt is still applied even if bookkeeping fails). Model this as two calls in your own code so you can review/approve the rewritten prompt, cache it, or re-use it across several generation attempts without paying for the improvement twice.

Read usage off the result, not out of the database. The package records token usage, model name, and an estimated cost, but you should treat your own captured usage as the source of truth. Capture what the call returns and persist it in your own table if billing or per-tenant quotas matter:

$result = $studio->generate($prompt);

Usage::create([
    'team_id'        => $team->id,
    'model'          => $result->model,
    'input_tokens'   => $result->usage->inputTokens  ?? $result->usage->promptTokens,
    'output_tokens'  => $result->usage->outputTokens ?? $result->usage->completionTokens,
]);

Normalise the laravel/ai version boundary in one place. 0.x reports promptTokens/completionTokens; 1.x reports inputTokens/outputTokens and adds ImageUsage. If you're writing your own usage reader, put the ?? fallback in a single helper rather than scattering it. Pin the major in composer.json unless you deliberately want the matrix — the package handles both, your code may not.

Multi-frame / multi-tenant. Key everything on a frame identifier from config or your own model, and pass it explicitly rather than relying on a global default. It makes tests trivial and lets one app drive a lobby display and a home frame without config gymnastics.

Dashboard/budget integration. 1.4.0 suggests spaanproductions/laravel-ai-usage for a token/cost dashboard with budgets. If you need spend visibility, install that rather than building your own aggregation — the package's own bookkeeping is deliberately best-effort and not a reporting system.

Test with fakes. Http::fake() around the SwitchBot calls plus a fake AI response object means you can assert on the prompt sent and the payload pushed to the device without hitting either API. Assert on the shape of the usage object for both laravel/ai majors if you support both — that's the code most likely to break silently.

Gotchas and Tips

Bookkeeping failures are silent by design. As of 1.4.0, token usage, model name, and cost estimation are rescued without being reported. That's the right call for UX — a generated image still ends up marked ready and an improved prompt still applies — but it means you cannot assume your usage rows exist. If you need auditability, record usage yourself and treat the package's numbers as a convenience. Equally, don't debug "missing cost data" by looking for an exception in your logs: there isn't one. Add your own logging around the call if it matters.

Cost is an estimate, not an invoice. It's derived from token counts and a model price table. New models, cached input pricing, or image-token accounting will drift. Reconcile against provider billing before you show customers a number.

Image "ready" is not the same as "delivered". The lifecycle distinguishes generated/ready from pushed-to-device. If your UI says "done" on ready, users will see stale frames. Poll or listen for the delivery step.

Retries can double-bill. A queue retry re-runs generation. Combine $tries with idempotency on your side — check whether an image already exists for the prompt/job before regenerating, or accept the cost knowingly.

Version skew between the two laravel/ai majors. ImageUsage only exists on 1.x. Any code that reads usage->imageUsage unconditionally will blow up on 0.11, and any code that reads promptTokens will be null on 1.x. Guard with property_exists/isset, or pin.

Device constraints bite later. e-ink frames are picky about aspect ratio, colour depth, and file size, and the upload path usually needs a publicly reachable URL or a signed temporary one. If images render locally but not on the device, check the storage disk visibility and APP_URL before you check the AI output.

Config caching hides env changes. After editing credentials or model defaults, remember php artisan config:clear — the classic "it worked in tinker" trap.

Extension points to prefer. If the package exposes events around generation/upload, hook those rather than subclassing internals; the AI Studio internals are exactly what changed in 1.4.0 and are the most likely thing to change again. Anything you build on public facade methods and events will survive the laravel/ai bump.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox