diff --git a/source/_integrations/google_assistant.markdown b/source/_integrations/google_assistant.markdown
index 4cb7f6683df..4fefe4b916f 100644
--- a/source/_integrations/google_assistant.markdown
+++ b/source/_integrations/google_assistant.markdown
@@ -123,16 +123,16 @@ Your Google Assistant devices will still communicate via the internet to:
The [HTTP integration](/integrations/http) must **not** be configured to use an SSL certificate with the [`ssl_certificate` option](/integrations/http/#ssl_certificate).
-
+
This is because the Google Assistant device will connect directly to the IP of your Home Assistant instance and will fail if it encounters an invalid SSL certificate.
-
+
For secure remote access, use a reverse proxy such as the {% my supervisor_addon addon="core_nginx_proxy" title="NGINX SSL" %} add-on instead of directing external traffic straight to Home Assistant.
1. Open the project you created in the [Actions on Google console](https://console.actions.google.com/).
2. Click `Develop` on the top of the page, then click `Actions` located in the hamburger menu on the top left.
-3. Upload [this Javascript file](/assets/integrations/google_assistant/app.js) for both Node and Chrome by clicking the `Upload Javascript files` button.
+3. Upload `app.js` from [here](https://github.com/NabuCasa/home-assistant-google-assistant-local-sdk/releases/latest) for both Node and Chrome by clicking the `Upload Javascript files` button.
4. Add device scan configuration:
1. Click `+ New scan config` if no configuration exists
2. Select `MDNS`
@@ -251,7 +251,7 @@ Currently, the following domains are available to be used with Google Assistant,
- switch (on/off)
- fan (on/off/speed percentage/preset mode)
- light (on/off/brightness/rgb color/color temp)
-- lock
+- lock
- cover (on/off/set position)
- media_player (on/off/set volume (via set volume)/source (via set input source)/control playback)
- climate (temperature setting, hvac_mode)
@@ -307,7 +307,7 @@ The `request_sync` service may fail with a 404 if the `project_id` of the HomeGr
1. Removing your project from the [Google Cloud API Console](https://console.cloud.google.com).
2. Add a new project to the [Actions on Google console](https://console.actions.google.com) Here you get a new `project_id`.
3. Run through the previously mentioned [Actions on Google console] setup instructions until the step to create a `service_account`.
- 4. Once you begin to create a new `service_account` in the [Google Cloud API Console], ensure you select the project created in [Actions on Google console] by verifying the `project_id`.
+ 4. Once you begin to create a new `service_account` in the [Google Cloud API Console], ensure you select the project created in [Actions on Google console] by verifying the `project_id`.
5. Enable HomeGraph API to the new project.
Verify that the Google Assistant is available on `https://[YOUR HOME ASSISTANT URL:PORT]/api/google_assistant` If it is working it should return `405: Method Not Allowed` when opened in a browser or via curl.
diff --git a/source/assets/integrations/google_assistant/app.js b/source/assets/integrations/google_assistant/app.js
deleted file mode 100644
index 66e087e392d..00000000000
--- a/source/assets/integrations/google_assistant/app.js
+++ /dev/null
@@ -1,193 +0,0 @@
-"use strict";
-///
-/*
-BASED ON: https://github.com/NabuCasa/home-assistant-google-assistant-local-sdk
-Only removed the fart sound at the end.
-For license information please check the repository.
-*/
-var App = smarthome.App;
-var Constants = smarthome.Constants;
-var DataFlow = smarthome.DataFlow;
-var Execute = smarthome.Execute;
-var Intents = smarthome.Intents;
-var IntentFlow = smarthome.IntentFlow;
-const findHassCustomDeviceDataByMdnsData = (requestId, devices, mdnsScanData) => {
- let device;
- device = devices.find((dev) => {
- const customData = dev.customData;
- return (customData &&
- "webhookId" in customData &&
- (!mdnsScanData.uuid || customData.uuid === mdnsScanData.uuid) &&
- (!mdnsScanData.baseUrl || customData.baseUrl === mdnsScanData.baseUrl));
- });
- // backwards compatibility for HA < 0.109
- if (!device) {
- device = devices.find((dev) => dev.customData &&
- "webhookId" in dev.customData);
- }
- if (!device) {
- console.log(requestId, "Unable to find HASS connection info.", devices);
- throw new IntentFlow.HandlerError(requestId, "invalidRequest", "Unable to find HASS connection info.");
- }
- return device.customData;
-};
-const findHassCustomDeviceDataByDeviceId = (requestId, devices, deviceId) => {
- let device;
- device = devices.find((dev) => {
- const customData = dev.customData;
- return (customData &&
- "webhookId" in customData &&
- customData.proxyDeviceId === deviceId);
- });
- if (!device) {
- console.log(requestId, "Unable to find HASS connection info.", devices);
- throw new IntentFlow.HandlerError(requestId, "invalidRequest", "Unable to find HASS connection info.");
- }
- return device.customData;
-};
-const createResponse = (request, payload) => ({
- intent: request.inputs[0].intent,
- requestId: request.requestId,
- payload,
-});
-class UnknownInstance extends Error {
- constructor(requestId) {
- super();
- this.requestId = requestId;
- }
- throwHandlerError() {
- throw new IntentFlow.HandlerError(this.requestId, "invalidRequest", "Unknown Instance");
- }
-}
-const forwardRequest = async (hassDeviceData, targetDeviceId, request) => {
- const command = new DataFlow.HttpRequestData();
- command.method = Constants.HttpOperation.POST;
- command.requestId = request.requestId;
- command.deviceId = targetDeviceId;
- command.isSecure = hassDeviceData.httpSSL;
- command.port = hassDeviceData.httpPort;
- command.path = `/api/webhook/${hassDeviceData.webhookId}`;
- command.data = JSON.stringify(request);
- command.dataType = "application/json";
- console.log(request.requestId, "Sending", command);
- const deviceManager = await app.getDeviceManager();
- let resp;
- try {
- resp = await new Promise((resolve, reject) => {
- setTimeout(() => reject(-1), 10000);
- deviceManager
- .send(command)
- .then((response) => resolve(response), reject);
- });
- // resp = (await deviceManager.send(command)) as HttpResponseData;
- console.log(request.requestId, "Raw Response", resp);
- }
- catch (err) {
- console.error(request.requestId, "Error making request", err);
- throw new IntentFlow.HandlerError(request.requestId, "invalidRequest", err === -1 ? "Timeout" : err.message);
- }
- // Response if the webhook is not registered.
- if (resp.httpResponse.statusCode === 200 && !resp.httpResponse.body) {
- throw new UnknownInstance(request.requestId);
- }
- try {
- const response = JSON.parse(resp.httpResponse.body);
- // Local SDK wants this.
- response.intent = request.inputs[0].intent;
- console.log(request.requestId, "Response", response);
- return response;
- }
- catch (err) {
- console.error(request.requestId, "Error parsing body", err);
- throw new IntentFlow.HandlerError(request.requestId, "invalidRequest", err.message);
- }
-};
-const identifyHandler = async (request) => {
- console.log("IDENTIFY intent:", request);
- const deviceToIdentify = request.inputs[0].payload.device;
- if (!deviceToIdentify.mdnsScanData) {
- console.error(request.requestId, "No usable mdns scan data");
- return createResponse(request, {});
- }
- if (!deviceToIdentify.mdnsScanData.serviceName.endsWith("._home-assistant._tcp.local")) {
- console.error(request.requestId, "Not Home Assistant type");
- return createResponse(request, {});
- }
- try {
- const hassCustomData = findHassCustomDeviceDataByMdnsData(request.requestId, request.devices, deviceToIdentify.mdnsScanData.txt);
- return await forwardRequest(hassCustomData, "", request);
- }
- catch (err) {
- if (err instanceof UnknownInstance) {
- return createResponse(request, {});
- }
- throw err;
- }
-};
-const reachableDevicesHandler = async (request) => {
- console.log("REACHABLE_DEVICES intent:", request);
- const hassCustomData = findHassCustomDeviceDataByDeviceId(request.requestId, request.devices, request.inputs[0].payload.device.id);
- try {
- return forwardRequest(hassCustomData,
- // Old code would sent it to the proxy ID: hassCustomData.proxyDeviceId
- // But tutorial claims otherwise, but maybe it is not for hub devices??
- // https://developers.google.com/assistant/smarthome/develop/local#implement_the_execute_handler
- // Sending it to the device that has to receive the command as per the tutorial
- request.inputs[0].payload.device.id, request);
- }
- catch (err) {
- if (err instanceof UnknownInstance) {
- err.throwHandlerError();
- }
- throw err;
- }
-};
-const executeHandler = async (request) => {
- console.log("EXECUTE intent:", request);
- const device = request.inputs[0].payload.commands[0].devices[0];
- try {
- return forwardRequest(device.customData, device.id, request);
- }
- catch (err) {
- if (err instanceof UnknownInstance) {
- err.throwHandlerError();
- }
- throw err;
- }
-};
-const queryHandler = async (request) => {
- console.log("QUERY intent:", request);
- const device = request.inputs[0].payload.devices[0];
- try {
- return await forwardRequest(device.customData, device.id, request);
- } catch (err) {
- if (err instanceof UnknownInstance) {
- err.throwHandlerError();
- }
- throw err;
- }
-};
-
-const app = new App("1.1.0");
-app
- .onIdentify(identifyHandler)
- .onReachableDevices(reachableDevicesHandler)
- .onExecute(executeHandler)
- .onQuery(queryHandler)
- // @ts-ignore
- .onIndicate((req) => console.log("Indicate", req))
- // @ts-ignore
- .onParseNotification((req) => console.log("ParseNotification", req))
- // @ts-ignore
- .onProvision((req) => console.log("Provision", req))
- // @ts-ignore
- .onRegister((req) => console.log("Register", req))
- // @ts-ignore
- .onUnprovision((req) => console.log("Unprovision", req))
- // @ts-ignore
- .onUpdate((req) => console.log("Update", req))
- .listen()
- .then(() => {
- console.log("Ready!");
- })
- .catch((e) => console.error(e));