homebridge-orbit-irrigation
Version:
Orbit Irrigation System platform plugin for [Homebridge](https://github.com/nfarina/homebridge).
689 lines • 56.9 kB
JavaScript
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unused-expressions */
'use strict';
import { PLATFORM_NAME, PLUGIN_NAME } from './settings.js';
import OrbitAPI from './orbitapi.js';
import OrbitUpdate from './orbitupdate.js';
import battery from './devices/battery.js';
import bridge from './devices/bridge.js';
import irrigation from './devices/irrigation.js';
import valve from './devices/valve.js';
import sensor from './devices/sensor.js';
import basicSwitch from './devices/switch.js';
export default class OrbitPlatform {
log;
config;
api;
Service;
Characteristic;
HAPStatus;
HapStatusError;
accessories = [];
constructor(log, config, api) {
this.log = log;
this.config = config;
this.api = api;
this.Service = api.hap.Service;
this.Characteristic = api.hap.Characteristic;
this.HapStatusError = api.hap.HapStatusError;
this.platform = this;
this.genUUID = api.hap.uuid.generate;
this.log.debug('Finished initializing platform:', config.name);
this.orbitapi = new OrbitAPI(this);
this.orbit = new OrbitUpdate(this);
this.battery = new battery(this);
this.bridge = new bridge(this);
this.irrigation = new irrigation(this);
this.valve = new valve(this);
this.sensor = new sensor(this);
this.basicSwitch = new basicSwitch(this);
this.email = config.email;
this.password = config.password;
this.token;
this.retryWait = config.retryWait ? config.retryWait : 60; //sec
this.retryMax = config.retryMax ? config.retryMax : 3; //attempts
this.retryAttempt = 0;
this.userId;
this.useIrrigationDisplay = config.useIrrigationDisplay;
this.showSimpleValve = config.showSimpleValve ? config.showSimpleValve : false;
this.displayValveType = config.displayValveType ? config.displayValveType : 0;
this.defaultRuntime = config.defaultRuntime * 60;
this.runtimeSource = config.runtimeSource;
this.showStandby = config.showStandby;
this.showRunall = config.showRunall;
this.showSchedules = config.showSchedules;
this.locationAddress = config.locationAddress;
this.showIrrigation = config.showIrrigation;
this.showBridge = config.showBridge;
this.showFloodSensor = config.showFloodSensor;
this.showTempSensor = config.showTempSensor;
this.showLimitsSensor = config.showLimitsSensor;
this.showAPIMessages = config.showAPIMessages ? config.showAPIMessages : false;
this.showIncomingMessages = config.showIncomingMessages ? config.showIncomingMessages : false;
this.showOutgoingMessages = config.showOutgoingMessages ? config.showOutgoingMessages : false;
this.showExtraDebugMessages = config.showExtraDebugMessages ? config.showExtraDebugMessages : false;
this.lowBattery = config.lowBattery ? config.lowBattery : 20;
this.lastMessage = {};
this.secondLastMessage = {};
this.endTime = [];
this.activeZone = [];
this.activeProgram = false;
this.meshNetwork;
this.meshId;
this.networkTopology;
this.networkTopologyId;
this.deviceGraph;
if (!config.email || !config.password) {
this.log.error('Valid email and password are required in order to communicate with the b-hyve, please check the plugin config');
}
else {
this.log.info('Starting Orbit Platform using homebridge API', api.version);
}
//**
//** Platforms should wait until the "didFinishLaunching" event has fired before registering any new accessories.
//**
api.on('didFinishLaunching', () => {
log.debug('Executed didFinishLaunching');
// Get Orbit devices
this.getDevices();
});
}
//**
//** REQUIRED - Homebridge will call the "configureAccessory" method once for every cached accessory restored
//**
configureAccessory(accessory) {
// Added cached devices to the accessories array
this.log.debug('Found cached accessory %s', accessory.displayName);
this.accessories.push(accessory);
}
identify() {
this.log.info('Identify the sprinkler!');
}
async getDevices() {
try {
let locationMatch;
this.log.debug('Fetching Build info...');
this.log.info('Getting Account info...');
//login to API and get token
const signinResponse = await this.orbitapi.getToken(this.email, this.password).catch((err) => {
this.log.debug(`Failed to get api token ${err}`);
throw new Error('Authentication failed or invalid response from Orbit API');
});
if (signinResponse && signinResponse.user_name) {
this.log.info('Found account for', signinResponse.user_name);
//this.log.debug('Found api key',signinResponse.orbit_api_key)
this.log.debug('Found api key %s********************%s', signinResponse.orbit_api_key.substring(0, 35), signinResponse.orbit_api_key.substring(signinResponse.orbit_api_key.length - 35));
this.token = signinResponse.orbit_api_key;
this.userId = signinResponse.user_id;
}
else {
throw new Error('Authentication failed or invalid response from Orbit API');
}
//connect WebSocket
this.log.debug('Establish WebSocket connection');
this.orbitapi.openConnection(this.token, null);
this.irrigation.localMessage(this.orbit.updateService.bind(this));
this.valve.localMessage(this.orbit.updateService.bind(this));
//get device graph
this.deviceGraph = await this.orbitapi.getDeviceGraph(this.token, this.userId).catch((err) => {
throw new Error(`Failed to get graph info ${err}`);
});
this.deviceGraph.devices = this.deviceGraph.devices.sort((a, b) => {
// read bridge info first
return a.type > b.type ? 1 : a.type < b.type ? -1 : 0;
});
this.log.debug('Found device graph for user id %s, %s', this.userId, this.deviceGraph);
this.deviceGraph.devices
.filter((device) => {
if (device.address == undefined) {
device.address = {
line_1: 'undefined location',
line_2: '',
city: '',
state: '',
country: '',
};
this.log.debug('No location address defined, adding dummy location %s', device.address);
}
if (!this.locationAddress || this.locationAddress == device.address.line_1) {
if (device.is_connected) {
this.log.info('Online device %s %s found at the configured location address: %s', device.hardware_version, device.name, device.address.line_1);
if (device.network_topology_id) {
this.networkTopologyId = device.network_topology_id;
this.networkTopology = this.orbitapi.getNetworkTopologies(this.token, device.network_topology_id).catch((err) => {
this.log.error('Failed to get network topology %s', err);
});
}
if (device.mesh_id) {
this.meshId = device.mesh_id;
this.meshNetwork = this.orbitapi.getMeshes(this.token, device.mesh_id).catch((err) => {
this.log.error('Failed to get network mesh %s', err);
});
}
}
else {
this.log.info('Offline device %s %s found at the configured location address: %s', device.hardware_version, device.name, device.address.line_1);
this.log.warn('%s is disconnected! This will show as non-responding in Homekit until the connection is restored.', device.name);
}
locationMatch = true;
}
else if (device.address.line_1 == 'undefined location' && (this.networkTopologyId == device.network_topology_id || this.meshId == device.mesh_id)) {
if (device.is_connected) {
this.log.info('Online device %s %s found for the location: %s', device.hardware_version, device.name, device.location_name);
}
else {
this.log.info('Offline device %s %s found for the location: %s', device.hardware_version, device.name, device.location_name);
this.log.warn('%s is disconnected! This will show as non-responding in Homekit until the connection is restored.', device.name);
}
locationMatch = true;
}
else {
this.log.info('Skipping device %s %s at %s, not found at the configured location address: %s', device.hardware_version, device.name, device.address.line_1, this.locationAddress);
locationMatch = false;
}
return locationMatch;
}).forEach(async (device) => {
// adding devices that met filter criteria
try {
const newDevice = await this.orbitapi.getDevice(this.token, device.id).catch((err) => {
throw (`Failed to get devices info ${err}`);
});
const uuid = this.genUUID(newDevice.id);
const index = this.accessories.findIndex(accessory => accessory.UUID === uuid);
switch (newDevice.type) {
//Handle Water accessories
case 'sprinkler_timer':
if (!this.showIrrigation) {
this.log.info('Skipping Irrigation System %s %s based on config', newDevice.hardware_version, newDevice.name);
if (this.accessories[index]) {
this.log.debug('Removed cached device', device.id);
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [this.accessories[index]]);
this.accessories.splice(index, 1);
}
return;
}
this.log.debug('Adding Sprinkler Timer Device');
if (newDevice.status.run_mode) {
this.log.debug('Found device %s with status %s', newDevice.name, newDevice.status.run_mode);
}
else {
this.log.warn('Found device %s with an unknown status %s, please check connection status', newDevice.name); ////error maybe
}
//this.log.warn(newDevice.hardware_version)
// ***** Create and configure Valve Service ***** //
if (this.showSimpleValve && newDevice.hardware_version.includes('HT25')) {
this.log.debug('Creating and configuring new device');
if (this.accessories[index]) {
// Check if accessory changed
if (this.accessories[index].getService(this.Service.AccessoryInformation).getCharacteristic(this.Characteristic.ProductData).value != 'Valve') {
this.log.warn('Changing from Irrigation to Valve, check room assignments in Homekit');
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [this.accessories[index]]);
this.accessories.splice(index, 1);
}
}
const valveAccessory = this.valve.createValveAccessory(newDevice, newDevice.zones[0], uuid, this.accessories[index]);
const valveService = valveAccessory.getService(this.Service.Valve);
this.valve.updateValveService(newDevice, newDevice.zones[0], valveService);
this.valve.configureValveService(newDevice, valveService);
// set current device status
valveService.getCharacteristic(this.Characteristic.StatusFault).updateValue(!newDevice.is_connected);
// Register platform accessory
if (!this.accessories[index]) {
this.log.debug('Registering platform accessory');
this.log.info('Adding new accessory %s', valveAccessory.displayName);
this.accessories.push(valveAccessory);
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [valveAccessory]);
}
// Create and configure Battery Service if needed
if (newDevice.battery != null) {
this.log.info('Adding Battery status for %s', newDevice.name);
let batteryStatus = valveAccessory.getService(this.Service.Battery);
if (batteryStatus) {
//update
batteryStatus
.setCharacteristic(this.Characteristic.ChargingState, this.Characteristic.ChargingState.NOT_CHARGEABLE)
.setCharacteristic(this.Characteristic.StatusLowBattery, this.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL)
.setCharacteristic(this.Characteristic.BatteryLevel, newDevice.battery.percent);
}
else {
//add new
batteryStatus = this.battery.createBatteryService(newDevice);
this.battery.configureBatteryService(batteryStatus);
valveAccessory.addService(batteryStatus);
this.api.updatePlatformAccessories([valveAccessory]);
}
batteryStatus = valveAccessory.getService(this.Service.Battery);
valveAccessory.getService(this.Service.Valve).addLinkedService(batteryStatus);
}
else {
//remove
this.log.debug('%s has no battery found, skipping add battery service', newDevice.name);
const batteryStatus = valveAccessory.getService(this.Service.Battery);
if (batteryStatus) {
valveAccessory.removeService(batteryStatus);
this.api.updatePlatformAccessories([valveAccessory]);
}
}
if (this.showSchedules) {
let scheduleResponse = await this.orbitapi.getTimerPrograms(this.token, newDevice).catch((err) => {
//this.log.error('Failed to get schedules for device', err)
throw (`Failed to get schedules for device ${err}`);
});
scheduleResponse = scheduleResponse.sort((a, b) => {
//return a.program - b.program
return a.program > b.program ? 1 : a.program < b.program ? -1 : 0;
});
scheduleResponse.forEach((schedule) => {
if (schedule.enabled) {
this.log.debug('adding schedules %s program %s', schedule.name, schedule.program);
let switchService = valveAccessory.getServiceById(this.Service.Switch, this.genUUID(schedule.device_id + schedule.program));
if (switchService) {
//update
switchService
.setCharacteristic(this.Characteristic.On, false)
.setCharacteristic(this.Characteristic.Name, device.name + ' ' + schedule.name)
.setCharacteristic(this.Characteristic.ConfiguredName, schedule.name + ' ' + device.name)
.setCharacteristic(this.Characteristic.SerialNumber, schedule.id)
.setCharacteristic(this.Characteristic.StatusFault, !device.is_connected);
this.basicSwitch.configureSwitchService(newDevice, switchService);
this.api.updatePlatformAccessories([valveAccessory]);
}
else {
//add new
switchService = this.basicSwitch.createScheduleSwitchService(newDevice, schedule);
this.basicSwitch.configureSwitchService(newDevice, switchService);
valveAccessory.addService(switchService, uuid);
this.api.updatePlatformAccessories([valveAccessory]);
}
valveAccessory.getService(this.Service.Valve).addLinkedService(switchService);
this.api.updatePlatformAccessories([valveAccessory]);
}
else {
//skip
this.log.warn('Skipping switch for disabled program %s %s', schedule.program, schedule.name);
const switchService = valveAccessory.getServiceById(this.Service.Switch, schedule.program);
if (switchService) {
valveAccessory.removeService(switchService);
this.api.updatePlatformAccessories([valveAccessory]);
}
}
});
}
else {
//remove
const scheduleResponse = await this.orbitapi.getTimerPrograms(this.token, newDevice).catch((err) => {
//this.log.error('Failed to get schedules for device', err)
throw (`Failed to get schedules for device ${err}`);
});
scheduleResponse.forEach((schedule) => {
this.log.debug('removed schedule switch');
const switchService = valveAccessory.getServiceById(this.Service.Switch, this.genUUID(schedule.device_id + schedule.program));
if (switchService) {
valveAccessory.removeService(switchService);
this.api.updatePlatformAccessories([valveAccessory]);
}
});
}
if (this.showStandby) {
const switchType = 'Standby';
this.log.debug('adding new standby switch');
const uuid = this.genUUID(newDevice.id + switchType);
let switchService = valveAccessory.getServiceById(this.Service.Switch, uuid);
if (switchService) {
//update
switchService
.setCharacteristic(this.Characteristic.Name, newDevice.name + ' ' + switchType)
.setCharacteristic(this.Characteristic.ConfiguredName, switchType + ' ' + newDevice.name)
.setCharacteristic(this.Characteristic.StatusFault, !newDevice.is_connected);
this.basicSwitch.configureSwitchService(newDevice, switchService);
this.api.updatePlatformAccessories([valveAccessory]);
}
else {
//add new
switchService = this.basicSwitch.createSwitchService(newDevice, switchType);
this.basicSwitch.configureSwitchService(newDevice, switchService);
valveAccessory.addService(switchService, uuid);
this.api.updatePlatformAccessories([valveAccessory]);
}
valveAccessory.getService(this.Service.Valve).addLinkedService(switchService);
this.api.updatePlatformAccessories([valveAccessory]);
}
else {
//remove
this.log.debug('removed standby switch');
const switchService = valveAccessory.getService(this.Service.Switch);
if (switchService) {
valveAccessory.removeService(switchService);
this.api.updatePlatformAccessories([valveAccessory]);
}
}
}
else {
// ***** Create and configure Irrigation Service ***** //
this.log.debug('Creating and configuring new device');
if (this.accessories[index]) {
// Check if accessory changed
if (this.accessories[index].getService(this.Service.AccessoryInformation).getCharacteristic(this.Characteristic.ProductData).value != 'Irrigation') {
this.log.warn('Changing from Valve to Irrigation, check room assignments in Homekit');
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [this.accessories[index]]);
this.accessories.splice(index, 1);
}
}
const irrigationAccessory = this.irrigation.createIrrigationAccessory(newDevice, uuid, this.accessories[index]);
const irrigationSystemService = irrigationAccessory.getService(this.Service.IrrigationSystem);
this.irrigation.configureIrrigationService(newDevice, irrigationSystemService);
// set current device status
irrigationSystemService.getCharacteristic(this.Characteristic.StatusFault).updateValue(!newDevice.is_connected);
// Register platform accessory
if (!this.accessories[index]) {
this.log.debug('Registering platform accessory');
this.log.info('New accessory %s', irrigationAccessory.displayName);
this.accessories.push(irrigationAccessory);
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [irrigationAccessory]);
}
// Create and configure Battery Service if needed
if (newDevice.battery != null) {
this.log.info('Adding Battery status for %s', newDevice.name);
let batteryStatus = irrigationAccessory.getService(this.Service.Battery);
if (batteryStatus) {
//update
batteryStatus
.setCharacteristic(this.Characteristic.ChargingState, this.Characteristic.ChargingState.NOT_CHARGEABLE)
.setCharacteristic(this.Characteristic.StatusLowBattery, this.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL)
.setCharacteristic(this.Characteristic.BatteryLevel, newDevice.battery.percent);
}
else {
//add new
batteryStatus = this.battery.createBatteryService(newDevice);
this.battery.configureBatteryService(batteryStatus);
irrigationAccessory.addService(batteryStatus);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
batteryStatus = irrigationAccessory.getService(this.Service.Battery);
irrigationAccessory.getService(this.Service.IrrigationSystem).addLinkedService(batteryStatus);
}
else {
//remove
this.log.debug('%s has no battery found, skipping add battery service', newDevice.name);
const batteryStatus = irrigationAccessory.getService(this.Service.Battery);
if (batteryStatus) {
irrigationAccessory.removeService(batteryStatus);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
}
// Create and configure Values services and link to Irrigation Service
newDevice.zones = newDevice.zones.sort((a, b) => {
return a.station - b.station;
});
newDevice.zones.forEach((zone) => {
zone.enabled = true; // need orbit version of enabled
if (!this.useIrrigationDisplay && !zone.enabled) {
this.log.info('Skipping disabled zone %s', zone.name);
}
else {
this.log.debug('adding zone %s', zone.name);
let valveService = irrigationAccessory.getServiceById(this.Service.Valve, zone.station);
if (valveService) {
valveService
.setCharacteristic(this.Characteristic.ValveType, this.useIrrigationDisplay ? 1 : this.displayValveType)
.setCharacteristic(this.Characteristic.RemainingDuration, 0)
.setCharacteristic(this.Characteristic.ServiceLabelIndex, zone.station)
.setCharacteristic(this.Characteristic.StatusFault, !device.is_connected)
.setCharacteristic(this.Characteristic.SerialNumber, this.genUUID('zone-' + zone.station))
.setCharacteristic(this.Characteristic.Name, zone.name)
.setCharacteristic(this.Characteristic.ConfiguredName, zone.name)
.setCharacteristic(this.Characteristic.Model, zone.sprinkler_type);
if (zone.enabled) {
valveService.setCharacteristic(this.Characteristic.IsConfigured, this.Characteristic.IsConfigured.CONFIGURED);
}
else {
valveService.setCharacteristic(this.Characteristic.IsConfigured, this.Characteristic.IsConfigured.NOT_CONFIGURED);
}
this.irrigation.configureValveService(newDevice, valveService);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
else {
// add new
valveService = this.irrigation.createValveService(newDevice, zone);
this.irrigation.configureValveService(newDevice, valveService);
irrigationAccessory.addService(valveService);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
if (this.useIrrigationDisplay) {
this.log.debug('Using Irrigation system');
irrigationAccessory.getService(this.Service.IrrigationSystem).addLinkedService(valveService);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
else {
this.log.debug('Using separate tiles');
}
}
});
if (this.showSchedules) {
let scheduleResponse = await this.orbitapi.getTimerPrograms(this.token, newDevice).catch((err) => {
//this.log.error('Failed to get schedules for device', err)
throw (`Failed to get schedules for device ${err}`);
});
scheduleResponse = scheduleResponse.sort((a, b) => {
//return a.program - b.program
return a.program > b.program ? 1 : a.program < b.program ? -1 : 0;
});
scheduleResponse.forEach((schedule) => {
if (schedule.enabled) {
this.log.debug('adding schedules %s program %s', schedule.name, schedule.program);
let switchService = irrigationAccessory.getServiceById(this.Service.Switch, this.genUUID(schedule.device_id + schedule.program));
if (switchService) {
//update
switchService
.setCharacteristic(this.Characteristic.On, false)
.setCharacteristic(this.Characteristic.Name, device.name + ' ' + schedule.name)
.setCharacteristic(this.Characteristic.ConfiguredName, schedule.name + ' ' + device.name)
.setCharacteristic(this.Characteristic.SerialNumber, schedule.id)
.setCharacteristic(this.Characteristic.StatusFault, !device.is_connected);
this.basicSwitch.configureSwitchService(newDevice, switchService);
irrigationAccessory.getService(this.Service.IrrigationSystem).addLinkedService(switchService);
}
else {
//add new
switchService = this.basicSwitch.createScheduleSwitchService(newDevice, schedule);
this.basicSwitch.configureSwitchService(newDevice, switchService);
irrigationAccessory.addService(switchService, uuid);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
irrigationAccessory.getService(this.Service.IrrigationSystem).addLinkedService(switchService);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
else {
//skip
this.log.warn('Skipping switch for disabled program %s %s', schedule.program, schedule.name);
const switchService = irrigationAccessory.getServiceById(this.Service.Switch, schedule.program);
if (switchService) {
irrigationAccessory.removeService(switchService);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
}
});
}
else {
//remove
const scheduleResponse = await this.orbitapi.getTimerPrograms(this.token, newDevice).catch((err) => {
//this.log.error('Failed to get schedules for device', err)
throw (`Failed to get schedules for device ${err}`);
});
scheduleResponse.forEach((schedule) => {
this.log.debug('removed schedule switch');
const switchService = irrigationAccessory.getServiceById(this.Service.Switch, this.genUUID(schedule.device_id + schedule.program));
if (switchService) {
irrigationAccessory.removeService(switchService);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
});
}
if (this.showRunall) {
const switchType = 'Run All';
this.log.debug('adding new run all switch');
const uuid = this.genUUID(newDevice.id + switchType);
let switchService = irrigationAccessory.getServiceById(this.Service.Switch, uuid);
if (switchService) {
//update
switchService
.setCharacteristic(this.Characteristic.Name, newDevice.name + ' ' + switchType)
.setCharacteristic(this.Characteristic.ConfiguredName, switchType + ' ' + newDevice.name)
.setCharacteristic(this.Characteristic.StatusFault, !newDevice.is_connected);
this.basicSwitch.configureSwitchService(newDevice, switchService);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
else {
//add new
switchService = this.basicSwitch.createSwitchService(newDevice, switchType);
this.basicSwitch.configureSwitchService(newDevice, switchService);
irrigationAccessory.addService(switchService, uuid);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
irrigationAccessory.getService(this.Service.IrrigationSystem).addLinkedService(switchService);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
else {
//remove
const switchType = 'Run All';
this.log.debug('removed run all switch');
const uuid = this.genUUID(newDevice.id + switchType);
const switchService = irrigationAccessory.getServiceById(this.Service.Switch, uuid);
if (switchService) {
irrigationAccessory.removeService(switchService);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
}
if (this.showStandby) {
const switchType = 'Standby';
this.log.debug('adding new standby switch');
const uuid = this.genUUID(newDevice.id + switchType);
let switchService = irrigationAccessory.getServiceById(this.Service.Switch, uuid);
if (switchService) {
//update
switchService
.setCharacteristic(this.Characteristic.Name, newDevice.name + ' ' + switchType)
.setCharacteristic(this.Characteristic.ConfiguredName, switchType + ' ' + newDevice.name)
.setCharacteristic(this.Characteristic.StatusFault, !newDevice.is_connected);
this.basicSwitch.configureSwitchService(newDevice, switchService);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
else {
//add new
switchService = this.basicSwitch.createSwitchService(newDevice, switchType);
this.basicSwitch.configureSwitchService(newDevice, switchService);
irrigationAccessory.addService(switchService, uuid);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
irrigationAccessory.getService(this.Service.IrrigationSystem).addLinkedService(switchService);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
else {
//remove
const switchType = 'Standby';
this.log.debug('removed standby switch');
const uuid = this.genUUID(newDevice.id + switchType);
const switchService = irrigationAccessory.getServiceById(this.Service.Switch, uuid);
if (switchService) {
irrigationAccessory.removeService(switchService);
this.api.updatePlatformAccessories([irrigationAccessory]);
}
}
}
break;
// Handle Bridge accessories
case 'bridge': {
if (!this.showBridge) {
this.log.info('Skipping Bridge %s %s based on config', newDevice.hardware_version, newDevice.name);
if (this.accessories[index]) {
this.log.debug('Removed cached device', device.id);
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [this.accessories[index]]);
this.accessories.splice(index, 1);
}
return;
}
this.log.debug('Adding Bridge Device');
this.log.debug('Found device %s', newDevice.name);
let bridgeAccessory;
let bridgeService;
switch (newDevice.hardware_version.split('-')[0]) {
case 'BH1': {
// Create and configure Gen 1Bridge Service
const meshNetwork = await this.orbitapi.getMeshes(this.token, newDevice.mesh_id).catch((err) => {
this.log.error('Failed to add G1 bridge %s', err);
});
this.log.debug('Creating and configuring new bridge');
bridgeAccessory = this.bridge.createBridgeAccessory(newDevice, uuid, this.accessories[index]);
bridgeService = bridgeAccessory.getService(this.Service.WiFiTransport);
// Set current device status
if (!bridgeService) {
bridgeService = this.bridge.createBridgeService(newDevice, meshNetwork, false);
bridgeAccessory.addService(bridgeService);
}
this.log.info('Adding Gen-1 Bridge');
this.bridge.configureBridgeService(bridgeService);
bridgeService.getCharacteristic(this.Characteristic.StatusFault).updateValue(!newDevice.is_connected);
break;
}
case 'BH1G2': {
// Create and configure Gen2 Bridge Service
const networkTopology = await this.orbitapi.getNetworkTopologies(this.token, newDevice.network_topology_id).catch((err) => {
this.log.error('Failed to add G2 bridge %s', err);
});
this.log.debug('Creating and configuring new bridge');
bridgeAccessory = this.bridge.createBridgeAccessory(newDevice, uuid, this.accessories[index]);
bridgeService = bridgeAccessory.getService(this.Service.WiFiTransport);
// Set current device status
if (!bridgeService) {
bridgeService = this.bridge.createBridgeService(newDevice, networkTopology, true);
bridgeAccessory.addService(bridgeService);
}
this.log.info('Adding Gen-2 Bridge');
this.bridge.configureBridgeService(bridgeService);
bridgeService.getCharacteristic(this.Characteristic.StatusFault).updateValue(!newDevice.is_connected);
break;
}
default:
this.log.warn('Wifi Hub hardware %s, not supported', newDevice.hardware_version);
return;
}
if (!this.accessories[index]) {
this.log.debug('Registering platform accessory');
this.accessories.push(bridgeAccessory);
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [bridgeAccessory]);
}
break;
}
// Handle Flood sensor accessories
case 'flood_sensor': {
if (!this.showFloodSensor && !this.showTempSensor && !this.showLimitsSensor) {
this.log.info('Skipping Flood Sensor %s %s based on config', newDevice.hardware_version, newDevice.name);
if (this.accessories[index]) {
this.log.debug('Removed cached device', device.id);
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [this.accessories[index]]);
this.accessories.splice(index, 1);
}
return;
}
this.log.debug('Found device %s', newDevice.name);
let floodAccessory;
let batteryStatus;
if (this.showFloodSensor || this.showTempSensor || this.showLimitsSensor) {
floodAccessory = this.sensor.createFloodAccessory(newDevice, uuid, this.accessories[index]);
if (!this.accessories[index]) {
this.log.debug('Adding Flood Sensor Device');
this.log.debug('Registering platform accessory');
this.accessories.push(floodAccessory);
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [floodAccessory]);
}
this.log.info('Adding Battery status for %s %s', newDevice.location_name, newDevice.name);
batteryStatus = this.sensor.createBatteryService(newDevice, floodAccessory);
this.sensor.configureBatteryService(batteryStatus);
const service = floodAccessory.getService(this.Service.Battery);
if (!service) {
floodAccessory.addService(batteryStatus);
this.api.updatePlatformAccessories([floodAccessory]);
}
}
else {
if (this.accessori