Yerel sipariş karşılama uygulamasını uygulayın

Yerel intent karşılama özelliğini desteklemek için aşağıdaki akıllı ev intent'lerini işleyecek bir uygulama oluşturmanız gerekir:

  • IDENTIFY: Yerel olarak kontrol edilebilen akıllı cihazların bulunmasını destekler. Amaç işleyici, akıllı cihazınızın keşif sırasında döndürdüğü verileri ayıklar ve bunları Google'a yanıt olarak gönderir.
  • EXECUTE: Komutların yürütülmesini destekler.
  • QUERY: Cihaz durumunu sorgulamayı destekler.
  • REACHABLE_DEVICES: (İsteğe bağlı) Bir hub (veya köprü) cihazının arkasındaki yerel olarak kontrol edilebilir uç cihazların bulunmasını destekler.

Bu uygulama, kullanıcının Google Home veya Google Nest cihazlarında çalışır ve akıllı cihazınızı Asistan'a bağlar. Uygulamayı TypeScript (tercih edilen) veya JavaScript kullanarak oluşturabilirsiniz.

TypeScript, uygulamanızın döndürdüğü verilerin platformun beklediği türlerle eşleşmesini statik olarak sağlamak için bağlamalardan yararlanabileceğinizden önerilir.

API hakkında daha fazla bilgi için Local Home SDK API referansı'na bakın.

Aşağıdaki snippet'lerde, yerel karşılama uygulamasını nasıl başlatabileceğiniz ve işleyicilerinizi nasıl ekleyebileceğiniz gösterilmektedir.

Bağımsız
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");
  });

Projenizi oluşturma

Yerel karşılama uygulamanızı dağıtmak için kodunuz ve tüm bağımlılıkları için bir JavaScript paketi oluşturmanız gerekir.

Tercih ettiğiniz paketleyici yapılandırmasıyla uygun proje yapısını başlatmak için yerel karşılama uygulaması project initializer'ı kullanın.

Proje şablonları

Paketleyici yapılandırmanızı seçmek için aşağıdaki örneklerde gösterildiği gibi npm init komutunu çalıştırın:

Yok

Paketleyici yapılandırması olmayan TypeScript:

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

Proje yapısı:

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

project-directory kısmını, yerel karşılama uygulaması projesini içerecek yeni bir dizinle değiştirin.

Webpack

webpack paketleyici ile TypeScript yapılandırması:

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

Proje yapısı:

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 kısmını, yerel karşılama uygulaması projesini içerecek yeni bir dizinle değiştirin.

Grup

Rollup ile TypeScript paketleyici yapılandırması:

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

Proje yapısı:

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

project-directory kısmını, yerel karşılama uygulaması projesini içerecek yeni bir dizinle değiştirin.

Parcel

Parcel paketleyici yapılandırmasıyla TypeScript:

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

Proje yapısı:

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

project-directory kısmını, yerel karşılama uygulaması projesini içerecek yeni bir dizinle değiştirin.

Sık gerçekleştirilen proje düzeyindeki görevleri yerine getirme

Oluşturulan proje aşağıdaki npm komut dosyalarını destekler:

Paket
cd project-directory/
npm run build

Bu komut dosyası, TypeScript kaynağını derler ve uygulamanızı dist/web alt dizinindeki Chrome çalışma zamanı ortamı ile dist/node alt dizinindeki Node.js çalışma zamanı ortamı için bağımlılıklarıyla birlikte paketler.

Doğrula
cd project-directory/
npm run lint
npm run compile
npm test

Bu komut dosyası, TypeScript kodunuzun söz dizimini doğrular, dist/ alt dizininde herhangi bir çıktı oluşturmadan derler ve test.ts'den otomatik testler çalıştırır.

Yayınlama
cd project-directory/
npm run start

Bu komut dosyası, geliştirme sırasında Chrome ve Node.js çalışma zamanı ortamları için uygulama paketlerinizi yerel olarak sunar.

IDENTIFY işleyicisini uygulama

Google Home veya Google Nest cihazı yeniden başlatıldığında ve doğrulanmamış yerel cihazlar (hub'a bağlı uç cihazlar dahil) gördüğünde IDENTIFY işleyici tetiklenir. Yerel Ev platformu, daha önce belirttiğiniz tarama yapılandırması bilgilerini kullanarak yerel cihazları tarar ve tarama sonuçlarıyla IDENTIFY işleyicinizi çağırır.

Yerel Ev platformundaki IdentifyRequest bir LocalIdentifiedDevice örneğinin tarama verilerini içerir. Cihazı keşfeden tarama yapılandırmasına göre yalnızca bir device örneği doldurulur.

Tarama sonuçları cihazınızla eşleşiyorsa IDENTIFY işleyiciniz, akıllı ev meta verilerini (ör. türler, özellikler ve rapor durumu) içeren bir device nesnesiyle birlikte bir IdentifyResponsePayload nesnesi döndürmelidir.

Google, IDENTIFY yanıtındaki verificationId, SYNC yanıtı tarafından döndürülen otherDeviceIds değerlerinden biriyle eşleşirse cihaz ilişkilendirmesi oluşturur.

Örnek

Aşağıdaki snippet'lerde, sırasıyla bağımsız cihaz ve hub entegrasyonları için nasıl IDENTIFY işleyicileri oluşturabileceğiniz gösterilmektedir.

Bağımsız
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;
  };

