Mengimplementasikan aplikasi fulfillment lokal

Untuk mendukung fulfillment lokal, Anda perlu membuat aplikasi untuk menangani intent smart home berikut:

  • IDENTIFY: Mendukung penemuan perangkat smart yang dapat dikontrol secara lokal. Handler intent mengekstrak data yang ditampilkan perangkat smart Anda selama penemuan dan mengirimkannya dalam respons ke Google.
  • EXECUTE: Mendukung eksekusi perintah.
  • QUERY: Mendukung kueri status perangkat.
  • REACHABLE_DEVICES: (Opsional) Mendukung penemuan perangkat akhir yang dapat dikontrol secara lokal di belakang perangkat hub (atau bridge).

Aplikasi ini berjalan di perangkat Google Home atau Google Nest pengguna dan menghubungkan perangkat smart Anda ke Asisten. Anda dapat membuat aplikasi menggunakan TypeScript (disarankan) atau JavaScript.

TypeScript direkomendasikan karena Anda dapat memanfaatkan binding untuk memastikan secara statis bahwa data yang ditampilkan aplikasi Anda cocok dengan jenis yang diharapkan platform.

Untuk mengetahui detail selengkapnya tentang API, lihat referensi API Local Home SDK.

Cuplikan berikut menunjukkan cara menginisialisasi aplikasi pemenuhan lokal dan melampirkan handler Anda.

Mandiri
import App = smarthome.App;
const localHomeApp: App = new App("1.0.0");
localHomeApp
  .onIdentify(identifyHandler)
  .onExecute(executeHandler)
  .listen()
  .then(() => {
    console.log("Ready");
  });
Hub
import App = smarthome.App;
const localHomeApp: App = new App("1.0.0");
localHomeApp
  .onIdentify(identifyHandler)
  .onReachableDevices(reachableDevicesHandler)
  .onExecute(executeHandler)
  .listen()
  .then(() => {
    console.log("Ready");
  });

Buat project Anda

Untuk men-deploy aplikasi pemenuhan lokal, Anda harus membuat paket JavaScript untuk kode dan semua dependensinya.

Gunakan penginisialisasi project aplikasi pemenuhan lokal untuk mem-bootstrap struktur project yang sesuai dengan konfigurasi bundler pilihan Anda.

Template project

Untuk memilih konfigurasi bundler, jalankan perintah npm init seperti yang ditunjukkan dalam contoh berikut:

Tidak ada

TypeScript tanpa konfigurasi bundler:

npm init @google/local-home-app project-directory/ --bundler none

Struktur project:

project-directory/
├── node_modules/
├── package.json
├── .gitignore
├── index.ts
├── test.ts
├── tsconfig.json
├── tslint.json
└── serve.js

Ganti project-directory dengan direktori baru yang akan berisi project aplikasi pemenuhan lokal.

Webpack

TypeScript dengan konfigurasi bundler webpack:

npm init @google/local-home-app project-directory/ --bundler webpack

Struktur project:

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

Ganti project-directory dengan direktori baru yang akan berisi project aplikasi pemenuhan lokal.

Rollup

Konfigurasi bundler TypeScript dengan Rollup:

npm init @google/local-home-app project-directory/ --bundler rollup

Struktur project:

project-directory/
├── node_modules/
├── package.json
├── .gitignore
├── index.ts
├── test.ts
├── tsconfig.json
├── tslint.json
├── rollup.config.js
└── serve.js

Ganti project-directory dengan direktori baru yang akan berisi project aplikasi pemenuhan lokal.

Parcel

TypeScript dengan konfigurasi bundler Parcel:

npm init @google/local-home-app project-directory/ --bundler parcel

Struktur project:

project-directory/
├── node_modules/
├── package.json
├── .gitignore
├── index.ts
├── test.ts
├── tsconfig.json
├── tslint.json
└── serve.js

Ganti project-directory dengan direktori baru yang akan berisi project aplikasi pemenuhan lokal.

Melakukan tugas umum tingkat project

Project yang dihasilkan mendukung skrip npm berikut:

Paket
cd project-directory/
npm run build

Skrip ini mengompilasi sumber TypeScript, dan memaketkan aplikasi Anda dengan dependensinya untuk lingkungan runtime Chrome di subdirektori dist/web dan lingkungan runtime Node.js di subdirektori dist/node.

Verifikasi
cd project-directory/
npm run lint
npm run compile
npm test

Skrip ini memverifikasi sintaksis kode TypeScript Anda, mengompilasinya tanpa menghasilkan output apa pun di subdirektori dist/, dan menjalankan pengujian otomatis dari test.ts.

Menyajikan
cd project-directory/
npm run start

Selama pengembangan, skrip ini menyajikan app bundle Anda untuk lingkungan runtime Chrome dan Node.js secara lokal.

Menerapkan pengendali IDENTIFY

Handler IDENTIFY akan dipicu saat perangkat Google Home atau Google Nest di-reboot dan melihat perangkat lokal yang tidak terverifikasi (termasuk perangkat akhir yang terhubung ke hub). Platform Local Home akan memindai perangkat lokal menggunakan informasi konfigurasi pemindaian yang Anda tentukan sebelumnya dan memanggil pengendali IDENTIFY dengan hasil pemindaian.

IdentifyRequest dari platform Local Home berisi data pemindaian instance LocalIdentifiedDevice. Hanya satu instance device yang diisi, berdasarkan konfigurasi pemindaian yang menemukan perangkat.

