Ecobee Thermostat (Cloud)
GEM controls Ecobee smart thermostats through Ecobee's cloud REST API at api.ecobee.com. One GEM device represents one Ecobee homeowner account; every thermostat registered to that account becomes a Climate zone underneath it. The link is established once, through Ecobee's PIN authorization, after which GEM keeps itself signed in automatically — there is nothing to re-enter on a server restart unless the pairing is revoked.
This is a cloud integration: there is no LAN/local path. The GEM server needs outbound internet access to reach Ecobee.
What's controlled
- Per-thermostat heat and cool setpoints, with an automatic gap (deadband) kept between them.
- System mode —
auto/cool/heat/off. - Fan mode —
auto/on. - Live feedback published back onto each zone: current temperature, relative humidity, the active heat/cool setpoints, the running system and fan mode, and the thermostat's online/offline state.
Prerequisites
- An Ecobee homeowner account with at least one thermostat already commissioned in the Ecobee app (if it shows up in the app, GEM can reach it).
- A developer API key. Register a developer application at
https://www.ecobee.com/developersand set its Authorization Method to ecobee PIN. The application's API key is what you paste into GEM. - Access to the homeowner account during setup, to type the pairing PIN into Ecobee's web portal.
- Outbound HTTPS (port 443) from the GEM server to
api.ecobee.com.
Setup
1. Add the device
- Open Devices and add a new device of type Ecobee Thermostat.
- In the API Key field, paste the developer API key from your Ecobee developer application. This is stored encrypted.
- Save the device.
2. Pair with the homeowner account (one time)
The first link uses Ecobee's PIN flow. You start it from GEM, then approve it in Ecobee's web portal.
- Run the
authorizecommand against the device — from the device's command list, the Commands screen, or the Script Console. - GEM generates a pairing PIN and shows it to you. The same value also lands in the device's read-only Authorization PIN attribute and is emailed to the site's mail recipient.
- Within about three minutes, sign in to the Ecobee web portal, open My Apps → Add Application, enter the PIN, and confirm/add the application.
- GEM polls Ecobee every few seconds in the background. As soon as you approve the PIN, it
fills in the read-only Access Token and Refresh Token attributes and begins
syncing. The PIN is single-use — if you miss the three-minute window, run
authorizeagain for a fresh one.
After the first successful pairing, GEM only needs the Refresh Token to reconnect. You do
not run authorize again on reboots or reloads. Re-authorize only if you removed GEM's
application from the Ecobee account, or re-paired the same account elsewhere (which revokes
the old refresh token).
3. Create one zone per thermostat
Zones are not created automatically — you add one Climate zone for each thermostat.
- Run
get_thermostatsagainst the device to list everything on the account. The response is keyed by both the thermostat's identifier and its name. - Open Zones and create a zone under the Climate subsystem for each thermostat.
- Set the zone Address to that thermostat's identifier or its name exactly as
it appears in the
get_thermostatsoutput. Either works; the name must match character-for-character.
Once a zone's address matches, GEM starts populating its temperature, humidity, setpoints, mode and fan attributes on the next poll (within ~3 minutes), and the standard climate controls light up in the UI.
Attribute reference
Device attributes
| Attribute | Required | Type | Default | Notes |
|---|---|---|---|---|
api_key | yes | string (secure) | — | Developer API key from the Ecobee developer portal. |
pin | auto | string (read-only) | — | Pairing PIN produced by authorize; you type this into Ecobee's web portal. |
token | auto | string (secure, read-only) | — | OAuth access token. Filled in and rotated automatically. |
refresh_token | auto | string (secure, read-only) | — | OAuth refresh token. This is what lets GEM reconnect without re-pairing — do not clear it. |
hold_type | no | string | indefinite | How long a setpoint hold lasts. One of indefinite, nextTransition, dateTime, holdHours. |
Zone attributes
| Attribute | Required | Type | Notes |
|---|---|---|---|
address | yes | string | Thermostat identifier or name on the Ecobee account. Run get_thermostats to list valid values. |
deadband | no | int (°F) | Minimum gap GEM enforces between the heat and cool setpoints. If unset, the Climate subsystem's deadband default is used. |
The driver keeps the following feedback attributes in sync on each zone automatically — you do
not set them by hand: temperature, humidity, heat_setpoint, cool_setpoint,
system_mode, fan_mode, and the connected (online) flag. It also publishes
system_modes (auto/cool/heat/off) and fan_modes (auto/on) so the admin UI
renders the correct pickers.
All temperatures and setpoints are whole degrees Fahrenheit — Ecobee's API is Fahrenheit-based and the driver does not convert to Celsius.
Commands
These target a Climate zone; GEM supplies the thermostat address from the zone, so in a macro you only provide the values below.
| Command | Args | Notes |
|---|---|---|
authorize | — | Starts the one-time PIN pairing and returns the PIN to enter at Ecobee's web portal. |
setpoint | mode (heat/cool), setpoint | Applies a hold at the target temperature (whole °F). GEM writes both heat and cool setpoints, keeping them at least the deadband apart, and the hold lasts according to hold_type. |
system_mode | mode (auto/cool/heat/off) | Sets the thermostat's HVAC mode. |
fan_mode | mode (auto/on) | Sets the fan mode. Speeds beyond auto/on are not supported on all models. |
get_thermostats | — | Lists every thermostat on the account; use it to find a zone's Address. |
get_system_mode | — | Listed for completeness but not currently wired — the live mode is already published to the zone's system_mode attribute, so read it there instead. |
How control works
Setpoints and the deadband. When you set a heat (or cool) setpoint, GEM also derives
the opposite setpoint so the two stay at least the deadband apart — e.g. with a 3° deadband,
setting cool to 72 nudges heat to 69. The pair is applied as a single Ecobee hold. The
deadband comes from the zone's deadband attribute, falling back to the Climate subsystem
default.
Hold duration. Every setpoint change is sent as a hold whose length is the device's
hold_type:
indefinite(default) — holds until you clear it on the thermostat or send a new value.nextTransition— holds until the thermostat's next scheduled program change, then resumes the schedule.dateTime/holdHours— Ecobee's timed-hold modes.
If a setpoint "takes" and then reverts a while later, the thermostat's schedule resumed —
switch hold_type to indefinite to make manual changes stick.
Polling and tokens. GEM refreshes thermostat state about every 3 minutes, so feedback (temperature, humidity, mode, setpoints) reflects the thermostat within that window. The access token is renewed roughly every 50 minutes using the stored refresh token; this is automatic and invisible to the integrator.
Known limitations
- Cloud only. No local/LAN control — the integration depends on internet reachability to
api.ecobee.com. - Holds, not schedules. GEM applies temporary holds; it does not edit the thermostat's comfort schedules, comfort profiles (Home/Away/Sleep), or vacation events.
- Fan is
auto/on. Multi-speed fan control is not exposed and is not supported on all models. - No remote-sensor or equipment-runtime detail. Per-room occupancy sensors and stage/equipment runtime data are not surfaced as attributes.
- Fahrenheit only. Setpoints and readings are whole °F; there is no Celsius mode.
get_system_modeis a no-op — use the polledsystem_modezone attribute instead.
Troubleshooting
| Symptom | Check |
|---|---|
authorize returns no PIN | The API Key must belong to a developer application whose authorization method is ecobee PIN. Re-check the key and the app's setting in the Ecobee developer portal. |
| PIN entered but nothing links | The PIN expires about three minutes after authorize. Run authorize again and enter the fresh PIN promptly. |
unmatched ecobee thermostat address in the device log | A zone's Address doesn't equal any thermostat identifier or name on the account. Run get_thermostats and copy an exact value. |
| Zone shows disconnected | The thermostat is offline to Ecobee's cloud (no Wi-Fi or power). GEM mirrors the thermostat's online state; restore the thermostat's connection. |
| Setpoint accepted but reverts later | A thermostat schedule resumed. Set hold_type to indefinite, or place the hold on the thermostat itself. |
| Feedback stopped updating after about an hour | Token refresh failed — usually because the refresh token was revoked (the account was re-paired elsewhere, or GEM's app was removed). Reload the device; if it still can't refresh, re-run authorize. |
See also
- Zones — create one Climate zone per thermostat; the zone Address is the thermostat identifier or name.
- Subsystems — set the Climate subsystem's deadband default used when a zone has none.
- Devices — where the Ecobee account device is added and
authorizeis run. - Commands — where
setpoint,system_mode, andfan_modeare dispatched and wired into macros.