homebridge-enphase-envoy
Version:
Homebridge plugin for Photovoltaic Energy System manufactured by Enphase.
966 lines (880 loc) • 449 kB
JavaScript
import { promises as fsPromises } from 'fs';
import axios from 'axios';
import { Agent } from 'https';
import { XMLParser, XMLBuilder, XMLValidator } from 'fast-xml-parser';
import EventEmitter from 'events';
import RestFul from './restful.js';
import Mqtt from './mqtt.js';
import EnvoyToken from './envoytoken.js';
import DigestAuth from './digestauth.js';
import PasswdCalc from './passwdcalc.js';
import ImpulseGenerator from './impulsegenerator.js';
import { ApiUrls, PartNumbers, Authorization, ApiCodes, LedStatus } from './constants.js';
let Accessory, Characteristic, Service, Categories, AccessoryUUID;
class EnvoyDevice extends EventEmitter {
constructor(api, deviceName, host, displayType, envoyFirmware7xxTokenGenerationMode, envoyPasswd, envoyToken, envoyTokenInstaller, enlightenUser, enlightenPasswd, envoyIdFile, envoyTokenFile, device) {
super();
Accessory = api.platformAccessory;
Characteristic = api.hap.Characteristic;
Service = api.hap.Service;
Categories = api.hap.Categories;
AccessoryUUID = api.hap.uuid;
//device configuration
this.name = deviceName;
this.host = host;
this.displayType = displayType;
this.envoyFirmware7xxTokenGenerationMode = envoyFirmware7xxTokenGenerationMode;
this.envoyPasswd = envoyPasswd;
this.enlightenUser = enlightenUser;
this.enlightenPassword = enlightenPasswd;
this.envoyToken = envoyToken;
this.envoyTokenInstaller = envoyTokenInstaller;
this.productionStateControl = device.productionStateControl || {};
this.productionStateSensor = device.productionStateSensor || {};
this.plcLevelControl = device.plcLevelControl || {};
this.powerProductionSummary = device.powerProductionSummary || 1;
this.powerProductionStateSensor = device.powerProductionStateSensor || {};
this.powerProductionLevelSensors = device.powerProductionLevelSensors || [];
this.energyProductionStateSensor = device.energyProductionStateSensor || {};
this.energyProductionLevelSensors = device.energyProductionLevelSensors || [];
this.energyProductionLifetimeOffset = device.energyProductionLifetimeOffset || 0;
this.powerConsumptionTotalStateSensor = device.powerConsumptionTotalStateSensor || {};
this.powerConsumptionTotalLevelSensors = device.powerConsumptionTotalLevelSensors || [];
this.energyConsumptionTotalStateSensor = device.energyConsumptionTotalStateSensor || {};
this.energyConsumptionTotalLevelSensors = device.energyConsumptionTotalLevelSensors || [];
this.energyConsumptionTotalLifetimeOffset = device.energyConsumptionTotalLifetimeOffset || 0;
this.powerConsumptionNetStateSensor = device.powerConsumptionNetStateSensor || {};
this.powerConsumptionNetLevelSensors = device.powerConsumptionNetLevelSensors || [];
this.energyConsumptionNetStateSensor = device.energyConsumptionNetStateSensor || {};
this.energyConsumptionNetLevelSensors = device.energyConsumptionNetLevelSensors || [];
this.energyConsumptionNetLifetimeOffset = device.energyConsumptionNetLifetimeOffset || 0;
//qRelay
this.qRelayStateSensor = device.qRelayStateSensor || {};
//ac battery
this.acBatterieName = device.acBatterieName || 'AC Batterie';
this.acBatterieBackupLevelSummaryAccessory = device.acBatterieBackupLevelSummaryAccessory || {};
this.acBatterieBackupLevelAccessory = device.acBatterieBackupLevelAccessory || {};
//enpower
this.enpowerDryContactsControl = envoyFirmware7xxTokenGenerationMode > 0 ? device.enpowerDryContactsControl || false : false;
this.enpowerDryContactsSensor = envoyFirmware7xxTokenGenerationMode > 0 ? device.enpowerDryContactsSensor || false : false;
this.enpowerGridStateControl = envoyFirmware7xxTokenGenerationMode > 0 ? device.enpowerGridStateControl || {} : {};
this.enpowerGridStateSensor = envoyFirmware7xxTokenGenerationMode > 0 ? device.enpowerGridStateSensor || {} : {};
this.enpowerGridModeSensors = envoyFirmware7xxTokenGenerationMode > 0 ? device.enpowerGridModeSensors || [] : [];
//encharge
this.enchargeName = device.enchargeName || 'Encharge';
this.enchargeBackupLevelSummaryAccessory = envoyFirmware7xxTokenGenerationMode > 0 ? device.enchargeBackupLevelSummaryAccessory || {} : {};
this.enchargeBackupLevelAccessory = envoyFirmware7xxTokenGenerationMode > 0 ? device.enchargeBackupLevelAccessory || {} : {};
this.enchargeStateSensor = envoyFirmware7xxTokenGenerationMode > 0 ? device.enchargeStateSensor || {} : {};
this.enchargeProfileControls = envoyFirmware7xxTokenGenerationMode > 0 ? device.enchargeProfileControls || [] : [];
this.enchargeProfileSensors = envoyFirmware7xxTokenGenerationMode > 0 ? device.enchargeProfileSensors || [] : [];
this.enchargeGridStateSensor = envoyFirmware7xxTokenGenerationMode > 0 ? device.enchargeGridStateSensor || {} : {};
this.enchargeGridModeSensors = envoyFirmware7xxTokenGenerationMode > 0 ? device.enchargeGridModeSensors || [] : [];
this.enchargeBackupLevelSensors = envoyFirmware7xxTokenGenerationMode > 0 ? device.enchargeBackupLevelSensors || [] : [];
//solar
this.solarGridStateSensor = envoyFirmware7xxTokenGenerationMode > 0 ? device.solarGridStateSensor || {} : {};
this.solarGridModeSensors = envoyFirmware7xxTokenGenerationMode > 0 ? device.solarGridModeSensors || [] : [];
//generator
this.generatorStateControl = envoyFirmware7xxTokenGenerationMode > 0 ? device.generatorStateControl || {} : {};
this.generatorStateSensor = envoyFirmware7xxTokenGenerationMode > 0 ? device.generatorStateSensor || {} : {};
this.generatorModeContols = envoyFirmware7xxTokenGenerationMode > 0 ? device.generatorModeControls || [] : [];
this.generatorModeSensors = envoyFirmware7xxTokenGenerationMode > 0 ? device.generatorModeSensors || [] : [];
//data refresh
this.dataRefreshControl = device.dataRefreshControl || {};
this.dataRefreshSensor = device.dataRefreshSensor || {};
this.metersDataRefreshTime = device.metersDataRefreshTime * 1000 || 5000;
this.productionDataRefreshTime = device.productionDataRefreshTime * 1000 || 10000;
this.liveDataRefreshTime = device.liveDataRefreshTime * 1000 || 3000;
this.ensembleDataRefreshTime = device.ensembleDataRefreshTime * 1000 || 15000;
//log
this.enableDebugMode = device.enableDebugMode || false;
this.disableLogInfo = device.disableLogInfo || false;
this.disableLogDeviceInfo = device.disableLogDeviceInfo || false;
//external integrations
this.restFul = device.restFul ?? {};
this.restFulConnected = false;
this.mqtt = device.mqtt ?? {};
this.mqttConnected = false;
//system
const systemAccessoryDisplayType = this.displayType ?? 0;
if (systemAccessoryDisplayType > 0) {
const tile = {};
tile.serviceType = ['', Service.Lightbulb, Service.Fan, Service.HumiditySensor, Service.CarbonMonoxideSensor][systemAccessoryDisplayType];
tile.characteristicType = ['', Characteristic.On, Characteristic.On, Characteristic.StatusActive, Characteristic.CarbonMonoxideDetected][systemAccessoryDisplayType];
tile.characteristicType1 = ['', Characteristic.Brightness, Characteristic.RotationSpeed, Characteristic.CurrentRelativeHumidity, Characteristic.CarbonMonoxideLevel][systemAccessoryDisplayType];
tile.state = false;
tile.level = 0;
this.systemAccessoryActive = tile;
};
//production state control
const productionStateControlDisplayType = this.productionStateControl.displayType ?? 0;
if (productionStateControlDisplayType > 0) {
const tile = {};
tile.name = this.productionStateControl.name || 'Production State Control';
tile.serviceType = ['', Service.Switch, Service.Outlet, Service.Lightbulb][productionStateControlDisplayType];
tile.characteristicType = ['', Characteristic.On, Characteristic.On, Characteristic.On][productionStateControlDisplayType];
tile.state = false;
this.productionStateActiveControl = tile;
};
//production state sensor
const productionStateSensorDisplayType = this.productionStateSensor.displayType ?? 0;
if (productionStateSensorDisplayType > 0) {
const sensor = {};
sensor.name = this.productionStateSensor.name || 'Production State Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][productionStateSensorDisplayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][productionStateSensorDisplayType];
sensor.state = false;
this.productionStateActiveSensor = sensor;
};
//plc level control
const plcLevelControlDisplayType = this.plcLevelControl.displayType ?? 0;
if (plcLevelControlDisplayType > 0) {
const tile = {};
tile.name = this.plcLevelControl.name || 'PLC Level Refresh Control';
tile.serviceType = ['', Service.Switch, Service.Outlet, Service.Lightbulb][plcLevelControlDisplayType];
tile.characteristicType = ['', Characteristic.On, Characteristic.On, Characteristic.On][plcLevelControlDisplayType];
tile.state = false;
this.plcLevelActiveControl = tile;
}
//data refresh control
const dataRefreshControlDisplayType = this.dataRefreshControl.displayType ?? 0;
if (dataRefreshControlDisplayType > 0) {
const tile = {};
tile.name = this.dataRefreshControl.name || 'Data Refresh Control';
tile.serviceType = ['', Service.Switch, Service.Outlet, Service.Lightbulb][dataRefreshControlDisplayType];
tile.characteristicType = ['', Characteristic.On, Characteristic.On, Characteristic.On][dataRefreshControlDisplayType];
tile.state = false;
this.dataRefreshActiveControl = tile;
};
//data refresh sensor
const dataRefreshSensorDisplayType = this.dataRefreshSensor.displayType ?? 0;
if (dataRefreshSensorDisplayType > 0) {
const sensor = {};
sensor.name = this.dataRefreshSensor.name || 'Data Refresh Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][dataRefreshSensorDisplayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][dataRefreshSensorDisplayType];
sensor.state = false;
this.dataRefreshActiveSensor = sensor;
};
//power production level sensors
this.powerProductionLevelActiveSensors = [];
for (const sensor of this.powerProductionLevelSensors) {
const displayType = sensor.displayType ?? 0;
if (displayType === 0) {
continue;
};
sensor.name = sensor.name || 'Power Production Level Sensor';
sensor.compareMode = sensor.compareMode ?? 0;
sensor.powerLevel = sensor.powerLevel ?? 0;
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][displayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][displayType];
sensor.state = false;
this.powerProductionLevelActiveSensors.push(sensor);
}
this.powerProductionLevelActiveSensorsCount = this.powerProductionLevelActiveSensors.length || 0;
//power production state sensor
const powerProductionStateSensorDisplayType = this.powerProductionStateSensor.displayType ?? 0;
if (powerProductionStateSensorDisplayType > 0) {
const sensor = {};
sensor.name = this.powerProductionStateSensor.name || 'Power Production State Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][powerProductionStateSensorDisplayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][powerProductionStateSensorDisplayType];
sensor.state = false;
this.powerProductionStateActiveSensor = sensor;
};
//energy production state sensor
const energyProductionStateSensorDisplayType = this.energyProductionStateSensor.displayType ?? 0;
if (energyProductionStateSensorDisplayType > 0) {
const sensor = {};
sensor.name = this.energyProductionStateSensor.name || 'Energy Production State Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][energyProductionStateSensorDisplayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][energyProductionStateSensorDisplayType];
sensor.state = false;
this.energyProductionStateActiveSensor = sensor;
};
this.energyProductionLevelActiveSensors = [];
for (const sensor of this.energyProductionLevelSensors) {
const displayType = sensor.displayType ?? 0;
if (displayType === 0) {
continue;
};
sensor.name = sensor.name || 'Energy Production Levele Sensor';
sensor.compareMode = sensor.compareMode ?? 0;
sensor.energyLevel = sensor.energyLevel ?? 0;
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][displayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][displayType];
sensor.state = false;
this.energyProductionLevelActiveSensors.push(sensor);
}
this.energyProductionLevelActiveSensorsCount = this.energyProductionLevelActiveSensors.length || 0;
//power consumption total state sensor
const powerConsumptionTotalStateSensorDisplayType = this.powerConsumptionTotalStateSensor.displayType ?? 0;
if (powerConsumptionTotalStateSensorDisplayType > 0) {
const sensor = {};
sensor.name = this.powerConsumptionTotalStateSensor.name || 'Power Consumption Total State Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][powerConsumptionTotalStateSensorDisplayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][powerConsumptionTotalStateSensorDisplayType];
sensor.state = false;
this.powerConsumptionTotalStateActiveSensor = sensor;
};
this.powerConsumptionTotalLevelActiveSensors = [];
for (const sensor of this.powerConsumptionTotalLevelSensors) {
const displayType = sensor.displayType ?? 0;
if (displayType === 0) {
continue;
};
sensor.name = sensor.name || 'Power Consumption Total Level Sensor';
sensor.compareMode = sensor.compareMode ?? 0;
sensor.powerLevel = sensor.powerLevel ?? 0;
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][displayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][displayType];
sensor.state = false;
this.powerConsumptionTotalLevelActiveSensors.push(sensor);
}
this.powerConsumptionTotalLevelActiveSensorsCount = this.powerConsumptionTotalLevelActiveSensors.length || 0;
//energy consumption total state sensor
const energyConsumptionTotalStateSensorDisplayType = this.energyConsumptionTotalStateSensor.displayType ?? 0;
if (energyConsumptionTotalStateSensorDisplayType > 0) {
const sensor = {};
sensor.name = this.energyConsumptionTotalStateSensor.name || 'Energy Consumption Total State Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][energyConsumptionTotalStateSensorDisplayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][energyConsumptionTotalStateSensorDisplayType];
sensor.state = false;
this.energyConsumptionTotalStateActiveSensor = sensor;
};
this.energyConsumptionTotalLevelActiveSensors = [];
for (const sensor of this.energyConsumptionTotalLevelSensors) {
const displayType = sensor.displayType ?? 0;
if (displayType === 0) {
continue;
};
sensor.name = sensor.name || 'Energy Consumption Total Level Sensor';
sensor.compareMode = sensor.compareMode ?? 0;
sensor.energyLevel = sensor.energyLevel ?? 0;
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][displayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][displayType];
sensor.state = false;
this.energyConsumptionTotalLevelActiveSensors.push(sensor);
}
this.energyConsumptionTotalLevelActiveSensorsCount = this.energyConsumptionTotalLevelActiveSensors.length || 0;
//power consumption net state sensor
const powerConsumptionNetStateSensorDisplayType = this.powerConsumptionNetStateSensor.displayType ?? 0;
if (powerConsumptionNetStateSensorDisplayType > 0) {
const sensor = {};
sensor.name = this.powerConsumptionNetStateSensor.name || 'Power Consumption Net State Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][powerConsumptionNetStateSensorDisplayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][powerConsumptionNetStateSensorDisplayType];
sensor.state = false;
this.powerConsumptionNetStateActiveSensor = sensor;
};
this.powerConsumptionNetLevelActiveSensors = [];
for (const sensor of this.powerConsumptionNetLevelSensors) {
const displayType = sensor.displayType ?? 0;
if (displayType === 0) {
continue;
};
sensor.name = sensor.name || 'Power Consumption Net Level Sensor';
sensor.compareMode = sensor.compareMode ?? 0;
sensor.powerLevel = sensor.powerLevel ?? 0;
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][displayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][displayType];
sensor.state = false;
this.powerConsumptionNetLevelActiveSensors.push(sensor);
}
this.powerConsumptionNetLevelActiveSensorsCount = this.powerConsumptionNetLevelActiveSensors.length || 0;
//energy consumption net state sensor
const energyConsumptionNetStateSensorDisplayType = this.energyConsumptionNetStateSensor.displayType ?? 0;
if (energyConsumptionNetStateSensorDisplayType > 0) {
const sensor = {};
sensor.name = this.energyConsumptionNetStateSensor.name || 'Energy Consumption Net State Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][energyConsumptionNetStateSensorDisplayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][energyConsumptionNetStateSensorDisplayType];
sensor.state = false;
this.energyConsumptionNetStateActiveSensor = sensor;
};
this.energyConsumptionNetLevelActiveSensors = [];
for (const sensor of this.energyConsumptionNetLevelSensors) {
const displayType = sensor.displayType ?? 0;
if (displayType === 0) {
continue;
}
sensor.name = sensor.name || 'Energy Consumption Net Level Sensor';
sensor.compareMode = sensor.compareMode ?? 0;
sensor.energyLevel = sensor.energyLevel ?? 0;
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][displayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][displayType];
sensor.state = false;
this.energyConsumptionNetLevelActiveSensors.push(sensor);
}
this.energyConsumptionNetLevelActiveSensorsCount = this.energyConsumptionNetLevelActiveSensors.length || 0;
//qRelay
const qRelayStateSensorDisplayType = this.qRelayStateSensor.displayType ?? 0;
if (qRelayStateSensorDisplayType > 0) {
const sensor = {};
sensor.name = this.qRelayStateSensor.name || 'State Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][qRelayStateSensorDisplayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][qRelayStateSensorDisplayType];
sensor.state = false;
this.qRelayStateActiveSensor = sensor;
};
//ac battery
const acBatterieBackupLevelSummaryAccessoryDisplayType = this.acBatterieBackupLevelSummaryAccessory.displayType ?? 0;
if (acBatterieBackupLevelSummaryAccessoryDisplayType > 0) {
const tile = {};
tile.serviceType = ['', Service.Lightbulb, Service.Fan, Service.HumiditySensor, Service.CarbonMonoxideSensor, Service.Battery][acBatterieBackupLevelSummaryAccessoryDisplayType];
tile.characteristicType = ['', Characteristic.On, Characteristic.On, Characteristic.StatusActive, Characteristic.CarbonMonoxideDetected, Characteristic.StatusLowBattery][acBatterieBackupLevelSummaryAccessoryDisplayType];
tile.characteristicType1 = ['', Characteristic.Brightness, Characteristic.RotationSpeed, Characteristic.CurrentRelativeHumidity, Characteristic.CarbonMonoxideLevel, Characteristic.BatteryLevel][acBatterieBackupLevelSummaryAccessoryDisplayType];
tile.displayType = this.acBatterieBackupLevelSummaryAccessory.displayType;
tile.minSoc = this.acBatterieBackupLevelSummaryAccessory.minSoc ?? 0;
tile.state = false;
tile.backupLevel = 0;
this.acBatterieBackupLevelSummaryActiveAccessory = tile;
};
const acBatterieBackupLevelAccessoryDisplayType = this.acBatterieBackupLevelAccessory.displayType ?? 0;
if (acBatterieBackupLevelAccessoryDisplayType > 0) {
const tile = {};
tile.serviceType = ['', Service.Battery][acBatterieBackupLevelAccessoryDisplayType];
tile.characteristicType = ['', Characteristic.StatusLowBattery][acBatterieBackupLevelAccessoryDisplayType];
tile.characteristicType1 = ['', Characteristic.BatteryLevel][acBatterieBackupLevelAccessoryDisplayType];
tile.characteristicType2 = ['', Characteristic.ChargingState][acBatterieBackupLevelAccessoryDisplayType];
tile.displayType = this.acBatterieBackupLevelAccessory.displayType;
tile.minSoc = this.acBatterieBackupLevelAccessory.minSoc ?? 0;
this.acBatterieBackupLevelActiveAccessory = tile;
};
//enpower
const enpowerGridStateControlDisplaqyType = this.enpowerGridStateControl.displayType ?? 0;
if (enpowerGridStateControlDisplaqyType > 0) {
const tile = {};
tile.name = this.enpowerGridStateControl.name || 'Enpower Grid State Control';
tile.serviceType = ['', Service.Switch, Service.Outlet, Service.Lightbulb][enpowerGridStateControlDisplaqyType];
tile.characteristicType = ['', Characteristic.On, Characteristic.On, Characteristic.On][enpowerGridStateControlDisplaqyType];
tile.state = false;
this.enpowerGridStateActiveControl = tile;
};
const enpowerGridStateSensorDisplayType = this.enpowerGridStateSensor.displayType ?? 0;
if (enpowerGridStateSensorDisplayType > 0) {
const sensor = {};
sensor.name = this.enpowerGridStateSensor.name || 'Enpower Grid State Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][enpowerGridStateSensorDisplayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][enpowerGridStateSensorDisplayType];
sensor.state = false;
this.enpowerGridStateActiveSensor = sensor;
};
this.enpowerGridModeActiveSensors = [];
for (const sensor of this.enpowerGridModeSensors) {
const displayType = sensor.displayType ?? 0;
if (displayType === 0) {
continue;
};
sensor.name = sensor.name || 'Enpower Grid Mode Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][displayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][displayType];
sensor.state = false;
this.enpowerGridModeActiveSensors.push(sensor);
}
this.enpowerGridModeActiveSensorsCount = this.enpowerGridModeActiveSensors.length || 0;
//encharge
const enchargeBackupLevelSummaryAccessoryDisplayType = this.enchargeBackupLevelSummaryAccessory.displayType ?? 0;
if (enchargeBackupLevelSummaryAccessoryDisplayType > 0) {
const tile = {};
tile.serviceType = ['', Service.Lightbulb, Service.Fan, Service.HumiditySensor, Service.CarbonMonoxideSensor, Service.Battery][enchargeBackupLevelSummaryAccessoryDisplayType];
tile.characteristicType = ['', Characteristic.On, Characteristic.On, Characteristic.StatusActive, Characteristic.CarbonMonoxideDetected, Characteristic.StatusLowBattery][enchargeBackupLevelSummaryAccessoryDisplayType];
tile.characteristicType1 = ['', Characteristic.Brightness, Characteristic.RotationSpeed, Characteristic.CurrentRelativeHumidity, Characteristic.CarbonMonoxideLevel, Characteristic.BatteryLevel][enchargeBackupLevelSummaryAccessoryDisplayType];
tile.displayType = this.enchargeBackupLevelSummaryAccessory.displayType;
tile.minSoc = this.enchargeBackupLevelSummaryAccessory.minSoc ?? 0;
tile.state = false;
tile.backupLevel = 0;
this.enchargeBackupLevelSummaryActiveAccessory = tile;
};
const enchargeBackupLevelAccessoryDisplayType = this.enchargeBackupLevelAccessory.displayType ?? 0;
if (enchargeBackupLevelAccessoryDisplayType > 0) {
const tile = {};
tile.serviceType = ['', Service.Battery][enchargeBackupLevelAccessoryDisplayType];
tile.characteristicType1 = ['', Characteristic.StatusLowBattery][enchargeBackupLevelAccessoryDisplayType];
tile.characteristicType = ['', Characteristic.BatteryLevel][enchargeBackupLevelAccessoryDisplayType];
tile.characteristicType2 = ['', Characteristic.ChargingState][enchargeBackupLevelAccessoryDisplayType];
tile.displayType = this.enchargeBackupLevelAccessory.displayType;
tile.minSoc = this.enchargeBackupLevelAccessory.minSoc ?? 0;
this.enchargeBackupLevelActiveAccessory = tile;
};
const enchargeStateSensorDisplayType = this.enchargeStateSensor.displayType ?? 0;
if (enchargeStateSensorDisplayType > 0) {
const sensor = {};
sensor.name = this.enchargeStateSensor.name || 'State Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][enchargeStateSensorDisplayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][enchargeStateSensorDisplayType];
sensor.state = false;
this.enchargeStateActiveSensor = sensor;
};
this.enchargeProfileActiveControls = [];
for (const tile of this.enchargeProfileControls) {
const displayType = tile.displayType ?? 0;
if (displayType === 0) {
continue;
}
tile.name = tile.name || 'Echarge profile Control';
tile.serviceType = ['', Service.Lightbulb][displayType];
tile.characteristicType = ['', Characteristic.On][displayType];
tile.state = false;
tile.previousState = null;
this.enchargeProfileActiveControls.push(tile);
}
this.enchargeProfileActiveControlsCount = this.enchargeProfileActiveControls.length || 0;
this.enchargeProfileActiveSensors = [];
for (const sensor of this.enchargeProfileSensors) {
const displayType = sensor.displayType ?? 0;
if (displayType === 0) {
continue;
};
sensor.name = sensor.name || 'Profile Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][displayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][displayType];
sensor.state = false;
this.enchargeProfileActiveSensors.push(sensor);
}
this.enchargeProfileActiveSensorsCount = this.enchargeProfileActiveSensors.length || 0;
const enchargeGridStateSensorDisplayType = this.enchargeGridStateSensor.displayType ?? 0;
if (enchargeGridStateSensorDisplayType > 0) {
const sensor = {};
sensor.name = this.enchargeGridStateSensor.name || 'Grid State Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][enchargeGridStateSensorDisplayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][enchargeGridStateSensorDisplayType];
sensor.state = false;
this.enchargeGridStateActiveSensor = sensor;
};
this.enchargeGridModeActiveSensors = [];
for (const sensor of this.enchargeGridModeSensors) {
const displayType = sensor.displayType ?? 0;
if (displayType === 0) {
continue;
};
sensor.name = sensor.name || 'Grid Mode Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][displayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][displayType];
sensor.state = false;
this.enchargeGridModeActiveSensors.push(sensor);
}
this.enchargeGridModeActiveSensorsCount = this.enchargeGridModeActiveSensors.length || 0;
this.enchargeBackupLevelActiveSensors = [];
for (const sensor of this.enchargeBackupLevelSensors) {
const displayType = sensor.displayType ?? 0;
if (displayType === 0) {
continue;
}
sensor.name = sensor.name || 'Backup Level Sensor';
sensor.compareMode = sensor.compareMode ?? 0;
sensor.backupLevel = sensor.backupLevel ?? 0;
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][displayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][displayType];
sensor.state = false;
this.enchargeBackupLevelActiveSensors.push(sensor);
}
this.enchargeBackupLevelActiveSensorsCount = this.enchargeBackupLevelActiveSensors.length || 0;
//solar
const solarGridStateSensorDisplayType = this.solarGridStateSensor.displayType ?? 0;
if (solarGridStateSensorDisplayType > 0) {
const sensor = {};
sensor.name = this.solarGridStateSensor.name || 'Solar Grid State Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][solarGridStateSensorDisplayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][solarGridStateSensorDisplayType];
sensor.state = false;
this.solarGridStateActiveSensor = sensor;
};
this.solarGridModeActiveSensors = [];
for (const sensor of this.solarGridModeSensors) {
const displayType = sensor.displayType ?? 0;
if (displayType === 0) {
continue;
};
sensor.name = sensor.name || 'Solar Grid Mode Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][displayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][displayType];
sensor.state = false;
this.solarGridModeActiveSensors.push(sensor);
}
this.solarGridModeActiveSensorsCount = this.solarGridModeActiveSensors.length || 0;
//generator
const generatorStateControlDisplaqyType = this.generatorStateControl.displayType ?? 0;
if (generatorStateControlDisplaqyType > 0) {
const tile = {};
tile.name = this.generatorStateControl.name || 'Generator State Control';
tile.serviceType = ['', Service.Switch, Service.Outlet, Service.Lightbulb][generatorStateControlDisplaqyType];
tile.characteristicType = ['', Characteristic.On, Characteristic.On, Characteristic.On][generatorStateControlDisplaqyType];
tile.state = false;
this.generatorStateActiveControl = tile;
};
const generatorStateSensorDisplayType = this.generatorStateSensor.displayType ?? 0;
if (generatorStateSensorDisplayType > 0) {
const sensor = {};
sensor.name = this.generatorStateSensor.name || 'Generator State Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][generatorStateSensorDisplayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][generatorStateSensorDisplayType];
sensor.state = false;
this.generatorStateActiveSensor = sensor;
};
this.generatorModeActiveControls = [];
for (const tile of this.generatorModeContols) {
const displayType = tile.displayType ?? 0;
if (displayType === 0) {
continue;
};
tile.name = tile.name || 'Generator Mode Control';
tile.serviceType = ['', Service.Switch, Service.Outlet, Service.Lightbulb][displayType];
tile.characteristicType = ['', Characteristic.On, Characteristic.On, Characteristic.On][displayType];
tile.state = false;
tile.previousState = null;
this.generatorModeActiveControls.push(tile);
}
this.generatorModeActiveControlsCount = this.generatorModeActiveControls.length || 0;
this.generatorModeActiveSensors = [];
for (const sensor of this.generatorModeSensors) {
const displayType = sensor.displayType ?? 0;
if (displayType === 0) {
continue;
};
sensor.name = sensor.name || 'Generator Mode Sensor';
sensor.serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][displayType];
sensor.characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][displayType];
sensor.state = false;
this.generatorModeActiveSensors.push(sensor);
}
this.generatorModeActiveSensorsCount = this.generatorModeActiveSensors.length || 0;
//setup variables
this.envoyIdFile = envoyIdFile;
this.envoyTokenFile = envoyTokenFile;
this.startPrepareAccessory = true;
//url
this.url = envoyFirmware7xxTokenGenerationMode > 0 ? `https://${this.host}` : `http://${this.host}`;
//create axios instance
this.axiosInstance = axios.create({
method: 'GET',
baseURL: this.url,
withCredentials: true,
headers: {
Accept: 'application/json'
},
httpsAgent: new Agent({
keepAlive: false,
rejectUnauthorized: false
}),
timeout: 25000
});
//supported functions
this.feature = {
backboneApp: {
supported: false
},
envoy: {
installed: false
},
networkInterfaces: {
supported: false,
installed: false,
count: 0
},
wirelessConnections: {
supported: false,
installed: false,
count: 0
},
microinverters: {
supported: false,
installed: false,
count: 0,
status: {
supported: false
},
},
qRelays: {
supported: false,
installed: false,
count: 0
},
acBatteries: {
supported: false,
installed: false,
count: 0
},
meters: {
supported: false,
installed: false,
count: 0,
production: {
supported: false,
enabled: false,
voltageDivide: 1
},
consumption: {
supported: false,
enabled: false,
voltageDivide: 1
},
acBatterie: {
supported: false,
enabled: false,
voltageDivide: 1
},
reading: {
supported: false,
installed: false,
count: 0,
channels: {
supported: false,
installed: false,
count: 0
}
}
},
production: {
microinverters: {
supported: false
},
ct: {
inverters: {
supported: false
},
production: {
supported: false
},
consumption: {
supported: false
},
acBatterie: {
supported: false
}
},
all: {
production: {
supported: false
},
consumption: {
supported: false
}
}
},
ensembles: {
supported: false,
installed: false,
inventory: {
supported: false,
installed: false,
count: 0,
},
status: {
supported: false
}
},
enpowers: {
supported: false,
installed: false,
count: 0
},
encharges: {
supported: false,
installed: false,
count: 0,
settings: {
supported: false,
installed: false,
},
tariff: {
supported: false
}
},
dryContacts: {
supported: false,
installed: false,
count: 0,
settings: {
supported: false,
installed: false,
count: 0
}
},
generators: {
supported: false,
installed: false,
count: 0,
settings: {
supported: false
}
},
liveData: {
supported: false
},
arfProfile: {
supported: false
},
productionState: {
supported: false
},
plcLevel: {
supported: false
},
dataSampling: false
}
//pv object
this.pv = {
envoy: {
devId: '',
passwd: '',
installerPasswd: '',
firmware: 500,
firmware7xx: envoyFirmware7xxTokenGenerationMode > 0,
jwtToken: {
generation_time: 0,
token: envoyToken,
expires_at: 0,
installer: this.envoyFirmware7xxTokenGenerationMode === 2 ? this.envoyTokenInstaller : false
}
},
microinverters: [],
qRelays: [],
acBatteries: {
devices: []
},
ensembles: [],
meters: [],
production: {
microinverters: {},
ct: {
inverters: {},
production: {},
consumption: [],
acBatterie: {}
},
all: {
production: {},
consumption: {}
}
},
liveData: {},
arfProfile: {},
checkJwtTokenRunning: false,
cookie: false,
productionState: false,
plcLevelState: false,
powerState: false,
powerLevel: 0,
productionPowerPeak: 0,
consumptionTotalPowerPeak: 0,
consumptionNetPowerPeak: 0
};
//ensemble object
this.ensemble = {
enpowers: {
devices: []
},
encharges: {
devices: []
},
counters: {},
secctrl: {},
relay: {},
tariff: {},
dryContacts: [],
generator: {},
arfProfile: {}
};
//create impulse generator
this.impulseGenerator = new ImpulseGenerator();
this.impulseGenerator.on('updateProductionState', async () => {
try {
const tokenValid = await this.checkJwtToken();
const updateProductionState = !tokenValid ? false : await this.updateProductionState();
} catch (error) {
this.handleError(error);
};
}).on('updateHome', async () => {
try {
const tokenValid = await this.checkJwtToken();
const updateHome = !tokenValid ? false : await this.updateHome();
const updateInventory = updateHome ? await this.updateInventory() : false;
} catch (error) {
this.handleError(error);
};
}).on('updateMeters', async () => {
try {
const tokenValid = await this.checkJwtToken();
const updateMeters = !tokenValid ? false : await this.updateMeters();
const updateMetersReading = updateMeters ? await this.updateMetersReading() : false;
} catch (error) {
this.handleError(error);
};
}).on('updateMicroinvertersStatus', async () => {
try {
const tokenValid = await this.checkJwtToken();
const updateMicroinvertersStatus = !tokenValid ? false : await this.updateMicroinvertersStatus();
} catch (error) {
this.handleError(error);
};
}).on('updateProduction', async () => {
try {
const tokenValid = await this.checkJwtToken();
const updateProductionInverters = !tokenValid ? false : await this.updateProductionInverters();
const updateProductionCt = updateProductionInverters ? await this.updateProductionCt() : false;
} catch (error) {
this.handleError(error);
};
}).on('updateProductionAll', async () => {
try {
const tokenValid = await this.checkJwtToken();
const updateProductionAll = !tokenValid ? false : await this.updateProductionAll();
} catch (error) {
this.handleError(error);
};
}).on('updateEnsemble', async () => {
try {
const tokenValid = await this.checkJwtToken();
const updateEnsemble = !tokenValid ? false : await this.updateEnsembleInventory();
const updateEnsembleStatus = updateEnsemble ? await this.updateEnsembleStatus() : false;
const updateEnchargeSettings = updateEnsemble ? await this.updateEnchargesSettings() : false;
const updateTariffSettings = updateEnsemble ? await this.updateTariff() : false;
const updateDryContacts = updateEnsemble ? await this.updateDryContacts() : false;
const updateDryContactsSettings = updateDryContacts ? await this.updateDryContactsSettings() : false;
const updateGenerator = updateEnsemble ? await this.updateGenerator() : false;
const updateGeneratorSettings = updateGenerator ? await this.updateGeneratorSettings() : false;
} catch (error) {
this.handleError(error);
};
}).on('updateLiveData', async () => {
try {
const tokenValid = await this.checkJwtToken();
const updateLiveData = !tokenValid ? false : await this.updateLiveData();
} catch (error) {
this.handleError(error);
};
}).on('state', (state) => {
const emitState = state ? this.emit('success', `Impulse generator started`) : this.emit('warn', `Impulse generator stopped`);
this.feature.dataSampling = state;
if (this.dataRefreshActiveControl) {
this.dataRefreshActiveControl.state = state;
if (this.dataRefreshControlService) {
const characteristicType = this.dataRefreshActiveControl.characteristicType;
this.dataRefreshControlService
.updateCharacteristic(characteristicType, state)
}
}
if (this.dataRefreshActiveSensor) {
this.dataRefreshActiveSensor.state = state;
if (this.dataRefreshSensorService) {
const characteristicType = this.dataRefreshActiveSensor.characteristicType;
this.dataRefreshSensorService
.updateCharacteristic(characteristicType, state)
}
}
if (this.envoyService) {
this.envoyService
.updateCharacteristic(Characteristic.EnphaseEnvoyDataRefresh, state)
}
//restFul
const restFul = this.restFulConnected ? this.restFul1.update('datasampling', { state: state }) : false;
//mqtt
const mqtt = this.mqttConnected ? this.mqtt1.emit('publish', 'Data Sampling', { state: state }) : false;
});
};
handleError(error) {
const errorString = error.toString();
const tokenNotValid = errorString.includes('status code 401');
if (tokenNotValid) {
if (this.pv.checkJwtTokenRunning) {
return;