homebridge-smartthings-scenes
v1.0.1
Published
Expose SmartThings scenes (aka Routines) as Switch accessories for Home app automations.
Maintainers
Readme
homebridge-smartthings-scenes
Expose Samsung SmartThings scenes as Switch accessories in Homebridge (the plugin calls POST /v1/scenes/{sceneId}/execute). Use them in Home automations—for example: When [Routine switch] turns On → your SmartThings scene runs.
On startup the plugin logs all scenes (GET /v1/scenes, merged global and per-location lists); each switch runs the matching scene by name (or optional sceneId).
Two separate steps
| Step | Where | What you do |
|------|--------|----------------|
| 1. One-time OAuth setup | Your own computer (any machine with Node; not Homebridge-specific) | Start the OAuth helper, open its web form at http://127.0.0.1:38400/, and follow the steps there with ngrok and the SmartThings CLI to create the app and obtain Client ID, Client Secret, access token, and refresh token. Use the form’s Exchange code (via this server) for tokens (optional curl fallback). |
| 2. Plugin configuration | Homebridge—usually the web UI (Homebridge UI / Config UI X) | Open this plugin's settings and copy/paste those values into the matching fields, add your routine names, and save. Homebridge runs the plugin only; it does not run the Express OAuth server for normal operation. |
OAuth gives long-lived access. SmartThings requires an HTTPS redirect URI for registration (not localhost), which is why the one-time step uses ngrok (or similar) to reach the local helper.
Requirements
- A SmartThings account with scenes you want to run from Home (names must match what the API returns—see startup logs)
- ngrok (or equivalent) for HTTPS during OAuth setup
- Node.js (see
package.jsonengines)
The SmartThings CLI is needed to create the OAuth app. Install is optional: use npx @smartthings/cli … (downloads the CLI on demand) or install globally / via Homebrew—see SmartThings CLI — Get started. Authentication uses the CLI's browser login when a command needs your account (or a Personal Access Token in config—see those docs).
Install the plugin
npm install -g homebridge-smartthings-scenesIf you use Homebridge Config UI X, you can search for the plugin and install it from the UI instead.
What the plugin needs for SmartThings API calls
The plugin talks to Samsung's REST API (GET /v1/scenes to list scenes, POST /v1/scenes/{sceneId}/execute to run one). Everything required for authentication and for choosing which routines to run is set in the plugin config (Homebridge UI or config.json).
Fixed in code (not configurable)
| Item | Value |
|------|--------|
| API | https://api.smartthings.com/v1 (locations, scenes) |
| OAuth token endpoint | https://api.smartthings.com/oauth/token (used for authorize + refresh) |
You do not need to enter URLs for those unless we add optional overrides in a future version.
Set in plugin config (typical copy-paste setup)
| Config key | Used for |
|------------|----------|
| clientId | OAuth client id — required to refresh the access token |
| clientSecret | OAuth client secret — required for refresh |
| accessToken | Bearer token on every SmartThings API request (Authorization: Bearer …) |
| refreshToken | Refresh token grant with client id/secret when the access token expires |
| tokenExpiresInSeconds | Recommended. Paste expires_in from the token response (e.g. 86399) so the plugin knows when to refresh. Stays valid across token refreshes (each new access token uses the same typical lifetime). |
| routines | Required. Which scenes to expose; each entry is { "name": "…" } (scene name) or { "name": "…", "sceneId": "…" } to skip name lookup |
Together, client id + secret + access token + refresh token are what SmartThings expects for ongoing API access and token renewal. After a successful first start, tokens may be stored on disk (smartthings-tokens.json under your Homebridge storage path); you can keep accessToken / refreshToken in config or rely on the file—see below.
Optional (different setup path)
| Config key | Used for |
|------------|----------|
| redirectUri | Only if you do not paste tokens and instead use the plugin's browser OAuth flow (ngrok + port 38521). Not needed when you use the OAuth helper web form and paste tokens into Homebridge. |
Summary
For invoke scene via API after your one-time OAuth setup, put clientId, clientSecret, accessToken, refreshToken, tokenExpiresInSeconds (recommended), and routines in the plugin configuration. That is the full set of values the plugin reads to authenticate and call the Scenes API.
One-time setup: SmartThings OAuth app and tokens
Do this once on a machine where you can run Node, ngrok, and the CLI (your laptop is fine; it does not have to be the Homebridge host). Primary path: use the OAuth helper web form in your browser—do not rely on hand-built URLs or terminal curl unless you prefer to.
When you are done, copy the values into the plugin in the Homebridge UI.
- Run the local OAuth helper (see below), expose it with ngrok, and open
http://127.0.0.1:38400/(the web form). - Fill in the form (ngrok URL, Client ID / Secret from the CLI) and use the SmartThings CLI to create the OAuth-In App with the Target URL and Redirect URI the form shows.
- In the browser: confirm the webhook (confirmation URL), then authorize the app using the form’s OAuth authorize URL (Open in new tab—see §5).
- In the web form, Exchange code (via this server) to turn the authorization
codeinto access and refresh tokens (see §6). Alternative:curlif you want a manual copy-paste flow. - In the Homebridge web UI, open Plugins → this plugin → settings (or edit JSON) and paste Client ID, Client Secret, access token, and refresh token into the fields described below.
Which Samsung / SmartThings account to use in the browser
Whenever a step opens smartthings.com or asks you to sign in with Samsung (CLI flow, confirmation link, or OAuth redirect), use the same Samsung account you use for the SmartThings mobile app on your phone (iOS or Android). That login is your SmartThings identity: locations, devices, and manually-run routines all live under that account.
If you have more than one Samsung account, pick the one that actually has your SmartThings home and routines—not a work-only or unused Samsung ID.
Why a local server?
Samsung's Developer Workspace "Register app" flow targets Lambda or webhooks, which does not match what this plugin needs. Creating an OAuth-In App with the CLI is the approach that works. SmartThings will POST to your app's Target URL (/smartthings) during registration and redirect the browser to your Redirect URI (/callback) after you authorize.
1) Start the OAuth helper and open the web form
The helper is a small Express app in the oauth-tools folder. It is included in this repository and in the published npm package. This is where you collect Client ID, Secret, authorize Samsung, and exchange the code for access + refresh tokens—work in the browser UI, not only on the command line.
If you cloned this repository (or downloaded the source):
cd /path/to/homebridge-smartthings-routines
npm install
npm run oauth-serverIf you installed the plugin globally and did not clone the repo:
cd "$(npm root -g)/homebridge-smartthings-scenes"
npm run oauth-serverThe default port is 38400. Override with SMARTTHINGS_OAUTH_PORT if needed. When the server starts, it opens this URL in your default browser; set OPEN_OAUTH_BROWSER=0 to skip (e.g. SSH without display).
If the browser did not open, go to http://127.0.0.1:38400/ manually. The web form (wizard) walks you through: ngrok URL, Target URL / Redirect URI for the CLI, OAuth authorize URL (with Open in new tab), Exchange code (via this server) for tokens (no browser CORS), optional curl copy, and a Homebridge JSON snippet.
When the server starts, it also prints step-by-step hints in the terminal.
2) Start ngrok
In another terminal:
ngrok http 38400Use the HTTPS URL ngrok shows (for example https://abc123.ngrok-free.app). You will use:
- Target URL:
https://YOUR-NGROK-HOST/smartthings - Redirect URI:
https://YOUR-NGROK-HOST/callback
3) Create the OAuth app (SmartThings CLI)
From the same machine where you run npm run oauth-server (repository root is fine). Current CLI versions do not ship a separate smartthings login command—sign-in happens in the browser when you run a command that needs your Samsung account.
npx --yes @smartthings/cli apps:create(From a clone of this repo you can instead run npm run smartthings:apps:create, which runs the same npx command.)
When prompted:
| Prompt | Value |
|--------|--------|
| App type | OAuth-In App |
| Display name | e.g. Homebridge Routines |
| Description | Short description |
| Target URL | https://YOUR-NGROK-HOST/smartthings |
| Redirect URIs | https://YOUR-NGROK-HOST/callback |
| Scopes | r:locations:* x:locations:* r:scenes:* x:scenes:* (read + execute for scenes; no w: write scopes—same string as in plugin auth.ts) |
If you change scopes on an existing OAuth app, run authorize + token exchange again so the new scopes are granted.
Save the Client ID and Client Secret immediately; the secret may not be shown again.
4) Confirm registration (webhook only)
Watch the terminal running the OAuth helper.
- You should see a POST
/smartthingspayload. If SmartThings sends a confirmation URL, open it in a browser signed in with the same Samsung account as your SmartThings app (see Which Samsung / SmartThings account above). - A JSON body like
{"targetUrl":"https://…/smartthings"}means webhook registration succeeded. There is no OAuth consent screen on this step—that is normal.
5) Authorize the app (OAuth — this is where you "allow" access)
This is a separate step. Confirming the webhook does not show the OAuth permission screen. You must open SmartThings' authorize URL so Samsung can redirect to your /callback with a code.
Recommended: in the web form, open wizard step 3 — URLs for the app & OAuth, use the OAuth authorize URL box, and click Open in new tab—the URL is built with the correct client_id, redirect_uri, and scopes.
Manual URL (advanced): with oauth-server still running and ngrok still pointing at the same port, open a new browser tab and visit (replace placeholders):
https://api.smartthings.com/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI_URL_ENCODED&scope=r%3Alocations%3A*%20x%3Alocations%3A*%20r%3Ascenes%3A*%20x%3Ascenes%3A*&state=anyrandomstringYOUR_CLIENT_ID— from the CLI when you created the app (same as in Homebridge config later).YOUR_REDIRECT_URI_URL_ENCODED— must match the Redirect URI you registered exactly, URL-encoded.
Example:https://yttriferous-unmovable-cristen.ngrok-free.dev/callback→https%3A%2F%2Fyttriferous-unmovable-cristen.ngrok-free.dev%2Fcallback
You can build the query string in one line with Node (run from any directory):
node -e "const p=new URLSearchParams({response_type:'code',client_id:'YOUR_CLIENT_ID',redirect_uri:'https://YOUR-NGROK-HOST/callback',scope:'r:locations:* x:locations:* r:scenes:* x:scenes:*',state:'x'}); console.log('https://api.smartthings.com/oauth/authorize?'+p)"Paste the printed URL into the browser. You should get Samsung / SmartThings sign-in (if needed) and a screen to approve the requested permissions. Then the browser is redirected to https://YOUR-NGROK-HOST/callback?code=... — your OAuth helper terminal logs that code.
6) Exchange the code for tokens
Use the web form: in the OAuth helper page, wizard step 5 — Exchange code for tokens, click Exchange code (via this server). The browser sends your credentials to the local Express server, which calls SmartThings (POST /oauth/token) and puts the JSON response in the text area (no browser CORS). On success, the form can apply tokens to the Homebridge JSON snippet; copy access_token, refresh_token, and expires_in into the plugin config.
Optional — curl: if you prefer the terminal, use curl from the same machine (the form shows the exact command):
Replace placeholders with your values. redirect_uri must match the Redirect URI exactly (URL-encoded).
curl -X POST "https://api.smartthings.com/oauth/token" \
-u "CLIENT_ID:CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code&code=CODE_FROM_CALLBACK&redirect_uri=ENCODED_REDIRECT_URI"The JSON response includes access_token, refresh_token, and expires_in. Copy those into Homebridge (or use the paste flow in the web form).
Configure Homebridge (web UI or JSON)
Recommended: use the Homebridge web interface (e.g. Homebridge UI / Config UI X). Install the plugin from the Plugins tab, then open this plugin's settings form. Each field matches the values from the one-time setup—paste Client ID, Client Secret, Access token, Refresh token, and optionally Token expiry (seconds) (expires_in from the OAuth helper token JSON or curl response, often 86399). Add Routines with names that match your SmartThings scene names (same strings as in the startup log).
You do not need to run the OAuth Express server on your Homebridge machine for day-to-day use.
Editing config.json directly
If you prefer raw JSON, add a platform block to ~/.homebridge/config.json (or the path your UI uses). Use the exact scene names from the SmartThings app (Automation → Scenes, or as listed at startup).
{
"platforms": [
{
"name": "SmartThings Routines",
"platform": "SmartThingsRoutines",
"clientId": "YOUR_CLIENT_ID",
"clientSecret": "YOUR_CLIENT_SECRET",
"accessToken": "YOUR_ACCESS_TOKEN",
"refreshToken": "YOUR_REFRESH_TOKEN",
"tokenExpiresInSeconds": 86399,
"routines": [
{ "name": "Good Morning" },
{ "name": "Good Night" }
]
}
]
}clientId/clientSecret— From the OAuth app; required so the plugin can refresh the access token.accessToken/refreshToken— From the OAuth helper Exchange code response (or curl). On first successful start, the plugin may copy them tosmartthings-tokens.jsonunder your Homebridge storage path; you can remove them from the UI/config afterward if you prefer secrets only on disk.tokenExpiresInSeconds— Recommended:expires_infrom the token response (often86399). Does not need updating when tokens refresh.
Optional: browser OAuth from Homebridge (no pasted tokens)
If you omit accessToken and refreshToken, you can set redirectUri to your HTTPS callback (for example https://YOUR-NGROK-HOST/callback) and start Homebridge on a machine where a browser can open. The plugin runs a small local callback server on port 38521 and can open SmartThings login—point ngrok at 38521 for that flow (different from the OAuth helper on 38400).
After linking, restart Homebridge when prompted. Most users will use the copy-paste flow above instead.
Configuration reference
Same fields appear in the Homebridge UI plugin form and in config.json. Paste values from the one-time OAuth setup.
| Field | Required | Description |
|-------|----------|-------------|
| name | Yes | Platform display name |
| platform | Yes | Must be SmartThingsRoutines (set automatically in the UI) |
| clientId | Yes | OAuth app client ID (CLI) |
| clientSecret | Yes | OAuth app client secret |
| routines | Yes | At least one routine to expose |
| accessToken | No* | Paste with refreshToken from the OAuth helper token JSON or curl |
| refreshToken | No* | Paste with accessToken |
| tokenExpiresInSeconds | No | OAuth expires_in (seconds), e.g. 86399 — stable across refreshes |
| redirectUri | For in-plugin OAuth only | HTTPS callback; omit if using pasted tokens |
*If both access and refresh are omitted, set redirectUri and use the in-plugin browser flow instead.
Each routine object:
name(required) — Must match a scene name from the startup log ([scene] …).sceneId(optional) — If name matching fails, paste the UUID from logs or the SmartThings API to skip lookup.
Usage in the Home app
Each routine appears as a Switch. Example automation:
- When: [Your routine] turns On
- Then: …
The switch returns to Off after a short delay so automations can trigger "turn on" again later.
Troubleshooting
apiOnly.targetUrl is malformed / PatternError (HTTP 422) when creating the OAuth-In app
SmartThings validates the Target URL with a strict pattern. The CLI shows this when you finish Create OAuth-In SmartApp.
Check the following:
- Scheme — Must be
https://(nothttp://). No spaces before or after the URL. - Paste exactly what ngrok prints — e.g.
https://abc123.ngrok-free.app(your subdomain will differ). Do not add quotes in the CLI prompt. - Path — Use the callback path this plugin expects, with no trailing slash:
https://YOUR-NGROK-HOST/smartthings
If it still fails, try the same URL with a trailing slash (/smartthings/)—some validators are picky (use one style consistently everywhere: Target URL, Redirect URI, and later curlredirect_uri). - ngrok domain — Free tunnels sometimes use
*.ngrok-free.appor*.ngrok-free.dev. If one is rejected, start a new tunnel and try the other style, or use a reserved ngrok domain so the hostname stays stable and conventional. - OAuth helper running —
npm run oauth-servermust be up before registration so SmartThings can POST to/smartthings(validation may still fail withPatternErrorif the URL string alone is invalid—fix the URL first).
If the error persists, open the URL in a browser as https://YOUR-HOST/smartthings — you should not need a pretty page; you only need the tunnel to hit your local server. Then re-run npx --yes @smartthings/cli apps:create and enter the same Target URL again carefully.
redirect_uri could not be validated
The redirect URI in your OAuth app, in the curl -d string, and in config (if used) must match exactly (including trailing slashes, host, and HTTPS).
SmartThings CLI: invalid URL / undefined/apps
Some CLI versions need ~/.config/smartthings/config.yaml. See the CLI documentation or try:
default:
clientIdProvider:
baseURL: 'https://api.smartthings.com'
baseOAuthInURL: 'https://oauthin-regional.api.smartthings.com/oauth'
oauthAuthTokenRefreshURL: 'https://api.smartthings.com/oauth/token'
clientId: 'd18cf96e-c626-4433-bf51-ddbb10c5d1ed'Then run npx --yes @smartthings/cli apps:create again.
No scenes from the API (empty scene list on startup)
The plugin merges GET /v1/scenes (global) with per-location scene lists. If you see no scenes:
- Create or use scenes in the SmartThings app (Automation → Scenes, or equivalent).
- Use the same Samsung account in the app as the one used for OAuth.
- Token scopes must include
r:scenes:*andx:scenes:*for listing and execution; matchauth.ts.
Routine not found
Use the exact scene name from the startup log ([scene] Name — uuid). The plugin logs available scene names when a match fails.
Port already in use
- OAuth helper default: 38400 (override with
SMARTTHINGS_OAUTH_PORT). - In-plugin OAuth callback: 38521 — use
ngrok http 38521only for that flow.
Development
git clone https://github.com/davidjgonzalez/homebridge-smartthings-routines.git
cd homebridge-smartthings-routines
npm install
npm run build
npm link
homebridge -DWith debug enabled (-D or "debug": true in Homebridge config), startup logs include raw JSON for each GET /v1/scenes page (global and per-location) under [SmartThings raw scenes].
License
See LICENSE.
