UNPKG

homebridge-tuya-laundry

Version:

Allows washer/dryer cycle completion notifications using Tuya smart plugs with power meter, now using local control.

160 lines 8.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LaundryDeviceTracker = void 0; const luxon_1 = require("luxon"); class LaundryDeviceTracker { constructor(log, messageGateway, config, api, smartPlugService) { this.log = log; this.messageGateway = messageGateway; this.config = config; this.api = api; this.smartPlugService = smartPlugService; this.cumulativeConsumption = 0; // in watt-seconds (W·s) this.lastMeasurementTime = luxon_1.DateTime.now(); // Time of the last measurement this.lastDpsStatus = null; // Cached last DPS status this.currentInterval = 5000; // Dynamic update interval in milliseconds const deviceName = this.config.name || this.config.deviceId; this.log.debug(`Initializing LaundryDeviceTracker with config: ${JSON.stringify(this.config, null, 2)}`); } async init() { const deviceName = this.config.name || this.config.deviceId; if (this.config.startValue < this.config.endValue) { throw new Error('startValue cannot be smaller than endValue.'); } if (!this.config.localKey) { this.log.error(`Missing localKey for device ${deviceName}. Please provide a valid localKey.`); return; } try { const localDevices = await this.smartPlugService.discoverLocalDevices(); const selectedDevice = localDevices.find(device => device.deviceId === this.config.deviceId); if (!selectedDevice) { this.log.warn(`Device ${deviceName} not found on LAN.`); return; } selectedDevice.localKey = this.config.localKey; this.log.info(`Device ${deviceName} found on LAN. Starting power tracking.`); this.detectStartStop(selectedDevice); } catch (error) { this.log.error(`Error initializing device ${deviceName}: ${error.message}`); } } async detectStartStop(selectedDevice) { setInterval(async () => { try { const deviceName = this.config.name || this.config.deviceId; const powerValue = await this.getPowerValue(selectedDevice); if (typeof powerValue !== 'number') { this.log.error(`Received invalid power value: ${powerValue} (expected a number).`); return; } this.log.debug(`Current power for ${deviceName}: ${powerValue}W`); this.incomingData(powerValue); // Run the helper method to check start and stop conditions await this.checkStartStopConditions(deviceName, powerValue); } catch (error) { this.log.error(`Error during start/stop detection: ${error.message}`); } }, this.currentInterval); } // Helper method to get power value with caching async getPowerValue(selectedDevice) { var _a; const dpsStatus = await this.smartPlugService.getLocalDPS(selectedDevice, this.log); if (JSON.stringify(dpsStatus) === JSON.stringify(this.lastDpsStatus)) { this.log.debug(`No change in device status for ${selectedDevice.deviceId}, skipping further checks.`); return (_a = this.lastDpsStatus) === null || _a === void 0 ? void 0 : _a.dps[this.config.powerValueId]; } this.lastDpsStatus = dpsStatus; // Explizit prüfen, ob powerValue definiert ist, um 0 als gültigen Wert zu akzeptieren const powerValue = dpsStatus === null || dpsStatus === void 0 ? void 0 : dpsStatus.dps[this.config.powerValueId]; return powerValue !== undefined ? powerValue : null; } // Method to dynamically adjust the interval based on activity adjustInterval(isActive) { this.currentInterval = isActive ? 1000 : 5000; // 1 second when active, 5 seconds when idle this.log.debug(`Adjusted polling interval to ${this.currentInterval}ms based on activity.`); } // Helper method to check start and stop conditions async checkStartStopConditions(deviceName, powerValue) { // Check whether the machine started if (!this.isActive && this.startDetected && this.startDetectedTime) { const secondsDiff = luxon_1.DateTime.now().diff(this.startDetectedTime, 'seconds').seconds; this.log.debug(`Checking start confirmation: ${secondsDiff} seconds since start detected.`); if (secondsDiff > this.config.startDuration) { this.log.info(`${deviceName} has started!`); if (this.config.startMessage) { await this.messageGateway.send(this.config.startMessage); } this.isActive = true; this.updateAccessorySwitchState(true); this.cumulativeConsumption = 0; // Reset cumulative consumption for the new cycle this.startDetected = false; // Reset start detection this.startDetectedTime = undefined; this.adjustInterval(true); // Switch to a more frequent interval } } // Accumulate energy consumption if the machine is running if (this.isActive) { const now = luxon_1.DateTime.now(); const timeDiff = now.diff(this.lastMeasurementTime, 'seconds').seconds; this.lastMeasurementTime = now; const energyConsumed = (powerValue / 10) * timeDiff; // in watt-seconds (W-s) this.cumulativeConsumption += energyConsumed; this.log.debug(`Added ${energyConsumed} W·s. Total cumulativeConsumption: ${this.cumulativeConsumption} W·s, ${(this.cumulativeConsumption / 3600000).toFixed(4)} kWh`); } // Check whether the machine has stopped if (this.endDetected && this.endDetectedTime) { const secondsDiff = luxon_1.DateTime.now().diff(this.endDetectedTime, 'seconds').seconds; if (secondsDiff > this.config.endDuration && this.isActive) { this.isActive = false; const kWhConsumed = this.cumulativeConsumption / 3600000; // Convert watt-seconds to kWh this.log.info(`Device finished the job. Total consumption: ${kWhConsumed.toFixed(2)} kWh`); const endMessage = `${this.config.endMessage || ''} Total consumption: ${kWhConsumed.toFixed(2)} kWh.`; this.messageGateway.send(endMessage); this.updateAccessorySwitchState(false); this.cumulativeConsumption = 0; // Reset for the next cycle this.endDetected = false; // Reset end detection this.endDetectedTime = undefined; this.adjustInterval(false); // Switch to a less frequent interval } } } incomingData(value) { const deviceName = this.config.name || this.config.deviceId; this.log.debug(`Processing incoming power data for ${deviceName}: ${value}`); if (value >= this.config.startValue) { if (!this.isActive && !this.startDetected) { this.startDetected = true; this.startDetectedTime = luxon_1.DateTime.now(); this.log.debug(`Detected start value for ${deviceName}. Waiting ${this.config.startDuration} seconds for confirmation.`); } } else { this.startDetected = false; this.startDetectedTime = undefined; } if (value <= this.config.endValue) { if (this.isActive && !this.endDetected) { this.endDetected = true; this.endDetectedTime = luxon_1.DateTime.now(); this.log.debug(`Detected end value for ${deviceName}. Waiting ${this.config.endDuration} seconds for confirmation.`); } } else { this.endDetected = false; this.endDetectedTime = undefined; } } updateAccessorySwitchState(isOn) { if (this.config.exposeStateSwitch && this.accessory) { const service = this.accessory.getService(this.api.hap.Service.Switch); service === null || service === void 0 ? void 0 : service.setCharacteristic(this.api.hap.Characteristic.On, isOn); this.log.debug(`Updated accessory switch state for ${this.config.name}: ${isOn ? 'On' : 'Off'}`); } } } exports.LaundryDeviceTracker = LaundryDeviceTracker; //# sourceMappingURL=laundryDeviceTracker.js.map