homebridge-solaxcloud-api 2.4.1 → 2.5.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 +164 -150
- package/LICENSE +175 -175
- package/README.md +196 -196
- package/config.sample +15 -15
- package/config.schema.json +113 -113
- package/dist/batteryAccessory.d.ts +1 -1
- package/dist/batteryAccessory.d.ts.map +1 -1
- package/dist/batteryAccessory.js +17 -17
- package/dist/batteryAccessory.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/lightSensorAccessory.d.ts +23 -16
- package/dist/lightSensorAccessory.d.ts.map +1 -1
- package/dist/lightSensorAccessory.js +109 -32
- package/dist/lightSensorAccessory.js.map +1 -1
- package/dist/motionAccessory.d.ts +1 -2
- package/dist/motionAccessory.d.ts.map +1 -1
- package/dist/motionAccessory.js +17 -20
- package/dist/motionAccessory.js.map +1 -1
- package/dist/outletAccessory.d.ts +1 -1
- package/dist/outletAccessory.d.ts.map +1 -1
- package/dist/outletAccessory.js +49 -34
- package/dist/outletAccessory.js.map +1 -1
- package/dist/platform.d.ts +1 -1
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +30 -27
- package/dist/platform.js.map +1 -1
- package/dist/platformAccessory.d.ts.map +1 -1
- package/dist/platformAccessory.js +40 -18
- package/dist/platformAccessory.js.map +1 -1
- package/dist/platformInverter.d.ts.map +1 -1
- package/dist/platformInverter.js +129 -69
- package/dist/platformInverter.js.map +1 -1
- package/dist/platformMeters.d.ts +2 -2
- package/dist/platformMeters.d.ts.map +1 -1
- package/dist/platformMeters.js +1 -2
- package/dist/settings.js +2 -5
- package/dist/settings.js.map +1 -1
- package/dist/solaxcloudfetch.js +14 -19
- package/dist/solaxcloudfetch.js.map +1 -1
- package/dist/statistics.js +1 -5
- package/dist/statistics.js.map +1 -1
- package/dist/util.js +1 -5
- package/dist/util.js.map +1 -1
- package/package.json +59 -55
- package/test/batteryAccessory.test.ts +16 -16
- package/test/helpers.ts +80 -36
- package/test/lightSensorAccessory.test.ts +73 -28
- package/test/motionAccessory.test.ts +36 -36
- package/test/outletAccessory.test.ts +75 -75
- package/test/platformAccessory.test.ts +24 -24
- package/test/platformConfig.test.ts +188 -188
- package/test/platformTotalizer.test.ts +123 -97
- package/test/statistics.test.ts +50 -50
|
@@ -1,188 +1,188 @@
|
|
|
1
|
-
import { Logging, PlatformConfig } from 'homebridge';
|
|
2
|
-
|
|
3
|
-
import assert
|
|
4
|
-
|
|
5
|
-
import { SolaxCloudAPIPlatform } from '../src/platform';
|
|
6
|
-
|
|
7
|
-
interface TestLog extends Logging {
|
|
8
|
-
errors: string[];
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function createLog(): TestLog {
|
|
12
|
-
const noop = () => undefined;
|
|
13
|
-
const log = Object.assign(noop, {
|
|
14
|
-
debug: noop,
|
|
15
|
-
info: noop,
|
|
16
|
-
warn: noop,
|
|
17
|
-
log: noop,
|
|
18
|
-
prefix: '',
|
|
19
|
-
errors: [] as string[],
|
|
20
|
-
error(message: string) {
|
|
21
|
-
this.errors.push(message);
|
|
22
|
-
},
|
|
23
|
-
}) as unknown as TestLog;
|
|
24
|
-
|
|
25
|
-
return log;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function createConfig(pollingFrequency = 300): PlatformConfig {
|
|
29
|
-
return {
|
|
30
|
-
platform: 'SolaxCloudAPI',
|
|
31
|
-
inverters: [
|
|
32
|
-
{
|
|
33
|
-
brand: 'solax',
|
|
34
|
-
tokenId: '20200722185111234567890',
|
|
35
|
-
name: 'Test inverter',
|
|
36
|
-
sn: 'ABCDEFGHIJ',
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
pollingFrequency,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function createPlatformForConfigCheck(log: Logging): SolaxCloudAPIPlatform {
|
|
44
|
-
const platform = Object.create(SolaxCloudAPIPlatform.prototype);
|
|
45
|
-
|
|
46
|
-
platform.log = log;
|
|
47
|
-
|
|
48
|
-
return platform as SolaxCloudAPIPlatform;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
describe('SolaxCloudAPIPlatform config checks', () => {
|
|
52
|
-
[
|
|
53
|
-
{
|
|
54
|
-
name: 'missing inverters',
|
|
55
|
-
config: { platform: 'SolaxCloudAPI' } as PlatformConfig,
|
|
56
|
-
error: 'mandatory parameter "inverters"',
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
name: 'non-array inverters',
|
|
60
|
-
config: { ...createConfig(), inverters: 'invalid' },
|
|
61
|
-
error: 'Incorrect type for mandatory parameter "inverters"',
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
name: 'inverter missing mandatory fields',
|
|
65
|
-
config: { ...createConfig(), inverters: [{ brand: 'solax', name: 'Test inverter', sn: 'ABCDEFGHIJ' }] },
|
|
66
|
-
error: 'Invalid type for inverter under "inverters"',
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
name: 'null inverter entry',
|
|
70
|
-
config: { ...createConfig(), inverters: [null] },
|
|
71
|
-
error: 'Invalid type for inverter under "inverters"',
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
name: 'unsupported inverter brand',
|
|
75
|
-
config: {
|
|
76
|
-
...createConfig(),
|
|
77
|
-
inverters: [
|
|
78
|
-
{
|
|
79
|
-
brand: 'unsupported',
|
|
80
|
-
tokenId: '20200722185111234567890',
|
|
81
|
-
name: 'Test inverter',
|
|
82
|
-
sn: 'ABCDEFGHIJ',
|
|
83
|
-
},
|
|
84
|
-
],
|
|
85
|
-
},
|
|
86
|
-
error: 'Invalid type for inverter under "inverters"',
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
name: 'duplicate inverter names',
|
|
90
|
-
config: {
|
|
91
|
-
...createConfig(),
|
|
92
|
-
inverters: [
|
|
93
|
-
{
|
|
94
|
-
brand: 'solax',
|
|
95
|
-
tokenId: '20200722185111234567890',
|
|
96
|
-
name: 'Test inverter',
|
|
97
|
-
sn: 'ABCDEFGHIJ',
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
brand: 'qcells',
|
|
101
|
-
tokenId: '20200722185111234567891',
|
|
102
|
-
name: 'Test inverter',
|
|
103
|
-
sn: 'KLMNOPQRST',
|
|
104
|
-
},
|
|
105
|
-
],
|
|
106
|
-
},
|
|
107
|
-
error: 'Duplicate inverter names',
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
name: 'duplicate inverter serial numbers',
|
|
111
|
-
config: {
|
|
112
|
-
...createConfig(),
|
|
113
|
-
inverters: [
|
|
114
|
-
{
|
|
115
|
-
brand: 'solax',
|
|
116
|
-
tokenId: '20200722185111234567890',
|
|
117
|
-
name: 'Test inverter 1',
|
|
118
|
-
sn: 'ABCDEFGHIJ',
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
brand: 'qcells',
|
|
122
|
-
tokenId: '20200722185111234567891',
|
|
123
|
-
name: 'Test inverter 2',
|
|
124
|
-
sn: 'ABCDEFGHIJ',
|
|
125
|
-
},
|
|
126
|
-
],
|
|
127
|
-
},
|
|
128
|
-
error: 'Duplicate inverter SNs',
|
|
129
|
-
},
|
|
130
|
-
].forEach(testCase => {
|
|
131
|
-
it(`rejects invalid config: ${testCase.name}`, () => {
|
|
132
|
-
const log = createLog();
|
|
133
|
-
const platform = createPlatformForConfigCheck(log);
|
|
134
|
-
|
|
135
|
-
assert.equal(platform['checkConfig'](testCase.config as PlatformConfig), false);
|
|
136
|
-
assert.equal(log.errors.length, 1);
|
|
137
|
-
assert.match(log.errors[0], new RegExp(testCase.error));
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it('rejects polling frequencies that would produce an empty smoothing window', () => {
|
|
142
|
-
const log = createLog();
|
|
143
|
-
const platform = createPlatformForConfigCheck(log);
|
|
144
|
-
const config = createConfig(901);
|
|
145
|
-
|
|
146
|
-
assert.throws(
|
|
147
|
-
() => platform['checkConfig'](config),
|
|
148
|
-
/Polling frequency cannot be higher than 900 seconds/,
|
|
149
|
-
);
|
|
150
|
-
assert.equal(log.errors.length, 1);
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
it('accepts the largest polling frequency that keeps one smoothing period', () => {
|
|
154
|
-
const log = createLog();
|
|
155
|
-
const platform = createPlatformForConfigCheck(log);
|
|
156
|
-
const config = createConfig(900);
|
|
157
|
-
|
|
158
|
-
assert.equal(platform['checkConfig'](config), true);
|
|
159
|
-
assert.equal(config.pollingFrequency, 900);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('defaults history to enabled when not configured', () => {
|
|
163
|
-
const log = createLog();
|
|
164
|
-
const platform = createPlatformForConfigCheck(log);
|
|
165
|
-
const config = createConfig();
|
|
166
|
-
|
|
167
|
-
assert.equal(platform['checkConfig'](config), true);
|
|
168
|
-
assert.equal(config.enableHistory, true);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
it('keeps history disabled when configured', () => {
|
|
172
|
-
const log = createLog();
|
|
173
|
-
const platform = createPlatformForConfigCheck(log);
|
|
174
|
-
const config = { ...createConfig(), enableHistory: false };
|
|
175
|
-
|
|
176
|
-
assert.equal(platform['checkConfig'](config), true);
|
|
177
|
-
assert.equal(config.enableHistory, false);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('defaults invalid history config to enabled', () => {
|
|
181
|
-
const log = createLog();
|
|
182
|
-
const platform = createPlatformForConfigCheck(log);
|
|
183
|
-
const config = { ...createConfig(), enableHistory: 'invalid' };
|
|
184
|
-
|
|
185
|
-
assert.equal(platform['checkConfig'](config), true);
|
|
186
|
-
assert.equal(config.enableHistory, true);
|
|
187
|
-
});
|
|
188
|
-
});
|
|
1
|
+
import { Logging, PlatformConfig } from 'homebridge';
|
|
2
|
+
|
|
3
|
+
import assert from 'assert';
|
|
4
|
+
|
|
5
|
+
import { SolaxCloudAPIPlatform } from '../src/platform.js';
|
|
6
|
+
|
|
7
|
+
interface TestLog extends Logging {
|
|
8
|
+
errors: string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function createLog(): TestLog {
|
|
12
|
+
const noop = () => undefined;
|
|
13
|
+
const log = Object.assign(noop, {
|
|
14
|
+
debug: noop,
|
|
15
|
+
info: noop,
|
|
16
|
+
warn: noop,
|
|
17
|
+
log: noop,
|
|
18
|
+
prefix: '',
|
|
19
|
+
errors: [] as string[],
|
|
20
|
+
error(message: string) {
|
|
21
|
+
this.errors.push(message);
|
|
22
|
+
},
|
|
23
|
+
}) as unknown as TestLog;
|
|
24
|
+
|
|
25
|
+
return log;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function createConfig(pollingFrequency = 300): PlatformConfig {
|
|
29
|
+
return {
|
|
30
|
+
platform: 'SolaxCloudAPI',
|
|
31
|
+
inverters: [
|
|
32
|
+
{
|
|
33
|
+
brand: 'solax',
|
|
34
|
+
tokenId: '20200722185111234567890',
|
|
35
|
+
name: 'Test inverter',
|
|
36
|
+
sn: 'ABCDEFGHIJ',
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
pollingFrequency,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function createPlatformForConfigCheck(log: Logging): SolaxCloudAPIPlatform {
|
|
44
|
+
const platform = Object.create(SolaxCloudAPIPlatform.prototype);
|
|
45
|
+
|
|
46
|
+
platform.log = log;
|
|
47
|
+
|
|
48
|
+
return platform as SolaxCloudAPIPlatform;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
describe('SolaxCloudAPIPlatform config checks', () => {
|
|
52
|
+
[
|
|
53
|
+
{
|
|
54
|
+
name: 'missing inverters',
|
|
55
|
+
config: { platform: 'SolaxCloudAPI' } as PlatformConfig,
|
|
56
|
+
error: 'mandatory parameter "inverters"',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'non-array inverters',
|
|
60
|
+
config: { ...createConfig(), inverters: 'invalid' },
|
|
61
|
+
error: 'Incorrect type for mandatory parameter "inverters"',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'inverter missing mandatory fields',
|
|
65
|
+
config: { ...createConfig(), inverters: [{ brand: 'solax', name: 'Test inverter', sn: 'ABCDEFGHIJ' }] },
|
|
66
|
+
error: 'Invalid type for inverter under "inverters"',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'null inverter entry',
|
|
70
|
+
config: { ...createConfig(), inverters: [null] },
|
|
71
|
+
error: 'Invalid type for inverter under "inverters"',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'unsupported inverter brand',
|
|
75
|
+
config: {
|
|
76
|
+
...createConfig(),
|
|
77
|
+
inverters: [
|
|
78
|
+
{
|
|
79
|
+
brand: 'unsupported',
|
|
80
|
+
tokenId: '20200722185111234567890',
|
|
81
|
+
name: 'Test inverter',
|
|
82
|
+
sn: 'ABCDEFGHIJ',
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
error: 'Invalid type for inverter under "inverters"',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: 'duplicate inverter names',
|
|
90
|
+
config: {
|
|
91
|
+
...createConfig(),
|
|
92
|
+
inverters: [
|
|
93
|
+
{
|
|
94
|
+
brand: 'solax',
|
|
95
|
+
tokenId: '20200722185111234567890',
|
|
96
|
+
name: 'Test inverter',
|
|
97
|
+
sn: 'ABCDEFGHIJ',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
brand: 'qcells',
|
|
101
|
+
tokenId: '20200722185111234567891',
|
|
102
|
+
name: 'Test inverter',
|
|
103
|
+
sn: 'KLMNOPQRST',
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
error: 'Duplicate inverter names',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: 'duplicate inverter serial numbers',
|
|
111
|
+
config: {
|
|
112
|
+
...createConfig(),
|
|
113
|
+
inverters: [
|
|
114
|
+
{
|
|
115
|
+
brand: 'solax',
|
|
116
|
+
tokenId: '20200722185111234567890',
|
|
117
|
+
name: 'Test inverter 1',
|
|
118
|
+
sn: 'ABCDEFGHIJ',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
brand: 'qcells',
|
|
122
|
+
tokenId: '20200722185111234567891',
|
|
123
|
+
name: 'Test inverter 2',
|
|
124
|
+
sn: 'ABCDEFGHIJ',
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
error: 'Duplicate inverter SNs',
|
|
129
|
+
},
|
|
130
|
+
].forEach(testCase => {
|
|
131
|
+
it(`rejects invalid config: ${testCase.name}`, () => {
|
|
132
|
+
const log = createLog();
|
|
133
|
+
const platform = createPlatformForConfigCheck(log);
|
|
134
|
+
|
|
135
|
+
assert.equal(platform['checkConfig'](testCase.config as PlatformConfig), false);
|
|
136
|
+
assert.equal(log.errors.length, 1);
|
|
137
|
+
assert.match(log.errors[0], new RegExp(testCase.error));
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('rejects polling frequencies that would produce an empty smoothing window', () => {
|
|
142
|
+
const log = createLog();
|
|
143
|
+
const platform = createPlatformForConfigCheck(log);
|
|
144
|
+
const config = createConfig(901);
|
|
145
|
+
|
|
146
|
+
assert.throws(
|
|
147
|
+
() => platform['checkConfig'](config),
|
|
148
|
+
/Polling frequency cannot be higher than 900 seconds/,
|
|
149
|
+
);
|
|
150
|
+
assert.equal(log.errors.length, 1);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('accepts the largest polling frequency that keeps one smoothing period', () => {
|
|
154
|
+
const log = createLog();
|
|
155
|
+
const platform = createPlatformForConfigCheck(log);
|
|
156
|
+
const config = createConfig(900);
|
|
157
|
+
|
|
158
|
+
assert.equal(platform['checkConfig'](config), true);
|
|
159
|
+
assert.equal(config.pollingFrequency, 900);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('defaults history to enabled when not configured', () => {
|
|
163
|
+
const log = createLog();
|
|
164
|
+
const platform = createPlatformForConfigCheck(log);
|
|
165
|
+
const config = createConfig();
|
|
166
|
+
|
|
167
|
+
assert.equal(platform['checkConfig'](config), true);
|
|
168
|
+
assert.equal(config.enableHistory, true);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('keeps history disabled when configured', () => {
|
|
172
|
+
const log = createLog();
|
|
173
|
+
const platform = createPlatformForConfigCheck(log);
|
|
174
|
+
const config = { ...createConfig(), enableHistory: false };
|
|
175
|
+
|
|
176
|
+
assert.equal(platform['checkConfig'](config), true);
|
|
177
|
+
assert.equal(config.enableHistory, false);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('defaults invalid history config to enabled', () => {
|
|
181
|
+
const log = createLog();
|
|
182
|
+
const platform = createPlatformForConfigCheck(log);
|
|
183
|
+
const config = { ...createConfig(), enableHistory: 'invalid' };
|
|
184
|
+
|
|
185
|
+
assert.equal(platform['checkConfig'](config), true);
|
|
186
|
+
assert.equal(config.enableHistory, true);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
@@ -1,97 +1,123 @@
|
|
|
1
|
-
import { API, Logging, PlatformConfig } from 'homebridge';
|
|
2
|
-
|
|
3
|
-
import assert
|
|
4
|
-
|
|
5
|
-
import { SolaxCloudAPIPlatform } from '../src/platform';
|
|
6
|
-
import { SolaxCloudAPIPlatformInverter } from '../src/platformInverter';
|
|
7
|
-
import { createApi, createLog } from './helpers';
|
|
8
|
-
|
|
9
|
-
interface InverterCreation {
|
|
10
|
-
brand: number;
|
|
11
|
-
tokenId: string;
|
|
12
|
-
sn: string;
|
|
13
|
-
name: string;
|
|
14
|
-
hasBattery: boolean;
|
|
15
|
-
smoothingWindow: number;
|
|
16
|
-
virtual: boolean;
|
|
17
|
-
brandName?: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
let inverterCreations: InverterCreation[] = [];
|
|
21
|
-
|
|
22
|
-
class TestSolaxCloudAPIPlatform extends SolaxCloudAPIPlatform {
|
|
23
|
-
protected createPlatformInverter(log: Logging, config: PlatformConfig, api: API,
|
|
24
|
-
brand: number, tokenId: string, sn: string,
|
|
25
|
-
name: string, hasBattery: boolean,
|
|
26
|
-
smoothingWindow: number,
|
|
27
|
-
virtual = false,
|
|
28
|
-
brandName?: string): SolaxCloudAPIPlatformInverter {
|
|
29
|
-
inverterCreations.push({ brand, tokenId, sn, name, hasBattery, smoothingWindow, virtual, brandName });
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
getAccessories: () => [],
|
|
33
|
-
hasBattery: () => hasBattery,
|
|
34
|
-
} as unknown as SolaxCloudAPIPlatformInverter;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
protected async fetchDataPeriodically(): Promise<void> {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function createConfig(brands: string[]): PlatformConfig {
|
|
43
|
-
return {
|
|
44
|
-
platform: 'SolaxCloudAPI',
|
|
45
|
-
pollingFrequency: 300,
|
|
46
|
-
inverters: brands.map((brand, index) => ({
|
|
47
|
-
brand,
|
|
48
|
-
tokenId: `2020072218511123456789${index}`,
|
|
49
|
-
name: `Test inverter ${index}`,
|
|
50
|
-
sn: `ABCDEFGHI${index}`,
|
|
51
|
-
hasBattery: index === 0,
|
|
52
|
-
})),
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function createPlatform(config: PlatformConfig): void {
|
|
57
|
-
inverterCreations = [];
|
|
58
|
-
|
|
59
|
-
new TestSolaxCloudAPIPlatform(createLog(), config, createApi());
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
describe('SolaxCloudAPIPlatform totalizer inverter creation', () => {
|
|
63
|
-
it('creates a virtual totalizer without cloud credentials when all inverters use Solax', () => {
|
|
64
|
-
createPlatform(createConfig(['solax', 'solax']));
|
|
65
|
-
|
|
66
|
-
const totalizer = inverterCreations[2];
|
|
67
|
-
|
|
68
|
-
assert.equal(inverterCreations.length, 3);
|
|
69
|
-
assert.equal(totalizer.name, 'All inverters');
|
|
70
|
-
assert.equal(totalizer.tokenId, '');
|
|
71
|
-
assert.equal(totalizer.virtual, true);
|
|
72
|
-
assert.equal(totalizer.brandName, 'Solax');
|
|
73
|
-
assert.equal(totalizer.hasBattery, true);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
1
|
+
import { API, Logging, PlatformConfig } from 'homebridge';
|
|
2
|
+
|
|
3
|
+
import assert from 'assert';
|
|
4
|
+
|
|
5
|
+
import { SolaxCloudAPIPlatform } from '../src/platform.js';
|
|
6
|
+
import { SolaxCloudAPIPlatformInverter } from '../src/platformInverter.js';
|
|
7
|
+
import { createApi, createLog, createMatterApi } from './helpers.js';
|
|
8
|
+
|
|
9
|
+
interface InverterCreation {
|
|
10
|
+
brand: number;
|
|
11
|
+
tokenId: string;
|
|
12
|
+
sn: string;
|
|
13
|
+
name: string;
|
|
14
|
+
hasBattery: boolean;
|
|
15
|
+
smoothingWindow: number;
|
|
16
|
+
virtual: boolean;
|
|
17
|
+
brandName?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let inverterCreations: InverterCreation[] = [];
|
|
21
|
+
|
|
22
|
+
class TestSolaxCloudAPIPlatform extends SolaxCloudAPIPlatform {
|
|
23
|
+
protected createPlatformInverter(log: Logging, config: PlatformConfig, api: API,
|
|
24
|
+
brand: number, tokenId: string, sn: string,
|
|
25
|
+
name: string, hasBattery: boolean,
|
|
26
|
+
smoothingWindow: number,
|
|
27
|
+
virtual = false,
|
|
28
|
+
brandName?: string): SolaxCloudAPIPlatformInverter {
|
|
29
|
+
inverterCreations.push({ brand, tokenId, sn, name, hasBattery, smoothingWindow, virtual, brandName });
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
getAccessories: () => [],
|
|
33
|
+
hasBattery: () => hasBattery,
|
|
34
|
+
} as unknown as SolaxCloudAPIPlatformInverter;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
protected async fetchDataPeriodically(): Promise<void> {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function createConfig(brands: string[]): PlatformConfig {
|
|
43
|
+
return {
|
|
44
|
+
platform: 'SolaxCloudAPI',
|
|
45
|
+
pollingFrequency: 300,
|
|
46
|
+
inverters: brands.map((brand, index) => ({
|
|
47
|
+
brand,
|
|
48
|
+
tokenId: `2020072218511123456789${index}`,
|
|
49
|
+
name: `Test inverter ${index}`,
|
|
50
|
+
sn: `ABCDEFGHI${index}`,
|
|
51
|
+
hasBattery: index === 0,
|
|
52
|
+
})),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function createPlatform(config: PlatformConfig): void {
|
|
57
|
+
inverterCreations = [];
|
|
58
|
+
|
|
59
|
+
new TestSolaxCloudAPIPlatform(createLog(), config, createApi());
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
describe('SolaxCloudAPIPlatform totalizer inverter creation', () => {
|
|
63
|
+
it('creates a virtual totalizer without cloud credentials when all inverters use Solax', () => {
|
|
64
|
+
createPlatform(createConfig(['solax', 'solax']));
|
|
65
|
+
|
|
66
|
+
const totalizer = inverterCreations[2];
|
|
67
|
+
|
|
68
|
+
assert.equal(inverterCreations.length, 3);
|
|
69
|
+
assert.equal(totalizer.name, 'All inverters');
|
|
70
|
+
assert.equal(totalizer.tokenId, '');
|
|
71
|
+
assert.equal(totalizer.virtual, true);
|
|
72
|
+
assert.equal(totalizer.brandName, 'Solax');
|
|
73
|
+
assert.equal(totalizer.hasBattery, true);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('publishes only applicable meters through Matter', () => {
|
|
77
|
+
const matter = createMatterApi();
|
|
78
|
+
const config = {
|
|
79
|
+
enableHistory: false,
|
|
80
|
+
pureHomeApp: true,
|
|
81
|
+
smoothMeters: false,
|
|
82
|
+
smoothingMethod: 'sma',
|
|
83
|
+
} as PlatformConfig;
|
|
84
|
+
|
|
85
|
+
const inverter = new SolaxCloudAPIPlatformInverter(
|
|
86
|
+
createLog(),
|
|
87
|
+
config,
|
|
88
|
+
createApi(matter.api),
|
|
89
|
+
0,
|
|
90
|
+
'',
|
|
91
|
+
'virtual',
|
|
92
|
+
'Virtual inverter',
|
|
93
|
+
false,
|
|
94
|
+
3,
|
|
95
|
+
true,
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
assert.equal(matter.registrations.length, 5);
|
|
99
|
+
assert.equal(inverter.getAccessories().length, 6);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('creates a virtual totalizer with QCells as brand when all inverters use QCells', () => {
|
|
103
|
+
createPlatform(createConfig(['qcells', 'qcells']));
|
|
104
|
+
|
|
105
|
+
const totalizer = inverterCreations[2];
|
|
106
|
+
|
|
107
|
+
assert.equal(totalizer.name, 'All inverters');
|
|
108
|
+
assert.equal(totalizer.tokenId, '');
|
|
109
|
+
assert.equal(totalizer.virtual, true);
|
|
110
|
+
assert.equal(totalizer.brandName, 'QCells');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('creates a virtual totalizer with mixed brand name when inverter brands differ', () => {
|
|
114
|
+
createPlatform(createConfig(['solax', 'qcells']));
|
|
115
|
+
|
|
116
|
+
const totalizer = inverterCreations[2];
|
|
117
|
+
|
|
118
|
+
assert.equal(totalizer.name, 'All inverters');
|
|
119
|
+
assert.equal(totalizer.tokenId, '');
|
|
120
|
+
assert.equal(totalizer.virtual, true);
|
|
121
|
+
assert.equal(totalizer.brandName, 'Solax/QCells');
|
|
122
|
+
});
|
|
123
|
+
});
|