로컬 처리를 지원하려면 다음 스마트 홈 인텐트를 처리하는 앱을 빌드해야 합니다.
IDENTIFY
: 로컬에서 제어 가능한 스마트 기기의 검색을 지원합니다. 인텐트 핸들러는 스마트 기기가 검색 중에 반환하는 데이터를 추출하여 Google에 응답으로 전송합니다.EXECUTE
: 명령어 실행을 지원합니다.QUERY
: 기기 상태 쿼리를 지원합니다.REACHABLE_DEVICES
: (선택사항) 허브 (또는 브리지) 기기 뒤에 있는 로컬에서 제어 가능한 최종 기기의 검색을 지원합니다.
이 앱은 사용자의 Google Home 또는 Google Nest 기기에서 실행되며 스마트 기기를 어시스턴트에 연결합니다. TypeScript (권장) 또는 JavaScript를 사용하여 앱을 만들 수 있습니다.
바인딩을 활용하여 앱이 반환하는 데이터가 플랫폼에서 예상하는 유형과 일치하는지 정적으로 확인할 수 있으므로 TypeScript를 사용하는 것이 좋습니다.
API에 관한 자세한 내용은 로컬 Home SDK API 참조를 참고하세요.
다음 스니펫은 로컬 처리 앱을 초기화하고 핸들러를 연결하는 방법을 보여줍니다.
import App = smarthome.App; const localHomeApp: App = new App("1.0.0"); localHomeApp .onIdentify(identifyHandler) .onExecute(executeHandler) .listen() .then(() => { console.log("Ready"); });
import App = smarthome.App; const localHomeApp: App = new App("1.0.0"); localHomeApp .onIdentify(identifyHandler) .onReachableDevices(reachableDevicesHandler) .onExecute(executeHandler) .listen() .then(() => { console.log("Ready"); });
프로젝트 만들기
로컬 처리 앱을 배포하려면 코드와 모든 종속 항목의 JavaScript 번들을 빌드해야 합니다.
로컬 처리 앱 project initializer를 사용하여 원하는 번들러 구성으로 적절한 프로젝트 구조를 부트스트랩합니다.
프로젝트 템플릿
번들러 구성을 선택하려면 다음 예와 같이 npm init
명령어를 실행합니다.
번들러 구성이 없는 TypeScript:
npm init @google/local-home-app project-directory/ --bundler none
프로젝트 구조:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json └── serve.js
project-directory를 로컬 처리 앱 프로젝트가 포함될 새 디렉터리로 바꿉니다.
webpack 번들러 구성이 포함된 TypeScript:
npm init @google/local-home-app project-directory/ --bundler webpack
프로젝트 구조:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json ├── webpack.config.web.js ├── webpack.config.node.js └── serve.js
project-directory를 로컬 처리 앱 프로젝트가 포함될 새 디렉터리로 바꿉니다.
롤업 번들러 구성이 포함된 TypeScript:
npm init @google/local-home-app project-directory/ --bundler rollup
프로젝트 구조:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json ├── rollup.config.js └── serve.js
project-directory를 로컬 처리 앱 프로젝트가 포함될 새 디렉터리로 바꿉니다.
Parcel 번들러 구성이 포함된 TypeScript:
npm init @google/local-home-app project-directory/ --bundler parcel
프로젝트 구조:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json └── serve.js
project-directory를 로컬 처리 앱 프로젝트가 포함될 새 디렉터리로 바꿉니다.
일반적인 프로젝트 수준 작업 실행
생성된 프로젝트는 다음 npm 스크립트를 지원합니다.
cd project-directory/ npm run build
이 스크립트는 TypeScript 소스를 컴파일하고 dist/web
하위 디렉터리의 Chrome 런타임 환경 및 dist/node
하위 디렉터리의 Node.js 런타임 환경에 관한 종속 항목과 함께 앱을 번들로 묶습니다.
cd project-directory/ npm run lint npm run compile npm test
이 스크립트는 TypeScript 코드의 문법을 확인하고 dist/
하위 디렉터리에 출력을 생성하지 않고 컴파일하며 test.ts
에서 자동 테스트를 실행합니다.
cd project-directory/ npm run start
개발 중에 이 스크립트는 Chrome 및 Node.js 런타임 환경용 앱 번들을 로컬에서 제공합니다.
IDENTIFY 핸들러 구현
IDENTIFY
핸들러는 Google Home 또는 Google Nest 기기가 재부팅되고 확인되지 않은 로컬 기기 (허브에 연결된 최종 기기 포함)가 감지될 때 트리거됩니다. 로컬 Home 플랫폼은 이전에 지정한 스캔 구성 정보를 사용하여 로컬 기기를 스캔하고 스캔 결과를 사용하여 IDENTIFY
핸들러를 호출합니다.
로컬 Home 플랫폼의 IdentifyRequest
에는 LocalIdentifiedDevice
인스턴스의 스캔 데이터가 포함되어 있습니다. 기기를 검색한 스캔 구성에 따라 device
인스턴스 하나만 채워집니다.
스캔 결과가 기기와 일치하면 IDENTIFY
핸들러는 스마트 홈 메타데이터 (예: 유형, 트레잇, 보고서 상태)가 포함된 device
객체가 포함된 IdentifyResponsePayload
객체를 반환해야 합니다.
IDENTIFY
응답의 verificationId
가 SYNC
응답에서 반환된 otherDeviceIds
값 중 하나와 일치하면 Google에서 기기 연결을 설정합니다.
예
다음 스니펫은 각각 독립형 기기 및 허브 통합을 위한 IDENTIFY
핸들러를 만드는 방법을 보여줍니다.
const identifyHandler = (request: IntentFlow.IdentifyRequest): IntentFlow.IdentifyResponse => { // Obtain scan data from protocol defined in your scan config const device = request.inputs[0].payload.device; if (device.udpScanData === undefined) { throw Error("Missing discovery response"); } const scanData = device.udpScanData.data; // Decode scan data to obtain metadata about local device const verificationId = "local-device-id"; // Return a response const response: IntentFlow.IdentifyResponse = { intent: Intents.IDENTIFY, requestId: request.requestId, payload: { device: { id: device.id || "", verificationId, // Must match otherDeviceIds in SYNC response }, }, }; return response; };
const identifyHandler = (request: IntentFlow.IdentifyRequest): IntentFlow.IdentifyResponse => { // Obtain scan data from protocol defined in your scan config const device = request.inputs[0].payload.device; if (device.udpScanData === undefined) { throw Error("Missing discovery response"); } const scanData = device.udpScanData.data; // Decode scan data to obtain metadata about local device const proxyDeviceId = "local-hub-id"; // Return a response const response: IntentFlow.IdentifyResponse = { intent: Intents.IDENTIFY, requestId: request.requestId, payload: { device: { id: proxyDeviceId, isProxy: true, // Device can control other local devices isLocalOnly: true, // Device not present in `SYNC` response }, }, }; return response; };
허브 뒤에 있는 기기 식별
Google에서 허브 기기를 식별하면 허브를 허브에 연결된 최종 기기의 전달 경로로 취급하고 이러한 최종 기기를 확인하려고 시도합니다.
Google에서 허브 기기가 있는지 확인할 수 있도록 하려면 IDENTIFY
핸들러에 관한 다음 안내를 따르세요.
SYNC
응답이 허브에 연결된 로컬 최종 기기의 ID를 보고하는 경우IdentifyResponsePayload
에서isProxy
를true
로 설정합니다.SYNC
응답이 허브 기기를 보고하지 않으면IdentifyResponsePayload
에서isLocalOnly
를true
로 설정합니다.device.id
필드에는 허브 기기 자체의 로컬 기기 ID가 포함됩니다.
REACHABLE_DEVICES 핸들러 구현 (허브 통합만 해당)
REACHABLE_DEVICES
인텐트는 Google에서 로컬에서 제어할 수 있는 최종 기기를 확인하기 위해 전송합니다. 이 인텐트는 허브가 온라인으로 감지되는 한 Google에서 검색 스캔을 실행할 때마다 (대략 1분마다 한 번) 트리거됩니다.
REACHABLE_DEVICES
핸들러는 IDENTIFY
핸들러와 비슷하게 구현되지만, 핸들러가 로컬 프록시 (즉, 허브) 기기에 연결할 수 있는 추가 기기 ID를 수집해야 한다는 점이 다릅니다. device.verificationId
필드에는 허브에 연결된 최종 기기의 로컬 기기 ID가 포함됩니다.
로컬 홈 플랫폼의 ReachableDevicesRequest
에는 LocalIdentifiedDevice
의 인스턴스가 포함되어 있습니다.
이 인스턴스를 통해 스캔 결과에서 프록시 기기 ID와 데이터를 가져올 수 있습니다.
REACHABLE_DEVICES
핸들러는 허브가 제어하는 최종 기기를 나타내는 verificationId
값 배열이 포함된 devices
객체가 포함된 ReachableDevicesPayload
객체를 반환해야 합니다. verificationId
값은 SYNC
응답의 otherDeviceIds
중 하나와 일치해야 합니다.
다음 스니펫은 REACHABLE_DEVICES
핸들러를 만드는 방법을 보여줍니다.
const reachableDevicesHandler = (request: IntentFlow.ReachableDevicesRequest): IntentFlow.ReachableDevicesResponse => { // Reference to the local proxy device const proxyDeviceId = request.inputs[0].payload.device.id; // Gather additional device ids reachable by local proxy device // ... const reachableDevices = [ // Each verificationId must match one of the otherDeviceIds // in the SYNC response { verificationId: "local-device-id-1" }, { verificationId: "local-device-id-2" }, ]; // Return a response const response: IntentFlow.ReachableDevicesResponse = { intent: Intents.REACHABLE_DEVICES, requestId: request.requestId, payload: { devices: reachableDevices, }, }; return response; };
EXECUTE 핸들러 구현
앱의 EXECUTE
핸들러는 사용자 명령어를 처리하고 Local Home SDK를 사용하여 기존 프로토콜을 통해 스마트 기기에 액세스합니다.
Local Home 플랫폼은 클라우드 처리에 EXECUTE
인텐트와 동일한 입력 페이로드를 EXECUTE
핸들러 함수에 전달합니다. 마찬가지로 EXECUTE
핸들러는 EXECUTE
인텐트 처리와 동일한 형식의 출력 데이터를 반환합니다.
응답 생성을 간소화하려면 Local Home SDK에서 제공하는 Execute.Response.Builder
클래스를 사용하면 됩니다.
앱이 기기의 IP 주소에 직접 액세스할 수 없습니다. 대신 CommandRequest
인터페이스를 사용하여 UDP, TCP, HTTP 프로토콜 중 하나를 기반으로 명령어를 만드세요. 그런 다음 deviceManager.send()
함수를 호출하여 명령어를 전송합니다.
기기에 명령어를 타겟팅할 때는 SYNC
응답의 기기 ID(및 customData
필드의 매개변수(있는 경우))를 사용하여 기기와 통신합니다.
예
다음 코드 스니펫은 EXECUTE
핸들러를 만드는 방법을 보여줍니다.
const executeHandler = (request: IntentFlow.ExecuteRequest): Promise<IntentFlow.ExecuteResponse> => { // Extract command(s) and device target(s) from request const command = request.inputs[0].payload.commands[0]; const execution = command.execution[0]; const response = new Execute.Response.Builder() .setRequestId(request.requestId); const result = command.devices.map((device) => { // Target id of the device provided in the SYNC response const deviceId = device.id; // Metadata for the device provided in the SYNC response // Use customData to provide additional required execution parameters const customData: any = device.customData; // Convert execution command into payload for local device let devicePayload: string; // ... // Construct a local device command over TCP const deviceCommand = new DataFlow.TcpRequestData(); deviceCommand.requestId = request.requestId; deviceCommand.deviceId = deviceId; deviceCommand.data = devicePayload; deviceCommand.port = customData.port; deviceCommand.operation = Constants.TcpOperation.WRITE; // Send command to the local device return localHomeApp.getDeviceManager() .send(deviceCommand) .then((result) => { response.setSuccessState(result.deviceId, state); }) .catch((err: IntentFlow.HandlerError) => { err.errorCode = err.errorCode || IntentFlow.ErrorCode.INVALID_REQUEST; response.setErrorState(device.id, err.errorCode); }); }); // Respond once all commands complete return Promise.all(result) .then(() => response.build()); };
QUERY 핸들러 구현
앱의 QUERY
핸들러는 사용자 요청을 처리하고 Local Home SDK를 사용하여 스마트 기기의 상태를 보고합니다.
로컬 Home 플랫폼은 클라우드 처리에 QUERY
인텐트와 동일한 요청 페이로드를 'QUERY' 핸들러 함수에 전달합니다. 마찬가지로 QUERY
핸들러는 QUERY
인텐트 처리와 동일한 형식으로 데이터를 반환합니다.
허브 뒤에 있는 기기에 명령어 전송
허브 뒤에 있는 최종 기기를 제어하려면 허브가 명령어의 대상 기기를 식별할 수 있도록 허브에 전송되는 프로토콜별 명령어 페이로드에 추가 정보를 제공해야 할 수 있습니다. 경우에 따라 device.id
값에서 직접 추론할 수 있지만 그렇지 않은 경우에는 이 추가 데이터를 customData
필드의 일부로 포함해야 합니다.
TypeScript를 사용하여 앱을 만든 경우 앱을 JavaScript로 컴파일해야 합니다. 원하는 모듈 시스템을 사용하여 코드를 작성할 수 있습니다. Chrome 브라우저에서 타겟이 지원되는지 확인합니다.