I failed developing a Google Assistant app

Hi all,

I spent two days trying to build a Google Assistant app, to use Homey to send a text command to GA.

I got a bit frustrated no being able to let my Hubs and Nest play Spotify music, so i figured i could make a app that could send a textQuery (Play album X on cast device Y) with this library:

But i couldn’t get the oAuth to work because of my lacky experience with NodeJS. Maybe someone else has the same need for a “missing link” app like this, so thats why i’m sharing my frustrated development experience :smile:

I figured it shouldn’t be to hard for a more experienced developer to make this work:

Cheers, Daniel

Hi. just linking to the other similar post.
Use this documentation and npm package from Athom to get all oAuth logic for free :slight_smile:

Hi @RonnyW,

Thanks for your reply, i did try those links but i couldn’t get it to work for Google :sweat_smile: I hope that someone would check out my git repository and see what i’m doing wrong:

I think i’m messing up in the driver.ts file:

Where did you get an error or when?
Did you debug onto the auth/code exchange functions of the oAuthClient?
Is teh oAuth popup shown? Can you proceed?

What I’ve seen:

static API_URL = 'https://accounts.google.com/o/oauth2/auth?response_type=code&';
API_URL is the URL to call API services with your bearer token. It’s not for oAuth. I think this should be the Server for your assistant API.

An in your oAuthClient you call:

await this.post({
      path: '/api/1/...',
      json:{}
    });

and the API_URL is used as host.

Hi @RonnyW,

I get an popup, but i get this response:

When i copy the response from google from the console, i get this html:

But it actually receives these parameters:

PARAMS {
client_id: ‘361248910627-sbt2ehglhgptp0ksjqfgk1cv32f1162l.apps.googleusercontent.com’,
redirect_uri: ‘https://callback.athom.com/oauth2/callback’,
scope: ‘https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email
}

You defined the redirect URL in your MyBrandOAuth2Client.ts. Looks ok.
But your driver raises an execption fot “things”. The “things” function is only an example where you can call your API.

I’m not sure what you are doing here: nl.danielvanbreda.gaquery/drivers/google-assistant-driver/driver.ts at main · thadrax/nl.danielvanbreda.gaquery · GitHub

This list devices function is calles after oAuth process (oAuth is valid and you got your token) to read available devices you can add to Homey. I don’t know what “devices” you have for this API.

You oAuthClient redefinition should provide functions to read the API. The oAuthClient has access to the token etc.
Example: homey.tesla/lib/TeslaOAuth2Client.js at main · RonnyWinkler/homey.tesla · GitHub
In your driver, just call the method of your oAuthClient like this: homey.tesla/drivers/car/driver.js at main · RonnyWinkler/homey.tesla · GitHub

Hi @RonnyW

Thank you so much for all your help, i’m beginning to understand more and more of how this works thanks to you. NodeJS is a bit out of my comfort zone, but its nice to learn.

I now got the oauth authorization working, now i’m gonna figure out how to call that authorization in my app.ts or how i can move my query flow to the virtual Google Assistant device.

Thanks once more :smile:

You’re welcome :grinning:
And I know the difficulty to learn a nuw language, the SKD and oAuth on top :sweat_smile:

Hi @RonnyW

Would you happen to know how to fix this grpc error:

grpc is deprecated and now grpc-js is used. But google-assistant uses grpc, and now throws this error:

“googleCredentials.getRequestMetadata is not a function”

Thank you :slight_smile:

Does it?

uhm no it doesn’t :grimacing:
i’m sorry for the confusion, i did not read well.

This is my terminal error when i pass MyBrandOAuth2Client as oauth2Client. it contains:

