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

Honeywell Client Laravel Package

fruitcake/honeywell-client

A PHP client for the Honeywell API, offering a simple, framework-friendly way to authenticate and interact with Honeywell devices and data. Wraps Honeywell endpoints in clean, testable classes so Laravel apps can query and manage connected systems without handling raw HTTP requests.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a thin PHP wrapper around Honeywell's Total Connect Comfort (TCC) web portal — the same account you use at mytotalconnectcomfort.com (or the .eu equivalent) to control T5/T6-class thermostats. It is not the OAuth2 "Honeywell Home / Resideo" developer API, so don't go create a Resideo developer app: you need the username/password of the end-user's TCC portal account.

Minimal path:

composer require fruitcake/honeywell-client

Before writing any code, read in this order:

  1. README.md — the constructor signature and credential names.
  2. src/ — there is very little of it; the client class and any request/response models are the whole API surface. Read them end-to-end, it takes five minutes.
  3. tests/ (if present) — the most reliable documentation of real method names and return shapes.

Because there's no documented Laravel service provider, wire it yourself. Keep credentials out of code:

// config/services.php
'honeywell' => [
    'username' => env('HONEYWELL_USERNAME'),
    'password' => env('HONEYWELL_PASSWORD'),
],
// app/Providers/AppServiceProvider.php
$this->app->singleton(\Fruitcake\Honeywell\Client::class, fn () => new \Fruitcake\Honeywell\Client(
    config('services.honeywell.username'),
    config('services.honeywell.password'),
));

First use case: list the devices on the account and dump the current temperature and setpoint for one thermostat. Run it from php artisan tinker. If you get a list of devices with per-device IDs and current readings, the hard part is done — everything else is setpoint and mode writes.

Implementation Patterns

Wrap it, don't sprinkle it. The package is a one-star, single-maintainer project on an undocumented consumer API. Treat it as an implementation detail behind your own interface so you can swap or fork it later:

interface ThermostatGateway
{
    public function state(string $deviceId): ThermostatState; // a small DTO
    public function setSetpoint(string $deviceId, float $celsius): void;
    public function setMode(string $deviceId, Mode $mode): void;
}

Bind your HoneywellGateway to the interface. Every call site in your app then talks to ThermostatState, not to the vendor's array shapes.

Read path: poll, cache, persist. The portal does not push. The standard pattern is a scheduled command that fetches state every 5–10 minutes, writes it to a thermostat_readings table, and dispatches a broadcast event if it changed:

Schedule::command('thermostats:poll')->everyTenMinutes()->withoutOverlapping();

Cache the raw device list for a couple of minutes on top of that so a dashboard page refresh doesn't trigger a portal login. Never call the client from a request cycle that a user can spam.

Write path: queue, validate, log. Setpoint writes go through a queued job so a slow/flaky portal doesn't block a web request, and so you get retries. Clamp values before sending (TCC-style thermostats generally accept 0.5 °C / 1 °F steps and a bounded range), and log every write with old value, new value and user — you will want that audit trail when someone claims the heating went to 30 °C at 3 a.m.

Debounce UI controls. A slider or +/- stepper in Livewire/Inertia will fire on every tick. Collapse to the final value with a debounce or a ShouldBeUnique job keyed on the device ID, otherwise you'll hammer the portal and get throttled.

Testing. Fake the gateway at your interface boundary for feature tests. For contract tests against the real client, mock the HTTP layer — if the package uses Guzzle, that's a MockHandler with recorded portal HTML/JSON responses; if it uses the Laravel HTTP client, Http::fake(). Record one real login response and one real device response early; those fixtures are your only protection against the portal changing its markup.

Integration sweet spots. A Livewire dashboard with "current temp / target temp / mode" per room, an alert when a room drops below a threshold for N minutes, a holiday-mode artisan command, and a nightly setback schedule that sets off or a low setpoint at 22:00 and restores at 06:00.

Gotchas and Tips

  • It's an unofficial scraper-ish client on a legacy API. One star, zero dependents, last release October 2022. Pin the exact version in composer.json, and budget for the reality that the next portal change breaks it with no upstream fix. Keep the fork path short by isolating it behind your own interface from day one.
  • Honeywell is steering users off TCC. Newer devices and accounts increasingly live in the Honeywell Home / Resideo OAuth API. Confirm the specific thermostat models you're targeting are actually manageable in the TCC portal before building anything. If they're not, this package is the wrong tool entirely.
  • Login is session-based, not token-based. Expect a cookie jar, a form POST, and a redirect. It typically breaks silently — an HTTP 200 with the login page HTML instead of data, or an error string in the body rather than an exception. Always assert on the parsed payload, never on "no exception thrown".
  • 2FA and password changes will kill it. If the account owner enables two-factor auth or rotates the password, the client stops working with an unhelpful error. Document this in your runbook.
  • US vs EU base URLs. European accounts use mytotalconnectcomfort.eu. If you get auth failures with correct credentials, check which host the client defaults to and whether you can override it.
  • Units are a trap. The portal mixes °F and °C depending on account settings and endpoint. Normalise to one unit at your gateway boundary and never let raw portal values reach your domain model.
  • Setpoint semantics depend on mode. In Heat the heat setpoint applies; in Cool the cool setpoint; in Auto both. Writing "the temperature" without setting the mode means the change may appear to do nothing. Always read-modify-write the full control payload rather than sending a single field.
  • The readings are stale by design. The thermostat only checks in with the cloud periodically. "Current temperature" can be 15+ minutes old. Don't build closed-loop control on it, and don't alert on a single reading — require N consecutive samples.
  • Rate limits are real and unannounced. Roughly one poll per 5 minutes per device is safe; per-minute polling will get you temporarily blocked. Use withoutOverlapping() and a RateLimited job middleware.
  • Debugging: log the raw HTTP request and response bodies behind a config flag. When something breaks, the failure is almost always in the login handshake or a changed form field name — the raw bodies tell you which in seconds.
  • Extension points are thin. There's no event system or pluggable transport to hook into, so the practical extension mechanism is subclassing the client or forking. If you need more than "read state / write setpoint / write mode", fork rather than fight it.
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.
abbasudo/artisan-route
mirvan/ippanel
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