0

I'm creating a smart home integration. I'm up to the testing on device step - attempting to sign in to an account to add the device.

https://developers.google.com/actions/smarthome/#syncing_devices

I've setup the assistant to retrieve an OAuth token:

enter image description here

And this works - on my test device I can open: Settings > Home Control > Add Device and see my project. I can then also sign in with OAuth. However the next step is Google then should "Assistant sends an action.devices.SYNC intent to your fulfillment"

From the docs:

User set up their devices with the Google Assistant app to authenticate to your cloud services and the Assistant receives an OAuth token. At this point, the Assistant sends an action.devices.SYNC intent to your fulfillment to retrieve the initial list of user devices and capabilities from your cloud infrastructure.

Fulfilment is setup correctly:

enter image description here

My fulfilment looks like this:

 exports.helloWorld = functions.https.onRequest((request, response) => {
  const requestId = request.requestId;
  if(request.inputs == null) {
    console.log("unexpected request " + util.inspect(request, false, null));
    console.log("unexpected request id " + requestId);
    response.send(400);
    return;
  }

  const userId = request.get("Authorization");
  ... etc do other stuff then return correct response as a 200

I have checked the cloud function logs and the above fulfilment is called. However the documentation says it will send a action.devices.SYNC intent and it does not. (Therefore never getting past that first if statement).

It sends something that I don't recognise (and I don't see documented that I should recognise):

(every request should have a request id - and this one does not: request id undefined) enter image description here

Any idea's at all?


From the comments, here is the stackdriver log:

enter image description here

{
insertId:  "000000-751089a4-XXXX-XXXX-XXXX-f6a11a39b4d5"  
 labels: {
  execution_id:  "vXXXXsnaopim"   
 }
 logName:  "projects/XXXXX/logs/cloudfunctions.googleapis.com%2Fcloud-functions"  
 receiveTimestamp:  "2018-03-29T13:44:56.577854174Z"  
 resource: {
  labels: {
   function_name:  "helloWorld"    
   project_id:  "XXXXX"    
   region:  "us-central1"    
  }
  type:  "cloud_function"   
 }
 severity:  "INFO"  
 textPayload:  "unexpected request IncomingMessage {
  _readableState: 
   ReadableState {
     objectMode: false,
     highWaterMark: 16384,
     buffer: BufferList { head: null, tail: null, length: 0 },
     length: 0,
     pipes: null,
     pipesCount: 0,
     flowing: true,
     ended: true,
     endEmitted: true,
     reading: false,
     sync: false,
     needReadable: false,
     emittedReadable: false,
     readableListening: false,
     resumeScheduled: false,
     defaultEncoding: 'utf8',
     ranOut: false,
     awaitDrain: 0,
     readingMore: false,
     decoder: null,
     encoding: null },
  readable: false,
  domain: null,
  _events: {},
  _eventsCount: 0,
  _maxListeners: undefined,
  socket: 
   Socket {
     connecting: false,
     _hadError: false,
     _handle: 
      TCP {
        bytesRead: 917,
        _externalStream: {},
        fd: 12,
        reading: true,
        owner: [Circular],
        onread: [Function: onread],
        onconnection: null,
        writeQueueSize: 0,
        _consumed: true },
     _parent: null,
     _host: null,
     _readableState: 
      ReadableState {
        objectMode: false,
        highWaterMark: 16384,
        buffer: BufferList { head: null, tail: null, length: 0 },
        length: 0,
        pipes: null,
        pipesCount: 0,
        flowing: true,
        ended: false,
        endEmitted: false,
        reading: true,
        sync: false,
        needReadable: true,
        emittedReadable: false,
        readableListening: false,
        resumeScheduled: false,
        defaultEncoding: 'utf8',
        ranOut: false,
        awaitDrain: 0,
        readingMore: false,
        decoder: null,
        encoding: null },
     readable: true,
     domain: null,
     _events: 
      { end: 
         [ { [Function: g] listener: [Function: onend] },
           [Function: socketOnEnd] ],
        finish: [Function: onSocketFinish],
        _socketEnd: [Function: onSocketEnd],
        drain: [ [Function: ondrain], [Function: socketOnDrain] ],
        timeout: [Function],
        error: [ [Function: socketOnError], [Function: onevent] ],
        close: 
         [ [Function: serverSocketCloseListener],
           [Function: onServerResponseClose],
           [Function: onevent] ],
        data: [Function: socketOnData],
        resume: [Function: onSocketResume],
        pause: [Function: onSocketPause] },
     _eventsCount: 10,
     _maxListeners: undefined,
     _writableState: 
      WritableState {
        objectMode: false,
        highWaterMark: 16384,
        needDrain: false,
        ending: false,
        ended: false,
        finished: false,
        decodeStrings: false,
        defaultEncoding: 'utf8',
        length: 0,
        writing: false,
        corked: 0,
        sync: true,
        bufferProcessing: false,
        onwrite: [Function],
        writecb: null,
        writelen: 0,
        bufferedRequest: null,
        lastBufferedRequest: null,
        pendingcb: 0,
        prefinished: false,
        errorEmitted: false,
        bufferedRequestCount: 0,
        corkedRequestsFree: CorkedRequest { next: null, entry: null, finish: [Function] } },
     writable: true,
     allowHalfOpen: true,
     destroyed: false,
     _bytesDispatched: 0,
     _sockname: null,
     _pendingData: null,
     _pendingEncoding: '',
     server: 
      Server {
        domain: null,
        _events: 
         { request: 
            { [Function: app]
              domain: undefined,
              _events: { mount: [Function: onmount] },
              _maxListeners: undefined,
              setMaxListeners: [Function: setMaxListeners],
              getMaxListeners: [Function: getMaxListeners],
              emit: [Function: emit],
              addListener: [Function: addListener],
              on: [Function: addListener],
              prependListener: [Function: prependListener],
              once: [Function: once],
              prependOnceListener: [Function: prependOnceListener],
              removeListener: [Function: removeListener],
              removeAllListeners: [Function: removeAllListeners],
              listeners: [Function: listeners],
              listenerCount: [Function: listenerCount],
              eventNames: [Function: eventNames],
              init: [Function],
              defaultConfiguration: [Function],
              lazyrouter: [Function],
              handle: [Function],
              use: [Function: use],
              route: [Function],
              engine: [Function],
              param: [Function],
              set: [Function],
              path: [Function],
              enabled: [Function],
              disabled: [Function],
              enable: [Function],
              disable: [Function],
              acl: [Function],
              bind: [Function],
              checkout: [Function],
              connect: [Function],
              copy: [Function],
              delete: [Function],
              get: [Function],
      "  
 timestamp:  "2018-03-29T13:44:50.294Z"  
}
Blundell
  • 75,855
  • 30
  • 208
  • 233
  • Can you check Stackdriver logs for your action? https://developers.google.com/actions/smarthome/logging You should not be using Google's OAuth endpoints but have your own as I cannot guarantee that these endpoints will work correctly. If you just log the request, do you see anything interesting in it? – Nick Felker Mar 30 '18 at 17:21
  • as far as I understand, stackdriver shows the same logs as the firebase logs above. The above screenshot is logging the request. – Blundell Mar 30 '18 at 21:17
  • Googles OAuth endpoints work correctly according to my tests and to the spec. I can't see anything in the documentation that explains something more, care to expand? – Blundell Mar 30 '18 at 21:19
  • It's against policy, which is primarily for submitting. For StackDriver, it does show some additional errors from the Google Assistant side of the linking process. – Nick Felker Mar 30 '18 at 21:36
  • Added the stackdriver logs. I'll look into changing the OAuth - but is that contributing to this problem? (happy to change that if I go to production - still POC right now) – Blundell Apr 01 '18 at 18:51
  • I don't know if OAuth is the reason for the issue. It seems like the `request` object isn't a simple string payload but an [IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage) – Nick Felker Apr 02 '18 at 18:16

1 Answers1

0

Your logging statement fails as it might not be possible to access request.requestId like that in the cloud function. If you want to have an end-to-end working example that uses cloud functions and firebase, you can follow the steps in the Smart Home Washer codelab.

Anish Yadav
  • 141
  • 4