diff --git a/README.md b/README.md index 5184d49..b3f06b6 100644 --- a/README.md +++ b/README.md @@ -1 +1,182 @@ -# wwst-skills +# SmartThings Developer Skills + +> **📢 Notice** +> Features, documentation, and skill behaviors may change. Your feedback via GitHub Issues is highly appreciated! + +A collection of AI skills that accelerates SmartThings device integration. It supports the full lifecycle, from initial code generation to WWST certification. + +## 📖 Overview + +This project provides AI skills for developers who want to integrate devices into the SmartThings ecosystem. Each skill improves development productivity with step-by-step guidance, best practices, code generation, and debugging support. + +### SmartThings Device Integration Types + +SmartThings supports three integration types depending on the device characteristics and the manufacturer's infrastructure: + +| Integration Type | Description | Best For | +|------------------|-------------|----------| +| **Cloud Connected** | A Device Integration in which devices communicate to the SmartThings cloud via your own cloud | Your devices connect to SmartThings through your own cloud backend | +| **Hub Connected** | A Device Integration in which devices connect to SmartThings via a SmartThings hub using Matter, Zigbee, or Z-Wave | Your devices integrate into the ecosystem through a SmartThings Hub | +| **Direct Connected** | A Device Integration in which devices communicate directly to the SmartThings cloud via MQTT / SmartThings SDK | Your IP devices connect to SmartThings without a separate cloud backend | + +--- + +## 🚀 Installation and Usage + +### Prerequisites + +- SmartThings Developer account ([Sign up](https://developer.smartthings.com/)) +- SmartThings CLI (optional, recommended) +- A coding assistant environment such as Claude Code, Codex, or Antigravity + +### How To Use These Skills + +These skills can be used with AI assistants that support MCP (Model Context Protocol), such as Cline, Cursor, and Claude Desktop. + +1. **Installation** + Install the full skill directory under `skills/` that matches your AI development environment. + + You can instruct your AI assistant to install the skills directly by pasting the following prompt: + + ```text + Install Agent Skills from https://github.com/SmartThingsCommunity/wwst-skills. + ``` + + > **💡 Installation Tip**: If your AI Coding Assistant does not support automatic skill installation, refer to the [Open Agent Skills specification](https://agentskills.io/client-implementation/adding-skills-support#step-1-discover-skills) or your AI Coding Assistant's Skills documentation for manual setup instructions. + + **Uninstall** + - Delete the copied skill directory, or remove the reference from your tool's configuration. + +2. **Invoking a skill** + + When you ask in natural language, the AI assistant can automatically activate the appropriate skill: + + - **Cloud Connected (With API Spec)** + ```text + Help me build a SmartThings Cloud Connected device integration. I have my own REST API specification ready in cloud_spec.md. + ``` + - **Hub Connected (With Device Spec Details)** + ```text + I want to integrate this Zigbee device with SmartThings. It uses a Zigbee endpoint with Basic, Identify, On/Off, Level Control, and Electrical Measurement clusters. + ``` + - **Direct Connected / MQTT (With Product URL)** + ```text + How can I integrate my smart fan into SmartThings using MQTT? It has speed control, oscillation, and a timer. Here is the product description page URL: https://example.com/product + ``` + +--- + +## 📚 Skill List + +This English README currently documents the following skills under `skills/`. + +### 1. Cloud Connected (Schema App) + +> **Skill**: `smartthings-cloud-connected-developer` + +This skill guides developers through the entire lifecycle of creating a SmartThings Cloud Connected (Schema App) integration, from organization setup to code generation, registration, and final WWST certification. + +**Key features** +- Step-by-step progression from org setup through certification (5-step workflow) +- Device Profiles and Capabilities mapping +- Schema App code generation +- OAuth configuration, hosting, and Schema App registration guidance +- Debugging support for common integration issues (OAuth, discovery, state sync) + +**Best fit** +- Teams with an existing cloud backend who want Cloud Connected integration +- Developers building a Schema App using Node.js +- Teams preparing WWST certification for Cloud Connected devices + +### 2. Hub Connected + +> **Skill**: `smartthings-hub-connected-developer` + +This skill guides WWST certification for hub-connected products that use Zigbee, Matter, or Z-Wave through SmartThings Hub. + +**Key features** +- Standard vs Custom path guidance +- Developer Console and Test Suite workflow +- Zigbee Edge driver PR worked example +- Capability mapping and certification guidance + +**Best fit** +- Hub-connected products using Zigbee, Matter, or Z-Wave +- Teams preparing WWST certification or driver contribution work + +### 3. Direct Connected Device SDK for C + +> **Skill**: `smartthings-direct-connected-device-sdk-c-developer` + +This skill guides SmartThings Direct Connected integration using the SmartThings Device SDK for C over MQTT. + +**Key features** +- IoT core device library vs SDK Reference starting guidance +- Porting boundary and application layer guidance +- Console setup and onboarding asset guidance +- Device identity registration and WWST prerequisites + +**Best fit** +- Direct Connected products using the SmartThings Device SDK for C +- Teams working on porting, provisioning, and certification readiness + +### 4. Device Onboarding QR Codes + +> **Skill**: `smartthings-device-onboarding-qr` + +This skill explains SmartThings device onboarding QR requirements across Matter, Zigbee 3.0, Direct Connected, and Mobile Connected products. + +**Key features** +- Integration-type-specific QR payload guidance +- Zigbee minimum vs recommended payload coverage +- Direct Connected and Mobile Connected QR field guidance +- Product-oriented payload examples and partner publication notes + +**Best fit** +- Teams defining device labels and onboarding assets +- Developers validating QR payload fields before publication +- Partners handling Matter, Zigbee 3.0, Direct Connected, or Mobile Connected onboarding flows + +--- + +## ⚠️ Limitations and Notes + +These skills provide development guidance and code generation support for SmartThings device integration. Before applying their output, verify the relevant content with the official SmartThings documentation, Developer Console, SmartThings CLI, and real-device testing. + +--- + +## 🤝 Contributing + +If you find a bug, have a suggestion for improvement, or encounter issues while using the skills, please **create an Issue** in this repository. Your feedback is highly appreciated and will help us improve the skills. + +--- + +## 📁 Project Structure + +```text +wwst-skills/ +├── README.md # README +├── skills/ # Skills +│ ├── smartthings-cloud-connected-developer/ +│ ├── smartthings-direct-connected-device-sdk-c-developer/ +│ ├── smartthings-device-onboarding-qr/ +│ ├── smartthings-hub-connected-developer/ +│ └── ... +``` + +--- + +## 🔗 Useful Links + +### Official Documentation +- [SmartThings Developer Center](https://developer.smartthings.com/) +- [Device Profiles Guide](https://developer.smartthings.com/docs/devices/device-profiles) +- [Capabilities Reference](https://developer.smartthings.com/docs/devices/capabilities/capabilities-reference) + +### Developer Tools +- [SmartThings CLI](https://github.com/SmartThingsCommunity/smartthings-cli) +- [Schema App SDK (Node.js)](https://github.com/SmartThingsCommunity/st-schema-nodejs) + +### Certification and Release +- [WWST Certification Requirements](https://developer.smartthings.com/docs/certification/required-capabilities) +- [Works With SmartThings](https://www.smartthings.com/works-with-smartthings) diff --git a/skills/smartthings-cloud-connected-developer/SKILL.md b/skills/smartthings-cloud-connected-developer/SKILL.md new file mode 100644 index 0000000..9512135 --- /dev/null +++ b/skills/smartthings-cloud-connected-developer/SKILL.md @@ -0,0 +1,96 @@ +--- +name: smartthings-cloud-connected-developer +description: Guides developers through the entire lifecycle of creating a SmartThings Cloud Connected (ST-Schema) integration, from organization setup to code generation, registration, and final certification. Use whenever the user wants to connect their cloud IoT devices to SmartThings, build a Schema App, or pass Works With SmartThings (WWST) certification. +metadata: + version: "2026-05-29" +--- + +# SmartThings Cloud Connected Guide + +This skill is a prompt and process framework that helps users integrate their cloud devices into the SmartThings ecosystem using the ST-Schema method. + +## Core Operating Principles + +1. **Adapt to User Language and Context**: Respond in the language the user is using (Korean, English, etc.). Do not re-ask for information already provided in documents or conversation. +2. **Strict Step-by-Step Progression (Human-in-the-Loop)**: From Step 1 through Step 5, **always proceed one step at a time with user confirmation and data provision**. Do not guide through 2 or more steps at once or assume (hallucinate) that steps have been completed. +3. **Hard-Blocking on User Input**: When explicit user information is required—such as OAuth details, data mapping confirmation, or `ST_CLIENT` issued keys—**stop and wait** until the user provides an appropriate response. Never fabricate dummy values or make assumptions to force progression. +4. **Progress Notification**: Clearly inform the user which step is currently in progress and what the next blocker (reason) is. +5. **Modular Guide Review**: Before proceeding with each step, **always read** the corresponding `references/*.md` document using the `view_file` tool and use it as the top-level rule for performing specific tasks. +6. **Verification and Reference Compliance (Anti-Hallucination)**: All technical decisions—Capability IDs, attribute specifications, SDK API specs—must be verified in real-time via CLI (`smartthings-cli`) or official documentation (`browser`) before proposing. Verification results must be reported to and approved by the user. +7. **Work Method Selection Principle (CLI First, User Choice for Console Tasks)**: When performing technical tasks, follow these criteria: + - **When CLI can handle it**: Use `smartthings-cli` as the primary method. + - **Proactive Search**: If `smartthings` fails, try common paths (e.g., `/usr/local/bin`, `C:\Program Files\SmartThings`) or `npm config get prefix` before falling back. + - **When CLI cannot handle it or console (GUI) work is needed**: Do not decide the method arbitrarily; ask the user first. *"Would you like to proceed in the console yourself, or shall I open the browser and we can do it together?"* + - **User chooses to do it themselves (Manual)**: Provide step-by-step text guides for the user to follow. + - **User chooses to work with the agent (Login-Assist Flow)**: The agent opens the console URL in a browser, and once the user confirms login, the agent automates the remaining input/extraction work via `browser_subagent`. + +## 👥 Developer Persona and Goals +This skill primarily supports the following users: +- External developers with limited prior knowledge of the SmartThings integration framework +- Developers who want to build Node.js-based projects using Vibe Coding (natural language instruction-driven) methods +- Developers who already have an API server for their own IoT devices but need ST-Schema integration + +## 🐛 Specialized Debugging Summary (Quick Reference) +When dealing with complex issues or log analysis, always consult the `references/best-practice-debugging.md` document first for cross-reference. When users report any of the following key issues, provide immediate guidance. + +| Symptom | Key Cause and Troubleshooting Guide | +|---------|--------------------------------------| +| Integration item not visible in My Testing Device app | SmartThings mobile app Developer mode is off / Schema not registered in Console. | +| OAuth login screen or popup not appearing | Client ID/Secret typos or missing settings in Console / Redirect URI mismatch on the hosting side. | +| Device list is empty or only loading | Discovery response JSON format does not match Device Profile specification / Check interactionResultHandler logs. | +| External device state updates not reflected | callbackAccessHandler not implemented or Access Token refresh logic missing. | + +## 💻 Code Writing Reference (SDK Specification) + +When writing or reviewing Schema App code, the following SDK specifications must be strictly followed. + +- **Capability ID Prefix (`st.`)**: When using SmartThings standard Capabilities in SDK methods (such as `device.addState`, `response.addDevice`, etc.), the `st.` prefix must always be included. + - **Correct**: `st.switch`, `st.switchLevel`, `st.temperatureMeasurement` + - **Incorrect**: `switch`, `switchLevel`, `temperatureMeasurement` +- **Attribute and Command Names**: Do not add the `st.` prefix to attribute and command names. +- **State Callback Token Mapping**: The Schema App's endpoint receiving events from the partner backend MUST identify which SmartThings user's `accessToken` maps to the incoming `deviceId`. The AI must explicitly guide the user to design a database or mapping logic (e.g., `deviceId` ➔ `partnerUserId` ➔ `ST accessToken`) to correctly route state callbacks. + +## 💡 Conversation and Response Scenario Examples +The agent should guide or lead to the next step in the following manner depending on the situation. +- **Initial Start**: "I'd like to integrate a smart plug." → "Welcome! Let's start by checking Step 1 (Organization Setup) for your device integration. Have you ever created an account and organization on the SmartThings Developer Console?" +- **Data Modeling Step (Step 2)**: "Please help me write a thermostat Profile." → "Sure, a thermostat requires Capabilities such as `temperatureMeasurement`, `thermostatMode`, etc. I'll compose the Device Profile JSON with this structure, and you can register it via the SmartThings CLI." +- **Code Auto-Generation Step (Step 3)**: "Please write connector code using /spec/api.json." → "I'll analyze the spec you provided and write a Node.js skeleton code mapping to the SDK's required handlers (discovery, stateRefresh, command). Please review the generated code and let me know whether to proceed to the next step." + +## Overall Process (ST-Schema Integration Sequence) + +### Step 1: Organization (ORG) and Brand Setup +Set up the Developer Console environment for WWST certification and device registration. +**-> Read the `references/01-org-setup.md` document and guide the user.** + +### Step 2: Product and Data Model (Device Profile) Configuration +Select appropriate Device Profiles and Capabilities based on device information, and register the device in the console. +**-> Read the `references/02-device-profile.md` document and guide the user.** + +### Step 3: Schema App (ST-Schema) Development +Write the SmartThings Schema server code (Node.js, etc.) that actually controls devices and synchronizes their states. +**-> Read the `references/03-schema-app.md` document and write/guide the code.** + +### Step 4: Hosting, App Registration, and Device Callback Setup +Deploy the developed code to a hosting environment (or ngrok), register it in the SmartThings console, and configure OAuth client information. +**-> Read the `references/04-hosting-and-registration.md` document and guide the user.** + +### Step 5: Development Testing and Certification +Perform Developer Mode device testing and the official certification process based on CbS/STTS. +**-> Read the `references/05-certification.md` document and guide the user.** + +## 🔗 Key Reference Links (Global References) +The agent refers to the following official documentation when verifying concepts or specifications. + +| Item | URL | +|------|-----| +| Cloud-Connected Getting Started | https://developer.smartthings.com/docs/devices/cloud-connected/get-started | +| OAuth2 Auth Server | https://developer.smartthings.com/docs/devices/cloud-connected/auth-server | +| Interaction Types | https://developer.smartthings.com/docs/devices/cloud-connected/interaction-types | +| Device Handler Types | https://developer.smartthings.com/docs/devices/cloud-connected/device-handler-types | +| Device Profiles | https://developer.smartthings.com/docs/devices/device-profiles | +| Capabilities Reference | https://developer.smartthings.com/docs/devices/capabilities/capabilities-reference | +| ST-Schema SDK (Node.js) | https://github.com/SmartThingsCommunity/st-schema-nodejs | +| SmartThings CLI | https://github.com/SmartThingsCommunity/smartthings-cli | +| WWST Certification Requirements | https://developer.smartthings.com/docs/certification/required-capabilities | + +Now greet the user, ask if they have information about the device they want to integrate, and begin Step 1. \ No newline at end of file diff --git a/skills/smartthings-cloud-connected-developer/references/01-org-setup.md b/skills/smartthings-cloud-connected-developer/references/01-org-setup.md new file mode 100644 index 0000000..c9822a8 --- /dev/null +++ b/skills/smartthings-cloud-connected-developer/references/01-org-setup.md @@ -0,0 +1,31 @@ +# Step 1: Organization (ORG) and Brand Setup Guide + +This step sets up the foundational development environment (Developer Console) for integrating with the SmartThings platform. + +## Goals +- Establish an **Organization**, which is the entity that will proceed with Works With SmartThings (WWST) certification. +- Set up a **Brand** under which products (devices) will belong. + +## Development Guide and Instructions + +> **[Console Task Notice]** +> This step is performed through the console GUI. If the user is experiencing difficulties or wants help, first ask *"Shall I open the browser and we can proceed together?"* Only enter the Login-Assist Flow if the user wants it. + +1. **Verify/Create Organization** + - Development and WWST certification must be conducted at the Organization level, not under a personal account. + - Ask the user whether they currently have an organization set up. + - If not set up, guide them through the creation process. + - Guide URL: [SmartThings Console - Organization](https://developer.smartthings.com/console/organization) + - Inform the user that they can change the organization they are currently working under via the profile in the upper right corner of the console (`USING CONSOLE AS`). + - If an existing organization exists, inform them that they can request a team invitation (invitation email) from the organization Admin. + +2. **Verify/Create Brand** + - Devices must be registered under a specific brand. + - Ask the user whether the brand their product belongs to is registered, and if not, instruct them to create a brand in the console. + - Guide URL: [SmartThings Console - Brands](https://developer.smartthings.com/console/brands) + +3. **Requirements Check** + - Remind the user that this step requires their own OAuth2 authentication server. (A mandatory requirement for ST-Schema) + - Authentication server guide: [Auth Server Guide](https://developer.smartthings.com/docs/devices/cloud-connected/auth-server) + +Once this step is complete (when the user confirms completion), the agent should inform them that they will proceed to Step 2 (02-device-profile.md) to define the device's detailed specifications. \ No newline at end of file diff --git a/skills/smartthings-cloud-connected-developer/references/02-device-profile.md b/skills/smartthings-cloud-connected-developer/references/02-device-profile.md new file mode 100644 index 0000000..fd92886 --- /dev/null +++ b/skills/smartthings-cloud-connected-developer/references/02-device-profile.md @@ -0,0 +1,66 @@ +# Step 2: Product Configuration and Data Model (Device Profile) Preparation Guide + +This step maps the physical (or virtual) device to be integrated into a logical interface model on SmartThings and registers it. + +## 1. Collect Product Information + +The following information is needed to register the device in the console. Ask the user if they have a document with this information organized, and if not, request them to provide it. +- **Product name**: Marketing product name displayed in the SmartThings App +- **Product number**: Unique identifier such as EAN, UPC, SKU +- **Product category**: Category used to search for the device in SmartThings +- **Product description**: Brief description of the device +- **Product image**: Image with transparent background, at least 584x584px (A strictly 1:1 aspect ratio is required; even a 1-pixel deviation will cause the upload to fail) +- **Distribution**: Launch countries/regions where the device will be serviced +- **(Optional)** Purchase link + +Once the above information is collected, the integration must be registered in the SmartThings console. + +> **[CLI Not Supported - Console Task Required]** Product Details registration is not currently supported by the SmartThings CLI. Ask the user about their preferred method first. +> *"Would you like to proceed in the console yourself, or shall I open the browser and we can do it together?"* + +- **User chooses to do it themselves (Manual)**: Guide them to access [SmartThings Console - Device Integrations](https://developer.smartthings.com/console/integrations) and click **Create** ➔ select **Cloud Connected** to enter the information directly. +- **User chooses to work with the agent (Login-Assist)**: The agent opens [SmartThings Console - Device Integrations](https://developer.smartthings.com/console/integrations) in a browser, and once the user logs in, the agent performs the **Create** ➔ **Cloud Connected** selection and Product information input on their behalf. + +--- + +## 2. Data Model (Device Profile) Configuration + +> **[Best Practice Review Instruction]** +> Before setting up and designing device profile categories, first review the `best-practice-device-profiles.md` document to reference specifications and attribute constraints (recommended/prohibited items). + +Determine the Device Type (Profile) by identifying what features the device has. + +1. **Obtain Feature Information**: Ask the user exactly what actions the device performs (turn power on/off, adjust temperature, camera streaming, etc.). +2. **Explore Device Handler Types**: + - Look for a suitable one among the [Device Handler Types](https://developer.smartthings.com/docs/devices/cloud-connected/device-handler-types) provided by default in SmartThings and recommend it. + - **If a built-in Handler is suitable**: Simply enter the Handler Name in the Schema App's `discoveryResponse`. → No separate Device Profile creation needed. + - **If a Custom Device Profile needs to be created**: Create one using the method below. + +### Device Profile Creation Method + +**[Console Task Required]** +To customize the dashboard card layout, choose precise device icons, and configure default detail states in the SmartThings app, the device profile must be created via the **SmartThings Developer Console's Device Profile Builder (Web GUI)**. Creating the profile directly via CLI is restricted in this workflow. + +Ask the user about their preferred Console method first. +*"Would you like to proceed in the console yourself, or shall I open the browser and we can do it together?"* + +- **User chooses to do it themselves (Manual)**: Guide them to [SmartThings Console - Integrations](https://developer.smartthings.com/console/integrations), click their integration project, select the **Device Profiles** menu, and manually build the profile. + - Step 1: Click "Create a Device Profile" and enter the profile name. + - Step 2: Search for the verified Capabilities and drag them into the component. + - Step 3: Choose the category icon (e.g., Light Bulb, Plug) and configure the state/action displays. + - Step 4: Click Save and copy the resulting **Device Profile ID (UUID)**. +- **User chooses to work with the agent (Login-Assist)**: The agent opens the console's Device Profile Builder in a browser, and once the user logs in, the agent performs Capability addition and layout configuration on their behalf. + +--- + +## 3. Verification and Constraints When Recommending Capabilities (Core Rule - Must Not Be Skipped) + +- **Agent Verification Obligation**: Before recommending a Capability, **you must perform real-time verification via CLI**. Recommending a hallucinated Capability will result in non-functional code and WWST certification failure. + - `smartthings capabilities -s` — View the full list (Standard capabilities) + - `smartthings capabilities -j` — Check detailed specifications +- **Standard Only (WWST Required)**: If the CLI result shows a **`namespace` field** or **an ID containing a period (`.`)**, it is a custom Capability and must never be recommended. (e.g., `myorg.myCapability` ❌ `switch` ✅) +- **Status and Version Check**: Capabilities in `deprecated` status will be rejected during certification. Capabilities in `proposed` status can be used for development/testing, but exercise caution as their specifications may change before final release. Cross-check the current status with the [Capabilities Reference](https://developer.smartthings.com/docs/devices/capabilities/capabilities-reference). +- **Camera and video doorbell Device Specific**: Explain that the choice between `videoStream` and `webrtc` Capabilities depends on the streaming protocol (RTSP vs WebRTC). +- [Reference: Certification Required Constraints Document](https://developer.smartthings.com/docs/certification/required-capabilities) + +Once this step is complete (Profile creation and decision complete), the agent must report the device's detailed specifications along with verification data (Verification Report) and obtain user approval. After approval, inform the user that they will proceed to Step 3 (03-schema-app.md), the full code development phase. diff --git a/skills/smartthings-cloud-connected-developer/references/03-schema-app.md b/skills/smartthings-cloud-connected-developer/references/03-schema-app.md new file mode 100644 index 0000000..388a314 --- /dev/null +++ b/skills/smartthings-cloud-connected-developer/references/03-schema-app.md @@ -0,0 +1,75 @@ +# Step 3: Schema App (ST-Schema) Development Guide + +This step involves writing the core logic (Schema App) that integrates the user's IoT cloud with the SmartThings cloud. + +## Integration Architecture Lifecycle (Important Context) +Before writing code and providing guidance, the agent must understand the following event call sequence and construct defensive logic: +1. **OAuth Authentication**: The user logs in through the app to link their account. +2. **`discovery` ➔ `stateRefresh`**: Immediately after linking, the SmartThings cloud requests the device list (`discoveryRequest`), followed by a request for initial state values (`stateRefreshRequest`). +3. **`command`**: When the user taps a switch in the app, a control request (`commandRequest`) is sent. +4. **`callbackAccess` Issuance**: During initial linking, the `grantCallbackAccess` interaction provides token issuance authority from SmartThings to us. The connector uses this authority to obtain the `accessToken` that will be used for future push communications. +5. **`stateCallback` (Proactive)**: When the user operates the device via a physical button or their own external app, the server proactively pushes the changed state to the SmartThings app using the `accessToken` obtained in step 4. + > **[Architectural Consideration for AI]**: The Schema App's endpoint receiving events from the partner backend MUST be able to distinguish which SmartThings user's `accessToken` corresponds to the incoming event. You must explicitly remind the user to design a mapping logic (e.g., `deviceId` ➔ `partnerUserId` ➔ `ST accessToken`) to correctly route state callbacks without mixing up users. + +## 🏗 Default Schema App Architecture to Be Generated +The structure and required handlers of the Node.js server that will be created through this skill's guidance are shown below. Always keep this structure in mind when generating code and providing template guidance. +- **`src/index.js`**: Express server entry point and environment variable configuration +- **`src/connector.js`**: `st-schema` SDK instance configuration +- **`src/handlers/`** + - `discovery.js`: Device list and profile return handler + - `state-refresh.js`: Current device state return handler + - `command.js`: Control command processing handler + - `callback-access.js`: Token storage for asynchronous state synchronization (`st-schema` callback) + - `integration-deleted.js`: Integration removal (deletion) handling + +## 1. Development Environment Setup +> **[Best Practice Review Instruction]** +> - When writing handlers and code, **always** review `best-practice-schema-app-code.md` and use the provided template code and snippets. +> - When mapping your own API specs to SmartThings attributes, review `best-practice-api-mapping.md` first to understand the standard mapping rules. + +- Ask the user about their preferred environment, such as Node.js. Recommend Node.js and guide development based on the `st-schema` SDK. +- (Reference link: [ST-Schema NodeJS SDK GitHub](https://github.com/SmartThingsCommunity/st-schema-nodejs)) + +## 2. Required Interaction Types Handler Implementation +The Schema App must handle various types of requests (Interaction Types) coming from SmartThings. Ask if the user has their own Device API specification document. +- **If a specification exists**: Write code based on that specification, following the [Agent Mandatory Obligation] below. +- **If the specification is unclear or unavailable**: If the user wants to test or prototype, first generate a **Mock-Up (dummy) Schema App code** that uses memory data or arbitrary dummy variables instead of the actual API, so they can test the overall structure. + +> **Agent Mandatory Obligation (Data Transformation Map Verification - Required When Specification Is Available)** +> If an actual API specification is provided, do not generate code immediately. **First, output a "data transformation mapping table" (e.g., `1/0` ➔ `on/off`) between the user's device attributes and SmartThings Capabilities in markdown table format, obtain user confirmation (approval), and then** write the actual control logic. **This mapping table must include official IDs and attribute names verified through verification tools (CLI preferred for speed).** This fundamentally eliminates runtime value mismatch errors. + +The following handlers are mandatory and must be implemented. + +1. **`discoveryHandler` (Discovery Request)** + - Called by SmartThings during initial setup or on a 24-hour cycle. + - Retrieves the device list via the manufacturer's cloud API and responds in `DiscoveryResponse` format. + - Emphasize that the Profile ID (Device Handler Type Name) must be accurately mapped. + +2. **`stateRefreshHandler` (State Refresh Request)** + - Called when the SmartThings app requests the current state of a device. + - Queries the device state using the manufacturer's cloud API and responds with `StateRefreshResponse`. + +3. **`commandHandler` (Command Request)** + - Called when the user issues a command such as turning a device switch on or off via the SmartThings app or automation flow. + - Calls the manufacturer's cloud API to send the actual control command to the device and responds with `CommandResponse`. + +## 3. Supplementary/Debugging Handler Implementation +Guide the implementation of the following items for long-term stable integration. + +1. **`callbackAccessHandler`** + - A handler that handles token exchange, where the user's cloud receives and stores `callbackUrls` and `accessToken` information for pushing information to SmartThings (e.g., stateCallback). + + > [!IMPORTANT] + > **Must Return After Step 4 Registration Is Complete** + > At this stage, leave it as a Placeholder and proceed. `ST_CLIENT_ID` and `ST_CLIENT_SECRET` are only issued during the **Step 4 (Schema App Registration)** process. Once app registration is complete, you must inject these keys into the `SchemaConnector` initialization (`.clientId()` and `.clientSecret()`) for asynchronous state synchronization to work. + > **Note on Testing:** `grantCallbackAccess` interactions cannot be successfully mocked with dummy data locally. The SDK strictly validates the callback tokens against the real SmartThings API. Developers MUST perform a real device installation via the SmartThings App or Developer Workspace to receive valid tokens and avoid `400/401` errors during testing. + +2. **`integrationDeletedHandler`** + - Called when the user removes the integration from their SmartThings account. + - Guide the user to perform database deletion or invalidation of the integration token on their own API. + +3. **`interactionResultHandler`** + - Receives detailed reasons when errors (Invalid format, etc.) occur during console or server testing. + - Guide implementation to output logs (e.g., `console.log()`) by default to assist with debugging. + +Once code scaffolding is complete and the user considers development finished, inform them that they will proceed to Step 4 (04-hosting-and-registration.md) to host the code on an actual server or ngrok and establish a communication path with SmartThings. \ No newline at end of file diff --git a/skills/smartthings-cloud-connected-developer/references/04-hosting-and-registration.md b/skills/smartthings-cloud-connected-developer/references/04-hosting-and-registration.md new file mode 100644 index 0000000..41bde9c --- /dev/null +++ b/skills/smartthings-cloud-connected-developer/references/04-hosting-and-registration.md @@ -0,0 +1,128 @@ +# Step 4: Hosting and Schema App Registration Guide + +This step involves setting up a deployment environment so that the developed Schema App can actually communicate with SmartThings, and registering it in the SmartThings Developer Center. + +## 1. Hosting and Webhook URL Preparation + +Ask if the goal is local testing, and if so, guide them to generate an HTTPS-accessible Webhook URL using `ngrok` or similar tools. + +```bash +# Run local server and generate public URL with ngrok +node src/index.js & +ngrok http 3000 + +# Check the generated URL via CLI (ngrok API) +curl -s http://localhost:4040/api/tunnels | python3 -m json.tool +``` + +> [!IMPORTANT] +> **[Production Hosting Precautions]** +> If the user is deploying for production rather than local testing, ensure they are aware of the following: +> - **AWS Lambda**: You must add permissions for the SmartThings principal ID (`148790070172`) via AWS CLI so SmartThings can invoke the function. +> - **Webhook**: Must be served over HTTPS with a valid public certificate. +> - Detailed instructions can be found in the [Schema App Hosting & Registration Guide](https://developer.smartthings.com/docs/devices/cloud-connected/schema-app). + +--- + +## 2. SmartThings Schema App Registration + +Combine the Webhook URL, your own OAuth authentication information, and the Product information from Step 2 to register. + +### Schema App Registration Method + +**[First Choice] CLI (Recommended)** + +The agent collects the following information, writes `connector.json`, and registers it via CLI. + +Required information: +- `webhookUrl`: Webhook URL secured via ngrok etc. +- `oAuthAuthorizationUrl`: Your own OAuth Authorization endpoint +- `oAuthTokenUrl`: Your own OAuth Token endpoint +- `oAuthClientId`: Your own OAuth Client ID +- `oAuthClientSecret`: Your own OAuth Client Secret +- `oAuthScope`: OAuth Scope to request (e.g., `device:read device:write`) +- `appName`: Schema app display name +- `partnerName`: Company name +- `userEmail`: Developer email + +```bash +# Create Schema App based on connector.json file +smartthings schema:create -i connector.json + +# Query ST Client credentials after creation +smartthings schema +smartthings schema +``` + +> **connector.json Example** +> ```json +> { +> "appName": "My IoT Platform", +> "partnerName": "My Company", +> "hostingType": "webhook", +> "userEmail": "developer@mycompany.com", +> "webhookUrl": "https://xxxx.ngrok-free.app", +> "oAuthAuthorizationUrl": "https://myplatform.example.com/oauth/authorize", +> "oAuthTokenUrl": "https://myplatform.example.com/oauth/token", +> "oAuthClientId": "my-client-id", +> "oAuthClientSecret": "my-client-secret", +> "oAuthScope": "device:read device:write" +> } +> ``` + +**[CLI Not Supported or Console Preferred]** Ask the user about their preferred method first. +*"Would you like to proceed in the console yourself, or shall I open the browser and we can do it together?"* + +- **User chooses to do it themselves (Manual)**: Guide them to [SmartThings Console - Integrations](https://developer.smartthings.com/console/integrations), select the in-progress integration, and manually enter the Webhook and OAuth information. +- **User chooses to work with the agent (Login-Assist)**: The agent opens [SmartThings Console - Integrations](https://developer.smartthings.com/console/integrations) in a browser, and once the user logs in, the agent performs the OAuth field input and key extraction on their behalf. + +--- + +> **Agent Mandatory Notice (Distinguishing Two OAuth Keys)** +> Clearly explain the "bidirectional authentication key" concept that developers most commonly confuse. +> 1. The **OAuth settings just entered (your own server keys prepared in advance)**: Used when SmartThings logs into your server. +> 2. The newly issued **`ST_CLIENT_ID` and `ST_CLIENT_SECRET`** after registration: Used when your server proactively sends state callbacks to SmartThings. +> Make sure the user understands these two are completely different, and instruct them to safely copy the newly issued 'ST_CLIENT' key pair. + +--- + +## 3. Product Registration and Schema-Profile Mapping (Console Task) + +> [!IMPORTANT] +> **[Prerequisite for Test Device Visibility]** +> Simply registering a Schema App via CLI or Console will not make it appear under the mobile app's "My Testing Devices" list. You must register the final product (Integration) in the **Integrations** menu and map all components. +> +> Guide the user to complete the following 4-element mapping steps: +> 1. Navigate to the [SmartThings Console - Integrations](https://developer.smartthings.com/console/integrations). +> 2. In the **Device Integrations** menu, click **Create** ➔ Select **Cloud Connected**. +> 3. Fill in the **Product Overview** fields under the **Product Details** menu: +> - **Product name** (e.g., `Lumos Smart Color Bulb`) +> - **Model number** (e.g., unique model identifier or SKU) +> - **Product category** (Select the appropriate category, e.g., `Light`) +> - **Product description** (Brief description up to 500 characters) +> - **Product image** (A transparent PNG, minimum 584x584 pixels) +> 4. Select the registered **Brand** (created in Step 1). +> 5. Select the registered **Schema App** (created in Step 4). +> 6. Map the corresponding **Device Profile** (created in Step 2). +> 7. Click **Save** to finalize. Without this mapping, the SmartThings platform will not recognize your test setup, and it will not appear under "My Testing Devices". + +--- + +## 4. Device Callback (Proactive Callback) Code Update + +The issued `ST_CLIENT_ID` and `ST_CLIENT_SECRET` must be injected into the code written in Step 3 for complete device state tracking. + +1. **Inject Keys into Connector Initialization Code**: + When using the `st-schema` Node library, inject `clientId` and `clientSecret` as environment variables. + (Reference: [Proactive State Callbacks Github](https://github.com/SmartThingsCommunity/st-schema-nodejs/tree/master?tab=readme-ov-file#proactive-state-callbacks)) + +2. **Activate `callbackAccessHandler`**: + To enable the logic for proactively sending device state changes to SmartThings (stateCallback) when the device state changes on the server side (e.g., when a user turns off a light in their own app), or pinging SmartThings to discover a device (discoveryCallback) when a new device is manually added, explain the usage syntax of the corresponding handler. + + > [!TIP] +> Now go back to the **[callbackAccessHandler Implementation Section](./03-schema-app.md#3-supplementarydebugging-handler-implementation)** from Step 3 and guide the user to complete the actual logic using the issued keys. + +> **Agent Mandatory Obligation (Local Debugging Support)** +> Do not stop at just explaining the code settings. **Be sure to generate and provide a `curl`-based test snippet** so the user can test whether the callback (stateCallback) works correctly in a terminal environment. + +Once all the above items are reflected in the code and the server is running, inform the user that they will proceed to Step 5 (05-certification.md) to test whether the integration actually works. \ No newline at end of file diff --git a/skills/smartthings-cloud-connected-developer/references/05-certification.md b/skills/smartthings-cloud-connected-developer/references/05-certification.md new file mode 100644 index 0000000..ef1089b --- /dev/null +++ b/skills/smartthings-cloud-connected-developer/references/05-certification.md @@ -0,0 +1,59 @@ +# Step 5: Development Testing and Certification Guide + +This step involves performing self-testing on the app/device and applying for official Works With SmartThings (WWST) certification. + +## 1. Development Testing Phase (Developer Mode) +Guide the user on how to [enable Developer Mode](https://developer.smartthings.com/docs/devices/enable-developer-mode) in the SmartThings App: +1. Launch the SmartThings App. +2. Tap the *Menu* tab on the bottom navigation bar. +3. Tap the *Settings* (gear icon) in the upper right-hand corner to open *SmartThings settings*. +4. Long-press the *About SmartThings* option for 10 seconds. +5. Enable the *Developer mode* toggle at the bottom of the menu. +6. Restart the SmartThings App. + +Key test scenarios and debugging FAQ to guide: + +- **When the app doesn't appear under "My Testing Devices":** + - Verify two prerequisites: + 1. **Product-Schema Mapping**: Make sure the Integration is registered at [Developer Console - Integrations](https://developer.smartthings.com/console/integrations) and all four components (Product Info, Brand, Schema App, Device Profile) are linked. + 2. **Developer Mode**: Confirm that Developer Mode is enabled in the mobile app. +- **When your own OAuth login page doesn't appear after selecting integration:** + - Check the webview top link and recommend checking the webhook/address spelling in the registration step (04-hosting-and-registration.md) +- **When the device list doesn't appear even after successful login:** + - It is highly likely a response format error in `discoveryRequest` and `stateRefreshRequest`. Review the code from Step 3. + - Guide the user to check the server terminal for any error logs coming through `interactionResultHandler` + +## 2. Self-Checklist Before Certification +> **[Best Practice Review Instruction]** +> Before proceeding with certification and STTS testing, be sure to review the `best-practice-stts-checklist.md` document and guide the user through the detailed checklist for each feature. + +> **Agent Mandatory Obligation (Production Migration Reminder)** +> Before applying for certification, you MUST proactively remind the user to migrate their local or test environment to a production-ready state. +> *Examples of production migration items you should mention include:* +> - Hosting/Security (SSL) (e.g., replacing `ngrok` with a reliable cloud infrastructure and a valid HTTPS SSL certificate) +> - DB expansion for multi-user mapping (e.g., replacing `callbacks.json` with a scalable Database like RDBMS/NoSQL) +> - Console settings update (e.g., updating the SmartThings Developer Console with the new production Webhook URL) + +Before applying for certification in earnest, ask the user whether they have confirmed the following items. +- [ ] **Production Domain Replacement Confirmed (Required)**: Addresses like `ngrok` used for local testing will always be rejected during certification review. **Make sure to replace the integration app's Webhook address with a valid single production cloud domain (AWS, GCP, own server, etc.) with an SSL certificate applied.** +- [ ] **Production DB for Callback Tokens Confirmed (Required)**: Local file storage (like `callbacks.json`) used during testing MUST be replaced with a robust Database (DynamoDB, MongoDB, RDBMS, etc.). The DB must map `deviceId` ➔ `partnerUserId` ➔ `ST accessToken` to accurately route state callbacks for multiple users. +- [ ] Regional account login: Verify that your own OAuth callback works properly even after changing the Samsung account country (US, EU, AP, etc.) +- [ ] Device list and state display confirmed: Devices are displayed normally in the app, and `online/offline` status handling is perfectly applied +- [ ] Bidirectional state synchronization: When the device state is changed in your own app, it is immediately reflected in the SmartThings app via `stateCallback` + +## 3. Certification Application and Submission +Guide the user to navigate to the **'Certification' tab** on the SmartThings Developer Console's integration project detail page and click the Submit button to proceed with the STTS (SmartThings Test Suite) submission. +- [STTS Certification Test Guide](https://developer.smartthings.com/docs/certification/test-suite) + +## 4. Special Certification Process: Certification by Similarity (CbS) Guide +When the user wants to register derivative models of devices with similar specifications, provide a tip about the "Certification by Similarity" policy to save time and cost. + +- **What is CbS?**: A program where only one main model goes through full test certification for a family of devices with the same functionality/base (e.g., products that differ only in color/shape), and derivative models can pass certification without paying fees. +- **Required Conditions**: + - The Brand must be the same. + - The Device Category must be the same. + - The Connector ID (Schema ID) must be the same. + - The Capability list must be a subset of or exactly match the existing main model. (Emphasize that even one additionally added Capability will disqualify it as a derivative model) +- **How to Apply**: First submit the base model for full certification review and pass it, then check the CbS eligibility when submitting variant models in the Developer Console. + +Once all processes are completed, offer congratulations and conclude the integration guide. \ No newline at end of file diff --git a/skills/smartthings-cloud-connected-developer/references/best-practice-api-mapping.md b/skills/smartthings-cloud-connected-developer/references/best-practice-api-mapping.md new file mode 100644 index 0000000..63c9c95 --- /dev/null +++ b/skills/smartthings-cloud-connected-developer/references/best-practice-api-mapping.md @@ -0,0 +1,574 @@ +# API Spec Mapping Guide + +This document explains how to map your own Device API specs to SmartThings Schema App handlers. + +## Table of Contents + +1. [Overview](#overview) +2. [API Spec Input Methods](#api-spec-input-methods) +3. [Swagger/OpenAPI Parsing](#swaggeropenapi-parsing) +4. [Handler Mapping Rules](#handler-mapping-rules) +5. [State Mapping](#state-mapping) +6. [Command Mapping](#command-mapping) +7. [Mapping Examples](#mapping-examples) + +--- + +## Overview + +API mapping proceeds through the following process: + +1. **Load API Spec**: Swagger/OpenAPI JSON, text description, or separate file +2. **Analyze Endpoints**: Identify device list, state query, and control APIs +3. **Map to SmartThings Handlers**: Map to Discovery, StateRefresh, and Command handlers +4. **Code Generation**: Generate Schema App code based on the mapped information + +--- + +## API Spec Input Methods + +### 1. Swagger/OpenAPI JSON + +Save the file in the `/spec/` directory or provide it directly: + +```json +{ + "openapi": "3.0.0", + "info": { + "title": "Device API", + "version": "1.0.0" + }, + "paths": { + "/devices": { + "get": { + "summary": "Get device list", + "responses": { + "200": { + "description": "Device list" + } + } + } + } + } +} +``` + +### 2. Text Description + +Provide API description in natural language: + +``` +Device list query: GET /api/v1/devices +- Header: Authorization: Bearer {token} +- Response: { devices: [{ id, name, type, ... }] } + +Device state query: GET /api/v1/devices/{deviceId}/status +- Response: { power: "on", level: 80, ... } + +Device control: POST /api/v1/devices/{deviceId}/command +- Body: { command: "setPower", value: true } +``` + +### 3. Separate Spec Files + +Save various format files in the `/spec/` directory: +- `api-spec.json` (OpenAPI/Swagger) +- `api-spec.yaml` (OpenAPI/Swagger YAML) +- `api-docs.md` (Markdown document) +- `endpoints.txt` (Text description) + +--- + +## Swagger/OpenAPI Parsing + +### Target Information for Parsing + +| Information | Description | Mapping Target | +|-------------|-------------|----------------| +| `GET /devices` | Device list query | discoveryHandler | +| `GET /devices/{id}` | Device detail information | discoveryHandler | +| `GET /devices/{id}/state` | Device state query | stateRefreshHandler | +| `POST /devices/{id}/power` | Power control | commandHandler (st.switch) | +| `POST /devices/{id}/level` | Level control | commandHandler (st.switchLevel) | +| `POST /devices/{id}/color` | Color control | commandHandler (st.colorControl) | +| `POST /devices/{id}/temperature` | Temperature setting | commandHandler (st.thermostatSetpoint) | + +### OpenAPI Example Analysis + +```json +{ + "openapi": "3.0.0", + "paths": { + "/devices": { + "get": { + "operationId": "getDevices", + "tags": ["Device"], + "parameters": [ + { + "name": "Authorization", + "in": "header", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "devices": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Device" + } + } + } + } + } + } + } + } + } + }, + "/devices/{deviceId}/state": { + "get": { + "operationId": "getDeviceState", + "parameters": [ + { "name": "deviceId", "in": "path", "required": true } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeviceState" + } + } + } + } + } + } + }, + "/devices/{deviceId}/power": { + "post": { + "operationId": "setPower", + "parameters": [ + { "name": "deviceId", "in": "path", "required": true } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "power": { "type": "string", "enum": ["on", "off"] } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Device": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "type": { "type": "string" }, + "model": { "type": "string" }, + "online": { "type": "boolean" } + } + }, + "DeviceState": { + "type": "object", + "properties": { + "power": { "type": "boolean" }, + "level": { "type": "integer", "minimum": 0, "maximum": 100 }, + "temperature": { "type": "number" } + } + } + } + } +} +``` + +--- + +## Handler Mapping Rules + +### Discovery Handler Mapping + +| Your API | SmartThings Discovery | +|----------|----------------------| +| `GET /devices` | Device list query | +| `id` → `externalDeviceId` | Device unique ID | +| `name` → `friendlyName` | Display name | +| `type` → `deviceHandlerType` | Device Handler Type | + +**Mapping Code Example:** + +```javascript +// API response +{ + "devices": [ + { "id": "dev-001", "name": "Living Room Light", "type": "light" } + ] +} + +// Converted to SmartThings Discovery response +{ + "externalDeviceId": "dev-001", + "friendlyName": "Living Room Light", + "deviceHandlerType": "light" +} +``` + +### StateRefresh Handler Mapping + +| Your API | SmartThings StateRefresh | +|----------|-------------------------| +| `GET /devices/{id}/state` | Device state query | +| `power` → `st.switch.switch` | Power state | +| `level` → `st.switchLevel.level` | Level | +| `temperature` → `st.temperatureMeasurement.temperature` | Temperature | + +### Command Handler Mapping + +| Your API | SmartThings Command | +|----------|---------------------| +| `POST /devices/{id}/power` | `st.switch.on/off` | +| `POST /devices/{id}/level` | `st.switchLevel.setLevel` | +| `POST /devices/{id}/color` | `st.colorControl.setColor` | + +--- + +## State Mapping + +### Basic State Mapping Table + +| Your API Field | SmartThings Capability | Attribute | Value Conversion | +|----------------|------------------------|-----------|------------------| +| `power: true/false` | `st.switch` | `switch` | `"on"` / `"off"` | +| `level: 0-100` | `st.switchLevel` | `level` | Use as-is | +| `hue: 0-100` | `st.colorControl` | `hue` | Use as-is | +| `saturation: 0-100` | `st.colorControl` | `saturation` | Use as-is | +| `colorTemperature: 2200-6500` | `st.colorTemperature` | `colorTemperature` | Use as-is | +| `temperature: number` | `st.temperatureMeasurement` | `temperature` | Check unit (C/F) | +| `humidity: number` | `st.relativeHumidityMeasurement` | `humidity` | Use as-is | +| `mode: string` | `st.thermostatMode` | `thermostatMode` | Mapping required | +| `locked: boolean` | `st.lock` | `lock` | `"locked"` / `"unlocked"` | +| `online: boolean` | `st.healthCheck` | `healthStatus` | `"online"` / `"offline"` | +| `battery: 0-100` | `st.battery` | `battery` | Use as-is | +| `motion: boolean` | `st.motionSensor` | `motion` | `"active"` / `"inactive"` | +| `contact: boolean` | `st.contactSensor` | `contact` | `"open"` / `"closed"` | + +### Thermostat Mode Mapping + +| Your API Value | SmartThings Value | +|----------------|-------------------| +| `off` | `off` | +| `cool` / `cooling` | `cool` | +| `heat` / `heating` | `heat` | +| `auto` / `automatic` | `auto` | +| `emergency` / `emergencyHeat` | `emergencyHeat` | +| `precool` / `precooling` | `precooling` | + +### Air Conditioner Mode Mapping + +| Your API Value | SmartThings Value | +|----------------|-------------------| +| `off` | `off` | +| `auto` | `auto` | +| `cool` | `cool` | +| `heat` | `heat` | +| `dry` | `dry` | +| `fan` | `wind` | + +--- + +## Command Mapping + +### Switch Commands + +| SmartThings Command | Your API Request | +|---------------------|------------------| +| `st.switch.on` | `POST /devices/{id}/power { "power": "on" }` | +| `st.switch.off` | `POST /devices/{id}/power { "power": "off" }` | + +### Level Commands + +| SmartThings Command | Your API Request | +|---------------------|------------------| +| `switchLevel.setLevel([80])` | `POST /devices/{id}/level { "level": 80 }` | + +### Color Commands + +| SmartThings Command | Your API Request | +|---------------------|------------------| +| `colorControl.setColor({hue: 50, saturation: 100})` | `POST /devices/{id}/color { "hue": 50, "saturation": 100 }` | +| `colorControl.setHue([50])` | `POST /devices/{id}/color { "hue": 50 }` | +| `colorControl.setSaturation([100])` | `POST /devices/{id}/color { "saturation": 100 }` | + +### Thermostat Commands + +| SmartThings Command | Your API Request | +|---------------------|------------------| +| `st.thermostatMode.setThermostatMode(["cool"])` | `POST /devices/{id}/mode { "mode": "cool" }` | +| `st.thermostatCoolingSetpoint.setCoolingSetpoint([24])` | `POST /devices/{id}/cooling-setpoint { "temperature": 24 }` | +| `st.thermostatHeatingSetpoint.setHeatingSetpoint([20])` | `POST /devices/{id}/heating-setpoint { "temperature": 20 }` | + +--- + +## Mapping Examples + +### Example 1: Smart Light API + +**Swagger Spec:** + +```json +{ + "openapi": "3.0.0", + "info": { "title": "Smart Light API", "version": "1.0.0" }, + "paths": { + "/lights": { + "get": { + "operationId": "getLights", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { "$ref": "#/components/schemas/Light" } + } + } + } + } + } + } + }, + "/lights/{lightId}": { + "get": { + "operationId": "getLightState", + "parameters": [ + { "name": "lightId", "in": "path", "required": true } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/LightState" } + } + } + } + } + } + }, + "/lights/{lightId}/power": { + "post": { + "operationId": "setLightPower", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "on": { "type": "boolean" } + } + } + } + } + } + } + }, + "/lights/{lightId}/brightness": { + "post": { + "operationId": "setLightBrightness", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "brightness": { "type": "integer", "min": 0, "max": 100 } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Light": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "room": { "type": "string" } + } + }, + "LightState": { + "type": "object", + "properties": { + "on": { "type": "boolean" }, + "brightness": { "type": "integer" }, + "colorTemp": { "type": "integer" } + } + } + } + } +} +``` + +**Mapping Result:** + +```javascript +// device-api.js auto-generated +const deviceApi = { + async getDevices(authToken) { + const response = await axios.get(`${BASE_URL}/lights`, { + headers: { 'Authorization': `Bearer ${authToken}` } + }); + return response.data.map(light => ({ + id: light.id, + name: light.name, + deviceHandlerType: 'light' // or 'colorTemperatureLight' + })); + }, + + async getDeviceState(authToken, deviceId) { + const response = await axios.get(`${BASE_URL}/lights/${deviceId}`, { + headers: { 'Authorization': `Bearer ${authToken}` } + }); + return { + power: response.data.on, + level: response.data.brightness, + colorTemperature: response.data.colorTemp + }; + }, + + async setPower(authToken, deviceId, power) { + await axios.post(`${BASE_URL}/lights/${deviceId}/power`, { + on: power + }, { + headers: { 'Authorization': `Bearer ${authToken}` } + }); + }, + + async setLevel(authToken, deviceId, level) { + await axios.post(`${BASE_URL}/lights/${deviceId}/brightness`, { + brightness: level + }, { + headers: { 'Authorization': `Bearer ${authToken}` } + }); + } +}; +``` + +### Example 2: Text Description Based Mapping + +**Input Text:** + +``` +Our company IoT API spec: + +1. Device list query + - GET /api/devices + - Header: Authorization: Bearer {token} + - Response: [{ deviceId, deviceName, deviceType, isOnline }] + +2. Device state query + - GET /api/devices/{deviceId} + - Response: { status: "on"/"off", brightness: 0-100, currentTemp: number } + +3. Device control + - POST /api/devices/{deviceId}/control + - Body: { action: "turnOn"|"turnOff"|"setBrightness", value: any } +``` + +**Mapping Analysis:** + +| API Information | Mapping Result | +|----------------|----------------| +| `GET /api/devices` | discoveryHandler | +| `deviceId` → `externalDeviceId` | Discovery | +| `deviceName` → `friendlyName` | Discovery | +| `deviceType` → `deviceHandlerType` | Discovery | +| `GET /api/devices/{id}` | stateRefreshHandler | +| `status` → `st.switch.switch` | StateRefresh | +| `brightness` → `st.switchLevel.level` | StateRefresh | +| `currentTemp` → `st.temperatureMeasurement.temperature` | StateRefresh | +| `POST /api/devices/{id}/control` | commandHandler | +| `action: turnOn/turnOff` | `st.switch.on/off` | +| `action: setBrightness` | `st.switchLevel.setLevel` | + +--- + +## Authentication Method Handling + +### OAuth2 Bearer Token + +```javascript +const response = await axios.get(url, { + headers: { + 'Authorization': `Bearer ${authToken}`, + 'Content-Type': 'application/json' + } +}); +``` + +### API Key + +```javascript +const response = await axios.get(url, { + headers: { + 'X-API-Key': process.env.DEVICE_API_KEY, + 'Content-Type': 'application/json' + } +}); +``` + +### Basic Auth + +```javascript +const response = await axios.get(url, { + auth: { + username: process.env.API_USERNAME, + password: process.env.API_PASSWORD + } +}); +``` + +--- + +## Error Mapping + +| Your API Error | SmartThings Error | +|----------------|-------------------| +| 401 Unauthorized | `AUTHORIZATION-ERROR` | +| 404 Not Found | `DEVICE-ERROR` (device not found) | +| 500 Internal Error | `INTEGRATION-ERROR` | +| 429 Rate Limited | `RATE-LIMIT-ERROR` | +| Device offline | `DEVICE-ERROR` | +| Timeout | `DEVICE-ERROR` | + +--- + +## Checklist + +Items to verify when performing API mapping: + +- [ ] Device list query API confirmed +- [ ] Device state query API confirmed +- [ ] Device control API confirmed +- [ ] Authentication method confirmed (OAuth2, API Key, etc.) +- [ ] State field and Capability mapping confirmed +- [ ] Command and API action mapping confirmed +- [ ] Error handling method confirmed +- [ ] Timeout settings confirmed \ No newline at end of file diff --git a/skills/smartthings-cloud-connected-developer/references/best-practice-debugging.md b/skills/smartthings-cloud-connected-developer/references/best-practice-debugging.md new file mode 100644 index 0000000..083dc4a --- /dev/null +++ b/skills/smartthings-cloud-connected-developer/references/best-practice-debugging.md @@ -0,0 +1,669 @@ +# Debugging FAQ and Troubleshooting Guide + +This document compiles problems that may occur during SmartThings Cloud-Connected integration development and their solutions. + +## Table of Contents + +1. [Development Testing Phase Issues](#development-testing-phase-issues) +2. [Discovery Issues](#discovery-issues) +3. [StateRefresh Issues](#staterefresh-issues) +4. [Command Issues](#command-issues) +5. [OAuth Issues](#oauth-issues) +6. [Callback Issues](#callback-issues) +7. [Logging and Debugging](#logging-and-debugging) +8. [Common Error Codes](#common-error-codes) + +--- + +## Development Testing Phase Issues + +### Problem 0: SmartThings CLI Command Not Found +**Cause**: PATH environment issue. +**Solution**: Check common paths (`/usr/local/bin`, `C:\Program Files\SmartThings`) or run `npm config get prefix` to find the binary and use its absolute path. + +--- + +### Problem 1: Integration Not Visible in My Testing Device + +**Symptom:** +The integration does not appear under SmartThings App → Add device → My Testing Device + +**Possible Causes:** + +1. **SmartThings Schema Not Registered** + - Check Schema registration in Console + - Check registration status via CLI: `smartthings schema` + +2. **Developer Mode Disabled** + - SmartThings App → Settings → Developer mode needs to be enabled + +3. **Incorrect Region Setting** + - Mismatch between SmartThings account region and Schema registration region + +**Solutions:** + +```bash +# Check Schema registration +smartthings schema + +# Register Schema if not present +smartthings schema:create -i schema-config.json +``` + +**Enable Developer Mode:** +1. Open SmartThings App +2. Go to Settings +3. Enable Developer mode +4. Restart the app + +--- + +### Problem 2: OAuth Login Screen Not Appearing + +**Symptom:** +After selecting the integration, the OAuth login screen does not appear in the webview + +**Possible Causes:** + +1. **Schema Registration Information Error** + - redirectUri mismatch + - clientId/clientSecret mismatch + +2. **OAuth Authentication Server Issue** + - No response from authentication server + - Incorrect OAuth URL + +**Solutions:** + +1. Check the webview top link + - Verify the link is the correct OAuth URL + +2. Re-check Schema information in Console + - OAuth Authorization URL + - OAuth Token URL + - OAuth Client ID / Secret + +3. Check OAuth server logs + +**Test OAuth with curl:** + +```bash +# Test Authorization URL +curl -v "https://your-oauth-server.com/oauth/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=https://c2c-us.smartthings.com/oauth/callback" + +# Test Token URL (after code is issued) +curl -X POST "https://your-oauth-server.com/oauth/token" \ + -d "grant_type=authorization_code" \ + -d "code=AUTHORIZATION_CODE" \ + -d "redirect_uri=https://c2c-us.smartthings.com/oauth/callback" \ + -u "CLIENT_ID:CLIENT_SECRET" +``` + +--- + +### Problem 3: Device List Empty After Login + +**Symptom:** +OAuth login was successful but nothing is displayed in the device list + +**Possible Causes:** + +1. **Discovery Handler Error** + - API call failure + - Response format mismatch + +2. **StateRefresh Handler Error** + - State query failure + +3. **Token Issue** + - OAuth token expired + - User identification via token failed + +**Solutions:** + +1. Check `interactionResultHandler` logs + +```javascript +async function interactionResultHandler(request) { + console.log('[InteractionResult] Error:', JSON.stringify(request.interactionResult, null, 2)); +} +``` + +2. Debug Discovery handler + +```javascript +async function discoveryHandler(request) { + console.log('[Discovery] Request:', JSON.stringify(request, null, 2)); + + try { + const devices = await deviceApi.getDevices(request.authentication.token); + console.log('[Discovery] Devices from API:', JSON.stringify(devices, null, 2)); + // ... + } catch (error) { + console.error('[Discovery] Error:', error); + } +} +``` + +3. Check response format + +```javascript +// Correct Discovery response format +{ + "headers": { + "schema": "st-schema", + "version": "1.0", + "interactionType": "discoveryResponse" + }, + "authentication": { + "token": "user-oauth-token" + }, + "devices": [ + { + "externalDeviceId": "device-001", + "friendlyName": "Living Room Light", + "deviceHandlerType": "c2c-rgb-color-bulb" // Standard Device Handler Type OR Custom Device Profile ID + } + ] +} +``` + +--- + +## Discovery Issues + +### Problem 4: Device Appears But Name/Icon Is Wrong + +**Symptom:** +Device is displayed but the name or icon does not appear as intended + +**Causes:** + +1. **friendlyName not set** +2. **deviceHandlerType mismatch** + +**Solutions:** + +```javascript +// Include all fields in Discovery response +{ + "externalDeviceId": "device-001", + "friendlyName": "Living Room Light", // User-friendly name + "deviceHandlerType": "c2c-rgb-color-bulb", // Standard Device Handler Type OR Custom Device Profile ID (UUID) + "deviceUniqueId": "serial-12345" // Optional +} +``` + +--- + +### Problem 5: Only Specific Devices Not Discovered + +**Symptom:** +Only some devices are missing from Discovery + +**Causes:** + +1. **Device type mismatch** +2. **Device is offline** +3. **Excluded from API response** + +**Solutions:** + +1. Output full API response log +2. Check deviceHandlerType for each device +3. Check whether offline devices are being filtered + +--- + +## StateRefresh Issues + +### Problem 6: Device State Not Updated + +**Symptom:** +Device state is displayed differently from actual state + +**Possible Causes:** + +1. **StateRefresh handler not implemented** +2. **State value format error** +3. **Capability mismatch** + +**Solutions:** + +1. Check StateRefresh response format + +```javascript +// Correct StateRefresh response +{ + "headers": { + "schema": "st-schema", + "version": "1.0", + "interactionType": "stateRefreshResponse" + }, + "authentication": { + "token": "user-oauth-token" + }, + "deviceState": [ + { + "externalDeviceId": "device-001", + "deviceError": null, + "states": [ + { + "component": "main", + "capability": "switch", + "attribute": "switch", + "value": "on" // "on" or "off" (not boolean) + }, + { + "component": "main", + "capability": "switchLevel", + "attribute": "level", + "value": 80 // number + } + ] + } + ] +} +``` + +2. Check state value format + +| Capability | Attribute | Correct Value Format | +|------------|-----------|---------------------| +| switch | switch | `"on"`, `"off"` (string) | +| switchLevel | level | `0` - `100` (number) | +| colorControl | hue | `0` - `100` (number) | +| colorControl | saturation | `0` - `100` (number) | +| colorTemperature | colorTemperature | `2200` - `6500` (number) | +| temperatureMeasurement | temperature | Number (unit can be included) | +| lock | lock | `"locked"`, `"unlocked"` (string) | +| healthCheck | healthStatus | `"online"`, `"offline"` (string) | + +--- + +### Problem 7: Device Continuously Shows "Checking Status" + +**Symptom:** +Device continuously displays loading state + +**Causes:** + +1. **StateRefresh timeout** +2. **API response delay** +3. **Handler exception occurred** + +**Solutions:** + +1. Check timeout settings + +```javascript +// axios timeout setting +const response = await axios.get(url, { + headers: { 'Authorization': `Bearer ${token}` }, + timeout: 5000 // 5 seconds +}); +``` + +2. Add error handling + +```javascript +async function stateRefreshHandler(request) { + try { + // ... + } catch (error) { + if (error.code === 'ECONNABORTED') { + // Timeout handling + return { + headers: { ... }, + authentication: { ... }, + deviceState: [ + { + externalDeviceId: 'device-001', + deviceError: [ + { + errorEnum: 'DEVICE-UNAVAILABLE', + detail: 'Request timeout' + } + ] + } + ] + }; + } + throw error; + } +} +``` + +--- + +## Command Issues + +### Problem 8: Command Not Executed + +**Symptom:** +Command was sent from the app but the device did not respond + +**Possible Causes:** + +1. **Command handler not implemented** +2. **Capability/Command mismatch** +3. **API call failure** + +**Solutions:** + +1. Add logging to Command handler + +```javascript +async function commandHandler(request) { + console.log('[Command] Request:', JSON.stringify(request, null, 2)); + + for (const device of request.devices) { + for (const cmd of device.commands) { + console.log(`[Command] Capability: ${cmd.capability}, Command: ${cmd.command}, Args: ${JSON.stringify(cmd.arguments)}`); + } + } +} +``` + +2. Correct Command response format + +```javascript +{ + "headers": { + "schema": "st-schema", + "version": "1.0", + "interactionType": "commandResponse" + }, + "authentication": { + "token": "user-oauth-token" + }, + "deviceState": [ + { + "externalDeviceId": "device-001", + "deviceError": null, + "states": [ + // Updated state after command execution + { + "component": "main", + "capability": "switch", + "attribute": "switch", + "value": "on" + } + ] + } + ] +} +``` + +--- + +### Problem 9: Command Executes But State Not Updated + +**Symptom:** +Device operates but state does not change in the app + +**Causes:** + +1. **State not included in Command response** +2. **State update missing** + +**Solutions:** + +```javascript +async function commandHandler(request) { + // Execute command + await executeCommand(...); + + // Get latest state and include in response + const updatedState = await deviceApi.getDeviceState(authToken, deviceId); + + return { + headers: { ... }, + authentication: { ... }, + deviceState: [{ + externalDeviceId: deviceId, + states: formatDeviceStates(updatedState) + }] + }; +} +``` + +--- + +## OAuth Issues + +### Problem 10: Re-authentication Fails After Token Expiration + +**Symptom:** +Integration disconnects or stops working after a certain period + +**Causes:** + +1. **Refresh Token not implemented** +2. **Token refresh logic missing** + +**Solutions:** + +SmartThings automatically attempts re-authentication when a token expires. Your own OAuth server must support Refresh Tokens. + +``` +1. SmartThings calls API with token +2. Token expired response (401) +3. SmartThings requests token refresh with Refresh Token +4. Call API again with new token +``` + +--- + +### Problem 11: Authentication Fails in Specific Regions + +**Symptom:** +Integration fails only in specific regions + +**Causes:** + +1. **Regional OAuth servers not separated** +2. **Callback URL region mismatch** + +**Solutions:** + +SmartThings uses different callback URLs for each region: + +| Region | Callback URL | +|--------|-------------| +| US | `https://c2c-us.smartthings.com/oauth/callback` | +| EU | `https://c2c-eu.smartthings.com/oauth/callback` | +| AP | `https://c2c-ap.smartthings.com/oauth/callback` | + +Your OAuth server must allow callback URLs from all regions. + +--- + +## Callback Issues + +### Problem 12: State Change Callback Not Working + +**Symptom:** +Device state changes are not reflected in the SmartThings app + +**Possible Causes:** + +1. **callbackAccessHandler not implemented** +2. **Callback URL not saved** +3. **ST_CLIENT_ID/SECRET not set** + +**Solutions:** + +1. Implement callbackAccessHandler + +```javascript +async function callbackAccessHandler(request) { + const { authentication, callbackUrls, callbackAuth } = request; + + // Save callback info to DB + await saveCallbackInfo(authentication.token, { + callbackUrls, + callbackAuth + }); + + return { + headers: { + schema: 'st-schema', + version: '1.0', + interactionType: 'callbackAccessResponse' + }, + authentication: { token: authentication.token }, + callbackUrls + }; +} +``` + +2. Implement callback sending code + +```javascript +async function sendStateCallback(authToken, deviceStates) { + // Retrieve saved callback info + const callbackInfo = await getCallbackInfo(authToken); + + // Get SmartThings OAuth token + const stToken = await getSmartThingsToken( + callbackInfo.callbackAuth.clientId, + callbackInfo.callbackAuth.clientSecret + ); + + // Send state callback + await axios.post(callbackInfo.callbackUrls.state, { + headers: { + schema: 'st-schema', + version: '1.0', + interactionType: 'stateCallback' + }, + authentication: { token: authToken }, + deviceState: deviceStates + }, { + headers: { 'Authorization': `Bearer ${stToken}` } + }); +} +``` + +--- + +## Logging and Debugging + +### Logging Configuration + +```javascript +// Log all requests/responses +async function logInteraction(type, data) { + console.log(`[${new Date().toISOString()}] ${type}:`); + console.log(JSON.stringify(data, null, 2)); +} + +// Use in handlers +async function discoveryHandler(request) { + logInteraction('Discovery Request', request); + // ... + logInteraction('Discovery Response', response); + return response; +} +``` + +### Local Debugging with ngrok + +```bash +# Run ngrok +ngrok http 3000 + +# Check ngrok logs (separate terminal) +ngrok http 3000 --log stdout +``` + +### Request Tracing + +```javascript +// Trace by request ID +async function discoveryHandler(request) { + const requestId = request.headers.requestId; + console.log(`[${requestId}] Discovery started`); + // ... + console.log(`[${requestId}] Discovery completed`); +} +``` + +--- + +## Common Error Codes + +### SmartThings Error Codes + +#### Global Error Enums (Examples) + +| Error Enum | Description | Common Cause | +|------------|-------------|--------------| +| `BAD-REQUEST` | Bad Request | Malformed request, missing headers, or failed JSON parsing | +| `INVALID-TOKEN` | Invalid Token | Token is malformed or wrong callback URL was used | +| `TOKEN-EXPIRED` | Token Expired | The provided access token is no longer valid | +| `INTEGRATION-DELETED` | Integration Deleted | User removed the integration on the partner side | + +#### Device Error Enums (Examples) + +| Error Enum | Description | Common Cause | +|------------|-------------|--------------| +| `DEVICE-UNAVAILABLE` | Device Unavailable | Device is temporarily unreachable or offline | +| `DEVICE-OFFLINE` | Device Offline | Device is powered off or disconnected from network | +| `DEVICE-DELETED` | Device Deleted | Device was removed from the partner backend | +| `CAPABILITY-NOT-SUPPORTED` | Capability Not Supported | Requested capability or command is not supported by the device | +| `RESOURCE-CONSTRAINT-VIOLATION`| Resource Constraint | Requested action violates a constraint (e.g. out of bounds value) | + +### HTTP Status Codes + +| Code | Meaning | Response | +|------|---------|----------| +| 200 | Success | Normal processing | +| 400 | Bad Request | Check request format | +| 401 | Unauthorized | Check token | +| 403 | Forbidden | Check permissions | +| 404 | Not Found | Check device ID | +| 429 | Rate Limited | Reduce request frequency | +| 500 | Server Error | Check server logs | +| 503 | Service Unavailable | Check server status | + +--- + +## Troubleshooting Checklist + +### Discovery Issues + +- [ ] Check Schema registration +- [ ] Check Developer mode enabled +- [ ] Check OAuth token validity +- [ ] Check Device API response +- [ ] Check Discovery response format + +### StateRefresh Issues + +- [ ] Check StateRefresh handler implementation +- [ ] Check state value format (string vs number vs boolean) +- [ ] Check Capability names +- [ ] Check API timeout settings + +### Command Issues + +- [ ] Check Command handler implementation +- [ ] Check Capability/Command names +- [ ] Check API call success +- [ ] Check updated state included in response + +### OAuth Issues + +- [ ] Check OAuth URLs +- [ ] Check Client ID/Secret +- [ ] Check Redirect URI +- [ ] Check Refresh Token support + +### Callback Issues + +- [ ] Check callbackAccessHandler implementation +- [ ] Check callback info saved +- [ ] Check ST_CLIENT_ID/SECRET settings +- [ ] Check callback sending logic \ No newline at end of file diff --git a/skills/smartthings-cloud-connected-developer/references/best-practice-device-profiles.md b/skills/smartthings-cloud-connected-developer/references/best-practice-device-profiles.md new file mode 100644 index 0000000..69ba915 --- /dev/null +++ b/skills/smartthings-cloud-connected-developer/references/best-practice-device-profiles.md @@ -0,0 +1,128 @@ +# Cloud-Connected Device Profiles Guide + +When connecting a Cloud-Connected (ST-Schema) IoT device to SmartThings, you must define **how the device will appear to the user** (UI/UX layout, card icon) and **what specific features (Capabilities) will be integrated**. + +To implement this, you can choose between two methods: +1. **Device Handler Types (DHT)**: Predefined, standard platform templates. +2. **Custom Device Profiles**: Bespoke profiles custom-built via the Developer Console. + +This guide provides a concise reference to help you make this optimal architectural choice, construct custom profiles, and systematically validate capabilities. + +--- + +## 🗺️ DHT vs. Custom Device Profile Decision Framework + +When integrating your device, choosing between DHT and Custom Device Profiles determines how the interface and capabilities are mapped. + +```mermaid +graph TD + A[Analyze Device Features] --> B[Search Predefined DHT List] + B --> C{Matching DHT found?} + C -- "No" --> F[Create Custom Device Profile] + C -- "Yes" --> E[Use Predefined DHT] + E --> G[No Console Setup Needed
Return DHT ID in Discovery] + F --> H[Build in Developer Console
Map Capabilities & Layouts] + H --> I[Save & Copy UUID
Return UUID in Discovery] +``` + +### 📊 Comparative Quick View + +| Feature | Device Handler Types (DHT) | Custom Device Profiles | +| :--- | :--- | :--- | +| **Concept** | Pre-built standard platform templates. | Bespoke developer-defined UI & capabilities. | +| **Setup Cost** | **Zero**. Reference a predefined string. | **Moderate**. Register & design in Developer Console. | +| **Capability Limit**| Single/Simple standard features. | Multi-component & complex features. | + +### 📝 Decision Checklist +* **Choose DHT if:** Device strictly matches standard types (e.g. simple switch, dimmer, rgb bulb), fast deployment is critical, and custom layouts are unnecessary. +* **Choose Custom Device Profile if:** No matching DHT exists, the device has multiple sensors/controls (e.g. multi-sensor), requires custom attributes/ranges, or needs a specific dashboard layout. + +--- + +## 🛠️ Step-by-Step Profile Creation (Console Web UI) + +1. **Log in and Select Organization**: Go to [SmartThings Developer Console](https://developer.smartthings.com/console/integrations) and select your target **Organization** from the top-right profile selector. +2. **Navigate to Device Profiles**: Select the **`Device Profiles`** tab from the main screen's top navigation bar. +3. **Start Profile Creation**: Click the **`Create`** button on the right side. +4. **Configure Basic Profile Info**: + - **Profile Name**: Enter a descriptive name (e.g., `Lumos Smart Color Bulb`). + - **Category & Icon**: Select the appropriate device category (e.g., `Light`) to bind the corresponding mobile app icon. +5. **Map Capabilities**: + - Search and add standard Capabilities from the right panel. + > [!IMPORTANT] + > **Mandate for WWST Certification** + > Custom Device Profiles **must** include **`healthCheck`** (to prevent a permanent "Checking status..." error). Most devices with readable attributes should also include **`refresh`** (to enable the pull-to-refresh action). Stateless devices without readable attributes may omit it. (Note: When sending states via Schema payload, these are prefixed with the namespace, e.g., `st.healthCheck`). +6. **Configure Dashboard Layout**: + - **Dashboard State**: Select the component and capability to represent the device's status on the dashboard card (e.g., `main → Temperature Measurement` or `main → Switch`). + - **Dashboard Action**: Select the component and capability for the quick action control on the dashboard card (e.g., `main → Switch`). +7. **Save and Copy UUID**: Click **`Save`** to complete the profile creation, and copy the generated **Device Profile ID (UUID)** to use in your SDK's Discovery response. +8. **(Highly Recommended) Verify & Review via CLI**: + - Before implementing discovery or handler code, retrieve and audit the live profile structure registered in the platform using the CLI to ensure no components or capabilities (especially mandatory ones) are missing or misconfigured. + - Run the following command in your terminal: + ```bash + # Fetch the registered profile details in JSON format + smartthings deviceprofiles -j + ``` + - **Verification Checklist**: + - Check if the `components` list and their IDs (e.g., `main`) align perfectly with your hardware spec and planned code logic. + - Ensure **`healthCheck`** (and **`refresh`** if applicable) are explicitly present inside the capabilities list. + - Validate that dashboard state and action mappings point to the correct active attributes. + +--- + +## 📋 Standard Mappings & Recommended Capabilities + +### Standard DHT Mapping (No Console Setup Needed) +Return the exact **Handler ID** as the `deviceHandlerType` in your Discovery payload: + +| Category | Physical Capabilities | Required Capabilities | Standard DHT ID | +| :--- | :--- | :--- | :--- | +| **Switch** | On/Off Switch | `st.switch` | `c2c-switch` | +| **Dimmer** | On/Off + Brightness | `st.switch`, `st.switchLevel` | `c2c-dimmer` | +| **RGB Bulb** | On/Off + Brightness + RGB Color | `st.switch`, `st.switchLevel`, `st.colorControl` | `c2c-rgb-color-bulb` | +| **RGBW Bulb** | On/Off + Brightness + RGB + Color Temp | `st.switch`, `st.switchLevel`, `st.colorControl`, `st.colorTemperature` | `c2c-rgbw-color-bulb` | +| **Motion** | Motion + Battery | `st.motionSensor`, `st.battery` | `c2c-motion-2` | +| **Contact** | Open/Close + Battery | `st.contactSensor`, `st.battery` | `c2c-contact-3` | + +### Recommended Custom Profile Capabilities +Ensure you append **`healthCheck`** to all Custom Device Profiles (and **`refresh`** if the device has readable attributes). Note that these use standard IDs without the `st.` prefix in the Developer Console: + +* **Multi-Color Light**: `switch`, `switchLevel`, `colorControl`, `colorTemperature` +* **Thermostat**: `temperatureMeasurement`, `thermostatMode`, `thermostatCoolingSetpoint`, `thermostatHeatingSetpoint`, `thermostatOperatingState` +* **Environmental Sensor**: `temperatureMeasurement`, `relativeHumidityMeasurement`, `motionSensor`, `battery` + +--- + +## 🔍 Capability Usability & Validation + +Ensure capabilities are valid and supported to pass WWST certification. + +### 📌 3-Step Selection Workflow +1. **Physical Feature Mapping**: Translate spec sheet controls into actuators and sensors. +2. **Search Standard Capabilities**: Find matching standard capability IDs in SmartThings. +3. **CLI Real-Time Validation**: Inspect schemas and status using the CLI. + +### 💻 Essential CLI Commands +Run these in your terminal to inspect capabilities before coding or building profiles: +```bash +# List all standard capabilities to verify existence +smartthings capabilities -s + +# Get schema and details for a specific capability (e.g., switchLevel v1) +smartthings capabilities switchLevel 1 -j +``` + +### 🛡️ WWST Usability Checklist +* [ ] **Namespace Verification (Standard Only)**: + * *Rule*: Use pure standard IDs (e.g., `switch`, `switchLevel`). + * *Violation*: Custom namespace capabilities (e.g., `companyabc.customLight`) will fail standard WWST pipelines. +* [ ] **Status Inspection (Live / Proposed)**: + * *Live/Active* 🟢: Safe for production and WWST. + * *Proposed* 🟡: Active development. **Can be considered and used at the same level as Live** (verification during actual integration is recommended). + * *Deprecated/Dead* 🔴: **Never use.** Automatically fails WWST certification. +* [ ] **Data & Command Alignment**: + * Verify value types (e.g., mapping a physical 0.0-1.0 range to `switchLevel`'s 0-100 integer range using a code mapper). + * Ensure physical commands match capability schema commands. + +> [!WARNING] +> **Anti-Hallucination Rule**: Never invent or use custom namespaces (e.g., `st.myCustomDimmer`) in your Discovery code or Console profiles. \ No newline at end of file diff --git a/skills/smartthings-cloud-connected-developer/references/best-practice-schema-app-code.md b/skills/smartthings-cloud-connected-developer/references/best-practice-schema-app-code.md new file mode 100644 index 0000000..8b379e2 --- /dev/null +++ b/skills/smartthings-cloud-connected-developer/references/best-practice-schema-app-code.md @@ -0,0 +1,939 @@ +This document explains the standard interface and implementation best practices when developing a Node.js-based Schema App using the **SmartThings Schema SDK (st-schema)**. + +> [!TIP] +> The ST-Schema SDK provides abstracted handler signatures and builder patterns for each SmartThings Interaction Type (Discovery, State, Command, etc.). Using SDK methods instead of constructing HTTP headers and response bodies directly helps prevent specification errors and makes maintenance easier. + +## Table of Contents + +1. [Project Structure](#project-structure) +2. [Package Installation](#package-installation) +3. [Code Templates](#code-templates) +4. [Handler Implementation](#handler-implementation) +5. [Own Device API Integration](#own-device-api-integration) +6. [Environment Variable Configuration](#environment-variable-configuration) +7. [Local Testing](#local-testing) +8. [Deployment Guide](#deployment-guide) +9. [Code Writing and Review Principles](#code-writing-and-review-principles) + +--- + +## Code Writing and Review Principles + +When generating or reviewing code using the ST-Schema SDK, the following principles must be strictly observed. + +### 1. Capability ID Prefix Usage (st.) +When adding states or processing commands via SDK methods (`addState`, `addDevice`, etc.), all **standard Capability IDs (SmartThings Official Capabilities) must include the `st.` prefix.** + +- **Correct**: `st.switch`, `st.switchLevel`, `st.temperatureMeasurement` +- **Incorrect**: `switch`, `switchLevel`, `temperatureMeasurement` (In this case, the SDK may not recognize them or may treat them as custom Capabilities) + +### 2. Attribute and Command Names +Attribute names and Command names use standard naming without the `st.` prefix. +- **Example**: capability: `st.switch`, attribute: `switch`, command: `on`/`off` + +### 3. Interaction Result Verification +During development, `interactionResultHandler` must be implemented to monitor specification errors (Invalid format, etc.) delivered from the SmartThings app in real-time. + +--- + +## Project Structure + +``` +schema-app/ +├── package.json # Project configuration +├── src/ +│ ├── index.js # Express server entry point +│ ├── connector.js # ST-Schema connector instance +│ ├── handlers/ +│ │ ├── discovery.js # Discovery handler +│ │ ├── state-refresh.js # StateRefresh handler +│ │ ├── command.js # Command handler +│ │ ├── callback-access.js # CallbackAccess handler +│ │ ├── integration-deleted.js # IntegrationDeleted handler +│ │ └── interaction-result.js # InteractionResult handler (optional) +│ └── api/ +│ └── device-api.js # Own Device API client +├── .env.example # Environment variable template +├── .gitignore +└── README.md +``` + +--- + +## Package Installation + +### package.json + +```json +{ + "name": "smartthings-schema-app", + "version": "1.0.0", + "description": "SmartThings Cloud Connected Schema App", + "main": "src/index.js", + "scripts": { + "start": "node src/index.js", + "dev": "nodemon src/index.js", + "test": "jest" + }, + "dependencies": { + "st-schema": "^1.5.1", + "uuid": "^9.0.1", + "express": "^4.18.2", + "axios": "^1.6.0", + "dotenv": "^16.3.1", + "body-parser": "^1.20.2" + }, + "devDependencies": { + "nodemon": "^3.0.1", + "jest": "^29.7.0" + }, + "engines": { + "node": ">=18.0.0" + } +} +``` + +### Installation Command + +```bash +npm init -y +npm install st-schema express axios dotenv body-parser +npm install -D nodemon jest +``` + +--- + +## Code Templates + +### src/index.js (Express Server Entry Point) + +```javascript +require('dotenv').config(); +const express = require('express'); +const bodyParser = require('body-parser'); +const { connector } = require('./connector'); + +const app = express(); +const PORT = process.env.PORT || 3000; + +// Middleware +app.use(bodyParser.json()); + +// Health check endpoint +app.get('/health', (req, res) => { + res.status(200).json({ status: 'ok', timestamp: new Date().toISOString() }); +}); + +// SmartThings ST-Schema endpoint +app.post('/', (req, res) => { + connector.handleHttpCallback(req, res); +}); + +// Start server +app.listen(PORT, () => { + console.log(`Schema App server running on port ${PORT}`); + console.log(`Health check: http://localhost:${PORT}/health`); + console.log(`ST-Schema endpoint: http://localhost:${PORT}/`); +}); +``` + +### src/connector.js (ST-Schema Connector Instance) + +```javascript +const { SchemaConnector } = require('st-schema'); +const discoveryHandler = require('./handlers/discovery'); +const stateRefreshHandler = require('./handlers/state-refresh'); +const commandHandler = require('./handlers/command'); +const callbackAccessHandler = require('./handlers/callback-access'); +const integrationDeletedHandler = require('./handlers/integration-deleted'); +const interactionResultHandler = require('./handlers/interaction-result'); + +const connector = new SchemaConnector() + .clientId(process.env.ST_CLIENT_ID) + .clientSecret(process.env.ST_CLIENT_SECRET) + .discoveryHandler(discoveryHandler) + .stateRefreshHandler(stateRefreshHandler) + .commandHandler(commandHandler) + .callbackAccessHandler(callbackAccessHandler) + .integrationDeletedHandler(integrationDeletedHandler) + .interactionResultHandler(interactionResultHandler); + +module.exports = { connector }; +``` + +--- + +## Handler Implementation + +### src/handlers/discovery.js (Discovery Handler) + +```javascript +const deviceApi = require('../api/device-api'); + +/** + * Discovery Handler + * Called when SmartThings requests the device list + */ +async function discoveryHandler(accessToken, response) { + console.log('[Discovery] Request received for token:', accessToken.substring(0, 10) + '...'); + + try { + const devices = await deviceApi.getDevices(accessToken); + + for (const device of devices) { + const stDevice = response.addDevice( + device.id, // externalDeviceId + device.name, // friendlyName + device.deviceHandlerType // deviceHandlerType: Standard Device Handler Type (e.g., 'c2c-switch') OR Custom Device Profile ID (UUID) + ); + + stDevice.manufacturerName(process.env.MANUFACTURER_NAME || 'MyCompany') + .modelName(device.modelName || 'SmartDevice-V1') + .deviceUniqueId(device.serialNumber || device.id); + + if (device.roomName) { + stDevice.roomName(device.roomName); + } + } + + console.log(`[Discovery] Success: ${devices.length} devices found.`); + } catch (error) { + console.error('[Discovery] Error:', error.message); + response.setError(error.message, 'INTEGRATION-OFFLINE'); + } +} + +module.exports = discoveryHandler; +``` + +### src/handlers/state-refresh.js (StateRefresh Handler) + +```javascript +const deviceApi = require('../api/device-api'); + +/** + * StateRefresh Handler + * Called when SmartThings requests device state + */ +async function stateRefreshHandler(accessToken, response, data) { + console.log('[StateRefresh] Request received for devices:', data.devices.map(d => d.externalDeviceId)); + + try { + for (const requestedDevice of data.devices) { + const externalDeviceId = requestedDevice.externalDeviceId; + try { + const deviceState = await deviceApi.getDeviceState(accessToken, externalDeviceId); + addStatesToResponse(response, externalDeviceId, deviceState); + } catch (deviceError) { + console.error(`[StateRefresh] Error for device ${externalDeviceId}:`, deviceError.message); + response.addDevice(externalDeviceId).setError(deviceError.message, 'DEVICE-OFFLINE'); + } + } + console.log('[StateRefresh] Success'); + } catch (error) { + console.error('[StateRefresh] Global Error:', error.message); + response.setError(error.message, 'INTEGRATION-OFFLINE'); + } +} + +function addStatesToResponse(response, externalDeviceId, deviceState) { + const device = response.addDevice(externalDeviceId); + const component = device.addComponent('main'); + + if (deviceState.power !== undefined) { + component.addState('st.switch', 'switch', deviceState.power ? 'on' : 'off'); + } + if (deviceState.level !== undefined) { + component.addState('st.switchLevel', 'level', deviceState.level); + } + if (deviceState.temperature !== undefined) { + component.addState('st.temperatureMeasurement', 'temperature', deviceState.temperature, 'C'); + } + if (deviceState.humidity !== undefined) { + component.addState('st.relativeHumidityMeasurement', 'humidity', deviceState.humidity, '%'); + } + component.addState('st.healthCheck', 'healthStatus', deviceState.online ? 'online' : 'offline'); +} + +module.exports = stateRefreshHandler; +``` + +### src/handlers/command.js (Command Handler) + +```javascript +const deviceApi = require('../api/device-api'); + +/** + * Command Handler + * Called when SmartThings sends a device control command + */ +async function commandHandler(accessToken, response, devices, data) { + console.log('[Command] Request received for devices:', devices.map(d => d.externalDeviceId)); + + try { + for (const requestedDevice of devices) { + const externalDeviceId = requestedDevice.externalDeviceId; + const commands = requestedDevice.commands; + + try { + for (const command of commands) { + const { capability, command: cmd, arguments: args } = command; + console.log(`[Command] Executing: ${cmd} on device ${externalDeviceId}`); + await executeCommand(accessToken, externalDeviceId, capability, cmd, args); + } + const deviceState = await deviceApi.getDeviceState(accessToken, externalDeviceId); + addStatesToResponse(response, externalDeviceId, deviceState); + } catch (deviceError) { + console.error(`[Command] Device Error for ${externalDeviceId}:`, deviceError.message); + response.addDevice(externalDeviceId).setError(deviceError.message, 'DEVICE-OFFLINE'); + } + } + console.log('[Command] Success'); + } catch (error) { + console.error('[Command] Global Error:', error.message); + response.setError(error.message, 'INTEGRATION-OFFLINE'); + } +} + +async function executeCommand(authToken, deviceId, capability, cmd, args) { + switch (capability) { + case 'st.switch': + return deviceApi.setPower(authToken, deviceId, cmd === 'on'); + case 'st.switchLevel': + if (cmd === 'setLevel') return deviceApi.setLevel(authToken, deviceId, args[0]); + break; + case 'st.colorControl': + if (cmd === 'setColor') return deviceApi.setColor(authToken, deviceId, args[0]); + if (cmd === 'setHue') return deviceApi.setHue(authToken, deviceId, args[0]); + if (cmd === 'setSaturation') return deviceApi.setSaturation(authToken, deviceId, args[0]); + break; + case 'st.colorTemperature': + if (cmd === 'setColorTemperature') return deviceApi.setColorTemperature(authToken, deviceId, args[0]); + break; + case 'st.thermostatMode': + if (cmd === 'setThermostatMode') return deviceApi.setThermostatMode(authToken, deviceId, args[0]); + break; + case 'st.thermostatCoolingSetpoint': + if (cmd === 'setCoolingSetpoint') return deviceApi.setCoolingSetpoint(authToken, deviceId, args[0]); + break; + case 'st.thermostatHeatingSetpoint': + if (cmd === 'setHeatingSetpoint') return deviceApi.setHeatingSetpoint(authToken, deviceId, args[0]); + break; + case 'st.lock': + return deviceApi.setLock(authToken, deviceId, cmd === 'lock' ? 'locked' : 'unlocked'); + case 'st.doorControl': + case 'st.garageDoorControl': + return deviceApi.setDoorState(authToken, deviceId, cmd === 'open' ? 'open' : 'closed'); + case 'st.windowShade': + if (cmd === 'open') return deviceApi.setWindowShade(authToken, deviceId, 'open'); + if (cmd === 'close') return deviceApi.setWindowShade(authToken, deviceId, 'closed'); + if (cmd === 'pause') return deviceApi.setWindowShade(authToken, deviceId, 'partially_opened'); + break; + case 'st.windowShadeLevel': + if (cmd === 'setShadeLevel') return deviceApi.setShadeLevel(authToken, deviceId, args[0]); + break; + case 'st.refresh': + return Promise.resolve(); + default: + throw new Error(`Unsupported capability: ${capability}`); + } +} + +module.exports = commandHandler; +``` + +### src/handlers/callback-access.js (CallbackAccess Handler) + +```javascript +/** + * CallbackAccess Handler + * Called when SmartThings delivers callback URLs and tokens + * Used to send push notifications to SmartThings when device state changes + */ +async function callbackAccessHandler(accessToken, callbackAuthentication, callbackUrls, body) { + console.log('[CallbackAccess] Request received'); + + try { + const callbackInfo = { + userAccessToken: accessToken, + callbackUrls, + callbackAuth: callbackAuthentication, + updatedAt: new Date().toISOString() + }; + + // IMPORTANT: You must save these tokens (callbackUrls, callbackAuth) to send proactive state updates later. + // They should be stored uniquely per user (e.g., keyed by userAccessToken). + + // For local testing, you can save them to a file: + // const fs = require('fs'); + // let callbacksDB = {}; + // if (fs.existsSync('callbacks.json')) { + // callbacksDB = JSON.parse(fs.readFileSync('callbacks.json', 'utf8')); + // } + // callbacksDB[accessToken] = callbackInfo; + // fs.writeFileSync('callbacks.json', JSON.stringify(callbacksDB, null, 2)); + + // For production: Save to DB + // await db.saveCallbackInfo(accessToken, callbackInfo); + + console.log('[CallbackAccess] Callback info stored for proactive updates'); + } catch (error) { + console.error('[CallbackAccess] Error:', error.message); + } +} + +module.exports = callbackAccessHandler; +``` + +### src/handlers/integration-deleted.js (IntegrationDeleted Handler) + +```javascript +/** + * IntegrationDeleted Handler + * Called when the user removes the integration from the SmartThings App + */ +async function integrationDeletedHandler(accessToken, response) { + console.log('[IntegrationDeleted] Request received'); + + try { + // TODO: Clean up integration-related data + // await db.removeUser(accessToken); + console.log('[IntegrationDeleted] Cleanup complete'); + } catch (error) { + console.error('[IntegrationDeleted] Error during cleanup:', error.message); + } +} + +module.exports = integrationDeletedHandler; +``` + +### src/handlers/interaction-result.js (InteractionResult Handler) + +```javascript +/** + * InteractionResult Handler + * Called when SmartThings notifies the result of a request processing + * Used for debugging purposes + */ +async function interactionResultHandler(accessToken, response, data) { + console.log('[InteractionResult] Request received'); + + const { interactionResult } = data; + + if (interactionResult?.errorState) { + console.error('[InteractionResult] Error state:', interactionResult.errorState); + console.error('[InteractionResult] Error reason:', interactionResult.errorReason); + console.error('[InteractionResult] Description:', interactionResult.errorDescription); + } else { + console.log('[InteractionResult] Success'); + } +} + +module.exports = interactionResultHandler; +``` + +--- + +## Own Device API Integration + +### src/api/device-api.js + +```javascript +const axios = require('axios'); + +const DEVICE_API_BASE_URL = process.env.DEVICE_API_URL || 'https://api.yourcompany.com/v1'; + +const deviceApi = { + async getDevices(authToken) { + try { + const response = await axios.get(`${DEVICE_API_BASE_URL}/devices`, { + headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' } + }); + return response.data.devices || response.data; + } catch (error) { + console.error('[DeviceAPI] getDevices error:', error.message); + throw new Error('Failed to get device list'); + } + }, + + async getDeviceState(authToken, deviceId) { + try { + const response = await axios.get(`${DEVICE_API_BASE_URL}/devices/${deviceId}/state`, { + headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' } + }); + return response.data; + } catch (error) { + console.error('[DeviceAPI] getDeviceState error:', error.message); + throw new Error(`Failed to get device state: ${deviceId}`); + } + }, + + async setPower(authToken, deviceId, power) { + try { + await axios.post(`${DEVICE_API_BASE_URL}/devices/${deviceId}/power`, { + power: power ? 'on' : 'off' + }, { headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' } }); + } catch (error) { + console.error('[DeviceAPI] setPower error:', error.message); + throw new Error(`Failed to set power: ${deviceId}`); + } + }, + + async setLevel(authToken, deviceId, level) { + try { + await axios.post(`${DEVICE_API_BASE_URL}/devices/${deviceId}/level`, { + level: level + }, { headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' } }); + } catch (error) { + console.error('[DeviceAPI] setLevel error:', error.message); + throw new Error(`Failed to set level: ${deviceId}`); + } + }, + + async setColor(authToken, deviceId, color) { + try { + await axios.post(`${DEVICE_API_BASE_URL}/devices/${deviceId}/color`, { + hue: color.hue, saturation: color.saturation + }, { headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' } }); + } catch (error) { + console.error('[DeviceAPI] setColor error:', error.message); + throw new Error(`Failed to set color: ${deviceId}`); + } + }, + + async setColorTemperature(authToken, deviceId, colorTemperature) { + try { + await axios.post(`${DEVICE_API_BASE_URL}/devices/${deviceId}/color-temperature`, { + colorTemperature: colorTemperature + }, { headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' } }); + } catch (error) { + console.error('[DeviceAPI] setColorTemperature error:', error.message); + throw new Error(`Failed to set color temperature: ${deviceId}`); + } + }, + + async setThermostatMode(authToken, deviceId, mode) { + try { + await axios.post(`${DEVICE_API_BASE_URL}/devices/${deviceId}/thermostat/mode`, { + mode: mode + }, { headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' } }); + } catch (error) { + console.error('[DeviceAPI] setThermostatMode error:', error.message); + throw new Error(`Failed to set thermostat mode: ${deviceId}`); + } + }, + + async setCoolingSetpoint(authToken, deviceId, temperature) { + try { + await axios.post(`${DEVICE_API_BASE_URL}/devices/${deviceId}/thermostat/cooling-setpoint`, { + temperature: temperature + }, { headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' } }); + } catch (error) { + console.error('[DeviceAPI] setCoolingSetpoint error:', error.message); + throw new Error(`Failed to set cooling setpoint: ${deviceId}`); + } + }, + + async setHeatingSetpoint(authToken, deviceId, temperature) { + try { + await axios.post(`${DEVICE_API_BASE_URL}/devices/${deviceId}/thermostat/heating-setpoint`, { + temperature: temperature + }, { headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' } }); + } catch (error) { + console.error('[DeviceAPI] setHeatingSetpoint error:', error.message); + throw new Error(`Failed to set heating setpoint: ${deviceId}`); + } + }, + + async setLock(authToken, deviceId, state) { + try { + await axios.post(`${DEVICE_API_BASE_URL}/devices/${deviceId}/lock`, { + state: state + }, { headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' } }); + } catch (error) { + console.error('[DeviceAPI] setLock error:', error.message); + throw new Error(`Failed to set lock: ${deviceId}`); + } + }, + + async setDoorState(authToken, deviceId, state) { + try { + await axios.post(`${DEVICE_API_BASE_URL}/devices/${deviceId}/door`, { + state: state + }, { headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' } }); + } catch (error) { + console.error('[DeviceAPI] setDoorState error:', error.message); + throw new Error(`Failed to set door state: ${deviceId}`); + } + }, + + async setWindowShade(authToken, deviceId, state) { + try { + await axios.post(`${DEVICE_API_BASE_URL}/devices/${deviceId}/window-shade`, { + state: state + }, { headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' } }); + } catch (error) { + console.error('[DeviceAPI] setWindowShade error:', error.message); + throw new Error(`Failed to set window shade: ${deviceId}`); + } + }, + + async setShadeLevel(authToken, deviceId, level) { + try { + await axios.post(`${DEVICE_API_BASE_URL}/devices/${deviceId}/shade-level`, { + level: level + }, { headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' } }); + } catch (error) { + console.error('[DeviceAPI] setShadeLevel error:', error.message); + throw new Error(`Failed to set shade level: ${deviceId}`); + } + }, + + async setHue(authToken, deviceId, hue) { + try { + await axios.post(`${DEVICE_API_BASE_URL}/devices/${deviceId}/hue`, { + hue: hue + }, { headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' } }); + } catch (error) { + console.error('[DeviceAPI] setHue error:', error.message); + throw new Error(`Failed to set hue: ${deviceId}`); + } + }, + + async setSaturation(authToken, deviceId, saturation) { + try { + await axios.post(`${DEVICE_API_BASE_URL}/devices/${deviceId}/saturation`, { + saturation: saturation + }, { headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' } }); + } catch (error) { + console.error('[DeviceAPI] setSaturation error:', error.message); + throw new Error(`Failed to set saturation: ${deviceId}`); + } + } +}; + +module.exports = deviceApi; +``` + +--- + +## Environment Variable Configuration + +### .env.example + +```env +# Server Configuration +PORT=3000 +NODE_ENV=development + +# SmartThings Configuration +ST_CLIENT_ID=your-smartthings-client-id +ST_CLIENT_SECRET=your-smartthings-client-secret +MANUFACTURER_NAME=YourCompany + +# Device API Configuration +DEVICE_API_URL=https://api.yourcompany.com/v1 + +# OAuth2 Configuration (Own auth server) +OAUTH_AUTHORIZE_URL=https://auth.yourcompany.com/oauth/authorize +OAUTH_TOKEN_URL=https://auth.yourcompany.com/oauth/token +OAUTH_CLIENT_ID=your-oauth-client-id +OAUTH_CLIENT_SECRET=your-oauth-client-secret +``` + +### .gitignore + +``` +node_modules/ +.env +*.log +.DS_Store +``` + +--- + +## Local Testing + +### Local Testing with ngrok + +1. **Install ngrok** +```bash +npm install -g ngrok +``` + +2. **Run server** +```bash +npm run dev +``` + +3. **Create ngrok tunnel** +```bash +ngrok http 3000 +``` + +4. **Check ngrok URL** +``` +Forwarding https://xxxx-xx-xx-xxx-xx.ngrok.io -> http://localhost:3000 +``` + +5. **Register in SmartThings Schema** + - Register the ngrok URL as the SmartThings Schema endpoint + - Example: `https://xxxx-xx-xx-xxx-xx.ngrok.io` + +### Testing with curl + +#### Discovery Test +```bash +curl -X POST http://localhost:3000/ \ + -H "Content-Type: application/json" \ + -d '{ + "headers": { + "schema": "st-schema", + "version": "1.0", + "interactionType": "discoveryRequest", + "requestId": "test-request-id" + }, + "authentication": { + "token": "test-oauth-token", + "tokenType": "Bearer" + } + }' +``` + +#### StateRefresh Test +```bash +curl -X POST http://localhost:3000/ \ + -H "Content-Type: application/json" \ + -d '{ + "headers": { + "schema": "st-schema", + "version": "1.0", + "interactionType": "stateRefreshRequest", + "requestId": "test-request-id" + }, + "authentication": { + "token": "test-oauth-token", + "tokenType": "Bearer" + }, + "devices": [ + { + "externalDeviceId": "device-001" + } + ] + }' +``` + +#### Command Test +```bash +curl -X POST http://localhost:3000/ \ + -H "Content-Type: application/json" \ + -d '{ + "headers": { + "schema": "st-schema", + "version": "1.0", + "interactionType": "commandRequest", + "requestId": "test-request-id" + }, + "authentication": { + "token": "test-oauth-token", + "tokenType": "Bearer" + }, + "devices": [ + { + "externalDeviceId": "device-001", + "commands": [ + { + "component": "main", + "capability": "switch", + "command": "on", + "arguments": [] + } + ] + } + ] + }' +``` + +--- + +## Deployment Guide + +### AWS Lambda Deployment + +1. **Install Serverless Framework** +```bash +npm install -g serverless +``` + +2. **Create serverless.yml** +```yaml +service: smartthings-schema-app + +provider: + name: aws + runtime: nodejs18.x + stage: dev + region: us-east-1 + +functions: + connector: + handler: src/index.handler + events: + - http: + path: / + method: post + cors: true + - http: + path: health + method: get + cors: true +``` + +3. **Deploy** +```bash +serverless deploy +``` + +### Docker Deployment + +1. **Create Dockerfile** +```dockerfile +FROM node:18-alpine + +WORKDIR /app + +COPY package*.json ./ +RUN npm ci --only=production + +COPY src/ ./src/ + +EXPOSE 3000 + +CMD ["node", "src/index.js"] +``` + +2. **Build Docker image** +```bash +docker build -t smartthings-schema-app . +``` + +3. **Run Docker** +```bash +docker run -p 3000:3000 --env-file .env smartthings-schema-app +``` + +--- + +## Proactive State Callbacks + +How to send callbacks to SmartThings when device state changes. + +### Callback Implementation Example + +```javascript +const axios = require('axios'); + +/** + * Send state change callback to SmartThings + * + * @param {string} callbackUrl - Callback URL received from callbackAccessHandler + * @param {string} clientId - Client ID issued by SmartThings + * @param {string} clientSecret - Client secret issued by SmartThings + * @param {string} authToken - User OAuth token + * @param {Array} deviceStates - List of changed device states + */ +async function sendStateCallback(callbackUrls, clientId, clientSecret, callbackAuth, deviceStates) { + try { + const { StateUpdateRequest } = require('st-schema'); + + // Use SDK's StateUpdateRequest class + const callback = new StateUpdateRequest(clientId, clientSecret); + + await callback.updateState(callbackUrls, callbackAuth, deviceStates); + + console.log('[Callback] State callback sent successfully via SDK'); + } catch (error) { + console.error('[Callback] Error sending state callback:', error.message); + throw error; + } +} +``` + +### Usage Example + +```javascript +// When device state change is detected +const deviceStates = [ + { + externalDeviceId: 'device-001', + states: [ + { + component: 'main', + capability: 'switch', + attribute: 'switch', + value: 'on' + } + ] + } +]; + +await sendStateCallback( + callbackUrls, // Saved callbackUrls object + process.env.ST_CLIENT_ID, + process.env.ST_CLIENT_SECRET, + callbackAuth, // Saved callbackAuth/callbackAuthentication object + deviceStates +); +``` + +--- + +## Error Handling + +### Error Types (Examples) + +| Error Enum | Description | +|------------|-------------| +| `DEVICE-OFFLINE` | Device is offline and cannot accept commands. | +| `DEVICE-UNAVAILABLE` | Device is temporarily unavailable (e.g. firmware update). | +| `DEVICE-DELETED` | Device is deleted and cannot accept commands. | +| `CAPABILITY-NOT-SUPPORTED` | Requested capability or command is not supported by the device. | +| `RESOURCE-CONSTRAINT-VIOLATION` | Requested action violates a resource constraint (e.g. out of bounds value). | +| `BAD-REQUEST` | Bad request or missing st-schema headers/authentication. | +| `TOKEN-EXPIRED` | Token has expired. | +| `INTEGRATION-OFFLINE` | All devices in the integration are offline, or the integration is unreachable. | +| `INTEGRATION-DELETED` | User has removed the integration. | + +### Error Response Format + +```javascript +{ + headers: { + schema: 'st-schema', + version: '1.0', + interactionType: 'commandResponse' + }, + authentication: { + token: authToken + }, + deviceState: [ + { + externalDeviceId: 'device-001', + deviceError: [ + { + errorEnum: 'DEVICE-OFFLINE', + detail: 'Device is offline' + } + ] + } + ] +} +``` + +--- + +## References + +- [ST-Schema SDK (Node.js)](https://github.com/SmartThingsCommunity/st-schema-nodejs) +- [Interaction Types](https://developer.smartthings.com/docs/devices/cloud-connected/interaction-types) +- [Proactive State Callbacks](https://github.com/SmartThingsCommunity/st-schema-nodejs/tree/master?tab=readme-ov-file#proactive-state-callbacks) diff --git a/skills/smartthings-cloud-connected-developer/references/best-practice-stts-checklist.md b/skills/smartthings-cloud-connected-developer/references/best-practice-stts-checklist.md new file mode 100644 index 0000000..a6deef5 --- /dev/null +++ b/skills/smartthings-cloud-connected-developer/references/best-practice-stts-checklist.md @@ -0,0 +1,328 @@ +# WWST Certification Checklist + +This document provides a checklist for SmartThings WWST (Works With SmartThings) certification. + +## Table of Contents + +1. [Pre-Certification Preparations](#pre-certification-preparations) +2. [Feature-by-Feature Checklist](#feature-by-feature-checklist) +3. [Regional Testing](#regional-testing) +4. [STTS Test Suite](#stts-test-suite) +5. [How to Apply for Certification](#how-to-apply-for-certification) +6. [Post-Certification Management](#post-certification-management) + +--- + +## Pre-Certification Preparations + +### Required Items + +- [ ] SmartThings Developer account created +- [ ] Organization created or joined +- [ ] Brand registered +- [ ] Product registered +- [ ] Device Profile created (Optional) +- [ ] SmartThings Schema (Schema App) implemented +- [ ] SmartThings Schema (Schema App) registered +- [ ] Hosting environment set up + +### Document Preparation + +- [ ] Product image (transparent background, minimum 584x584px) +- [ ] Product description document +- [ ] Product number (M/N, EAN, UPC, SKU, etc.) +- [ ] Purchase link (optional) +- [ ] Supported regions list + +--- + +## Feature-by-Feature Checklist + +### 1. OAuth Authentication + +- [ ] OAuth 2.0 authentication server working properly +- [ ] Authorization Code Grant supported +- [ ] Refresh Token supported +- [ ] Correct Redirect URI settings + - [ ] US: `https://c2c-us.smartthings.com/oauth/callback` + - [ ] EU: `https://c2c-eu.smartthings.com/oauth/callback` + - [ ] AP: `https://c2c-ap.smartthings.com/oauth/callback` +- [ ] Re-authentication works when token expires +- [ ] Logout/integration removal works properly + +### 2. Discovery (Device Discovery) + +- [ ] Device list returned normally +- [ ] All device types displayed normally +- [ ] Device name (friendlyName) displayed normally +- [ ] Device icon displayed normally +- [ ] Offline devices handled appropriately +- [ ] Large number of devices (100+) can be processed + +### 3. StateRefresh (State Query) + +- [ ] Device state queried normally +- [ ] All Capability states returned normally +- [ ] State value formats correct (string, number, boolean) +- [ ] Offline device state handling +- [ ] Response time within 5 seconds +- [ ] Multi-device state query supported + +### 4. Command (Device Control) + +- [ ] Power control (on/off) works normally +- [ ] Level control (brightness, etc.) works normally +- [ ] Color control works normally (if supported) +- [ ] Mode control works normally (if supported) +- [ ] State update after command execution normal +- [ ] Error response on command failure normal +- [ ] Consecutive command processing supported + +### 5. Health Check + +- [ ] Device online/offline status displayed +- [ ] healthCheck Capability implemented +- [ ] Offline devices distinctly displayed +- [ ] Timeout handling appropriate + +### 6. Callback (State Change Notification) + +- [ ] callbackAccessHandler implemented +- [ ] Callback URL saving functionality +- [ ] Callback sent on state change +- [ ] Callback authentication working normally +- [ ] Multi-user callback supported + +### 7. Integration Deleted + +- [ ] integrationDeletedHandler implemented +- [ ] Data cleanup on integration removal +- [ ] Token invalidation processing + +--- + +## Regional Testing + +SmartThings is serviced in multiple regions, so testing for each region is required. + +### Regional Test Items + +#### US Region +- [ ] Change Samsung account to US region +- [ ] Integration works normally +- [ ] Device discovery normal +- [ ] State query normal +- [ ] Command control normal +- [ ] Callback works normally + +#### EU Region +- [ ] Change Samsung account to European region (e.g., Germany) +- [ ] Integration works normally +- [ ] Device discovery normal +- [ ] State query normal +- [ ] Command control normal +- [ ] Callback works normally + +#### AP Region +- [ ] Change Samsung account to Asian region (e.g., Korea) +- [ ] Integration works normally +- [ ] Device discovery normal +- [ ] State query normal +- [ ] Command control normal +- [ ] Callback works normally + +### Regional Test Accounts + +- You must create separate Samsung accounts for each region you wish to test. +- Changing the region of an existing Samsung account is not recommended and may cause integration issues. + +--- + +## STTS Test Suite + +The SmartThings Test Suite (STTS) is an automated certification testing tool. + +### How to Run STTS + +1. Access SmartThings Console +2. Select the project +3. Enter the Test Suite menu +4. Run the test + +### STTS Test Items + +#### Basic Tests +- [ ] Discovery Test + - Device list query + - Response format validation + +- [ ] State Refresh Test + - State query + - State value validation + +- [ ] Command Test + - Basic commands (on/off) + - State update validation + +#### Capability-Specific Tests + +**switch** +- [ ] on command normal +- [ ] off command normal +- [ ] State synchronization normal + +**switchLevel** +- [ ] setLevel command normal +- [ ] Level range (0-100) normal + +**colorControl** +- [ ] setColor command normal +- [ ] setHue command normal +- [ ] setSaturation command normal + +**colorTemperature** +- [ ] setColorTemperature command normal +- [ ] Color temperature range normal + +**thermostat** +- [ ] setThermostatMode command normal +- [ ] setCoolingSetpoint command normal +- [ ] setHeatingSetpoint command normal +- [ ] Temperature range normal + +**lock** +- [ ] lock command normal +- [ ] unlock command normal +- [ ] Lock state synchronization normal + +**Sensor Capabilities** +- [ ] temperatureMeasurement state normal +- [ ] relativeHumidityMeasurement state normal +- [ ] motionSensor state normal +- [ ] contactSensor state normal + +### STTS Result Confirmation + +- PASS: Test passed +- FAIL: Test failed (fix required) +- SKIP: Capability not applicable + +All tests must PASS to apply for certification. + +--- + +## How to Apply for Certification + +### 1. Verify Certification Requirements + +- [ ] All STTS tests passed +- [ ] All documents prepared +- [ ] 3 regional tests completed +- [ ] All feature checklist items completed + +### 2. Apply for Certification + +1. Access SmartThings Console +2. Select the project +3. Enter the Certification menu +4. Complete the certification application: + - Confirm product information + - Confirm test results + - Enter additional information (if needed) +5. Submit application + +### 3. Certification Review + +- SmartThings team conducts manual review +- May request additional information +- Approval or rejection decision + +### 4. Certification Complete + +- Upon certification approval, the Works With SmartThings logo can be used +- Product is published in the SmartThings App +- CbS (Certification by Similarity) program becomes available + +--- + +## Post-Certification Management + +### Maintenance + +- [ ] Maintain API compatibility +- [ ] Maintain server availability (99.9% target) +- [ ] Apply security updates +- [ ] Monitor errors + +### Handling Changes + +When there are changes to the product: + +1. **Minor Change** + - UI changes + - Internal logic improvements + - No separate certification required + +2. **Major Change** + - New Capability added + - API structure changes + - Re-certification required + +3. **Breaking Change** + - Existing devices no longer supported + - Full re-certification required + +### CbS (Certification by Similarity) + +Simplified procedure when adding products similar to an already certified product: + +**Application Conditions:** +- Uses the same Schema App +- Uses the same Device Profile +- Uses the same API structure +- Only brand/model name differs + +**Benefits:** +- Free certification +- Simplified testing +- Faster approval + +--- + +## Checklist Summary + +### Final Pre-Certification Check + +| Item | Status | +|------|--------| +| OAuth authentication normal | ☐ | +| Discovery normal | ☐ | +| StateRefresh normal | ☐ | +| Command normal | ☐ | +| Callback normal | ☐ | +| Health Check normal | ☐ | +| US region testing complete | ☐ | +| EU region testing complete | ☐ | +| AP region testing complete | ☐ | +| STTS tests passed | ☐ | +| Documents prepared | ☐ | + +### Common Problems and Solutions + +| Problem | Cause | Solution | +|---------|-------|----------| +| STTS Discovery failure | Response format error | Validate JSON schema | +| STTS Command failure | State not reflected | Query state after command | +| Regional failure | Callback URL mismatch | Allow callbacks for all regions | +| Timeout failure | Response delay | Keep response within 5 seconds | +| Certification rejected | Incomplete documents | Check required documents | + +--- + +## Reference Links + +- [WWST Certification Guide](https://developer.smartthings.com/docs/certification) +- [STTS Test Suite](https://developer.smartthings.com/docs/certification/test-suite) +- [Required Capabilities](https://developer.smartthings.com/docs/certification/required-capabilities) +- [CbS Program](https://developer.smartthings.com/docs/certification/certification-by-similarity) +- [SmartThings Console](https://developer.smartthings.com/console) \ No newline at end of file diff --git a/skills/smartthings-device-onboarding-qr/SKILL.md b/skills/smartthings-device-onboarding-qr/SKILL.md new file mode 100644 index 0000000..acb9dfb --- /dev/null +++ b/skills/smartthings-device-onboarding-qr/SKILL.md @@ -0,0 +1,147 @@ +--- +name: smartthings-device-onboarding-qr +description: Explains SmartThings device QR code purpose, security and onboarding role, and type-specific formats for Matter, Zigbee 3.0, Direct Connected (st-device-sdk-c), and Mobile Connected (SmartThings Find Device SDK). Covers Zigbee minimum vs recommended payloads (install code, manufacturer code, OUI), WWST partner notification, official publish docs, partner QR label template link, per-type field checklist, and product-oriented payload examples. Use when the user asks about SmartThings device QR codes, onboarding QR requirements, Zigbee 3.0 install-code QR, Matter CSA QR, Direct Connected or Mobile Connected QR specifications, Find Device SDK, WWST QR registration, or partner label print layout. +metadata: + version: "2026-05-29" +--- + +# SmartThings device onboarding QR codes + +## When to use this skill + +Apply when answering whether a SmartThings compliant product needs a QR code and what format or fields apply, by integration type: **Matter**, **Zigbee 3.0**, **Direct Connected**, **Mobile Connected**. + +**Out of scope:** Z-Wave and Cloud Connected QR requirements are not covered here. + +**Product-oriented answers:** When a concrete example helps, include **copy-pastable payload strings** in the reply, using the user’s values or clear placeholders (e.g. `YOUR_INSTALL_CODE`) for secrets. For QR **bitmaps**, use a real **QR encoder** (library or trusted tool), not generative image models—artistic or “drawn” codes usually fail to scan reliably. + +### Inputs by integration type + +| Type | Collect or reference | +|------|----------------------| +| **Matter** | Commissioning flow; **discriminator**, **setup passcode**, **Vendor ID (VID)**, **Product ID (PID)**; any additional fields **CSA Matter** and your **Matter stack / silicon vendor** docs require for the setup or QR payload. | +| **Zigbee 3.0** | **MAC** (64-bit as used in QR), **Install Code**; for recommended QR: **Model Number**, **Manufacturer Code** (or confirm OUI-only omission per [IEEE OUI](https://standards-oui.ieee.org/)). | +| **Direct Connected** | Identifiers and segments named in [Publish a Direct Connected Device](https://developer.smartthings.com/docs/devices/direct-connected/publish) for the partner QR (align with Developer Workspace / doc field names). | +| **Mobile Connected** | Fields required by [Developing your SmartThings Find device](https://developer.smartthings.com/docs/devices/mobile-connected/developing-your-find-device) and **Find Device SDK** / partner materials. | + +## Why QR codes matter + +- **Security:** Help establish protected communication (e.g. encrypted channel setup where the standard requires it). +- **Proof of possession:** Tie onboarding to a physical device the user has. +- **Onboarding UX:** User can start pairing by scanning a QR code. + +Payload **shape and content differ by integration type**; do not assume one QR format fits all. + +--- + +## Matter + +- Follow **CSA Matter** standard QR code rules. **No SmartThings-specific QR format** beyond that standard. +- The **QR payload format and encoding rules** are defined by **CSA Matter**. Use your **Matter stack** documentation only when implementation-specific details are needed. + +--- + +## Zigbee 3.0 + +Official requirements are cited by **document number** (e.g. **18-01000** *QR Code Requirements*, **05-3874** *Manufacturer Code Database*). Obtain current specifications through **Connectivity Standards Alliance** (Zigbee) documentation channels. + +### Minimum (required pattern) + +- Satisfy **dotdot** QR requirements per **Zigbee Document 18-01000** (*QR Code Requirements*). +- QR must include **MAC address** and **Install Code**. + +Example (minimum-style payload illustration): + +```text +Z:0123456789ABCDEF$I:023047432043AF3456FEB23452423423621A +``` + +### Recommended (beyond minimum) + +When possible, include both **manufacturer identity** and **model identity** in the QR. This lets SmartThings identify **which product is being onboarded** more accurately, so the user does not have to pick from a long model list and can be guided with more **product-specific onboarding instructions**. + +**On SmartThings:** + +- **With model + manufacturer identity (Manufacturer Code and/or OUI as allowed by the Zigbee rules):** After the user scans the QR, **SmartThings** can **determine which product** is being onboarded **from the QR payload**, without making the user pick the exact model from a long in-app list. Onboarding copy and flows that the manufacturer **preregistered in SmartThings Console** can then **bind to that product** and display **accurately**. +- **Minimum-only QR (MAC + Install Code, no usable model/manufacturer signal):** The platform often **cannot pinpoint a specific SKU**, so it can show **only generic** guidance—not **product-specific** Console content tuned for that device. + +That **simplifies the user journey**: **unbox the device → scan the QR → follow product-optimized in-app content** for the remaining steps (instead of manual catalog matching). + +### Ways to express manufacturer identity + +Explain manufacturer identity in this order: + +1. **Use a CSA-registered Manufacturer Code after `%M`** + Treat `%M` as the field marker used to carry the manufacturer code. The value after `%M` should be the manufacturer's unique code listed in **Zigbee Document 05-3874** (*Manufacturer Code Database*). If the manufacturer does not have its own code, this method is not available. +2. **Use the MAC address OUI** + If the Zigbee rules allow omitting `%M`, and the first 3 bytes of the MAC (**OUI / MA-L**) reliably identify the commercial manufacturer of the product, the OUI can be used instead. This is not a good fit for **OEM / multi-brand** situations where the OUI does not uniquely represent the sellable product identity. +3. **Use a Samsung-issued manufacturer identifier (MNID) through a SmartThings partner procedure** + If the standard manufacturer-identity approaches above are not enough for the intended onboarding UX, a **Samsung-issued manufacturer identifier (MNID)** may be handled through a separate **SmartThings partner procedure**. This is not the same thing as a standard Zigbee QR field, so direct partners to **partner@smartthings.com** for the exact process. + +### How to express model identity + +Explain model identity as **Model Number** carried in **`$M`** under the **Global Parameter (`G`)** section. + +**Uniqueness (OEM / multi-brand):** The **manufacturer + product identity** encoded in the QR (Manufacturer Code, OUI, or SmartThings partner-managed manufacturer identity, plus **Model Number**) should map to **one distinct commercial product**. If the **same underlying device** is sold under **different brands or model names** with **identical** manufacturer/model identifiers in the QR, SmartThings **cannot** tell those SKUs apart from the payload alone. In that case, each sellable variant needs its own distinguishing metadata. + +Example: + +```text +G$M:BOX%Z$A:0123456789ABCDEF$I:023047432043AF3456FEB23452423423621A%M:10E1 +``` + +Interpretation: + +| Field | In example | Notes | +|--------|------------|--------| +| Model Number | `BOX` | Carried under **Global Parameter (G)** as **$M** (Model Number). | +| Manufacturer Code | `10E1` | Manufacturer code placed after **`%M`**; must exist in **Zigbee Document 05-3874** (*Manufacturer Code Database*). Use the **device OEM’s** assigned code; **do not** use the chipset vendor’s code as a substitute. | + +### Omitting Manufacturer Code + +If the **first 3 bytes of the MAC** (OUI / MA-L) are already the manufacturer’s **standard** assignment, **Manufacturer Code may be omitted**. + +Example (no `%M:` when OUI is sufficient): + +```text +G$M:BOX%Z$A:0123456789ABCDEF$I:023047432043AF3456FEB23452423423621A +``` + +Here `012345` in `0123456789ABCDEF` is the OUI/MA-L portion; verify assignments at [IEEE OUI public listing](https://standards-oui.ieee.org/). + +### After WWST (recommended QR) + +If the product follows the **recommended** Zigbee QR pattern, or also needs an **MNID-based SmartThings partner procedure**, after **WWST** completion send the details to **partner@smartthings.com** so SmartThings can **store** the metadata and use it for that product’s **onboarding UX**. + +--- + +## Direct Connected and Mobile Connected + +Both paths require a **partner QR code** for publishing; format and fields follow the **SmartThings developer documentation** for that path (Direct: publish guide; Mobile: Find / Mobile Connected guides). The **product technology** differs. + +**Partner label (print / packaging):** For sticker or box artwork, SmartThings publishes **Illustrator-oriented** assets and layout notes under **[QR code design template](https://developer.smartthings.com/docs/devices/direct-connected/publish#qr-code-design-template)** on the Direct Connected publish page (e.g. last four serial digits above the QR, SmartThings branding below—per guidance on that page). Use that **documentation anchor** for links. + +### Direct Connected + +- Typical products use **[SmartThings SDK for Direct Connected Devices (C)](https://github.com/SmartThingsCommunity/st-device-sdk-c)** — cloud-oriented device firmware (e.g. customized MQTT, onboarding APIs) integrated with the SmartThings Cloud. +- **QR code is mandatory.** Follow the **SmartThings partner device QR specification** for publishing. +- Source of truth: [Publish a Direct Connected Device](https://developer.smartthings.com/docs/devices/direct-connected/publish). + +### Mobile Connected + +- Typical products use the **SmartThings Find Device SDK** (Find / BLE-UWB-style mobile integration; partner access and materials are managed through the Find partnership program). +- **QR code is mandatory** under the same **partner publishing** expectations; use SmartThings **Mobile Connected** / Find device documentation for your product’s QR and workflow. +- Orientation: [Developing your SmartThings Find device](https://developer.smartthings.com/docs/devices/mobile-connected/developing-your-find-device); partner program overview: [SmartThingsFindPartnershipProgram](https://github.com/SmartThingsCommunity/SmartThingsFindPartnershipProgram) (access is partnership-gated — contact **partners@smartthings.com** per that program). +- **Label artwork** uses the same **[QR code design template](https://developer.smartthings.com/docs/devices/direct-connected/publish#qr-code-design-template)** section as Direct Connected for recommended partner layout. + +--- + +## Quick reference + +| Integration | QR required? | Primary rule | +|-------------|--------------|--------------| +| Matter | Per CSA Matter | CSA + stack/vendor docs only; no extra SmartThings QR spec | +| Zigbee 3.0 | Yes (minimum: MAC + Install Code per 18-01000) | Recommended: + model + manufacturer code (05-3874); optional `%M` if OUI proves OEM | +| Direct Connected | **Yes** | **st-device-sdk-c** class products; [publish / QR spec](https://developer.smartthings.com/docs/devices/direct-connected/publish); print: [QR code design template](https://developer.smartthings.com/docs/devices/direct-connected/publish#qr-code-design-template) | +| Mobile Connected | **Yes** | **Find Device SDK** class products; Mobile Connected / Find docs + partner program; print: [QR code design template](https://developer.smartthings.com/docs/devices/direct-connected/publish#qr-code-design-template) | +| Z-Wave / Cloud | — | Not covered in this skill | diff --git a/skills/smartthings-direct-connected-device-sdk-c-developer/SKILL.md b/skills/smartthings-direct-connected-device-sdk-c-developer/SKILL.md new file mode 100644 index 0000000..dc20b86 --- /dev/null +++ b/skills/smartthings-direct-connected-device-sdk-c-developer/SKILL.md @@ -0,0 +1,247 @@ +--- +name: smartthings-direct-connected-device-sdk-c-developer +description: Guides SmartThings Direct Connected integration using the SmartThings Device SDK for C over MQTT. Covers when to start from the IoT core device library repository vs the SmartThings SDK Reference repository, strict porting boundaries, capability handling via capability_sample, Console project setup, project-specific onboarding_config.json replacement, device_info.json handling for prototype vs production flows, device identity registration with serial number and ed25519 public key, and WWST certification and product launch prerequisites. +metadata: + version: "2026-05-29" +--- + +# Direct Connected -> SmartThings Device SDK for C + +## When to use + +- Use this skill when working on a **SmartThings Direct Connected** device that integrates with SmartThings using the **SmartThings Device SDK for C** over **MQTT**. +- Use it when the target device firmware is built either from the **IoT core device library** repository or from the **SmartThings SDK Reference** repository for supported chipsets. +- Use it when you need guidance on **porting**, **capability handling**, **Console preparation**, or **device identity provisioning** for a Direct Connected product. + +--- + +## Scope + +**In scope** + +- Choosing the correct starting point between the IoT core device library repo and the SmartThings SDK Reference repository. +- Porting rules for unsupported chipsets. +- Recommended capability handling flow using `capability_sample`. +- Required SmartThings Console setup for a Direct Connected project. +- Required onboarding asset replacement and device identity registration. +- WWST certification and product launch prerequisites such as contract and certification testing. + +**Out of scope unless the user expands** + +- Hub Connected, Cloud Connected, or Mobile Connected flows. +- BSP-specific bring-up details for chipsets not already covered by the SmartThings SDK Reference repository. +- Secure element or manufacturing-line implementation details beyond the required key-registration workflow. + +--- + +## Core repositories + +- **IoT core device library:** [st-device-sdk-c](https://github.com/SmartThingsCommunity/st-device-sdk-c) +- **SmartThings SDK Reference:** [st-device-sdk-c-ref](https://github.com/SmartThingsCommunity/st-device-sdk-c-ref) + +Use these repositories differently: + +- For **ESP32**, **BL602**, and **BK7236**, start from the **SmartThings SDK Reference** repository when possible. +- For other chipsets, start from the **IoT core device library** repository and port it to the target platform yourself. + +--- + +## Critical porting guardrail + +When porting the IoT core device library to a new chipset: + +- You may modify the **port layer** under [`src/port`](https://github.com/SmartThingsCommunity/st-device-sdk-c/tree/main/src/port). +- Do **not** modify code outside the port layer in the IoT core device library repository. + +If the user proposes changing logic outside `src/port`, steer them back to a port-layer-only approach unless they explicitly have upstream guidance from SmartThings. + +--- + +## Recommended starting path + +1. Confirm whether the target BSP is supported in the **SmartThings SDK Reference** repository. +2. If yes, begin from the relevant example in the **SmartThings SDK Reference** repository and focus on implementing the application layer. +3. If not, first port the **IoT core device library** to the target BSP by implementing the required platform adaptation in `src/port`, then implement the application layer on top of it. +4. In all cases, build the device application by using the IoT core APIs exposed through `st_dev.h`. + +### Porting layer and application layer + +In this integration flow, the implementation is divided into two parts: + +- **Porting layer:** the low-level adaptation layer used to port the **IoT core device library** to the target BSP or chipset platform. +- **Application layer:** the device application built by using the IoT core APIs exposed through `st_dev.h`, including device behavior and capability handling. + +The device developer is responsible for both layers. + +However, for **ESP32**, **BL602**, and **BK7236**, the port layer is already provided in the **SmartThings SDK Reference** repository, so in those cases the developer usually only needs to implement the application layer. + +### Prerequisites check before application work + +Before starting application implementation, first verify that the prerequisites from the **SmartThings SDK Reference** README are already installed for the target chipset. + +- For ESP32, check whether the build-system prerequisites described by Espressif are installed. +- For ESP32, also check whether the ESP32 toolchain setup has been completed through `setup.py`. +- If those prerequisites are missing, guide the user to complete them before moving on to application-layer work. + +--- + +## Capability handling recommendation + +For capability handling, the preferred starting point is: + +- [`apps/capability_sample`](https://github.com/SmartThingsCommunity/st-device-sdk-c-ref/tree/main/apps/capability_sample) + +Recommended workflow: + +1. Find the matching capability-specific `caps_*.c` and `caps_*.h` files for the required capability in `capability_sample`. +2. Copy those matching capability-specific `caps_*.c` and `caps_*.h` files into the working project. +3. Adapt them inside the product application, for example in a project similar to [`apps/esp32/switch_example`](https://github.com/SmartThingsCommunity/st-device-sdk-c-ref/tree/main/apps/esp32/switch_example). +4. Use the copied capability files as the abstraction layer for SmartThings capability handling instead of rebuilding the capability logic from scratch. + +This path is usually more convenient than implementing capability message handling directly at the raw SDK layer. + +### Capability schema guardrail + +- Do not hardcode SmartThings capability enum strings, unit strings, or other schema-constrained constants in application code. +- Always use the matching definitions from `iot_caps_helper_*.h` when setting capability values, units, or enum-like strings. +- Before sending capability events, verify that the attribute value, unit, and allowed range come from the helper definitions for that capability. +- If a helper-defined constant exists, use it instead of writing a literal string directly. + +### Capability event rate-limit guidance + +- SmartThings applies device-side rate limits and guardrails to connected devices. The official guidance says devices should generally not emit more than one event per minute unless the state change was caused by user interaction. +- If a device sends events too aggressively, the connection to SmartThings Cloud may be interrupted and re-established, so periodic-reporting devices should control event volume within a range that does not harm usability. +- For SDK-based devices, rate limiting is effectively tied to how often the device sends attribute updates through `st_cap_send_attr()`. +- If several capability attributes need to be updated together, send them in a single `st_cap_send_attr()` call instead of splitting them into separate calls where possible. +- This is especially useful when the device reconnects and needs to publish its initial full state efficiently. + +References: + +- SmartThings rate limits: [Rate Limits and Guardrails - Devices](https://developer.smartthings.com/docs/getting-started/rate-limits#devices) +- SDK capability attribute updates: [Capability_Attribute_Update.md - Sending Capability Attribute data](https://github.com/SmartThingsCommunity/st-device-sdk-c/blob/main/doc/Capability_Attribute_Update.md#sending-capability-attribute-data) + +--- + +## SmartThings Console preparation + +Before firmware integration, the manufacturer must create a new project in **SmartThings Console**: + +1. Create a new project. +2. Choose **Direct Connected** as the integration type. +3. Define the device behavior and SmartThings-visible functionality for the product. +4. Download the project-specific `onboarding_config.json`. +5. Replace the placeholder `onboarding_config.json` included in the SDK/project with the downloaded file. + +Treat the Console-generated `onboarding_config.json` as product-specific configuration, not as a reusable placeholder. + +Repository note: + +- Example projects under paths such as `apps///main/` may include placeholder `onboarding_config.json` and `device_info.json` files in GitHub. +- Those checked-in files are only placeholders for repository distribution and must not be treated as ready-to-ship project assets. + +--- + +## Testing your device + +- Follow the official test flow in [Test Your Direct Connected Device](https://developer.smartthings.com/docs/devices/direct-connected/test-your-device-app). +- The recommended test sequence is: + 1. Deploy product information in **SmartThings Console** + 2. Register the test device + 3. Test the device in the **SmartThings app** +- Before testing in the SmartThings app, make sure **developer mode is enabled** in the app. +- If developer mode is not enabled, the test device will not appear in the SmartThings app. +- The SmartThings app and SmartThings Console should be signed in with the same Samsung account during testing. +- In the app, test devices are typically accessed through **Add device -> Partner devices -> My Testing Devices**. + +--- + +## Device identity and authentication + +Each device must be registered as a legitimate product instance before authentication succeeds. + +Notation rule in this section: + +- Use **serial number**, **public key**, and **private key** for the general concepts. +- Use `serialNumber`, `publicKey`, and `privateKey` only when referring to literal JSON field names. + +Required provisioning flow: + +1. Generate a device-specific **serial number**. +2. Generate an **ed25519 keypair** for the device. +3. Register the device's **serial number** and **public key** through SmartThings Console. +4. Inject the **private key** into the device through a secure manufacturing or provisioning flow. + +Additional requirement: + +- A **QR code** containing product-specific **serial number** information is also required. +- QR code details are out of scope for this skill and should be handled by a separate skill or guide. + +Security rule: + +- The **private key** must be handled securely and stored or used in a secure manner on the device. + +If the user asks about onboarding/authentication failures, check first whether the correct device identity and **public key** were registered in Console and whether the device is using the matching **private key**. + +### `device_info.json` for prototypes vs production + +- The placeholder `device_info.json` included in example projects should be replaced with a project/device-specific file before real testing. +- For prototyping or small-scale test-device work, `tools/keygen` in [`st-device-sdk-c`](https://github.com/SmartThingsCommunity/st-device-sdk-c/tree/main/tools/keygen) can be used to generate a device-specific **serial number**, keypair, and a ready-to-use `device_info.json`. +- In that prototype flow, register the generated **serial number** and **public key** in SmartThings Console and make sure the device uses the matching **private key**. +- For a production or mass-manufacturing project, do not ship `privateKey`, `publicKey`, or `serialNumber` fields inside `device_info.json`. +- In production guidance, tell the user to remove those identity fields from `device_info.json` and provision the device identity through the manufacturing/security flow instead. + +--- + +## WWST certification and launch notes + +- Development and commercialization with this SDK require a **separate commercial charging/contract arrangement with Samsung Electronics**. +- Product launch requires completing the required **WWST certification** process. +- WWST certification for Direct Connected devices requires not only functional validation but also a **Security Assessment**. +- Security features such as **firmware update**, **secure boot**, and **secure storage** should be implemented as mandatory parts of the product security design for certification readiness. +- Before requesting certification, review [Security Requirements for Direct Connected Devices](https://developer.smartthings.com/docs/devices/direct-connected/security-requirements) and the related security material available in **SmartThings Console**, then apply the relevant security features in advance. +- As part of the WWST certification submission flow, the manufacturer must also complete and submit the **WWST security form** in SmartThings Console. + +Do not imply that repository access alone is enough for commercial launch. + +### Device identity registration before and after WWST certification + +- Before WWST certification, SmartThings Console supports registering a limited number of device identities for test devices. +- After WWST certification is completed, SmartThings Console provides additional tooling for large-scale device identity registration. +- During pre-certification development, guide the user to the small-scale test-device registration flow first. +- Also remind the user that the required QR-code flow is handled by separate guidance. + +--- + +## Agent guidance + +- Prefer the **SmartThings SDK Reference** repository first for supported chipsets because it shortens bring-up work. +- For unsupported chipsets, keep the user focused on a clean **port-layer implementation** and avoid suggesting SDK core changes outside `src/port`. +- Before starting application implementation, verify that the target chipset's prerequisites from the `st-device-sdk-c-ref` README have already been installed. +- When capability questions arise, tell the user to copy the matching capability-specific `caps_*.c` and `caps_*.h` files from `capability_sample` into the project before designing any new abstraction. +- When implementing or editing capability handlers, always read the matching `iot_caps_helper_*.h` first and use helper-defined units, enum values, and schema constants instead of hardcoded literals. +- By default, write separate test-stub files for each capability handler. +- For sensor-style handlers, the default stub pattern is to feed arbitrary test patterns or sample values into the handler path. +- For output or command-style handlers, the default stub pattern is to log the received control command contents and then return or emit a success response. +- If the user explicitly asks for real hardware control, follow that request and implement the actual hardware-control path instead of keeping the behavior stubbed. +- After the device behavior and capability implementation are clear, summarize the implemented app in a project README similar in style to `apps/esp32/ventilation_test/README.md`. +- That README must include the list of applied SmartThings capabilities, even if some handlers are still stubbed or use dummy values. +- When setup is blocked, verify these prerequisites in order: + 1. Correct integration type in **SmartThings Console** + 2. Correct project-specific `onboarding_config.json` + 3. Registered **serial number** and **ed25519 public key** + 4. Securely provisioned matching **private key** + 5. Appropriate BSP starting point: SmartThings SDK Reference repository vs IoT core device library porting + +--- + +## Suggested response pattern + +When helping a user, explain the next action in natural language rather than exposing internal labels. A good default flow is: + +1. Identify whether the chipset is supported in the SmartThings SDK Reference repository. +2. Choose **SmartThings SDK Reference example** or **IoT core device library porting** as the starting point. +3. Point the user to the matching capability-specific `caps_*.c` and `caps_*.h` files in `capability_sample` for capability implementation. +4. Verify Console project creation and `onboarding_config.json` replacement. +5. Verify **serial number** and key registration. +6. Mention WWST certification completion, contract requirements, and launch prerequisites if the discussion is about product launch. +7. After implementation is complete, summarize the result in a README-style document and include the applied capability list explicitly. diff --git a/skills/smartthings-hub-connected-developer/SKILL.md b/skills/smartthings-hub-connected-developer/SKILL.md new file mode 100644 index 0000000..6321fea --- /dev/null +++ b/skills/smartthings-hub-connected-developer/SKILL.md @@ -0,0 +1,211 @@ +--- +name: smartthings-hub-connected-developer +description: Guides commercial SmartThings Hub Connected product integrations for manufacturers or partners pursuing Works With SmartThings (WWST) certification for Zigbee, Matter, or Z-Wave devices. Use for hub-side WWST registration, validation, Test Suite, Integration Details, Standard vs Custom path decisions, and Zigbee Edge driver PR guidance when manufacturer-side work is required for certification. Do not use for hobby-only driver experiments, Cloud Connected, Direct Connected, or Mobile Connected integrations. +metadata: + version: "2026-05-29" +--- + +# Hub-connected SmartThings Developer (Zigbee, Matter, Z-Wave) + +## When to use + +- Use this skill for **commercial SmartThings Hub Connected products** whose manufacturer or partner is preparing **WWST certification** and product launch. +- Use this skill only for **SmartThings Hub Connected** device integrations. +- Apply it when the product joins SmartThings through a **hub-side protocol path** such as **Zigbee**, **Matter**, or **Z-Wave**, and the task is about **WWST registration**, **validation**, **Test Suite**, **Integration Details**, **device configuration**, or **hub-side implementation fit**. +- Use it when you need to decide whether the device can stay on the **Standard** path or requires the **Custom** path. +- For detailed codework, this skill expands only the **Zigbee + SmartThingsEdgeDrivers** worked example. +- Do not use this skill for **hobby-only driver experiments**, **Cloud Connected (ST-Schema / Cloud Connector)**, **Direct Connected**, or **Mobile Connected** integrations. + +--- + +## Scope + +This skill owns: + +- Commercial certification readiness for manufacturer or partner products, not hobby-only driver experiments. +- Hub-connected WWST flow in **SmartThings Console**, including **Test Suite** and **Integration Details**. +- Path selection between **Standard** and **Custom** for **Zigbee**, **Matter**, and **Z-Wave** hub-connected products. +- Profile and device-configuration checks when standard onboarding does not expose all required functionality. +- Detailed worked-example guidance only for **Zigbee + SmartThingsEdgeDrivers** when manufacturer-side implementation is required. + +This skill does not own: + +- **Cloud Connected** integration design such as **Cloud Connector / ST-Schema**, OAuth, hosting, or cloud registration. +- **Direct Connected** integration work such as **SmartThings Device SDK for C**, MQTT-based firmware, onboarding assets, or device identity provisioning. +- **Mobile Connected** device flows. +- Detailed custom implementation procedures for **Matter** or **Z-Wave**. + +--- + +## Core assumptions + +This skill is intended to help an IoT device manufacturer connect **Zigbee, Matter, or Z-Wave products** to **SmartThings** and complete **WWST certification**. + +- In **most standard cases**, the flow finishes through **SmartThings Console** registration, hub validation, Test Suite, and certification submission without additional codework. +- A **custom implementation case** is one where the manufacturer's device implementation is not fully described by the protocol **standard model**, so SmartThings **standard Capability mapping** alone may not be enough to produce the expected device experience, and extra manufacturer-side implementation or submission artifacts may be needed. +- This skill explains the **detailed implementation workflow using Zigbee as the worked example**, but it does **not** assume that only Zigbee can require custom handling. + +## Assumption for the Zigbee worked example + +For the Zigbee implementation example in this skill, the device is expected to work correctly within the **Lua Edge driver** environment used by the [SmartThingsEdgeDrivers](https://github.com/SmartThingsCommunity/SmartThingsEdgeDrivers) repository. The certification and release flow in this worked example follows that assumption. + +--- + +## Agent-only: internal path evaluation + +Describe the user's situation and next action in natural language rather than exposing internal branch labels. + +| Radio | Internal check | +|--------|----------------| +| **Zigbee** | Do **Manufacturer Specific Clusters** or similar behavior require extra mapping into SmartThings **standard Capabilities**? Does onboarding alone satisfy all app and routine requirements? | +| **Matter** | Does the device stay within the normal **Matter standard onboarding** path, and is SmartThings **standard Capability mapping** enough to deliver the needed UX? | +| **Z-Wave** | On supported hubs and regions, are normal inclusion and **CC** combinations enough under the existing SmartThings **Capability mapping**? Does manufacturer-specific behavior require additional work? | + +**Internal mapping (for agent reasoning):** + +- **Standard path:** the protocol **standard model** and SmartThings **standard Capability mapping** are enough for the required behavior -> validation, Test Suite, **Integration Standard**. +- If the device uses the protocol **standard model** but the **Standard path** does not expose all required functionality, first use **SmartThings Console -> Integration Details -> Find an Edge Driver** to select the certification-target device among the devices onboarded to your account, then use **Modify Device Configuration** to check whether applying a different profile exposes the missing behavior. +- If changing the profile through **Modify Device Configuration** still does not expose all required functionality, move to the **Custom path** and prepare an Edge driver implementation and **Pull Request** for the device. +- **Custom path:** the protocol **standard model** alone is not enough, or SmartThings **standard Capability mapping** alone is not enough -> evaluate **Integration Custom**, and prepare PR URLs or partner-coordination artifacts if needed. +- **Current Zigbee worked example:** the codework example in this skill is only expanded using **Zigbee + SmartThingsEdgeDrivers**. +- **Reference routing:** read [reference/common.md](reference/common.md) for shared WWST flow, then open only the protocol-specific reference that matches the task: [reference/zigbee.md](reference/zigbee.md), [reference/matter.md](reference/matter.md), or [reference/zwave.md](reference/zwave.md). + +If the situation is unclear, ask a clarifying question. + +--- + +## Common path - when no extra codework is needed + +**Applies when:** the protocol **standard model** plus SmartThings **standard Capability mapping** is enough for the device to behave correctly in **Zigbee**, **Matter**, or **Z-Wave**. + +- **Core flow:** register the product, brand, and device information in **SmartThings Console**, connect the device to a supported hub, validate **Device UI** and **routines**, run **Test Suite**, and submit for certification. +- If the device uses the protocol **standard model** but the initially selected profile does not expose all required functionality, first use **Integration Details -> Find an Edge Driver -> Modify Device Configuration** to verify whether a different profile exposes the missing behavior while staying on the **Standard** path. +- **Certification:** submit through [SmartThings Console - Test Suite](https://developer.smartthings.com/console/test) and choose **Standard** in **Integration Details** where appropriate ([Publish hub-connected devices](https://developer.smartthings.com/docs/devices/hub-connected/certify-your-device/)). + +--- + +## Common path - when manufacturer-side implementation is required + +- If the device implementation is not fully captured by the protocol **standard model**, or if the protocol **standard model** is used but the **Standard** path still does not expose all required functionality after profile validation in **Modify Device Configuration**, first evaluate whether it can still be mapped into SmartThings [Capabilities](https://developer.smartthings.com/docs/devices/capabilities/) using a **Production** or **Proposed Capability**. +- **WWST** must not include **Custom Capabilities**, so user-facing functionality should be expressed through SmartThings **Standard Capabilities**. +- For any Zigbee or Z-Wave custom implementation beyond a fingerprint-only change, prefer the smallest reuse of existing Edge driver package, profile, and sub-driver structure; do not guide the user toward a standalone driver package for a commercial WWST submission when an existing package can be extended. +- In these cases, certification often needs the **Integration Custom** path, and the manufacturer may need to prepare additional supporting materials such as PR URLs or partner-coordination artifacts. +- The exact codework differs by protocol. This skill continues with a **Zigbee worked example**. + +--- + +## Zigbee worked example: reflecting device support in SmartThingsEdgeDrivers + +Use this path only when the hub-connected **Custom** flow needs Zigbee manufacturer-side implementation. + +- Keep the decision at the WWST level in this file: can the device stay on standard onboarding, or does it need Zigbee custom implementation? +- Before implementation, verify that the required behavior can be expressed through SmartThings **Production** or **Proposed Capabilities**. Do not guide the user toward **Custom Capabilities** for WWST. +- If implementation is needed, steer toward minimal reuse of an existing manufacturer or functional sub-driver before considering new structure. +- For Zigbee Edge driver implementation details such as **`lua_libs`**, **`test/`**, **fingerprints**, **profiles**, **`sub_driver`** structure, and PR preparation, open [reference/zigbee.md](reference/zigbee.md). + +--- + +## Matter + +**Standard path:** if the device can stay on the normal **Matter standard onboarding** path and SmartThings can map the exposed behavior into its **standard Capabilities** with the required UX and automation behavior, follow the normal Console-centered WWST path. + +- **Certification:** follow [Certification with CSA (Matter)](https://developer.smartthings.com/docs/certification/certification-with-csa). +- **Onboarding:** complete **Matter commissioning** in the app and hub, then validate the expected device behavior and scenarios. In this skill, the key question is whether the resulting SmartThings behavior fits the **standard path**, not whether the partner is responsible for low-level Matter standard modeling details. +- **Profile selection:** when the device stays on the **standard path** and the target Matter base driver already supports a **modular profile**, choose that modular profile rather than falling back to a non-modular alternative. For example, if the base driver supports `matter-switch/profiles/fan-modular.yml`, prefer that modular profile for the matching standard device shape. +- If the standard Matter implementation still does not expose all required functionality, use **Integration Details -> Find an Edge Driver -> Modify Device Configuration** to verify whether a different supported profile resolves the gap before moving to the **Custom** path. +- **Manufacturer-side implementation:** if the device depends on **custom clusters** or **vendor-specific extensions**, evaluate the **Custom** path instead. This skill does not expand Matter-specific codework details; use CSA, silicon-vendor, and partner guidance. + +--- + +## Z-Wave + +**Standard path:** if the device can be included on supported hubs and regions and the existing SmartThings **Capability mapping** exposes the required functionality, follow the normal Console-centered WWST path. + +- **Validation:** verify inclusion, re-inclusion, **S2**, and app/routine behavior. +- If the device uses standard **CC** behavior but the selected profile does not expose all required functionality, use **Integration Details -> Find an Edge Driver -> Modify Device Configuration** to test whether another supported profile resolves the gap before moving to the **Custom** path. +- **Certification:** use [Publish hub-connected devices](https://developer.smartthings.com/docs/devices/hub-connected/certify-your-device/) and **Test Suite**. Some categories may involve an **Authorized Test Provider**; rely on the latest official guidance. +- **Manufacturer-side implementation:** if additional handling is needed because of **Z-Wave LR**, **SmartStart**, proprietary **CCs**, or manufacturer-specific behavior, evaluate the **Custom** path. This skill does not expand Z-Wave-specific codework details. + +--- + +## Common - Device Preferences + +- Always review [Device Preferences](https://developer.smartthings.com/docs/devices/preferences) for device-card settings, and keep them aligned with WWST scope, Console configuration, and policy expectations. + +--- + +## Roles and artifacts + +| Artifact | Purpose | +|----------|---------| +| **Organization + brand** | Console product setup and certification ownership | +| **Console registration** | Core registration, validation, and certification steps for the standard WWST path | +| **Integration Details** | Submission choice between **Standard** and **Custom** | +| **Test Suite** | Validation before certification submission | +| **Protocol-specific implementation** | Additional mapping, driver work, PR work, and partner coordination prepared by the manufacturer when needed | +| **Edge driver / integration implementation** | Core implementation that connects protocol behavior to SmartThings **Standard Capabilities**. In this skill, the detailed execution example is Zigbee-based | +| **Fingerprint / device matching** | Information used to identify the device, such as manufacturer and model, and associate the joined device with the correct implementation | +| **Developer tooling + test channel** | Tools and deployment channels used to validate unpublished implementations on a real hub | +| **Dev env + `test/`** | Development environment and test assets required before opening a PR | + +--- + +## Phase 0 - Preparation + +1. Review [Certification overview](https://developer.smartthings.com/docs/certification/overview) and confirm Console **Organization / Brand** setup. +2. Use official documentation for **Product Policies** and category-specific UX requirements. +3. Apply the internal evaluation above, and explain the current situation and next action in natural language. + +--- + +## Phase 1 - Technical design notes (for the Custom path) + +1. First verify whether the protocol **standard model** plus SmartThings **standard Capability mapping** is sufficient. +2. If the device uses the protocol **standard model** but the initially selected profile does not expose all required functionality, verify through **Integration Details -> Find an Edge Driver -> Modify Device Configuration** whether another supported profile resolves the gap while staying on the **Standard** path. +3. If the behavior is still not sufficient, organize what is needed for **Integration Custom**, including PR URLs or partner-coordination artifacts. +4. Follow the protocol-specific reference file before giving implementation guidance. +5. In this skill, only **Zigbee** is expanded as a worked example, and its implementation details live in [reference/zigbee.md](reference/zigbee.md). +6. Do not invent Matter- or Z-Wave-specific custom implementation procedures in this skill. + +--- + +## Phase 2 - Self Test (before certification) + +- **When standard onboarding and standard Capability mapping are sufficient:** validate full hub, app, and routine scenarios, then run Test Suite. +- **For the Custom path:** validate the manufacturer-side implementation on real hub and app scenarios, and prepare the supporting materials needed for submission. +- **Zigbee worked example:** use [reference/zigbee.md](reference/zigbee.md) for Edge driver validation details before Console **Test Suite**. + +--- + +## Phase 3 - Certification submission (WWST) + +- Follow [Publish hub-connected devices](https://developer.smartthings.com/docs/devices/hub-connected/certify-your-device/). +- For **Matter**, also verify alignment with [Certification with CSA (Matter)](https://developer.smartthings.com/docs/certification/certification-with-csa). +- In **Integration Details**, use **Standard** when onboarding alone is sufficient; use the **Custom** path when additional manufacturer-side implementation or submission artifacts are required. +- In the **Zigbee worked example**, if there is a SmartThingsEdgeDrivers PR, submit with **Custom** + **PR URL**. + +--- + +## Phase 4 - Publishing and maintenance + +- Follow the latest Samsung guidance for WWST logo and catalog usage. +- Re-validate when firmware, fingerprints, radio stack behavior, packaging, onboarding materials, or labeling changes. + +--- + +## Agent behavior summary + +- **Common:** first decide whether the normal **Console-centered path** is sufficient; only guide the user into the **Custom** path when needed. +- **Zigbee:** internally evaluate whether MSS-like handling or extra mapping is needed, but explain the result to the user as current situation plus next action. +- **WWST guardrail:** never propose **Custom Capabilities** for certified product behavior; map custom or manufacturer-specific behavior to SmartThings **Production** or **Proposed Capabilities** when possible. +- For **Matter** on the **standard path**, prefer an existing base-driver **modular profile** when one is supported for the target device shape. +- For **Zigbee** custom implementation details, use [reference/zigbee.md](reference/zigbee.md) instead of restating Edge Driver workflow in this file. +- For **Z-Wave** custom implementation, keep guidance at the WWST/partner-coordination level and use [reference/zwave.md](reference/zwave.md); preserve the reuse-first rule and avoid standalone driver packages when an existing package can be extended. +- Do **not** describe custom-implementation possibilities as if they were limited to Zigbee. Only the detailed codework example in this skill is Zigbee-specific. +- For **Matter** and **Z-Wave**, do not invent codework details in this skill. Send the user to official or partner guidance for protocol-specific implementation details. +- Always review **Device Preferences**. + +## Additional material + +- If a companion [reference.md](reference.md) is available for this skill, consult it for supporting reference material. +- Do not read all reference material by default; open only the reference file that matches the current protocol and task. diff --git a/skills/smartthings-hub-connected-developer/reference.md b/skills/smartthings-hub-connected-developer/reference.md new file mode 100644 index 0000000..169a13c --- /dev/null +++ b/skills/smartthings-hub-connected-developer/reference.md @@ -0,0 +1,12 @@ +# Hub-connected WWST - reference index + +Policies and Console UI can change. Prefer the live developer site whenever this list conflicts with current documentation. + +Do not read every reference file by default. Open only the file that matches the current protocol and task. + +## Read this first when selecting a reference + +- [reference/common.md](reference/common.md): common WWST flow, Test Suite, certification, capabilities, preferences +- [reference/zigbee.md](reference/zigbee.md): Zigbee Edge drivers and the Zigbee custom worked example +- [reference/matter.md](reference/matter.md): Matter WWST + CSA guidance +- [reference/zwave.md](reference/zwave.md): Z-Wave hub-connected notes diff --git a/skills/smartthings-hub-connected-developer/reference/common.md b/skills/smartthings-hub-connected-developer/reference/common.md new file mode 100644 index 0000000..315c180 --- /dev/null +++ b/skills/smartthings-hub-connected-developer/reference/common.md @@ -0,0 +1,15 @@ +# Common WWST references + +Use this file for shared hub-connected WWST flow, Test Suite, certification, capabilities, and preferences. + +## WWST capability guardrail + +- Do not use **Custom Capabilities** for commercial WWST product behavior in any integration path. +- Express custom or manufacturer-specific behavior through SmartThings **Production** or **Proposed Capabilities** whenever manufacturer-side mapping is needed. + +## Reading order (hub-connected WWST) + +1. **Standard onboarding + Test Suite** - [SmartThings Console - Test Suite](https://developer.smartthings.com/console/test), [Publish hub-connected devices](https://developer.smartthings.com/docs/devices/hub-connected/certify-your-device/) +2. **Capabilities and preferences** - [Device capabilities](https://developer.smartthings.com/docs/devices/capabilities/), [Capabilities Reference](https://developer.smartthings.com/docs/devices/capabilities/capabilities-reference) (Production capability schema), [Proposed Capabilities](https://developer.smartthings.com/docs/devices/capabilities/proposed) (Proposed capability schema; open each capability's JSON link), [Device preferences](https://developer.smartthings.com/docs/devices/preferences) +3. **Certification** - [Certification overview](https://developer.smartthings.com/docs/certification/overview), [Apply for certification](https://developer.smartthings.com/docs/certification/apply-for-certification) +4. **Certification and publishing details** - [Test Suite documentation](https://developer.smartthings.com/docs/certification/test-suite) diff --git a/skills/smartthings-hub-connected-developer/reference/matter.md b/skills/smartthings-hub-connected-developer/reference/matter.md new file mode 100644 index 0000000..a1135e1 --- /dev/null +++ b/skills/smartthings-hub-connected-developer/reference/matter.md @@ -0,0 +1,10 @@ +# Matter WWST references + +Use this file when the task involves Matter WWST, CSA alignment, or Matter standard-path guidance. + +## Matter (WWST + CSA) + +- [Certification with CSA (Matter)](https://developer.smartthings.com/docs/certification/certification-with-csa) +- Hub-connected context: [Connect hub-connected devices](https://developer.smartthings.com/devices/hub-connected) (use site search if the URL changes) +- If a Matter device depends on custom or vendor-specific modeling beyond the standard onboarding path, follow current CSA, SmartThings partner, and silicon-vendor guidance. + diff --git a/skills/smartthings-hub-connected-developer/reference/zigbee.md b/skills/smartthings-hub-connected-developer/reference/zigbee.md new file mode 100644 index 0000000..8895ef3 --- /dev/null +++ b/skills/smartthings-hub-connected-developer/reference/zigbee.md @@ -0,0 +1,28 @@ +# Zigbee WWST references + +Use this file when the task involves Zigbee Edge driver work, Zigbee custom implementation, or the Zigbee worked example in this skill. + +## Custom implementation path - Zigbee worked example + +1. [SmartThingsEdgeDrivers Releases](https://github.com/SmartThingsCommunity/SmartThingsEdgeDrivers/releases) - download the latest **`lua_libs` `tar.gz`** and extract it +2. [Set up your development environment](https://developer.smartthings.com/docs/devices/hub-connected/set-up-dev-env) +3. [Test your Edge Driver](https://developer.smartthings.com/docs/devices/hub-connected/test-your-driver) - write or update **`test/`** integration tests and run them locally until all pass +4. [SmartThingsEdgeDrivers repo](https://github.com/SmartThingsCommunity/SmartThingsEdgeDrivers) +5. [Code formatting and submission criteria](https://developer.smartthings.com/docs/devices/hub-connected/code-formatting-criteria) +6. Validate on a custom channel and submit through [SmartThings Console - Test Suite](https://developer.smartthings.com/console/test) with **Integration Custom** + PR URL when applicable + +## WWST implementation guardrails + +- Except for fingerprint-only changes, reuse existing SmartThingsEdgeDrivers packages, profiles, and sub-drivers first. Avoid creating a standalone driver package when the device can fit into an existing package. +- Prefer extending the closest existing sub-driver rather than creating a new top-level driver package. +- First look for a manufacturer-specific sub-driver when the same manufacturer already has device handling in the target driver package. +- If there is no manufacturer-specific fit, look for a functional sub-driver that already models the same device shape or behavior. +- Examples in SmartThingsEdgeDrivers include manufacturer-oriented paths such as `zigbee-switch/src/aqara` or `zigbee-switch/src/frient`, and function-oriented paths such as `zigbee-button/src/zigbee-multi-button` or `zigbee-switch/src/multi-switch-no-master`. +- Keep the PR small: add only the needed fingerprints, profile reuse or minimal profile changes, handlers, and tests for the certification-target model. + +## Edge drivers and Zigbee + +- [Driver components and structure](https://developer.smartthings.com/docs/devices/hub-connected/driver-components-and-structure/) (fingerprints, profiles, `zigbeeManufacturer`) +- [Edge Device Drivers documentation](https://developer.smartthings.com/docs/edge-device-drivers/) +- [Edge Device Driver reference](https://developer.smartthings.com/docs/edge-device-drivers/reference/index.html) +- [SmartThingsEdgeDrivers (GitHub)](https://github.com/SmartThingsCommunity/SmartThingsEdgeDrivers) diff --git a/skills/smartthings-hub-connected-developer/reference/zwave.md b/skills/smartthings-hub-connected-developer/reference/zwave.md new file mode 100644 index 0000000..99da5d0 --- /dev/null +++ b/skills/smartthings-hub-connected-developer/reference/zwave.md @@ -0,0 +1,15 @@ +# Z-Wave WWST references + +Use this file when the task involves Z-Wave WWST validation or Z-Wave-specific platform limits. + +## Z-Wave notes + +- Treat Z-Wave as a **hub-connected** flow in Console. Follow **Publish hub-connected devices** and **Test Suite**. +- Validate **hub compatibility**, **region**, and **S2 / inclusion** behavior on real hardware. +- If the device depends on manufacturer-specific or non-standard handling, treat it as a **Custom** path and confirm the supported approach through official or partner guidance. +- For any custom implementation beyond a fingerprint-only change, reuse existing Edge driver packages, profiles, and sub-drivers first. Avoid creating a standalone driver package when the device can fit into an existing package. +- Prefer extending the closest existing sub-driver rather than creating a new top-level driver package. +- First look for a manufacturer-specific sub-driver when the same manufacturer already has device handling in the target driver package. +- If there is no manufacturer-specific fit, look for a functional sub-driver that already models the same device shape or behavior. +- Examples in SmartThingsEdgeDrivers include manufacturer-oriented paths such as `zwave-switch/src/inovelli` or `zwave-switch/src/qubino-switches`, and function-oriented paths such as `zwave-button/src/zwave-multi-button` or `zwave-window-treatment/src/window-treatment-venetian`. +- Keep any implementation guidance tied to official or partner direction; this skill does not define Z-Wave codework details.