UNPKG

homebridge-enphase-envoy

Version:

Homebridge plugin for Photovoltaic Energy System manufactured by Enphase.

185 lines (153 loc) 5.7 kB
import { promises as fsPromises } from 'fs'; import axios from 'axios'; import { Agent } from 'https'; import { ApiCodes, TimezoneLocaleMap } from './constants.js'; class Functions { constructor() { } async saveData(path, data, stringify = true) { try { data = stringify ? JSON.stringify(data, null, 2) : data; await fsPromises.writeFile(path, data); return true; } catch (error) { throw new Error(`Save data error: ${error}`); } } async readData(path, parseJson = false) { try { const data = await fsPromises.readFile(path, 'utf8'); if (parseJson) { if (!data.trim()) { // Empty file when expecting JSON return null; } try { return JSON.parse(data); } catch (jsonError) { throw new Error(`JSON parse error in file "${path}": ${jsonError.message}`); } } // For non-JSON, just return file content (can be empty string) return data; } catch (error) { if (error.code === 'ENOENT') { // File does not exist return null; } // Preserve original error details const wrappedError = new Error(`Read data error for "${path}": ${error.message}`); wrappedError.original = error; throw wrappedError; } } async getStatus(status) { if (!Array.isArray(status) || status.length === 0) { return 'OK'; } const mapped = status.map(a => { const value = ApiCodes[a]; return (typeof value === 'string' && value.trim() !== '') ? value.trim() : a; }).filter(Boolean); // Remove any empty/null/undefined values if (mapped.length === 0) { return 'OK'; } const result = mapped.join(', '); // Add ellipsis only if result is actually truncated return result.length > 64 ? result.slice(0, 61) + '…' : result; } async mapInventoryBySerial(data) { const result = {}; data.forEach(group => { const { type, devices } = group; devices.forEach(device => { result[device.serial_num] = { type, ...device }; }); }); return result; } async mapDevicesDataBySerial(data) { const result = {}; for (const key in data) { const item = data[key]; if (!item || typeof item !== "object") continue; if (!item.sn) continue; result[item.sn] = item; } return result; } isValidValue(v) { return v !== undefined && v !== null && !(typeof v === 'number' && Number.isNaN(v)); } scaleValue(value, inMin, inMax, outMin, outMax) { if (!this.isValidValue(value) || !this.isValidValue(inMin) || !this.isValidValue(inMax) || !this.isValidValue(outMin) || !this.isValidValue(outMax)) return null; if (inMax === inMin) return outMin; if (value <= inMin) return outMin; if (value >= inMax) return outMax; const scaled = ((value - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin; if (scaled > outMax) return outMax; return scaled < 0.5 ? outMin : Math.round(scaled); } evaluateCompareMode(value, threshold, mode) { switch (mode) { case 0: return value > threshold; case 1: return value >= threshold; case 2: return value === threshold; case 3: return value < threshold; case 4: return value <= threshold; case 5: return value !== threshold; default: return false; } } formatTimestamp(ts, timezone) { const locale = TimezoneLocaleMap[timezone] || 'en-US'; const options = { timeZone: timezone, year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', }; if (!ts) { return new Date().toLocaleString(locale, options); } const numeric = Number(ts); if (Number.isInteger(numeric)) { const ms = numeric < 1e12 ? numeric * 1000 : numeric; return new Date(ms).toLocaleString(locale, options); } return ts; } powerPeak(power, powerPeakStored) { if (!this.isValidValue(power) && !this.isValidValue(powerPeakStored)) return null; if (!this.isValidValue(power)) return powerPeakStored; if (!this.isValidValue(powerPeakStored)) return power; // dodatnie — szczyt rośnie w górę if (power >= 0 && power > powerPeakStored) return power; // ujemne — szczyt rośnie w dół if (power < 0 && power < powerPeakStored) return power; return powerPeakStored; } createAxiosInstance(url, authHeader = null, cookie = null) { return axios.create({ baseURL: url, headers: { Accept: 'application/json', ...(authHeader ? { Authorization: authHeader } : {}), ...(cookie ? { Cookie: cookie } : {}), }, withCredentials: true, httpsAgent: new Agent({ keepAlive: false, rejectUnauthorized: false }), timeout: 60000 }); } } export default Functions