Hub'ın arkasındaki cihazları tanımlama

Google bir hub cihazı tanımlarsa hub'ı, hub'a bağlı uç cihazlara giden kanal olarak değerlendirir ve bu uç cihazları doğrulamaya çalışır.

Google'ın bir hub cihazının mevcut olduğunu onaylamasını sağlamak için IDENTIFY işleyicinizle ilgili aşağıdaki talimatları uygulayın:

  • SYNC yanıtınız, hub'a bağlı yerel uç cihazların kimliklerini bildiriyorsa IdentifyResponsePayload içinde isProxy değerini true olarak ayarlayın.
  • SYNC yanıtınızda hub cihazınız bildirilmiyorsa IdentifyResponsePayload içinde isLocalOnly değerini true olarak ayarlayın.
  • device.id alanı, hub cihazının yerel cihaz kimliğini içerir.

REACHABLE_DEVICES işleyicisini uygulama (yalnızca hub entegrasyonları)

REACHABLE_DEVICES amacı, hangi uç cihazların yerel olarak kontrol edilebileceğini onaylamak için Google tarafından gönderilir. Bu amaç, Google bir keşif taraması (yaklaşık olarak her dakikada bir) çalıştırdığı her seferde tetiklenir. Bunun için hub'ın çevrimiçi olduğunun algılanması gerekir.

REACHABLE_DEVICES işleyiciyi, IDENTIFY işleyiciye benzer şekilde uygularsınız. Ancak işleyicinizin, yerel proxy (yani hub) cihazı tarafından erişilebilen ek cihaz kimliklerini toplaması gerekir. device.verificationId alanı, hub'a bağlı bir uç cihazın yerel cihaz kimliğini içerir.

Yerel Ev platformundaki ReachableDevicesRequest LocalIdentifiedDevice öğesinin bir örneğini içeriyor. Bu örnek üzerinden, tarama sonuçlarındaki verilerin yanı sıra proxy cihaz kimliğini de alabilirsiniz.

REACHABLE_DEVICES işleyiciniz, hub'ın kontrol ettiği uç cihazları temsil eden bir verificationId değerleri dizisi içeren bir devices nesnesi içeren bir ReachableDevicesPayload nesnesi döndürmelidir. verificationId değerleri, SYNC yanıtındaki otherDeviceIds değerlerinden biriyle eşleşmelidir.

Aşağıdaki snippet'te REACHABLE_DEVICES işleyicinizi nasıl oluşturabileceğiniz gösterilmektedir.

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

EXECUTE işleyicisini uygulama

Uygulamadaki EXECUTE işleyiciniz, kullanıcı komutlarını işler ve mevcut bir protokol aracılığıyla akıllı cihazlarınıza erişmek için Yerel Ev SDK'sını kullanır.

Local Home platformu, EXECUTE işleyici işlevine EXECUTE niyetinde olduğu gibi aynı giriş yükünü bulut sipariş karşılama işlevinize iletir. Benzer şekilde, EXECUTE işleyiciniz de EXECUTE amacının işlenmesinden elde edilenle aynı biçimde çıkış verileri döndürür. Yanıt oluşturmayı basitleştirmek için Local Home SDK'nın sağladığı Execute.Response.Builder sınıfını kullanabilirsiniz.

Uygulamanızın cihazın IP adresine doğrudan erişimi yoktur. Bunun yerine, UDP, TCP veya HTTP protokollerinden birine dayalı komutlar oluşturmak için CommandRequest arayüzünü kullanın. Ardından, komutları göndermek için deviceManager.send() işlevini çağırın.

Komutları cihazlara hedeflerken cihazla iletişim kurmak için SYNC yanıtındaki cihaz kimliğini (ve varsa customData alanındaki parametreleri) kullanın.

Örnek

Aşağıdaki kod snippet'inde, EXECUTE işleyicinizi nasıl oluşturabileceğiniz gösterilmektedir.

Bağımsız/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());
  };

QUERY işleyicisini uygulama

Uygulamadaki QUERY işleyiciniz, kullanıcı isteklerini işler ve akıllı cihazlarınızın durumunu bildirmek için Yerel Ev SDK'sını kullanır.

Local Home platformu, QUERY amacında olduğu gibi aynı istek yükünü bulut karşılamanıza yönelik "QUERY" işleyici işlevine iletir. Benzer şekilde, QUERY işleyici, QUERY amaç işlenirken olduğu gibi aynı biçimde veriler döndürür.

Hub'ın arkasındaki cihazlara komut gönderme

Bir hub'ın arkasındaki uç cihazları kontrol etmek için, hub'a gönderilen protokole özgü komut yükünde ek bilgiler sağlamanız gerekebilir. Bu bilgiler, hub'ın komutun hangi cihaza yönelik olduğunu belirlemesini sağlar. Bazı durumlarda bu, doğrudan device.id değerinden çıkarılabilir. Ancak bu durum söz konusu olmadığında, bu ek verileri customData alanına dahil etmeniz gerekir.

Uygulamanızı TypeScript kullanarak oluşturduysanız uygulamanızı JavaScript'e derlemeyi unutmayın. Kodunuzu yazmak için istediğiniz modül sistemini kullanabilirsiniz. Hedefinizin Chrome tarayıcı tarafından desteklendiğinden emin olun.