node-red-contrib-home-assistant-websocket
Version:
Node-RED integration with Home Assistant through websocket and REST API
234 lines (233 loc) • 10.6 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createRoutes = createRoutes;
const bonjour_1 = __importDefault(require("bonjour"));
const debug_1 = __importDefault(require("debug"));
const flat_1 = __importDefault(require("flat"));
const IssueService_1 = __importDefault(require("./common/services/IssueService"));
const const_1 = require("./const");
const globals_1 = require("./globals");
const diagnostics_1 = require("./helpers/diagnostics");
const node_1 = require("./helpers/node");
const homeAssistant_1 = require("./homeAssistant");
function disableCache(req, res, next) {
var _a;
const node = globals_1.RED.nodes.getNode(req.params.id);
if (((_a = node === null || node === void 0 ? void 0 : node.config) === null || _a === void 0 ? void 0 : _a.cacheJson) === false) {
res.setHeader('Surrogate-Control', 'no-store');
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', '0');
}
next();
}
function checkHomeAssistant(req, res, next) {
try {
const node = (0, node_1.getServerConfigNode)(req.params.serverId);
req.homeAssistant = (0, homeAssistant_1.getHomeAssistant)(node);
}
catch (err) {
const errorMessage = globals_1.RED._('config-server.errors.no_server_selected');
res.status(503).send({ error: errorMessage });
return;
}
next();
}
async function getDeviceActions(req, res) {
var _a, _b;
let message;
let success = true;
const deviceId = (_a = req.query.deviceId) === null || _a === void 0 ? void 0 : _a.toString();
const actions = await ((_b = req === null || req === void 0 ? void 0 : req.homeAssistant) === null || _b === void 0 ? void 0 : _b.websocket.getDeviceActions(deviceId).catch((e) => {
(0, debug_1.default)(`Error getting device actions. ${JSON.stringify(e)}`);
success = false;
message = e.message;
return [];
}));
res.json({ success, data: actions !== null && actions !== void 0 ? actions : [], message });
}
async function getDeviceActionCapabilities(req, res) {
var _a;
let success = true;
let message;
const queryEvent = req.query.event;
let event;
try {
event = JSON.parse(queryEvent);
}
catch (e) {
success = false;
message = 'Invalid event';
res.json({ success, data: [], message });
return;
}
const capabilities = await ((_a = req === null || req === void 0 ? void 0 : req.homeAssistant) === null || _a === void 0 ? void 0 : _a.websocket.getDeviceActionCapabilities(event).catch((e) => {
success = false;
message = e.message;
return [];
}));
res.json({ success, data: capabilities !== null && capabilities !== void 0 ? capabilities : [], message });
}
async function getDeviceTriggers(req, res) {
var _a, _b;
let success = true;
let message;
const deviceId = (_a = req.query.deviceId) === null || _a === void 0 ? void 0 : _a.toString();
const triggers = await ((_b = req === null || req === void 0 ? void 0 : req.homeAssistant) === null || _b === void 0 ? void 0 : _b.websocket.getDeviceTriggers(deviceId).catch((e) => {
success = false;
message = e.message;
return [];
}));
res.json({ success, data: triggers !== null && triggers !== void 0 ? triggers : [], message });
}
async function getDeviceTriggerCapabilities(req, res) {
var _a;
let success = true;
let message;
const queryEvent = req.query.event;
let event;
try {
event = JSON.parse(queryEvent);
}
catch (e) {
success = false;
message = 'Invalid event';
res.json({ success, data: [], message });
return;
}
const capabilities = await ((_a = req === null || req === void 0 ? void 0 : req.homeAssistant) === null || _a === void 0 ? void 0 : _a.websocket.getDeviceTriggerCapabilities(event).catch((e) => {
success = false;
message = e.message;
return [];
}));
res.json({ success, data: capabilities !== null && capabilities !== void 0 ? capabilities : [], message });
}
function getEntities(req, res) {
var _a;
const states = (_a = req === null || req === void 0 ? void 0 : req.homeAssistant) === null || _a === void 0 ? void 0 : _a.getEntities();
res.json(states !== null && states !== void 0 ? states : []);
}
function getStates(req, res) {
var _a, _b, _c;
const entityId = (_a = req.query.entityId) === null || _a === void 0 ? void 0 : _a.toString();
if (entityId === undefined) {
res.json((_b = req === null || req === void 0 ? void 0 : req.homeAssistant) === null || _b === void 0 ? void 0 : _b.websocket.getStates());
return;
}
const entity = (_c = req === null || req === void 0 ? void 0 : req.homeAssistant) === null || _c === void 0 ? void 0 : _c.websocket.getState(entityId);
res.json(entity !== null && entity !== void 0 ? entity : []);
}
function getServices(req, res) {
var _a;
const services = (_a = req === null || req === void 0 ? void 0 : req.homeAssistant) === null || _a === void 0 ? void 0 : _a.websocket.getServices();
res.json(services !== null && services !== void 0 ? services : []);
}
function getProperties(req, res) {
var _a, _b, _c, _d;
let flat = [];
const entityId = (_a = req.query.entityId) === null || _a === void 0 ? void 0 : _a.toString();
const entity = entityId
? (_b = req === null || req === void 0 ? void 0 : req.homeAssistant) === null || _b === void 0 ? void 0 : _b.websocket.getState(entityId)
: (_c = req === null || req === void 0 ? void 0 : req.homeAssistant) === null || _c === void 0 ? void 0 : _c.websocket.getStates();
if (Array.isArray(entity)) {
flat = Object.keys((0, flat_1.default)(entity)).filter((e) => { var _a; return ((_a = req === null || req === void 0 ? void 0 : req.query) === null || _a === void 0 ? void 0 : _a.term) && e.indexOf(req.query.term.toString()) !== -1; });
}
else {
const entities = (_d = req.homeAssistant) === null || _d === void 0 ? void 0 : _d.websocket.getStates();
if (!entities) {
res.json([]);
return;
}
flat = Object.values(entities).map((entity) => Object.keys((0, flat_1.default)(entity)));
}
const uniqProperties = Array.from(new Set([].concat(...flat)));
const sortedProperties = uniqProperties.sort((a, b) => {
if (!a.includes('.') && b.includes('.'))
return -1;
if (a.includes('.') && !b.includes('.'))
return 1;
if (a < b)
return -1;
if (a > b)
return 1;
return 0;
});
res.json(sortedProperties);
}
async function getTags(req, res) {
const homeAssistant = req === null || req === void 0 ? void 0 : req.homeAssistant;
const tags = req.query.update
? await (homeAssistant === null || homeAssistant === void 0 ? void 0 : homeAssistant.websocket.updateTagList())
: homeAssistant === null || homeAssistant === void 0 ? void 0 : homeAssistant.getTags();
const mappedTags = tags === null || tags === void 0 ? void 0 : tags.map((t) => {
var _a;
const tagName = (_a = homeAssistant === null || homeAssistant === void 0 ? void 0 : homeAssistant.websocket.getEntity(t.id)) === null || _a === void 0 ? void 0 : _a.name;
return {
id: t.id,
name: tagName !== null && tagName !== void 0 ? tagName : t.name,
};
});
res.json(mappedTags !== null && mappedTags !== void 0 ? mappedTags : []);
}
async function getTranslations(req, res) {
var _a, _b, _c, _d;
const category = (_a = req.query.cat) === null || _a === void 0 ? void 0 : _a.toString();
const language = (_c = (_b = req.query.lang) === null || _b === void 0 ? void 0 : _b.toString()) !== null && _c !== void 0 ? _c : 'en';
if (!category) {
res.json({});
return;
}
const results = await ((_d = req === null || req === void 0 ? void 0 : req.homeAssistant) === null || _d === void 0 ? void 0 : _d.websocket.getTranslations(category, language));
res.json(results !== null && results !== void 0 ? results : []);
}
function getIntegrationVersion(req, res) {
var _a, _b;
res.json({
version: (_b = (_a = req === null || req === void 0 ? void 0 : req.homeAssistant) === null || _a === void 0 ? void 0 : _a.integrationVersion) !== null && _b !== void 0 ? _b : const_1.NO_VERSION,
});
}
function postHandleHiddenIssue(req, res) {
const issue = req.body.issue;
IssueService_1.default.toggleIssueHiddenStatus(issue);
res.json({});
}
function findServers(req, res) {
const instances = [];
const browser = (0, bonjour_1.default)().find({ type: 'home-assistant' }, (service) => {
instances.push({
label: service.name
? `${service.name} (${service.txt.base_url})`
: service.txt.base_url,
value: service.txt.base_url,
});
});
// Add a bit of delay for all services to be discovered
setTimeout(() => {
res.json(instances);
browser.stop();
}, 3000);
}
function createRoutes() {
const endpoints = {
deviceActions: getDeviceActions,
deviceActionCapabilities: getDeviceActionCapabilities,
deviceTriggers: getDeviceTriggers,
deviceTriggerCapabilities: getDeviceTriggerCapabilities,
entities: getEntities,
properties: getProperties,
services: getServices,
states: getStates,
tags: getTags,
translations: getTranslations,
};
Object.entries(endpoints).forEach(([key, value]) => globals_1.RED.httpAdmin.get(`/homeassistant/${key}/:serverId?`, globals_1.RED.auth.needsPermission('server.read'), disableCache, checkHomeAssistant, value));
globals_1.RED.httpAdmin.get(`/homeassistant/version/:serverId`, globals_1.RED.auth.needsPermission('server.read'), checkHomeAssistant, getIntegrationVersion);
globals_1.RED.httpAdmin.get('/homeassistant/discover', findServers);
globals_1.RED.httpAdmin.get('/homeassistant/diagnostics', globals_1.RED.auth.needsPermission('server.read'), async (req, res) => {
res.send(await (0, diagnostics_1.getEnvironmentData)());
});
globals_1.RED.httpAdmin.post('/homeassistant/issues/hidden', postHandleHiddenIssue);
}
;