Jika hasil pemindaian cocok dengan perangkat Anda, handler IDENTIFY Anda harus menampilkan objek IdentifyResponsePayload, yang mencakup objek device dengan metadata smart home (seperti jenis, sifat, dan status laporan).

Google membuat asosiasi perangkat jika verificationId dari respons IDENTIFY cocok dengan salah satu nilai otherDeviceIds yang ditampilkan oleh respons SYNC.

Contoh

Cuplikan berikut menunjukkan cara membuat handler IDENTIFY untuk integrasi perangkat mandiri dan hub.

Mandiri
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;
  };
Hub
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;
  };

Mengidentifikasi perangkat di belakang hub

Jika Google mengidentifikasi perangkat hub, Google akan memperlakukan hub sebagai saluran ke perangkat akhir yang terhubung ke hub dan mencoba memverifikasi perangkat akhir tersebut.

Untuk mengizinkan Google mengonfirmasi bahwa perangkat hub ada, ikuti petunjuk berikut untuk pengendali IDENTIFY Anda:

  • Jika respons SYNC Anda melaporkan ID perangkat akhir lokal yang terhubung ke hub, tetapkan isProxy sebagai truedi IdentifyResponsePayload.
  • Jika respons SYNC tidak melaporkan perangkat hub Anda, tetapkan isLocalOnly sebagai true di IdentifyResponsePayload.
  • Kolom device.id berisi ID perangkat lokal untuk perangkat hub itu sendiri.

Menerapkan handler REACHABLE_DEVICES (khusus integrasi hub)

Maksud REACHABLE_DEVICES dikirim oleh Google untuk mengonfirmasi perangkat akhir mana yang dapat dikontrol secara lokal. Maksud ini dipicu setiap kali Google menjalankan pemindaian penemuan (kira-kira sekali setiap menit), selama hub terdeteksi sedang online.

Anda menerapkan pengendali REACHABLE_DEVICES dengan cara yang sama seperti pengendali IDENTIFY, kecuali pengendali Anda perlu mengumpulkan ID perangkat tambahan yang dapat dijangkau oleh perangkat proxy lokal (yaitu, hub). Kolom device.verificationId berisi ID perangkat lokal untuk perangkat akhir yang terhubung ke hub.

ReachableDevicesRequest dari platform Local Home berisi instance LocalIdentifiedDevice. Melalui instance ini, Anda bisa mendapatkan ID perangkat proxy serta data dari hasil pemindaian.

Handler REACHABLE_DEVICES Anda harus menampilkan objek ReachableDevicesPayload yang menyertakan objek devices yang berisi array nilai verificationId yang merepresentasikan perangkat akhir yang dikontrol hub. Nilai verificationId harus cocok dengan salah satu otherDeviceIds dari respons SYNC.

Cuplikan berikut menunjukkan cara membuat handler REACHABLE_DEVICES.

Hub
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;
  };

Menerapkan pengendali EXECUTE

Handler EXECUTE di aplikasi Anda memproses perintah pengguna dan menggunakan Local Home SDK untuk mengakses perangkat smart Anda melalui protokol yang ada.

Platform Local Home meneruskan payload input yang sama ke fungsi pengendali EXECUTE seperti untuk intent EXECUTE ke fulfillment cloud Anda. Demikian pula, handler EXECUTE Anda menampilkan data output dalam format yang sama seperti dari pemrosesan intent EXECUTE. Untuk menyederhanakan pembuatan respons, Anda dapat menggunakan class Execute.Response.Builder yang disediakan Local Home SDK.

Aplikasi Anda tidak memiliki akses langsung ke alamat IP perangkat. Sebagai gantinya, gunakan antarmuka CommandRequest untuk membuat perintah berdasarkan salah satu protokol berikut: UDP, TCP, atau HTTP. Kemudian, panggil fungsi deviceManager.send() untuk mengirim perintah.

Saat menargetkan perintah ke perangkat, gunakan ID perangkat (dan parameter dari kolom customData, jika disertakan) dari respons SYNC untuk berkomunikasi dengan perangkat.

Contoh

Cuplikan kode berikut menunjukkan cara membuat handler EXECUTE.

Mandiri/Hub
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());
  };

Menerapkan pengendali QUERY

Handler QUERY di aplikasi memproses permintaan pengguna dan menggunakan Local Home SDK untuk melaporkan status perangkat smart Anda.

Platform Local Home meneruskan payload permintaan yang sama ke fungsi handler 'QUERY' seperti untuk intent QUERY ke fulfillment cloud Anda. Demikian pula, handler QUERY Anda menampilkan data dalam format yang sama seperti dari pemrosesan intent QUERY.

Mengirim perintah ke perangkat di belakang hub

Untuk mengontrol perangkat akhir di belakang hub, Anda mungkin perlu memberikan informasi tambahan dalam payload perintah khusus protokol yang dikirim ke hub agar hub dapat mengidentifikasi perangkat yang menjadi target perintah. Dalam beberapa kasus, hal ini dapat disimpulkan secara langsung dari nilai device.id, tetapi jika tidak demikian, Anda harus menyertakan data tambahan ini sebagai bagian dari kolom customData.

Jika Anda membuat aplikasi menggunakan TypeScript, jangan lupa untuk mengompilasi aplikasi ke JavaScript. Anda dapat menggunakan sistem modul pilihan Anda untuk menulis kode. Pastikan target Anda didukung oleh browser Chrome.