homebridge-virtual-accessories
Version:
Virtual HomeKit accessories for Homebridge.
111 lines • 4.52 kB
JavaScript
/* eslint-disable brace-style */
import { Trigger } from './trigger.js';
import { Sensor } from '../sensor.js';
import dns from 'dns';
import net from 'net';
import ping from 'net-ping';
/**
* Private helper classes to pass values by reference
*/
class Counter {
value;
constructor(value) {
this.value = value;
}
}
/**
* PingTrigger - Trigger implementation
*/
export class PingTrigger extends Trigger {
NOT_IP = 0;
IPv4 = 4;
IPv6 = 6;
failureCount = new Counter(0);
constructor(sensor, name) {
super(sensor, name);
const triggerConfig = this.sensorConfig.pingTrigger;
if (triggerConfig.isDisabled) {
this.log.info(`[${this.sensorConfig.accessoryName}] Ping trigger is disabled`);
return;
}
this.setup(triggerConfig);
}
async setup(triggerConfig) {
let ipProtocolVersion = net.isIP(triggerConfig.host);
if (ipProtocolVersion === this.NOT_IP) {
const ip = await this.getIP(triggerConfig.host);
if (ip) {
ipProtocolVersion = net.isIP(ip);
triggerConfig.host = ip;
}
}
let protocol;
switch (ipProtocolVersion) {
case this.IPv4:
protocol = ping.NetworkProtocol.IPv4;
break;
case this.IPv6:
protocol = ping.NetworkProtocol.IPv6;
break;
default:
this.log.error(`[${this.sensorConfig.accessoryName}] Unkown or invalid IP protocol version: ${ipProtocolVersion}`);
return;
}
this.log.debug(`[${this.sensorConfig.accessoryName}] Protocol: ${ping.NetworkProtocol[protocol]}`);
const pingTimeoutMillis = 10 * 1000; // trigger.pingTimeout: 10 seconds
const intervalBetweenPingsMillis = 60 * 1000; // trigger.intervalBetweenPings: 60 seconds
setInterval(this.ping, intervalBetweenPingsMillis, this, triggerConfig, protocol, pingTimeoutMillis);
}
/**
* Private methods
*/
async ping(trigger, triggerConfig, protocol, pingTimeoutMillis) {
// If protocol === None, do a DNS lookup
// const host = await getIP(hostname: string);
// protocol = ping.NetworkProtocol.IPv4;
// Create a helper class for protocol, so the value can be updated
const options = {
networkProtocol: protocol,
packetSize: 16,
retries: 3,
sessionId: (process.pid % 65535),
timeout: pingTimeoutMillis,
ttl: 128,
};
const sensorConfig = trigger.sensor.accessoryConfiguration;
const session = ping.createSession(options);
session.pingHost(triggerConfig.host, (error, target, sent, rcvd) => {
const millis = rcvd - sent;
if (error) {
trigger.log.error(`[${sensorConfig.accessoryName}] Ping ${target}: ${error.toString()}`);
if (trigger.failureCount.value < Number.MAX_VALUE) {
trigger.failureCount.value++;
}
trigger.log.info(`[${sensorConfig.accessoryName}] Failure count: ${trigger.failureCount.value}`);
if (trigger.failureCount.value === triggerConfig.failureRetryCount) {
trigger.log.debug(`[${sensorConfig.accessoryName}] Reached failure retry count of ${triggerConfig.failureRetryCount}. Triggering sensor`);
trigger.sensor.triggerSensorState(Sensor.TRIGGERED, trigger);
}
}
else {
trigger.log.debug(`[${sensorConfig.accessoryName}] Ping ${target}: Alive (latency: ${millis}ms)`);
trigger.failureCount.value = 0;
trigger.sensor.triggerSensorState(Sensor.NORMAL, trigger);
}
session.close();
});
}
async getIP(hostname) {
const response = await dns.promises.lookup(hostname)
.then((result) => {
this.sensor.platform.log.info(`[${this.sensorConfig.accessoryName}] IP address retrieved for '${hostname}' is '${result.address}'`);
return result.address;
})
.catch((error) => {
this.sensor.platform.log.error(`[${this.sensorConfig.accessoryName}] Error retrieving IP address for '${hostname}': ${error.message}`);
});
return response;
}
}
export const dynamicTrigger = PingTrigger;
//# sourceMappingURL=triggerPing.js.map