UNPKG

homebridge-weather-noaa

Version:

Homebridge plugin providing temperature and humidity sensors using NOAA API.

138 lines (137 loc) 6.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.NOAAWeatherAccessory = void 0; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); class NOAAWeatherAccessory { constructor(platform, accessory) { this.platform = platform; this.accessory = accessory; this.lastTemperature = null; this.lastHumidity = null; try { const persistPath = this.platform.api.user.persistPath(); this.cacheFile = path_1.default.join(persistPath, 'noaa-weather-last.json'); let lastWeather = { temperature: 20, humidity: 50 }; if (fs_1.default.existsSync(this.cacheFile)) { try { lastWeather = JSON.parse(fs_1.default.readFileSync(this.cacheFile, 'utf8')); } catch (e) { NOAAWeatherAccessory.metrics.cacheResets++; this.logWarn('Corrupted weather cache detected. Resetting cache.', e); try { fs_1.default.unlinkSync(this.cacheFile); } catch { } } } this.lastTemperature = lastWeather.temperature; this.lastHumidity = lastWeather.humidity; accessory.context.weather = lastWeather; this.temperatureService = accessory.getService(this.platform.api.hap.Service.TemperatureSensor) || accessory.addService(this.platform.api.hap.Service.TemperatureSensor, 'NOAA Temperature', this.platform.api.hap.Service.TemperatureSensor.UUID); this.humidityService = accessory.getService(this.platform.api.hap.Service.HumiditySensor) || accessory.addService(this.platform.api.hap.Service.HumiditySensor, 'NOAA Humidity', this.platform.api.hap.Service.HumiditySensor.UUID); this.safeUpdateCharacteristic(this.temperatureService, this.platform.api.hap.Characteristic.CurrentTemperature, lastWeather.temperature); this.safeUpdateCharacteristic(this.humidityService, this.platform.api.hap.Characteristic.CurrentRelativeHumidity, lastWeather.humidity); this.logInfo(`Initialized HomeKit with cached NOAA weather: ${lastWeather.temperature}°C, ${lastWeather.humidity}%`); setInterval(() => this.logMetrics(), 60 * 60 * 1000); process.on('exit', () => this.logMetrics()); } catch (err) { this.logError('Failed during NOAAWeatherAccessory constructor:', err); } } updateValues() { try { const weather = this.accessory.context.weather; if (weather.temperature === null || weather.humidity === null) { this.logWarn('NOAA returned null values. Keeping last known HomeKit values.'); return; } this.logInfo(`Pushed NOAA weather to HomeKit: ${weather.temperature}°C, ${weather.humidity}%`); this.safeUpdateCharacteristic(this.temperatureService, this.platform.api.hap.Characteristic.CurrentTemperature, weather.temperature); this.safeUpdateCharacteristic(this.humidityService, this.platform.api.hap.Characteristic.CurrentRelativeHumidity, weather.humidity); try { fs_1.default.writeFileSync(this.cacheFile, JSON.stringify(weather)); } catch (e) { NOAAWeatherAccessory.metrics.cacheWriteErrors++; this.logError('Failed to write last weather cache:', e); } this.lastTemperature = weather.temperature; this.lastHumidity = weather.humidity; } catch (err) { this.logError('Error updating NOAA weather values:', err); } } safeUpdateCharacteristic(service, characteristic, value) { try { service.updateCharacteristic(characteristic, value); } catch (e) { NOAAWeatherAccessory.metrics.characteristicErrors++; this.logError(`Failed to update HomeKit characteristic ${characteristic.displayName || characteristic}:`, e); try { let newService = null; if (service.UUID === this.platform.api.hap.Service.TemperatureSensor.UUID) { newService = this.accessory.addService(this.platform.api.hap.Service.TemperatureSensor, 'NOAA Temperature', this.platform.api.hap.Service.TemperatureSensor.UUID); } else if (service.UUID === this.platform.api.hap.Service.HumiditySensor.UUID) { newService = this.accessory.addService(this.platform.api.hap.Service.HumiditySensor, 'NOAA Humidity', this.platform.api.hap.Service.HumiditySensor.UUID); } if (newService) { NOAAWeatherAccessory.metrics.serviceRecoveries++; newService.updateCharacteristic(characteristic, value); this.logInfo(`Recovered and updated ${service.displayName} service successfully.`); } else { this.logWarn(`Could not match service type for recovery: ${service.displayName}`); } } catch (recoverErr) { this.logError(`Failed to self-recover service ${service.displayName}:`, recoverErr); } } } logMetrics() { this.logInfo(`📊 NOAA Accessory Metrics → Cache Resets: ${NOAAWeatherAccessory.metrics.cacheResets}, ` + `Cache Write Errors: ${NOAAWeatherAccessory.metrics.cacheWriteErrors}, ` + `Characteristic Errors: ${NOAAWeatherAccessory.metrics.characteristicErrors}, ` + `Service Recoveries: ${NOAAWeatherAccessory.metrics.serviceRecoveries}`); } logInfo(message) { this.platform.log.info(this.formatLog(message)); } logWarn(message, data) { this.platform.log.warn(this.formatLog(message), data || ''); } logError(message, data) { this.platform.log.error(this.formatLog(message), data || ''); } formatLog(message) { const now = new Date(); const formattedTime = new Intl.DateTimeFormat('en-US', { timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone, hour12: true, hour: '2-digit', minute: '2-digit', second: '2-digit', }).format(now); return `[${formattedTime}] ${message}`; } } exports.NOAAWeatherAccessory = NOAAWeatherAccessory; NOAAWeatherAccessory.metrics = { cacheResets: 0, cacheWriteErrors: 0, characteristicErrors: 0, serviceRecoveries: 0, };