node-red-contrib-esphome
Version:
Node-RED nodes to ESPhome devices
178 lines (152 loc) • 4.48 kB
text/typescript
import {NodeAPI} from 'node-red';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const {Client} = require('@2colors/esphome-native-api');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Package = require('../../package.json');
import {LogLevel} from '../lib/utils';
module.exports = (RED: NodeAPI) => {
RED.nodes.registerType(
'esphome-device',
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);
self.setMaxListeners(0);
self.device = {};
self.entities = [];
self.current_status = 'disconnected';
self.logger = parseInt(config?.loglevel);
self.ble = Boolean(config?.ble);
if (!config?.host || !config?.port) {
return;
}
self.onStatus = function (string: string) {
self.current_status = string;
self.emit('onStatus', string);
self.emit('onState', {key: 'status', state: string});
};
self.onState = function (object: any) {
self.emit('onState', object);
};
self.onBle = function (object: any) {
self.emit('onBle', object);
};
let options: any = {
host: config.host,
port: config.port,
clientInfo: `${Package.name} ${Package.version}`,
initializeDeviceInfo: true,
initializeListEntities: true,
initializeSubscribeStates: true,
reconnect: true,
reconnectInterval: (config?.reconnect || 15) * 1000,
pingInterval: 15 * 1000,
initializeSubscribeBLEAdvertisements: self.ble
};
if (self.credentials.encryptionkey) {
options = {
...options,
encryptionKey: self.credentials.encryptionkey
};
} else {
options = {
...options,
password: self.credentials.password
};
}
if (self.logger) {
options = {
...options,
initializeSubscribeLogs: {
level: config.loglevel,
dumpConfig: config.logdump
}
};
}
self.client = new Client(options);
try {
self.client.connect();
self.client.connection.setMaxListeners(0);
} catch (e: any) {
self.error(e.message);
return;
}
self.client.on('error', (e: Error) => {
self.error(e.message);
self.onStatus('error');
});
self.client.on('disconnected', () => {
self.onStatus('disconnected');
});
self.client.on('connected', () => {
// clear entities
self.entities = [];
// logs to entities
if (self.logger) {
self.entities.push({
key: 'logs',
type: 'Systems',
name: 'Logs',
config: {
deviceClass: LogLevel[config.loglevel]
}
});
}
// ble to entities
if (self.ble) {
self.entities.push({
key: 'ble',
type: 'Systems',
name: 'BLE'
});
}
// status to entities
self.entities.push({
key: 'status',
type: 'Systems',
name: 'Status'
});
self.onStatus('connecting');
});
self.client.on('initialized', () => {
self.onStatus('connected');
});
self.client.on('deviceInfo', (deviceInfo: any) => {
self.device = deviceInfo;
});
self.client.on('newEntity', (entity: any) => {
self.entities.push({
key: entity.id,
type: entity.type,
name: entity.name,
config: entity.config
});
entity.on('state', (state: any) => {
self.onState({...state});
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
entity.on('error', (e: Error) => {
/* empty */
});
});
// logs
self.client.on('logs', (payload: any) => {
self.onState({key: 'logs', ...payload});
});
// ble
self.client.on('ble', (payload: any) => {
self.onBle({key: 'ble', ...payload});
});
self.on('close', () => {
self.client.disconnect();
});
},
{
credentials: {
encryptionkey: {type: 'password'},
password: {type: 'password'}
}
}
);
};