node-red-contrib-esphome
Version:
Node-RED nodes to ESPhome devices
98 lines (82 loc) • 2.85 kB
text/typescript
import {NodeAPI} from 'node-red';
import {Status} from '../lib/utils';
module.exports = (RED: NodeAPI) => {
RED.nodes.registerType('esphome-out', function (this: any, config: any) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this;
self.config = config;
RED.nodes.createNode(this, config);
try {
self.deviceNode = RED.nodes.getNode(config.device);
} catch (_) {
/* empty */
}
if (!self.deviceNode || !config.entity) {
return;
}
const clearStatus = (timeout = 0) => {
const current_status: string = self.deviceNode.current_status;
setTimeout(() => {
if (current_status) {
self.status(Status[current_status as string]);
} else {
self.status({});
}
}, timeout);
};
const setStatus = (status: any, timeout = 0) => {
self.status(status);
if (timeout) {
clearStatus(timeout);
}
};
const capitalize = (s: string) => (s[0].toLowerCase() + s.slice(1)) as string;
self.on('input', async (msg: any, send: () => any, done: () => any) => {
const entity: any = self.deviceNode.entities.find((e: any) => e.key == config.entity);
if (typeof entity == 'undefined') {
setStatus(Status['error'], 3000);
self.error(`Entity (${config.entity}) not found on device`);
done();
return;
}
const regexpType = /^(BinarySensor|Sensor|TextSensor)$/gi;
const regexpEntity = /^(Logs|BLE|Status)$/gi;
if (entity.type.match(regexpType) || config.entity.match(regexpEntity)) {
done();
return;
}
const payload: any = msg.payload;
let text: string;
if (typeof payload.state !== 'undefined' && typeof payload.state !== 'object') {
text = String(payload.state);
} else {
if (typeof payload !== 'undefined' && typeof payload === 'object') {
text = 'json';
} else {
text = String(payload);
}
}
if (text && text.length > 32) {
text = `${text.substring(0, 32)}...`;
}
try {
const command = capitalize(entity.type + 'CommandService');
await self.deviceNode.client.connection[command]({key: config.entity, ...payload});
if (text) setStatus({fill: 'yellow', shape: 'dot', text: text});
} catch (e: any) {
setStatus(Status['error'], 3000);
self.error(e.message);
}
done();
});
const onStatus = (status: string) => {
setStatus(Status[status as string]);
};
self.onStatus = (status: string) => onStatus(status);
self.deviceNode.on('onStatus', self.onStatus);
self.on('close', (_: any, done: () => any) => {
self.deviceNode.removeListener('onStatus', self.onStatus);
done();
});
});
};