כדי לספק תמיכה למילוי הזמנות באופן מקומי, צריך לפתח אפליקציה שתומכת בכוונות הבית החכם הבאות:
IDENTIFY
: תמיכה במציאת מכשירים חכמים שנשלטים באופן מקומי. ה-handler של הכוונות מחלץ את הנתונים שהמכשיר החכם מחזיר במהלך הגילוי, ושולח אותם בתגובה ל-Google.EXECUTE
: תמיכה בביצוע פקודות.QUERY
: תמיכה בשליחת שאילתות על מצב המכשיר.REACHABLE_DEVICES
: (אופציונלי) תמיכה בגילוי של מכשירי קצה שניתן לשלוט בהם באופן מקומי מאחורי מכשיר עם רכזת (או גשר).
האפליקציה הזו פועלת במכשירי Google Home או Google Nest של המשתמשים, ומחברת את המכשיר החכם ל-Assistant. ניתן ליצור את האפליקציה באמצעות TypeScript (מועדף) או JavaScript.
מומלץ להשתמש ב-TypeScript כי אפשר להשתמש בקישורים כדי להבטיח באופן סטטי שהנתונים שהאפליקציה מחזירה תואמים לסוגים שהפלטפורמה מצפה להם.
מידע נוסף על ה-API זמין במאמר חומר עזר בנושא Local Home SDK API.
בקטעי הקוד הבאים אפשר לראות איך אפשר לאתחל את אפליקציית מילוי ההזמנות המקומית ולצרף את ה-handlers שלכם.
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 לקוד ולכל יחסי התלות שלו.
אתם יכולים להשתמש באפליקציית projectizer מקומית למילוי הזמנות, כדי לאתחל את מבנה הפרויקט המתאים עם הגדרות ה-bundler שאתם מעדיפים.
תבניות לפרויקט
כדי לבחור את הגדרות ה-bundler, מריצים את הפקודה npm init
כפי שמוצג בדוגמאות הבאות:
TypeScript ללא הגדרת Bundler:
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 בספרייה חדשה שתכיל את פרויקט האפליקציה המקומית למילוי הזמנות.
TypeScript עם תצורת Bundles של webpack:
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 עם תצורת בונטר (bundler) על:
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 בספרייה חדשה שתכיל את פרויקט האפליקציה המקומית למילוי הזמנות.
TypeScript עם תצורת חבילה של Parcel:
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 ומקבץ את האפליקציה עם יחסי התלות שלו לסביבת זמן הריצה של Chrome בספריית המשנה dist/web
ובסביבת זמן הריצה של Node.js בספריית המשנה dist/node
.
cd project-directory/ npm run lint npm run compile npm test
הסקריפט מאמת את התחביר של קוד ה-TypeScript שלך, מהדר אותו בלי להפיק פלט בספריית המשנה dist/
ומפעיל בדיקות אוטומטיות מ-test.ts
.
cd project-directory/ npm run start
במהלך הפיתוח, הסקריפט הזה מציג את קובצי ה-App Bundle לסביבות זמן הריצה של Chrome ו-Node.js באופן מקומי.
הטמעת ה-handler של IDENTIFY
ה-handler של IDENTIFY
יופעל כשמכשיר Google Home או Google Nest יופעל מחדש ויוצגו בו מכשירים מקומיים שלא אומתו (כולל מכשירי קצה שמחוברים לרכזת). פלטפורמת Local Home תסרוק כדי למצוא מכשירים מקומיים באמצעות פרטי הגדרות הסריקה שציינתם קודם לכן, ותתחיל להפעיל את ה-handler של IDENTIFY
עם תוצאות הסריקה.
הקוד IdentifyRequest
מפלטפורמת הבית המקומי מכיל את נתוני הסריקה של מכונה LocalIdentifiedDevice
. רק מופע אחד של device
יאוכלס, על סמך הגדרות הסריקה שגילתה את המכשיר.
אם תוצאות הסריקה תואמות למכשיר שלכם, ה-handler של IDENTIFY
אמור להחזיר אובייקט IdentifyResponsePayload
שכולל אובייקט device
עם מטא-נתונים לבית החכם (כמו הסוגים, התכונות ומצב הדוח).
Google יוצרת שיוך מכשיר אם verificationId
מהתגובה IDENTIFY
תואם לאחד מערכי
otherDeviceIds
שהחזירו בתגובה SYNC
.
דוגמה
בקטעי הקוד הבאים מוסבר איך ליצור גורמי handler של 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 לוודא שיש מכשיר Hub, פועלים לפי ההוראות הבאות ב-handler של IDENTIFY
:
- אם התשובה של
SYNC
מדווחת על המזהים של מכשירי קצה מקומיים שמחוברים למרכז, צריך להגדיר אתisProxy
בתורtrue
ב-IdentifyResponsePayload
. - אם התשובה של
SYNC
לא מדווחת על המכשיר המרכזי שלכם, צריך להגדיר את הערךisLocalOnly
בתורtrue
ב-IdentifyResponsePayload
. - השדה
device.id
מכיל את מזהה המכשיר המקומי של מכשיר המרכז עצמו.
יישום הגורם המטפל REACHABLE_ מכשיר (שילובים של Hub בלבד)
Intent REACHABLE_DEVICES
נשלח על ידי Google כדי לבדוק באילו מכשירי קצה אפשר לשלוט באופן מקומי. הכוונה הזו מופעלת בכל פעם ש-Google מריצה סריקת Discovery (בערך פעם בדקה), כל עוד המערכת מזהה שהמרכז מחובר לאינטרנט.
ה-handler של REACHABLE_DEVICES
מוטמע באופן דומה ל-handler של IDENTIFY
, אלא שה-handler צריך לאסוף מזהי מכשירים נוספים
שאליו אפשר להגיע דרך שרת ה-proxy המקומי (כלומר, המכשיר של ה-Hub). השדה device.verificationId
מכיל את מזהה המכשיר המקומי של מכשיר קצה שמחובר לרכזת.
הערך ReachableDevicesRequest
מפלטפורמת הבית המקומי מכיל מופע של LocalIdentifiedDevice
.
באמצעות המכונה הזו, תוכלו לקבל את מזהה המכשיר של שרת ה-Proxy וכן נתונים מתוצאות הסריקה.
ה-handler של REACHABLE_DEVICES
צריך להחזיר אובייקט ReachableDevicesPayload
שכולל אובייקט devices
שמכיל מערך של ערכי verificationId
שמייצגים את מכשירי הקצה שה-Hub שולט בהם. הערכים של verificationId
��ייבים להתאים לאחד מהערכים של otherDeviceIds
מהתגובה SYNC
.
בקטע הקוד הבא מוסבר איך ליצור את ה-handler של 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; };
הטמעת ה-handler של EXECUTE
ה-handler של EXECUTE
באפליקציה מעבד פקודות של משתמשים ומשתמש ב-Local Home SDK כדי לגשת למכשירים החכמים באמצעות פרוטוקול קיים.
פלטפורמת Local Home מעבירה לפונקציית ה-handler של EXECUTE
את אותו מטען ייעודי (payload) של הפונקציה EXECUTE
למילוי הבקשה בענן. באופן דומה, ה-handler של EXECUTE
מחזיר נתוני
פלט באותו פורמט של העיבוד של ה-Intent EXECUTE
.
כדי ליצור תשובות בקלות, תוכלו להשתמש במחלקה Execute.Response.Builder
שמוצעת ב-Local Home SDK.
לאפליקציה שלך אין גישה ישירה לכתובת ה-IP של המכשיר. במקום זאת, השתמשו בממשק CommandRequest
כדי ליצור פקודות שמבוססות על אחד מהפרוטוקולים האלה: UDP, TCP או HTTP. לאחר מכן, מפעילים את הפונקציה deviceManager.send()
כדי לשלוח את הפקודות.
כשמטרגטים פקודות למכשירים, צריך להשתמש במזהה המכשיר (ובפרמטרים מהשדה customData
, אם הוא כלול) מהתגובה SYNC
כדי לתקשר עם המכשיר.
דוגמה
קטע הקוד הבא מראה איך ליצור את ה-handler של 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()); };
יישום ה-handler של QUERY
ה-handler של QUERY
באפליקציה מעבד בקשות של משתמשים ומשתמש ב-Local Home SDK כדי לדווח על מצב המכשירים החכמים.
פלטפורמת Local Home מעבירה לפונקציית ה-handler 'QUERY' את אותו מטען ייעודי (payload) של הבקשה, כמו גם עבור הכוונה QUERY
למילוי הבקשה בענן. באופן דומה, ה-handler של QUERY
מחזיר נתונים
בפורמט זהה לזה של עיבוד ה-Intent QUERY
.
שליחת פקודות למכשירים מאחורי רכזת
כדי לשלוט במכשירי קצה מאחורי רכזת, ייתכן שיהיה צורך לספק מידע נוסף
במטען הייעודי (payload) הספציפי לפרוטוקול שנשלח למרכז כדי שהמרכז יוכל לזהות לאיזה מכשיר הפקודה מיועדת. במקרים מסוימים אפשר להסיק זאת ישירות מהערך של device.id
, אבל אם זה לא המצב, צריך לכלול את הנתונים הנוספים האלה כחלק מהשדה customData
.
אם יצרתם את האפליקציה באמצעות TypeScript, זכרו להדר את האפליקציה ל-JavaScript. תוכל להשתמש במערכת המודול שתבחר כדי לכתוב את הקוד שלך. חשוב לוודא שדפדפן Chrome תומך ביעד.