MyBrandOAuth2Client {
    _events: [Object: null prototype] {
      log: [Function (anonymous)],
      error: [Function (anonymous)],
      debug: [Function (anonymous)],
      save: [Function (anonymous)],
      destroy: [Function (anonymous)]
    },
    _eventsCount: 5,
    _maxListeners: undefined,
    homey: Homey {
      _events: [Object: null prototype],
      _eventsCount: 4,
      _maxListeners: undefined,
      dir: '/app',
      tmpdir: '/app/tmp',
      version: '10.3.4',
      platform: 'local',
      platformVersion: 2,
      env: {},
      manifest: [Object],
      app: [MyBrandApp],
      __readyResolve: [Function (anonymous)],
      __readyPromise: [Promise],
      _timers: Set(0) {},
      _destroyed: false,
      apps: [ManagerApps],
      arp: [ManagerArp],
      audio: [ManagerAudio],
      ble: [ManagerBLE],
      cloud: [ManagerCloud],
      clock: [ManagerClock],
      drivers: [ManagerDrivers],
      discovery: [ManagerDiscovery],
      flow: [ManagerFlow],
      geolocation: [ManagerGeolocation],
      i18n: [ManagerI18n],
      images: [ManagerImages],
      insights: [ManagerInsights],
      ledring: [ManagerLedring],
      nfc: [ManagerNFC],
      notifications: [ManagerNotifications],
      rf: [ManagerRF],
      settings: [ManagerSettings],
      speechInput: [ManagerSpeechInput],
      speechOutput: [ManagerSpeechOutput],
      zigbee: [ManagerZigBee],
      zwave: [ManagerZwave],
      api: [ManagerApi],
      __strings: [Object],
      __: [Function: __],
      [Symbol(kCapture)]: false
    },
    _tokenConstructor: [class OAuth2Token],
    _clientId: '???',
    _clientSecret: '???',
    _apiUrl: 'https://accounts.google.com/o/oauth2/auth?response_type=code&',
    _tokenUrl: 'https://oauth2.googleapis.com/token',
    _authorizationUrl: 'https://accounts.google.com/o/oauth2/auth',
    _redirectUrl: 'https://callback.athom.com/oauth2/callback',
    _scopes: [
      'https://www.googleapis.com/auth/userinfo.profile',
      'https://www.googleapis.com/auth/userinfo.email'
    ],
    _token: OAuth2Token {
      access_token: '???',
      refresh_token: null,
      token_type: 'Bearer',
      expires_in: 3599
    },
    _title: null,
    [Symbol(kCapture)]: false
  }
}

and throws this error:

in failed with error: googleCredentials.getRequestMetadata is not a function
    at callErrorFromStatus (/app/node_modules/@grpc/grpc-js/build/src/call.js:31:19)
    at Object.onReceiveStatus (/app/node_modules/@grpc/grpc-js/build/src/client.js:420:73)
    at Object.onReceiveStatus (/app/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:323:181)
    at /app/node_modules/@grpc/grpc-js/build/src/resolving-call.js:129:78
    at processTicksAndRejections (node:internal/process/task_queues:78:11)
for call at
    at ServiceClientImpl.makeBidiStreamRequest (/app/node_modules/@grpc/grpc-js/build/src/client.js:404:32)
    at ServiceClientImpl.converse (/app/node_modules/@grpc/grpc-js/build/src/make-client.js:105:19)
    at new Conversation (/app/node_modules/google-assistant/components/conversation.js:136:34)
    at GoogleAssistant.start (/app/node_modules/google-assistant/index.js:49:26)
    at GoogleAssistant.<anonymous> (/app/drivers/google-assistant-driver/driver.js:99:42)
    at GoogleAssistant.emit (node:events:513:28)
    at assistantReady (/app/node_modules/google-assistant/index.js:22:12)
    at processTicksAndRejections (node:internal/process/task_queues:78:11) {

Also: Release v2.0.0 · googleapis/google-auth-library-nodejs · GitHub

Ah so should i try to update the google-auth-library dependency?
I tried that this way, but the google-auth-library dependency within google-assistant remains ^7.0.4 instead of ^9.8.0 :upside_down_face:

I think you should get rid of the override, since it clearly doesn’t work. If you can’t get google-assistant to work you may have to consider looking for an alternative, it’s been a couple of years since it was last updated so it may be deprecated itself.