Link to app.js releases from Nabu Casa (#22570)

This commit is contained in:
Paulus Schoutsen 2022-04-29 11:02:12 -07:00 committed by GitHub
parent 34335e17c0
commit 11dda79b18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 5 additions and 198 deletions

View File

@ -123,16 +123,16 @@ Your Google Assistant devices will still communicate via the internet to:
<div class='note'> <div class='note'>
The [HTTP integration](/integrations/http) must **not** be configured to use an SSL certificate with the [`ssl_certificate` option](/integrations/http/#ssl_certificate). 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. 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. 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.
</div> </div>
1. Open the project you created in the [Actions on Google console](https://console.actions.google.com/). 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. 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: 4. Add device scan configuration:
1. Click `+ New scan config` if no configuration exists 1. Click `+ New scan config` if no configuration exists
2. Select `MDNS` 2. Select `MDNS`
@ -251,7 +251,7 @@ Currently, the following domains are available to be used with Google Assistant,
- switch (on/off) - switch (on/off)
- fan (on/off/speed percentage/preset mode) - fan (on/off/speed percentage/preset mode)
- light (on/off/brightness/rgb color/color temp) - light (on/off/brightness/rgb color/color temp)
- lock - lock
- cover (on/off/set position) - cover (on/off/set position)
- media_player (on/off/set volume (via set volume)/source (via set input source)/control playback) - media_player (on/off/set volume (via set volume)/source (via set input source)/control playback)
- climate (temperature setting, hvac_mode) - 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). 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`. 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`. 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. 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. 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.

View File

@ -1,193 +0,0 @@
"use strict";
/// <reference types="@google/local-home-sdk" />
/*
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));