UNPKG

homebridge-airgradient

Version:

Fetches air quality information from AirGradient devices.

261 lines 10.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; const axios_1 = __importDefault(require("axios")); let hap; class AirGradientPlatform { constructor(log, config, api) { this.accessories = []; this.log = log; this.api = api; hap = api.hap; if (config.sensors) { for (const sensorConfig of config.sensors) { this.log.info('Initializing sensor with serial number:', sensorConfig.serialno); this.addAccessory(sensorConfig); } } api.on('didFinishLaunching', () => { this.log.info('Did finish launching'); }); } addAccessory(sensorConfig) { const uuid = hap.uuid.generate(sensorConfig.serialno); const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid); if (existingAccessory) { this.log.info('Restoring existing accessory from cache:', existingAccessory.displayName); new AirGradientSensor(this, existingAccessory, sensorConfig); } else { this.log.info('Adding new accessory for serial number:', sensorConfig.serialno); const accessory = new this.api.platformAccessory(`AirGradient Sensor ${sensorConfig.serialno}`, uuid); new AirGradientSensor(this, accessory, sensorConfig); this.api.registerPlatformAccessories('homebridge-airgradient', 'AirGradientPlatform', [accessory]); } } configureAccessory(accessory) { this.accessories.push(accessory); } } class AirGradientSensor { constructor(platform, accessory, sensorConfig) { this.data = null; this.platform = platform; this.accessory = accessory; this.log = platform.log; this.serialno = sensorConfig.serialno; this.pollingInterval = sensorConfig.pollingInterval || 60000; // Default to 1 minute this.useCompensatedValues = sensorConfig.useCompensatedValues || false; // Construct the local API URL using the serialno this.apiUrl = `http://airgradient_${this.serialno}.local/measures/current`; this.accessory.getService(hap.Service.AccessoryInformation) .setCharacteristic(hap.Characteristic.Manufacturer, 'AirGradient') .setCharacteristic(hap.Characteristic.SerialNumber, this.serialno); this.service = this.accessory.getService(hap.Service.AirQualitySensor) || this.accessory.addService(hap.Service.AirQualitySensor); this.serviceTemp = this.accessory.getService(hap.Service.TemperatureSensor) || this.accessory.addService(hap.Service.TemperatureSensor); this.serviceCO2 = this.accessory.getService(hap.Service.CarbonDioxideSensor) || this.accessory.addService(hap.Service.CarbonDioxideSensor); this.serviceHumid = this.accessory.getService(hap.Service.HumiditySensor) || this.accessory.addService(hap.Service.HumiditySensor); this.updateCharacteristics(); this.updateData(); } async fetchData() { try { const response = await axios_1.default.get(this.apiUrl); this.data = response.data; this.log.info('Data fetched successfully:', this.data); // Log the full response for debugging this.log.debug('API response:', this.data); } catch (error) { this.log.error('Error fetching data from AirGradient API:', error); throw error; } } async updateData() { try { await this.fetchData(); if (this.data) { this.updateCharacteristics(); } } catch (error) { this.log.error('Error updating data:', error); } finally { // Schedule the next update setTimeout(() => this.updateData(), this.pollingInterval); } } updateCharacteristics() { if (this.data) { // Use compensated values if enabled and available, otherwise fallback to the default values const pm2_5 = this.useCompensatedValues && this.data.pm02Compensated !== undefined ? this.data.pm02Compensated : this.data.pm02; const temp = this.useCompensatedValues && this.data.atmpCompensated !== undefined ? this.data.atmpCompensated : this.data.atmp; const humidity = this.useCompensatedValues && this.data.rhumCompensated !== undefined ? this.data.rhumCompensated : this.data.rhum; // Other values remain the same const pm10 = this.data.pm10; const tvoc = this.data.tvocIndex; const nox = this.data.noxIndex; const co2 = this.data.rco2; if (typeof pm2_5 === 'number' && isFinite(pm2_5)) { this.service.updateCharacteristic(hap.Characteristic.PM2_5Density, pm2_5); } else { this.log.warn('Invalid PM2.5 value:', pm2_5); } if (typeof pm10 === 'number' && isFinite(pm10)) { this.service.updateCharacteristic(hap.Characteristic.PM10Density, pm10); } else { this.log.warn('Invalid PM10 value:', pm10); } if (typeof tvoc === 'number' && isFinite(tvoc)) { this.service.updateCharacteristic(hap.Characteristic.VOCDensity, tvoc); } else { this.log.warn('Invalid TVOC value:', tvoc); } if (typeof nox === 'number' && isFinite(nox)) { this.service.updateCharacteristic(hap.Characteristic.NitrogenDioxideDensity, nox); } else { this.log.warn('Invalid NOx value:', nox); } if (typeof temp === 'number' && isFinite(temp)) { this.serviceTemp.updateCharacteristic(hap.Characteristic.CurrentTemperature, temp); } else { this.log.warn('Invalid Temperature value:', temp); } if (typeof co2 === 'number' && isFinite(co2)) { this.serviceCO2.updateCharacteristic(hap.Characteristic.CarbonDioxideDetected, this.calculateCO2Detected(co2)); this.serviceCO2.updateCharacteristic(hap.Characteristic.CarbonDioxideLevel, co2); } else { this.log.warn('Invalid CO2 value:', co2); } if (typeof humidity === 'number' && isFinite(humidity)) { this.serviceHumid.updateCharacteristic(hap.Characteristic.CurrentRelativeHumidity, humidity); } else { this.log.warn('Invalid Humidity value:', humidity); } this.service.updateCharacteristic(hap.Characteristic.AirQuality, this.calculateAirQuality(pm2_5)); this.log.info(`Updated characteristics - PM2.5: ${pm2_5}, PM10: ${pm10}, TVOC: ${tvoc}, ` + `NOx: ${nox}, TEMP: ${temp}, CO2: ${co2}, Humidity: ${humidity}`); } } calculateAirQuality(pm2_5) { if (pm2_5 <= 12) { return hap.Characteristic.AirQuality.EXCELLENT; } else if (pm2_5 <= 35.4) { return hap.Characteristic.AirQuality.GOOD; } else if (pm2_5 <= 55.4) { return hap.Characteristic.AirQuality.FAIR; } else if (pm2_5 <= 150.4) { return hap.Characteristic.AirQuality.INFERIOR; } else { return hap.Characteristic.AirQuality.POOR; } } calculateCO2Detected(co2) { if (co2 <= 800) { return hap.Characteristic.CarbonDioxideDetected.CO2_LEVELS_NORMAL; } else { return hap.Characteristic.CarbonDioxideDetected.CO2_LEVELS_ABNORMAL; } } handleAirQualityGet(callback) { if (this.data) { callback(null, this.calculateAirQuality(this.data.pm02)); } else { callback(new Error('No data available')); } } handlePM2_5DensityGet(callback) { if (this.data) { callback(null, this.data.pm02); } else { callback(new Error('No data available')); } } handlePM10DensityGet(callback) { if (this.data) { callback(null, this.data.pm10); } else { callback(new Error('No data available')); } } handleVOCDensityGet(callback) { if (this.data) { callback(null, this.data.tvocIndex); } else { callback(new Error('No data available')); } } handleNitrogenDioxideDensityGet(callback) { if (this.data) { callback(null, this.data.noxIndex); } else { callback(new Error('No data available')); } } handleCurrentTemperatureGet(callback) { if (this.data) { callback(null, this.data.atmp); } else { callback(new Error('No data available')); } } handleCarbonDioxideDetectedGet(callback) { if (this.data) { callback(null, this.calculateCO2Detected(this.data.rco2)); } else { callback(new Error('No data available')); } } handleCarbonDioxideLevelGet(callback) { if (this.data) { callback(null, this.data.rco2); } else { callback(new Error('No data available')); } } handleCurrentRelativeHumidityGet(callback) { if (this.data) { callback(null, this.data.rhum); } else { callback(new Error('No data available')); } } } module.exports = (homebridge) => { hap = homebridge.hap; homebridge.registerPlatform('homebridge-airgradient', 'AirGradientPlatform', AirGradientPlatform); }; //# sourceMappingURL=index.js.map