@teslemetry/node-red-contrib-teslemetry
Advanced tools
| //#region src/shared.ts | ||
| const instances = /* @__PURE__ */ new Map(); | ||
| /** | ||
| * Extract a useful error message from any error type. | ||
| * Handles Error objects, hey-api response objects, and plain objects. | ||
| */ | ||
| function getErrorMessage(error) { | ||
| if (!error) return "Unknown error"; | ||
| if (error instanceof Error) return error.message; | ||
| if (typeof error === "object") { | ||
| const obj = error; | ||
| if (typeof obj.error_description === "string") return obj.error_description; | ||
| if (typeof obj.error === "string") return obj.error; | ||
| if (typeof obj.message === "string") return obj.message; | ||
| if (obj.response && typeof obj.response === "object") { | ||
| const resp = obj.response; | ||
| if (typeof obj.error_description === "string") return obj.error_description; | ||
| if (typeof obj.error === "string") return obj.error; | ||
| if (resp.status) return `HTTP ${resp.status}: ${resp.statusText || "Error"}`; | ||
| } | ||
| try { | ||
| return JSON.stringify(error); | ||
| } catch { | ||
| return String(error); | ||
| } | ||
| } | ||
| return String(error); | ||
| } | ||
| /** | ||
| * Get instance and validate it exists. Sets error status on node if not found. | ||
| * @returns Instance or null if missing | ||
| */ | ||
| function getInstance(configId, node) { | ||
| const instance = instances.get(configId); | ||
| if (!instance) { | ||
| node.status({ | ||
| fill: "red", | ||
| shape: "ring", | ||
| text: "Config missing" | ||
| }); | ||
| node.error("No Teslemetry instance found"); | ||
| return null; | ||
| } | ||
| instance.products.finally(() => { | ||
| hasInstanceError(instance, node); | ||
| }); | ||
| return instance; | ||
| } | ||
| /** | ||
| * Check if instance has an error. Sets error status on node if so. | ||
| * @returns true if there's an error (caller should return early) | ||
| */ | ||
| function hasInstanceError(instance, node) { | ||
| if (instance.error) { | ||
| node.status({ | ||
| fill: "red", | ||
| shape: "ring", | ||
| text: "Error" | ||
| }); | ||
| node.error(`Teslemetry error: ${instance.error}`); | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| //#endregion | ||
| Object.defineProperty(exports, "getErrorMessage", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return getErrorMessage; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "getInstance", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return getInstance; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "hasInstanceError", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return hasInstanceError; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "instances", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return instances; | ||
| } | ||
| }); |
| //#region src/validation.ts | ||
| function validateParameters(msg, rules) { | ||
| const errors = []; | ||
| for (const [paramName, rule] of Object.entries(rules)) { | ||
| const value = msg[paramName]; | ||
| if (rule.required && (value === void 0 || value === null || value === "")) { | ||
| errors.push(`Required parameter '${paramName}' is missing`); | ||
| continue; | ||
| } | ||
| if (value === void 0 || value === null || value === "") continue; | ||
| if (rule.type === "number") { | ||
| const numValue = Number(value); | ||
| if (isNaN(numValue)) { | ||
| errors.push(`Parameter '${paramName}' must be a valid number, got '${value}'`); | ||
| continue; | ||
| } | ||
| if (rule.integer && !Number.isInteger(numValue)) { | ||
| errors.push(`Parameter '${paramName}' must be an integer, got '${value}'`); | ||
| continue; | ||
| } | ||
| if (rule.min !== void 0 && numValue < rule.min) errors.push(`Parameter '${paramName}' must be at least ${rule.min}, got ${numValue}`); | ||
| if (rule.max !== void 0 && numValue > rule.max) errors.push(`Parameter '${paramName}' must be at most ${rule.max}, got ${numValue}`); | ||
| } else if (rule.type === "string") { | ||
| if (typeof value !== "string") { | ||
| errors.push(`Parameter '${paramName}' must be a string, got ${typeof value}`); | ||
| continue; | ||
| } | ||
| if (rule.allowedValues && !rule.allowedValues.includes(value)) errors.push(`Parameter '${paramName}' must be one of: ${rule.allowedValues.join(", ")}, got '${value}'`); | ||
| } else if (rule.type === "boolean") { | ||
| if (typeof value !== "boolean") errors.push(`Parameter '${paramName}' must be a boolean, got ${typeof value}`); | ||
| } | ||
| } | ||
| if (errors.length > 0) throw new Error(errors.join("; ")); | ||
| } | ||
| //#endregion | ||
| Object.defineProperty(exports, "validateParameters", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return validateParameters; | ||
| } | ||
| }); |
@@ -1,4 +0,3 @@ | ||
| const require_shared = require('./shared-DlnhRLCp.cjs'); | ||
| const require_validation = require('./validation-Ctl8enVU.cjs'); | ||
| const require_shared = require("./shared-BdKmyM3n.cjs"); | ||
| const require_validation = require("./validation-Bcj5G3Yy.cjs"); | ||
| //#region src/nodes/teslemetry-energy-command.ts | ||
@@ -36,2 +35,5 @@ function teslemetry_energy_command_default(RED) { | ||
| break; | ||
| case "getTariff": | ||
| result = { response: await site.getTariff() }; | ||
| break; | ||
| case "setBackupReserve": | ||
@@ -98,4 +100,3 @@ require_validation.validateParameters(msg, { percentage: { | ||
| } | ||
| //#endregion | ||
| module.exports = teslemetry_energy_command_default; | ||
| module.exports = teslemetry_energy_command_default; |
@@ -100,2 +100,3 @@ <script type="text/javascript"> | ||
| <option value="getSiteInfo">Get Site Info</option> | ||
| <option value="getTariff">Get Tariff (TOU rates)</option> | ||
| <option value="setOperationModeSelfConsumption"> | ||
@@ -102,0 +103,0 @@ Mode: Self Consumption |
@@ -1,4 +0,3 @@ | ||
| const require_shared = require('./shared-DlnhRLCp.cjs'); | ||
| const require_validation = require('./validation-Ctl8enVU.cjs'); | ||
| const require_shared = require("./shared-BdKmyM3n.cjs"); | ||
| const require_validation = require("./validation-Bcj5G3Yy.cjs"); | ||
| //#region src/nodes/teslemetry-energy-history.ts | ||
@@ -89,4 +88,3 @@ function teslemetry_energy_history_default(RED) { | ||
| } | ||
| //#endregion | ||
| module.exports = teslemetry_energy_history_default; | ||
| module.exports = teslemetry_energy_history_default; |
@@ -1,3 +0,2 @@ | ||
| const require_shared = require('./shared-DlnhRLCp.cjs'); | ||
| const require_shared = require("./shared-BdKmyM3n.cjs"); | ||
| //#region src/nodes/teslemetry-event.ts | ||
@@ -48,4 +47,3 @@ function teslemetry_event_default(RED) { | ||
| } | ||
| //#endregion | ||
| module.exports = teslemetry_event_default; | ||
| module.exports = teslemetry_event_default; |
@@ -1,3 +0,2 @@ | ||
| const require_shared = require('./shared-DlnhRLCp.cjs'); | ||
| const require_shared = require("./shared-BdKmyM3n.cjs"); | ||
| //#region src/nodes/teslemetry-signal.ts | ||
@@ -65,4 +64,3 @@ function teslemetry_signal_default(RED) { | ||
| } | ||
| //#endregion | ||
| module.exports = teslemetry_signal_default; | ||
| module.exports = teslemetry_signal_default; |
@@ -1,4 +0,3 @@ | ||
| const require_shared = require('./shared-DlnhRLCp.cjs'); | ||
| const require_validation = require('./validation-Ctl8enVU.cjs'); | ||
| const require_shared = require("./shared-BdKmyM3n.cjs"); | ||
| const require_validation = require("./validation-Bcj5G3Yy.cjs"); | ||
| //#region src/nodes/teslemetry-vehicle-command.ts | ||
@@ -194,4 +193,3 @@ function teslemetry_vehicle_command_default(RED) { | ||
| } | ||
| //#endregion | ||
| module.exports = teslemetry_vehicle_command_default; | ||
| module.exports = teslemetry_vehicle_command_default; |
+3
-3
| { | ||
| "name": "@teslemetry/node-red-contrib-teslemetry", | ||
| "version": "0.2.1", | ||
| "version": "0.3.0", | ||
| "description": "Node-RED nodes for controlling Tesla vehicles and energy sites via Teslemetry API", | ||
@@ -54,4 +54,4 @@ "main": "dist/index.cjs", | ||
| "node-red-dev": "^0.1.6", | ||
| "tsdown": "^0.16.7", | ||
| "@teslemetry/api": "0.6.10" | ||
| "tsdown": "^0.22.4", | ||
| "@teslemetry/api": "0.9.0" | ||
| }, | ||
@@ -58,0 +58,0 @@ "scripts": { |
| //#region src/shared.ts | ||
| const instances = /* @__PURE__ */ new Map(); | ||
| /** | ||
| * Extract a useful error message from any error type. | ||
| * Handles Error objects, hey-api response objects, and plain objects. | ||
| */ | ||
| function getErrorMessage(error) { | ||
| if (!error) return "Unknown error"; | ||
| if (error instanceof Error) return error.message; | ||
| if (typeof error === "object") { | ||
| const obj = error; | ||
| if (typeof obj.error_description === "string") return obj.error_description; | ||
| if (typeof obj.error === "string") return obj.error; | ||
| if (typeof obj.message === "string") return obj.message; | ||
| if (obj.response && typeof obj.response === "object") { | ||
| const resp = obj.response; | ||
| if (typeof obj.error_description === "string") return obj.error_description; | ||
| if (typeof obj.error === "string") return obj.error; | ||
| if (resp.status) return `HTTP ${resp.status}: ${resp.statusText || "Error"}`; | ||
| } | ||
| try { | ||
| return JSON.stringify(error); | ||
| } catch { | ||
| return String(error); | ||
| } | ||
| } | ||
| return String(error); | ||
| } | ||
| /** | ||
| * Get instance and validate it exists. Sets error status on node if not found. | ||
| * @returns Instance or null if missing | ||
| */ | ||
| function getInstance(configId, node) { | ||
| const instance = instances.get(configId); | ||
| if (!instance) { | ||
| node.status({ | ||
| fill: "red", | ||
| shape: "ring", | ||
| text: "Config missing" | ||
| }); | ||
| node.error("No Teslemetry instance found"); | ||
| return null; | ||
| } | ||
| instance.products.finally(() => { | ||
| hasInstanceError(instance, node); | ||
| }); | ||
| return instance; | ||
| } | ||
| /** | ||
| * Check if instance has an error. Sets error status on node if so. | ||
| * @returns true if there's an error (caller should return early) | ||
| */ | ||
| function hasInstanceError(instance, node) { | ||
| if (instance.error) { | ||
| node.status({ | ||
| fill: "red", | ||
| shape: "ring", | ||
| text: "Error" | ||
| }); | ||
| node.error(`Teslemetry error: ${instance.error}`); | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| //#endregion | ||
| Object.defineProperty(exports, 'getErrorMessage', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return getErrorMessage; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'getInstance', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return getInstance; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'hasInstanceError', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return hasInstanceError; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'instances', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return instances; | ||
| } | ||
| }); |
| //#region src/validation.ts | ||
| function validateParameters(msg, rules) { | ||
| const errors = []; | ||
| for (const [paramName, rule] of Object.entries(rules)) { | ||
| const value = msg[paramName]; | ||
| if (rule.required && (value === void 0 || value === null || value === "")) { | ||
| errors.push(`Required parameter '${paramName}' is missing`); | ||
| continue; | ||
| } | ||
| if (value === void 0 || value === null || value === "") continue; | ||
| if (rule.type === "number") { | ||
| const numValue = Number(value); | ||
| if (isNaN(numValue)) { | ||
| errors.push(`Parameter '${paramName}' must be a valid number, got '${value}'`); | ||
| continue; | ||
| } | ||
| if (rule.integer && !Number.isInteger(numValue)) { | ||
| errors.push(`Parameter '${paramName}' must be an integer, got '${value}'`); | ||
| continue; | ||
| } | ||
| if (rule.min !== void 0 && numValue < rule.min) errors.push(`Parameter '${paramName}' must be at least ${rule.min}, got ${numValue}`); | ||
| if (rule.max !== void 0 && numValue > rule.max) errors.push(`Parameter '${paramName}' must be at most ${rule.max}, got ${numValue}`); | ||
| } else if (rule.type === "string") { | ||
| if (typeof value !== "string") { | ||
| errors.push(`Parameter '${paramName}' must be a string, got ${typeof value}`); | ||
| continue; | ||
| } | ||
| if (rule.allowedValues && !rule.allowedValues.includes(value)) errors.push(`Parameter '${paramName}' must be one of: ${rule.allowedValues.join(", ")}, got '${value}'`); | ||
| } else if (rule.type === "boolean") { | ||
| if (typeof value !== "boolean") errors.push(`Parameter '${paramName}' must be a boolean, got ${typeof value}`); | ||
| } | ||
| } | ||
| if (errors.length > 0) throw new Error(errors.join("; ")); | ||
| } | ||
| //#endregion | ||
| Object.defineProperty(exports, 'validateParameters', { | ||
| enumerable: true, | ||
| get: function () { | ||
| return validateParameters; | ||
| } | ||
| }); |
Sorry, the diff of this file is too big to display
219080
8.48%6579
9.36%