mirror of
https://github.com/home-assistant/home-assistant.io.git
synced 2025-07-21 00:06:51 +00:00
Link to app.js releases from Nabu Casa (#22570)
This commit is contained in:
parent
34335e17c0
commit
11dda79b18
@ -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.
|
||||||
|
@ -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));
|
|
Loading…
x
Reference in New Issue
Block a user