node-red-contrib-senec-cloud-v2 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +77 -0
- package/LICENSE +21 -0
- package/README.md +279 -0
- package/dist/lib/auth-manager.d.ts +63 -0
- package/dist/lib/auth-manager.d.ts.map +1 -0
- package/dist/lib/auth-manager.js +288 -0
- package/dist/lib/auth-manager.js.map +1 -0
- package/dist/lib/data-parser.d.ts +68 -0
- package/dist/lib/data-parser.d.ts.map +1 -0
- package/dist/lib/data-parser.js +197 -0
- package/dist/lib/data-parser.js.map +1 -0
- package/dist/lib/error-handler.d.ts +39 -0
- package/dist/lib/error-handler.d.ts.map +1 -0
- package/dist/lib/error-handler.js +139 -0
- package/dist/lib/error-handler.js.map +1 -0
- package/dist/lib/senec-api-client.d.ts +45 -0
- package/dist/lib/senec-api-client.d.ts.map +1 -0
- package/dist/lib/senec-api-client.js +145 -0
- package/dist/lib/senec-api-client.js.map +1 -0
- package/dist/nodes/senec-config.d.ts +2 -0
- package/dist/nodes/senec-config.d.ts.map +1 -0
- package/dist/nodes/senec-config.html +47 -0
- package/dist/nodes/senec-config.js +16 -0
- package/dist/nodes/senec-config.js.map +1 -0
- package/dist/nodes/senec-data.d.ts +2 -0
- package/dist/nodes/senec-data.d.ts.map +1 -0
- package/dist/nodes/senec-data.html +82 -0
- package/dist/nodes/senec-data.js +66 -0
- package/dist/nodes/senec-data.js.map +1 -0
- package/dist/nodes/senec-image.d.ts +2 -0
- package/dist/nodes/senec-image.d.ts.map +1 -0
- package/dist/nodes/senec-image.html +94 -0
- package/dist/nodes/senec-image.js +34 -0
- package/dist/nodes/senec-image.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Error Handler
|
|
4
|
+
*
|
|
5
|
+
* Centralized error handling with classification and retry logic.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.ErrorHandler = void 0;
|
|
9
|
+
class ErrorHandler {
|
|
10
|
+
/**
|
|
11
|
+
* Handle and classify an error
|
|
12
|
+
*/
|
|
13
|
+
handleError(error) {
|
|
14
|
+
const errorType = this.classifyError(error);
|
|
15
|
+
const shouldRetry = this.shouldRetry(error);
|
|
16
|
+
const retryDelay = shouldRetry ? this.getRetryDelay(1) : undefined;
|
|
17
|
+
return {
|
|
18
|
+
type: errorType,
|
|
19
|
+
message: this.getErrorMessage(error),
|
|
20
|
+
originalError: error,
|
|
21
|
+
shouldRetry,
|
|
22
|
+
retryDelay,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Classify error by type
|
|
27
|
+
*/
|
|
28
|
+
classifyError(error) {
|
|
29
|
+
if (this.isAxiosError(error)) {
|
|
30
|
+
const status = error.response?.status;
|
|
31
|
+
if (status === 401 || status === 403) {
|
|
32
|
+
return 'authentication';
|
|
33
|
+
}
|
|
34
|
+
if (status === 429) {
|
|
35
|
+
return 'rateLimit';
|
|
36
|
+
}
|
|
37
|
+
if (status && status >= 400 && status < 500) {
|
|
38
|
+
return 'client';
|
|
39
|
+
}
|
|
40
|
+
if (status && status >= 500) {
|
|
41
|
+
return 'server';
|
|
42
|
+
}
|
|
43
|
+
// Network errors, timeouts
|
|
44
|
+
if (error.code === 'ECONNABORTED' || error.code === 'ETIMEDOUT') {
|
|
45
|
+
return 'transient';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Default to transient for unknown errors
|
|
49
|
+
return 'transient';
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Determine if error should be retried
|
|
53
|
+
*/
|
|
54
|
+
shouldRetry(error) {
|
|
55
|
+
const errorType = this.classifyError(error);
|
|
56
|
+
switch (errorType) {
|
|
57
|
+
case 'transient':
|
|
58
|
+
case 'server':
|
|
59
|
+
case 'rateLimit':
|
|
60
|
+
return true;
|
|
61
|
+
case 'authentication':
|
|
62
|
+
// Authentication errors should trigger re-auth, not simple retry
|
|
63
|
+
return false;
|
|
64
|
+
case 'client':
|
|
65
|
+
// Client errors (bad request) should not be retried
|
|
66
|
+
return false;
|
|
67
|
+
default:
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Calculate retry delay with exponential backoff
|
|
73
|
+
* @param attempt - Retry attempt number (1-based)
|
|
74
|
+
*/
|
|
75
|
+
getRetryDelay(attempt) {
|
|
76
|
+
const delays = [
|
|
77
|
+
10000, // 10 seconds
|
|
78
|
+
30000, // 30 seconds
|
|
79
|
+
60000, // 1 minute
|
|
80
|
+
300000, // 5 minutes
|
|
81
|
+
];
|
|
82
|
+
const baseDelay = delays[Math.min(attempt - 1, delays.length - 1)];
|
|
83
|
+
// Add jitter (±20%)
|
|
84
|
+
const jitter = baseDelay * 0.2 * (Math.random() * 2 - 1);
|
|
85
|
+
return Math.floor(baseDelay + jitter);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get Retry-After header value if present (for rate limiting)
|
|
89
|
+
*/
|
|
90
|
+
getRetryAfter(error) {
|
|
91
|
+
const retryAfter = error.response?.headers['retry-after'];
|
|
92
|
+
if (!retryAfter) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
// Retry-After can be in seconds or HTTP date
|
|
96
|
+
const seconds = parseInt(retryAfter, 10);
|
|
97
|
+
if (!isNaN(seconds)) {
|
|
98
|
+
return seconds * 1000; // Convert to milliseconds
|
|
99
|
+
}
|
|
100
|
+
// Try parsing as date
|
|
101
|
+
const date = new Date(retryAfter);
|
|
102
|
+
if (!isNaN(date.getTime())) {
|
|
103
|
+
return Math.max(0, date.getTime() - Date.now());
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get user-friendly error message
|
|
109
|
+
*/
|
|
110
|
+
getErrorMessage(error) {
|
|
111
|
+
if (this.isAxiosError(error)) {
|
|
112
|
+
const status = error.response?.status;
|
|
113
|
+
if (status === 401) {
|
|
114
|
+
return 'Authentication failed. Please check your credentials.';
|
|
115
|
+
}
|
|
116
|
+
if (status === 429) {
|
|
117
|
+
return 'Rate limit exceeded. Please wait before retrying.';
|
|
118
|
+
}
|
|
119
|
+
if (status && status >= 500) {
|
|
120
|
+
return 'SENEC Cloud service error. Will retry automatically.';
|
|
121
|
+
}
|
|
122
|
+
if (error.code === 'ECONNABORTED' || error.code === 'ETIMEDOUT') {
|
|
123
|
+
return 'Connection timeout. Will retry automatically.';
|
|
124
|
+
}
|
|
125
|
+
if (error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED') {
|
|
126
|
+
return 'Cannot reach SENEC Cloud. Check your internet connection.';
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return error.message || 'Unknown error occurred';
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Type guard for AxiosError
|
|
133
|
+
*/
|
|
134
|
+
isAxiosError(error) {
|
|
135
|
+
return error.isAxiosError === true;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
exports.ErrorHandler = ErrorHandler;
|
|
139
|
+
//# sourceMappingURL=error-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/lib/error-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SENEC API Client
|
|
3
|
+
*
|
|
4
|
+
* Main API client for interacting with the SENEC Cloud App API
|
|
5
|
+
* (app-gateway.prod.senec.dev, in use since the August 2025 API change).
|
|
6
|
+
* Coordinates authentication, data retrieval, and error handling.
|
|
7
|
+
*/
|
|
8
|
+
import { SenecConfig, SenecData, ConnectionStatus } from '../types/senec';
|
|
9
|
+
export declare class SenecAPIClient {
|
|
10
|
+
private config;
|
|
11
|
+
private authManager;
|
|
12
|
+
private dataParser;
|
|
13
|
+
private errorHandler;
|
|
14
|
+
private httpClient;
|
|
15
|
+
private status;
|
|
16
|
+
private systemId;
|
|
17
|
+
private systemInfo;
|
|
18
|
+
constructor(config: SenecConfig);
|
|
19
|
+
/**
|
|
20
|
+
* Ensure a valid access token is available
|
|
21
|
+
*/
|
|
22
|
+
private ensureAuthenticated;
|
|
23
|
+
/**
|
|
24
|
+
* Get the ID of the first SENEC system associated with the account.
|
|
25
|
+
* The result is cached for subsequent calls.
|
|
26
|
+
*/
|
|
27
|
+
private getSystemId;
|
|
28
|
+
/**
|
|
29
|
+
* Get current energy data from SENEC Cloud
|
|
30
|
+
*/
|
|
31
|
+
getData(retried?: boolean): Promise<SenecData>;
|
|
32
|
+
/**
|
|
33
|
+
* Test connection to SENEC Cloud
|
|
34
|
+
*/
|
|
35
|
+
testConnection(): Promise<boolean>;
|
|
36
|
+
/**
|
|
37
|
+
* Get current connection status
|
|
38
|
+
*/
|
|
39
|
+
getStatus(): ConnectionStatus;
|
|
40
|
+
/**
|
|
41
|
+
* Disconnect and clear authentication
|
|
42
|
+
*/
|
|
43
|
+
disconnect(): void;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=senec-api-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"senec-api-client.d.ts","sourceRoot":"","sources":["../../src/lib/senec-api-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAO1E,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,MAAM,CAAoC;IAClD,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,UAAU,CAAa;gBAEnB,MAAM,EAAE,WAAW;IAwB/B;;OAEG;YACW,mBAAmB;IAgBjC;;;OAGG;YACW,WAAW;IAmBzB;;OAEG;IACG,OAAO,CAAC,OAAO,GAAE,OAAe,GAAG,OAAO,CAAC,SAAS,CAAC;IAyC3D;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAYxC;;OAEG;IACH,SAAS,IAAI,gBAAgB;IAI7B;;OAEG;IACH,UAAU,IAAI,IAAI;CAMnB"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SENEC API Client
|
|
4
|
+
*
|
|
5
|
+
* Main API client for interacting with the SENEC Cloud App API
|
|
6
|
+
* (app-gateway.prod.senec.dev, in use since the August 2025 API change).
|
|
7
|
+
* Coordinates authentication, data retrieval, and error handling.
|
|
8
|
+
*/
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.SenecAPIClient = void 0;
|
|
14
|
+
const axios_1 = __importDefault(require("axios"));
|
|
15
|
+
const auth_manager_1 = require("./auth-manager");
|
|
16
|
+
const data_parser_1 = require("./data-parser");
|
|
17
|
+
const error_handler_1 = require("./error-handler");
|
|
18
|
+
const API_BASE = 'https://app-gateway.prod.senec.dev';
|
|
19
|
+
class SenecAPIClient {
|
|
20
|
+
constructor(config) {
|
|
21
|
+
this.status = 'disconnected';
|
|
22
|
+
this.systemId = null;
|
|
23
|
+
this.systemInfo = null;
|
|
24
|
+
this.config = {
|
|
25
|
+
timeout: 30000,
|
|
26
|
+
retryAttempts: 3,
|
|
27
|
+
retryDelay: 10000,
|
|
28
|
+
...config,
|
|
29
|
+
};
|
|
30
|
+
this.authManager = new auth_manager_1.AuthenticationManager({
|
|
31
|
+
username: config.username,
|
|
32
|
+
password: config.password,
|
|
33
|
+
});
|
|
34
|
+
this.dataParser = new data_parser_1.DataParser();
|
|
35
|
+
this.errorHandler = new error_handler_1.ErrorHandler();
|
|
36
|
+
this.httpClient = axios_1.default.create({
|
|
37
|
+
timeout: this.config.timeout,
|
|
38
|
+
headers: {
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Ensure a valid access token is available
|
|
45
|
+
*/
|
|
46
|
+
async ensureAuthenticated() {
|
|
47
|
+
if (!this.authManager.isTokenValid()) {
|
|
48
|
+
if (this.authManager.canRefresh()) {
|
|
49
|
+
await this.authManager.refreshToken();
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
await this.authManager.authenticate();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const token = this.authManager.getToken();
|
|
56
|
+
if (!token) {
|
|
57
|
+
throw new Error('No authentication token available');
|
|
58
|
+
}
|
|
59
|
+
return token;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get the ID of the first SENEC system associated with the account.
|
|
63
|
+
* The result is cached for subsequent calls.
|
|
64
|
+
*/
|
|
65
|
+
async getSystemId(token) {
|
|
66
|
+
if (this.systemId) {
|
|
67
|
+
return this.systemId;
|
|
68
|
+
}
|
|
69
|
+
const response = await this.httpClient.get(`${API_BASE}/v1/senec/anlagen`, {
|
|
70
|
+
headers: { authorization: `Bearer ${token}` },
|
|
71
|
+
});
|
|
72
|
+
const systems = Array.isArray(response.data) ? response.data : [];
|
|
73
|
+
if (systems.length === 0 || !systems[0].id) {
|
|
74
|
+
throw new Error('No SENEC system found for this account');
|
|
75
|
+
}
|
|
76
|
+
this.systemId = String(systems[0].id);
|
|
77
|
+
this.systemInfo = systems[0];
|
|
78
|
+
return this.systemId;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Get current energy data from SENEC Cloud
|
|
82
|
+
*/
|
|
83
|
+
async getData(retried = false) {
|
|
84
|
+
try {
|
|
85
|
+
const token = await this.ensureAuthenticated();
|
|
86
|
+
const systemId = await this.getSystemId(token);
|
|
87
|
+
const response = await this.httpClient.get(`${API_BASE}/v2/senec/systems/${systemId}/dashboard`, {
|
|
88
|
+
headers: { authorization: `Bearer ${token}` },
|
|
89
|
+
});
|
|
90
|
+
this.status = 'connected';
|
|
91
|
+
// Parse and validate data
|
|
92
|
+
const data = this.dataParser.parseEnergyData(response.data, this.systemInfo);
|
|
93
|
+
const validation = this.dataParser.validateData(data);
|
|
94
|
+
if (!validation.valid) {
|
|
95
|
+
console.warn('Data validation errors:', validation.errors);
|
|
96
|
+
}
|
|
97
|
+
if (validation.warnings.length > 0) {
|
|
98
|
+
console.warn('Data validation warnings:', validation.warnings);
|
|
99
|
+
}
|
|
100
|
+
return data;
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
this.status = 'error';
|
|
104
|
+
const handledError = this.errorHandler.handleError(error);
|
|
105
|
+
// If it's an authentication error, clear token and retry once
|
|
106
|
+
if (handledError.type === 'authentication' && !retried) {
|
|
107
|
+
this.authManager.clearToken();
|
|
108
|
+
return this.getData(true);
|
|
109
|
+
}
|
|
110
|
+
throw new Error(handledError.message);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Test connection to SENEC Cloud
|
|
115
|
+
*/
|
|
116
|
+
async testConnection() {
|
|
117
|
+
try {
|
|
118
|
+
this.status = 'connecting';
|
|
119
|
+
await this.authManager.authenticate();
|
|
120
|
+
this.status = 'connected';
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
this.status = 'error';
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Get current connection status
|
|
130
|
+
*/
|
|
131
|
+
getStatus() {
|
|
132
|
+
return this.status;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Disconnect and clear authentication
|
|
136
|
+
*/
|
|
137
|
+
disconnect() {
|
|
138
|
+
this.authManager.clearToken();
|
|
139
|
+
this.systemId = null;
|
|
140
|
+
this.systemInfo = null;
|
|
141
|
+
this.status = 'disconnected';
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
exports.SenecAPIClient = SenecAPIClient;
|
|
145
|
+
//# sourceMappingURL=senec-api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"senec-api-client.js","sourceRoot":"","sources":["../../src/lib/senec-api-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"senec-config.d.ts","sourceRoot":"","sources":["../../src/nodes/senec-config.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('senec-config', {
|
|
3
|
+
category: 'config',
|
|
4
|
+
defaults: {
|
|
5
|
+
name: { value: '' },
|
|
6
|
+
username: { value: '', required: true }
|
|
7
|
+
},
|
|
8
|
+
credentials: {
|
|
9
|
+
password: { type: 'password' }
|
|
10
|
+
},
|
|
11
|
+
label: function() {
|
|
12
|
+
return this.name || 'SENEC Cloud Config';
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<script type="text/html" data-template-name="senec-config">
|
|
18
|
+
<div class="form-row">
|
|
19
|
+
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
20
|
+
<input type="text" id="node-config-input-name" placeholder="SENEC Cloud">
|
|
21
|
+
</div>
|
|
22
|
+
<div class="form-row">
|
|
23
|
+
<label for="node-config-input-username"><i class="fa fa-user"></i> Username</label>
|
|
24
|
+
<input type="text" id="node-config-input-username" placeholder="your@email.com">
|
|
25
|
+
</div>
|
|
26
|
+
<div class="form-row">
|
|
27
|
+
<label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label>
|
|
28
|
+
<input type="password" id="node-config-input-password">
|
|
29
|
+
</div>
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<script type="text/html" data-help-name="senec-config">
|
|
33
|
+
<p>Configuration node for SENEC Cloud API access.</p>
|
|
34
|
+
|
|
35
|
+
<h3>Configuration</h3>
|
|
36
|
+
<dl class="message-properties">
|
|
37
|
+
<dt>Username <span class="property-type">string</span></dt>
|
|
38
|
+
<dd>Your SENEC Cloud account email address</dd>
|
|
39
|
+
|
|
40
|
+
<dt>Password <span class="property-type">string</span></dt>
|
|
41
|
+
<dd>Your SENEC Cloud account password</dd>
|
|
42
|
+
</dl>
|
|
43
|
+
|
|
44
|
+
<h3>Details</h3>
|
|
45
|
+
<p>This configuration node stores your SENEC Cloud credentials securely.
|
|
46
|
+
It is used by the senec-data and senec-image nodes to authenticate with the SENEC Cloud API.</p>
|
|
47
|
+
</script>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
module.exports = function (RED) {
|
|
4
|
+
function SenecConfigNode(config) {
|
|
5
|
+
RED.nodes.createNode(this, config);
|
|
6
|
+
this.username = config.username;
|
|
7
|
+
// Credentials are stored separately by Node-RED
|
|
8
|
+
// Access via this.credentials.password
|
|
9
|
+
}
|
|
10
|
+
RED.nodes.registerType('senec-config', SenecConfigNode, {
|
|
11
|
+
credentials: {
|
|
12
|
+
password: { type: 'password' }
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=senec-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"senec-config.js","sourceRoot":"","sources":["../../src/nodes/senec-config.ts"],"names":[],"mappings":";;AAgBA,MAAM,CAAC,OAAO,GAAG,UAAS,GAAQ;IAChC,SAAS,eAAe,CAAwB,MAA0B;QACxE,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAEnC,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QAEhC,gDAAgD;QAChD,uCAAuC;IACzC,CAAC;IAED,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,eAAe,EAAE;QACtD,WAAW,EAAE;YACX,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;SAC/B;KACF,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"senec-data.d.ts","sourceRoot":"","sources":["../../src/nodes/senec-data.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('senec-data', {
|
|
3
|
+
category: 'SENEC',
|
|
4
|
+
color: '#00A0E3',
|
|
5
|
+
defaults: {
|
|
6
|
+
name: { value: '' },
|
|
7
|
+
config: { value: '', type: 'senec-config', required: true },
|
|
8
|
+
interval: { value: 0, validate: RED.validators.number() }
|
|
9
|
+
},
|
|
10
|
+
inputs: 1,
|
|
11
|
+
outputs: 1,
|
|
12
|
+
icon: 'font-awesome/fa-solar-panel',
|
|
13
|
+
label: function() {
|
|
14
|
+
return this.name || 'SENEC Data';
|
|
15
|
+
},
|
|
16
|
+
labelStyle: function() {
|
|
17
|
+
return this.name ? 'node_label_italic' : '';
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<script type="text/html" data-template-name="senec-data">
|
|
23
|
+
<div class="form-row">
|
|
24
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
25
|
+
<input type="text" id="node-input-name" placeholder="SENEC Data">
|
|
26
|
+
</div>
|
|
27
|
+
<div class="form-row">
|
|
28
|
+
<label for="node-input-config"><i class="fa fa-cog"></i> Config</label>
|
|
29
|
+
<input type="text" id="node-input-config">
|
|
30
|
+
</div>
|
|
31
|
+
<div class="form-row">
|
|
32
|
+
<label for="node-input-interval"><i class="fa fa-clock-o"></i> Interval (s)</label>
|
|
33
|
+
<input type="number" id="node-input-interval" placeholder="0 = manual only" min="0">
|
|
34
|
+
</div>
|
|
35
|
+
<div class="form-tips">
|
|
36
|
+
<p><b>Tip:</b> Set interval to 0 to fetch data only on input message.
|
|
37
|
+
For automatic polling, set interval in seconds (e.g., 60 for every minute).</p>
|
|
38
|
+
</div>
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<script type="text/html" data-help-name="senec-data">
|
|
42
|
+
<p>Fetches data from SENEC Cloud API.</p>
|
|
43
|
+
|
|
44
|
+
<h3>Inputs</h3>
|
|
45
|
+
<dl class="message-properties">
|
|
46
|
+
<dt>payload <span class="property-type">any</span></dt>
|
|
47
|
+
<dd>Any input triggers a data fetch</dd>
|
|
48
|
+
</dl>
|
|
49
|
+
|
|
50
|
+
<h3>Outputs</h3>
|
|
51
|
+
<dl class="message-properties">
|
|
52
|
+
<dt>payload <span class="property-type">object</span></dt>
|
|
53
|
+
<dd>Parsed SENEC system data including battery, grid, solar, and consumption values</dd>
|
|
54
|
+
|
|
55
|
+
<dt>topic <span class="property-type">string</span></dt>
|
|
56
|
+
<dd>Set to "senec/data"</dd>
|
|
57
|
+
</dl>
|
|
58
|
+
|
|
59
|
+
<h3>Configuration</h3>
|
|
60
|
+
<dl class="message-properties">
|
|
61
|
+
<dt>Config</dt>
|
|
62
|
+
<dd>SENEC Cloud configuration node with credentials</dd>
|
|
63
|
+
|
|
64
|
+
<dt>Interval</dt>
|
|
65
|
+
<dd>Automatic polling interval in seconds. Set to 0 to disable automatic polling.</dd>
|
|
66
|
+
</dl>
|
|
67
|
+
|
|
68
|
+
<h3>Details</h3>
|
|
69
|
+
<p>This node fetches current data from your SENEC system via the SENEC Cloud API.</p>
|
|
70
|
+
<p>You can trigger data fetching manually by sending any message to the input,
|
|
71
|
+
or configure automatic polling by setting an interval.</p>
|
|
72
|
+
|
|
73
|
+
<h3>Output Format</h3>
|
|
74
|
+
<p>The output payload contains:</p>
|
|
75
|
+
<ul>
|
|
76
|
+
<li><code>battery</code> - Battery status (charge level, power, state)</li>
|
|
77
|
+
<li><code>grid</code> - Grid connection data (power, state)</li>
|
|
78
|
+
<li><code>solar</code> - Solar production data</li>
|
|
79
|
+
<li><code>consumption</code> - House consumption data</li>
|
|
80
|
+
<li><code>timestamp</code> - Data timestamp</li>
|
|
81
|
+
</ul>
|
|
82
|
+
</script>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const senec_api_client_1 = require("../lib/senec-api-client");
|
|
4
|
+
module.exports = function (RED) {
|
|
5
|
+
function SenecDataNode(config) {
|
|
6
|
+
RED.nodes.createNode(this, config);
|
|
7
|
+
const node = this;
|
|
8
|
+
node.timer = null;
|
|
9
|
+
node.apiClient = null;
|
|
10
|
+
// Get config node
|
|
11
|
+
const configNode = RED.nodes.getNode(config.config);
|
|
12
|
+
if (!configNode) {
|
|
13
|
+
node.error('Missing SENEC configuration');
|
|
14
|
+
node.status({ fill: 'red', shape: 'ring', text: 'no config' });
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
// Initialize API client
|
|
18
|
+
try {
|
|
19
|
+
node.apiClient = new senec_api_client_1.SenecAPIClient({
|
|
20
|
+
username: configNode.username,
|
|
21
|
+
password: configNode.credentials.password
|
|
22
|
+
});
|
|
23
|
+
node.status({ fill: 'green', shape: 'dot', text: 'ready' });
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
node.error('Failed to initialize API client: ' + error);
|
|
27
|
+
node.status({ fill: 'red', shape: 'ring', text: 'error' });
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// Fetch data function
|
|
31
|
+
async function fetchData() {
|
|
32
|
+
if (!node.apiClient)
|
|
33
|
+
return;
|
|
34
|
+
try {
|
|
35
|
+
node.status({ fill: 'blue', shape: 'dot', text: 'fetching...' });
|
|
36
|
+
const parsedData = await node.apiClient.getData();
|
|
37
|
+
node.send({
|
|
38
|
+
payload: parsedData,
|
|
39
|
+
topic: 'senec/data'
|
|
40
|
+
});
|
|
41
|
+
node.status({ fill: 'green', shape: 'dot', text: 'success' });
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
node.error('Failed to fetch data: ' + error.message);
|
|
45
|
+
node.status({ fill: 'red', shape: 'ring', text: 'error' });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Handle input messages
|
|
49
|
+
node.on('input', async function (_msg) {
|
|
50
|
+
await fetchData();
|
|
51
|
+
});
|
|
52
|
+
// Setup polling if interval is set
|
|
53
|
+
if (config.interval && config.interval > 0) {
|
|
54
|
+
node.timer = setInterval(fetchData, config.interval * 1000);
|
|
55
|
+
}
|
|
56
|
+
// Cleanup on close
|
|
57
|
+
node.on('close', function () {
|
|
58
|
+
if (node.timer) {
|
|
59
|
+
clearInterval(node.timer);
|
|
60
|
+
node.timer = null;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
RED.nodes.registerType('senec-data', SenecDataNode);
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=senec-data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"senec-data.js","sourceRoot":"","sources":["../../src/nodes/senec-data.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"senec-image.d.ts","sourceRoot":"","sources":["../../src/nodes/senec-image.ts"],"names":[],"mappings":""}
|