Samsung SmartThings
GEM integrates with the Samsung SmartThings cloud as a controller — every device already paired in the SmartThings mobile app can be promoted to a GEM zone and controlled from macros, schedules, triggers, voice, or the UI. The driver speaks the public SmartThings REST API at https://api.smartthings.com with bearer-token (Personal Access Token, "PAT") auth.
Prerequisites
- A working Samsung SmartThings account with the mobile app set up, a SmartThings Hub (Aeotex, Aeotec, Samsung WiFi, V3 hub, or Station) or hub-less Wi-Fi devices on the account, and the devices you want to control already paired.
- Outbound HTTPS (port 443) from the GEM server to
api.smartthings.com. - A Personal Access Token from https://account.smartthings.com/tokens. PATs are tied to your SmartThings account; rotate yours whenever staff turns over.
Setup
- Sign in to https://account.smartthings.com/tokens and click Generate new token.
- Give the token a clear name (e.g.,
gem-<site>) and select the scopes:Devices— Read, Write, ExecuteLocations— ReadScenes— Read, Execute
- Copy the token immediately — Samsung does not show it again. If you lose it, you must mint a new one.
- In GEM, System → Devices → Add Device and pick driver
smartthings. - Paste the PAT into the
access_tokenattribute. Leaveapi_baseon the default. - Save and Reload the device. GEM logs
smartthings connected: <id> <name> devices: <n>when the PAT is accepted. - (Optional) Run the
get_locationscommand — note thelocationIdand set thelocation_idattribute to filter device enumeration to one location. - Run
get_devicesto enumerate paired devices, then create one GEM zone per device. Setzone.addressto the SmartThingsdeviceIdUUID. - (Optional) Run
get_scenesto enumerate scenes; trigger them withrun_sceneusing the scene UUID as the address.
Attribute reference
| Attribute | Required | Default | Description |
|---|---|---|---|
access_token | yes | — | SmartThings Personal Access Token (Bearer). Treated as a secret. |
api_base | no | https://api.smartthings.com | API endpoint. Only override if Samsung directs you to. |
location_id | no | — | Restrict get_devices / get_scenes to a single SmartThings location UUID. |
status_interval | no | 60000 | Status poll interval in ms. Lower for snappier UI; watch the 250 req/min cap. |
request_timeout | no | 15000 | Per-request HTTP timeout in ms. |
Zone address format
zone.address is the SmartThings deviceId — a UUID returned by get_devices. For scenes, the address is the scene UUID and the only valid command is run_scene.
Commands
The driver maps each GEM verb onto a SmartThings capability+command pair under component=main:
| GEM command | Capability | SmartThings command |
|---|---|---|
on / off | switch | on / off |
set_level | switchLevel (or windowShadeLevel for shades) | setLevel(level) / setShadeLevel(level) |
open / close | windowShade if shade, else doorControl | open / close |
stop | windowShade | pause |
lock / unlock | lock | lock / unlock |
arm_home / arm_away / disarm | securitySystem | armStay / armAway / disarm |
set_temperature | thermostatHeatingSetpoint or thermostatCoolingSetpoint (chosen from zone.system_mode) | setHeatingSetpoint / setCoolingSetpoint |
set_mode | thermostatMode | setThermostatMode(mode) |
set_fan_mode | thermostatFanMode | setThermostatFanMode(mode) |
set_volume / mute_on / mute_off | audioVolume / audioMute | setVolume / setMute |
play / pause | mediaPlayback | play / pause |
set_color_temperature | colorTemperature | setColorTemperature(K) |
set_hue / set_saturation | colorControl | setHue(%) / setSaturation(%) |
run_scene | — | POST /v1/scenes/{address}/execute |
raw_command | (caller-supplied) | (caller-supplied) — escape hatch for capabilities not in the table above |
get_devices, get_locations, get_scenes, and get_status return raw JSON from the SmartThings API for inspection and use in macros.
Status polling
The driver iterates Object.keys(self.zones) every status_interval ms and calls GET /v1/devices/{id}/status. The first matching capability sets zone.state:
switch.switch → lock.lock → contactSensor.contact → motionSensor.motion → doorControl.door → windowShade.windowShade → presenceSensor.presence → securitySystem.securitySystemStatus.
Additional attributes are surfaced when present: level, battery_level, temperature, humidity, illuminance, color_temperature, volume, mute_state, heating_setpoint, cooling_setpoint, system_mode, fan_mode, power_w, energy_kwh.
Known limitations
- No push events. PAT clients cannot subscribe to SmartThings event webhooks — state changes are visible only on the next poll. If sub-second responsiveness is required, deploy GEM behind the device's local hub instead.
- Rate limits. SmartThings caps PATs at 250 requests/minute and 12,000 requests/day. On large accounts (>60 zones) bump
status_intervalto 90–120s. - Token rotation. PATs cannot be refreshed. When one expires or is revoked, generate a new one and paste it into
access_token. - Capability coverage. Devices with custom capabilities (
<vendor>.<capability>) are not routed by the verb table — useraw_commandto drive them.
Troubleshooting
| Symptom | Likely cause |
|---|---|
unauthorized — check that the PAT has the required scopes | PAT missing one of r:devices:* / w:devices:* / x:devices:*, or the PAT was revoked. Mint a fresh one. |
rate limited by SmartThings (429) | Too many zones polled too often. Increase status_interval. |
| Commands report success but the device doesn't change | Some SmartThings capabilities (notably doorControl.open) require user confirmation in the mobile app — that's enforced cloud-side and not visible to the API. |
Zone never reaches connected | The PAT may be valid but for a different SmartThings account. Confirm at account.smartthings.com/tokens that the token belongs to the account that paired the devices. |