nodejs-poolcontroller 7.2.0 → 7.5.1
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/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- package/Changelog +13 -0
- package/Dockerfile +1 -0
- package/README.md +5 -5
- package/app.ts +11 -0
- package/config/Config.ts +3 -0
- package/config/VersionCheck.ts +8 -4
- package/controller/Constants.ts +165 -9
- package/controller/Equipment.ts +186 -65
- package/controller/Errors.ts +22 -1
- package/controller/State.ts +273 -57
- package/controller/boards/EasyTouchBoard.ts +194 -95
- package/controller/boards/IntelliCenterBoard.ts +115 -42
- package/controller/boards/IntelliTouchBoard.ts +104 -30
- package/controller/boards/NixieBoard.ts +155 -53
- package/controller/boards/SystemBoard.ts +1529 -514
- package/controller/comms/Comms.ts +219 -42
- package/controller/comms/messages/Messages.ts +16 -4
- package/controller/comms/messages/config/ChlorinatorMessage.ts +13 -3
- package/controller/comms/messages/config/CircuitGroupMessage.ts +6 -0
- package/controller/comms/messages/config/CircuitMessage.ts +1 -1
- package/controller/comms/messages/config/CoverMessage.ts +1 -0
- package/controller/comms/messages/config/EquipmentMessage.ts +4 -0
- package/controller/comms/messages/config/ExternalMessage.ts +43 -25
- package/controller/comms/messages/config/FeatureMessage.ts +8 -1
- package/controller/comms/messages/config/GeneralMessage.ts +8 -0
- package/controller/comms/messages/config/HeaterMessage.ts +15 -9
- package/controller/comms/messages/config/IntellichemMessage.ts +4 -1
- package/controller/comms/messages/config/OptionsMessage.ts +13 -1
- package/controller/comms/messages/config/PumpMessage.ts +4 -20
- package/controller/comms/messages/config/RemoteMessage.ts +4 -0
- package/controller/comms/messages/config/ScheduleMessage.ts +11 -0
- package/controller/comms/messages/config/SecurityMessage.ts +1 -0
- package/controller/comms/messages/config/ValveMessage.ts +12 -2
- package/controller/comms/messages/status/ChlorinatorStateMessage.ts +14 -6
- package/controller/comms/messages/status/EquipmentStateMessage.ts +78 -24
- package/controller/comms/messages/status/HeaterStateMessage.ts +25 -5
- package/controller/comms/messages/status/IntelliChemStateMessage.ts +55 -26
- package/controller/nixie/Nixie.ts +18 -16
- package/controller/nixie/NixieEquipment.ts +6 -6
- package/controller/nixie/bodies/Body.ts +7 -4
- package/controller/nixie/bodies/Filter.ts +7 -4
- package/controller/nixie/chemistry/ChemController.ts +800 -283
- package/controller/nixie/chemistry/Chlorinator.ts +22 -14
- package/controller/nixie/circuits/Circuit.ts +42 -7
- package/controller/nixie/heaters/Heater.ts +303 -30
- package/controller/nixie/pumps/Pump.ts +57 -30
- package/controller/nixie/schedules/Schedule.ts +10 -7
- package/controller/nixie/valves/Valve.ts +7 -5
- package/defaultConfig.json +32 -1
- package/issue_template.md +1 -1
- package/logger/DataLogger.ts +37 -22
- package/package.json +20 -18
- package/web/Server.ts +529 -31
- package/web/bindings/influxDB.json +157 -5
- package/web/bindings/mqtt.json +112 -13
- package/web/bindings/mqttAlt.json +109 -11
- package/web/interfaces/baseInterface.ts +2 -1
- package/web/interfaces/httpInterface.ts +2 -0
- package/web/interfaces/influxInterface.ts +103 -54
- package/web/interfaces/mqttInterface.ts +16 -5
- package/web/services/config/Config.ts +179 -43
- package/web/services/state/State.ts +51 -5
- package/web/services/state/StateSocket.ts +19 -2
|
@@ -33,7 +33,7 @@ Follow the instructions to complete a [packet capture](https://github.com/tagyou
|
|
|
33
33
|
- Pump(s) manufacturer and model: [e.g. IntelliFlow 2 VST 011056]
|
|
34
34
|
- Chlorinator: [e.g. iChlor, IntelliChlor-40]
|
|
35
35
|
- Heater(s): [e.g. gas, solar, heatpump, ultratemp]
|
|
36
|
-
- Chemical controller: [e.g. IntelliChem,
|
|
36
|
+
- Chemical controller: [e.g. IntelliChem, Relay Equipment Manager (REM)]
|
|
37
37
|
- Valves: [e.g. Intellivalve]
|
|
38
38
|
- Any other relevant equipment:
|
|
39
39
|
|
package/Changelog
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 7.5
|
|
4
|
+
1. Backup/restore
|
|
5
|
+
2. Intellitouch add expansion modules
|
|
6
|
+
## 7.4
|
|
7
|
+
1. Filter object, emit, monitoring
|
|
8
|
+
|
|
9
|
+
## 7.3.1
|
|
10
|
+
1. Influx 2.0 support
|
|
11
|
+
|
|
12
|
+
## 7.3
|
|
13
|
+
1. Dynamic chlorinating % based on ORP demand for Nixie
|
|
14
|
+
2. Docker creation updates
|
|
15
|
+
|
|
3
16
|
## 7.2
|
|
4
17
|
1. Refactor Intellichem and Chem Controllers
|
|
5
18
|
|
package/Dockerfile
CHANGED
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# nodejs-poolController - Version 7.
|
|
1
|
+
# nodejs-poolController - Version 7.5
|
|
2
2
|
|
|
3
3
|
## What is nodejs-poolController
|
|
4
4
|
|
|
@@ -15,13 +15,13 @@ Equipment supported
|
|
|
15
15
|
1. Pumps: Intelliflow VS/VSF/VF, older models
|
|
16
16
|
1. Chlorinators: Intellichlor, Aqua-Rite and OEM brands
|
|
17
17
|
1. Heaters: Gas, solar, heatpump
|
|
18
|
-
1. Intellichem and
|
|
18
|
+
1. Intellichem and Relay Equipment Manager (REM) chemical controllers
|
|
19
19
|
1. Intellivalve (coming soon)
|
|
20
20
|
1. Home Automation: SmartThings, Hubitat, ISY, Vera, Siri, Echo
|
|
21
21
|
1. Chemical probes (pH, ORP, flow sensors, EC, etc.)
|
|
22
22
|
|
|
23
23
|
## Latest Changes
|
|
24
|
-
See (
|
|
24
|
+
See [Changelog](https://github.com/tagyoureit/nodejs-poolController/blob/master/Changelog)
|
|
25
25
|
|
|
26
26
|
## What's new in 7.0?
|
|
27
27
|
|
|
@@ -84,8 +84,8 @@ To do anything with this app, you need a client to connect to it. A client can
|
|
|
84
84
|
* Temperature sensors (10k, NTC)
|
|
85
85
|
|
|
86
86
|
## Web Clients
|
|
87
|
-
1.
|
|
88
|
-
1.
|
|
87
|
+
1. [nodejs-poolController-dashPanel](https://github.com/rstrouse/nodejs-poolController-dashPanel). Full compatibility with IntelliCenter, *Touch, REM (RelayEquipmentManager).
|
|
88
|
+
1. Deprecated - ~~[nodejs-poolController-webClient](http://github.com/tagyoureit/nodejs-poolController-webClient). Built primarily around EasyTouch/IntelliTouch but will work with other systems.~~
|
|
89
89
|
|
|
90
90
|
* This app has the default to only listen to clients from localhost (127.0.0.1). If you need to have clients connect from other machines you will need to change the [ip](#module_nodejs-poolController--config.json) in `config.json`.
|
|
91
91
|
|
package/app.ts
CHANGED
|
@@ -35,6 +35,7 @@ export async function initAsync() {
|
|
|
35
35
|
await state.init();
|
|
36
36
|
await webApp.init();
|
|
37
37
|
await sys.start();
|
|
38
|
+
await webApp.initAutoBackup();
|
|
38
39
|
} catch (err) { console.log(`Error Initializing nodejs-PoolController ${err.message}`); }
|
|
39
40
|
//return Promise.resolve()
|
|
40
41
|
// .then(function () { config.init(); })
|
|
@@ -70,6 +71,7 @@ export async function stopAsync(): Promise<void> {
|
|
|
70
71
|
try {
|
|
71
72
|
console.log('Shutting down open processes');
|
|
72
73
|
// await sys.board.virtualPumpControllers.stopAsync();
|
|
74
|
+
await webApp.stopAutoBackup();
|
|
73
75
|
await sys.stopAsync();
|
|
74
76
|
await state.stopAsync();
|
|
75
77
|
await conn.stopAsync();
|
|
@@ -98,4 +100,13 @@ else {
|
|
|
98
100
|
try { return await stopAsync(); } catch (err) { console.log(`Error shutting down processes ${err.message}`); }
|
|
99
101
|
});
|
|
100
102
|
}
|
|
103
|
+
if (typeof process === 'object') {
|
|
104
|
+
process.on('unhandledRejection', (error: Error, promise) => {
|
|
105
|
+
console.group('unhandled rejection');
|
|
106
|
+
console.error("== Node detected an unhandled rejection! ==");
|
|
107
|
+
console.error(error.message);
|
|
108
|
+
console.error(error.stack);
|
|
109
|
+
console.groupEnd();
|
|
110
|
+
});
|
|
111
|
+
}
|
|
101
112
|
( async () => { await initAsync() })();
|
package/config/Config.ts
CHANGED
|
@@ -100,6 +100,8 @@ class Config {
|
|
|
100
100
|
c[section] = val;
|
|
101
101
|
this.update();
|
|
102
102
|
}
|
|
103
|
+
// RKS: 09-21-21 - We are counting on the return from this being immutable. A copy of the data
|
|
104
|
+
// should always be returned here.
|
|
103
105
|
public getSection(section?: string, opts?: any): any {
|
|
104
106
|
if (typeof section === 'undefined') return this._cfg;
|
|
105
107
|
let c: any = this._cfg;
|
|
@@ -118,6 +120,7 @@ class Config {
|
|
|
118
120
|
let baseDir = process.cwd();
|
|
119
121
|
this.ensurePath(baseDir + '/logs/');
|
|
120
122
|
this.ensurePath(baseDir + '/data/');
|
|
123
|
+
this.ensurePath(baseDir + '/backups/');
|
|
121
124
|
// this.ensurePath(baseDir + '/replay/');
|
|
122
125
|
//setTimeout(() => { config.update(); }, 100);
|
|
123
126
|
}
|
package/config/VersionCheck.ts
CHANGED
|
@@ -41,7 +41,7 @@ class VersionCheck {
|
|
|
41
41
|
public checkGitLocal() {
|
|
42
42
|
// check local git version
|
|
43
43
|
try {
|
|
44
|
-
let res = execSync('git rev-parse --abbrev-ref HEAD');
|
|
44
|
+
let res = execSync('git rev-parse --abbrev-ref HEAD', { stdio: 'pipe' });
|
|
45
45
|
let out = res.toString().trim();
|
|
46
46
|
logger.info(`The current git branch output is ${out}`);
|
|
47
47
|
switch (out) {
|
|
@@ -54,10 +54,11 @@ class VersionCheck {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
catch (err) {
|
|
57
|
-
|
|
57
|
+
state.appVersion.gitLocalBranch = '--';
|
|
58
|
+
logger.warn(`Unable to retrieve local git branch. ${err}`);
|
|
58
59
|
}
|
|
59
60
|
try {
|
|
60
|
-
let res = execSync('git rev-parse HEAD');
|
|
61
|
+
let res = execSync('git rev-parse HEAD', { stdio: 'pipe' });
|
|
61
62
|
let out = res.toString().trim();
|
|
62
63
|
logger.info(`The current git commit output is ${out}`);
|
|
63
64
|
switch (out) {
|
|
@@ -69,7 +70,10 @@ class VersionCheck {
|
|
|
69
70
|
state.appVersion.gitLocalCommit = out;
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
|
-
catch (err) {
|
|
73
|
+
catch (err) {
|
|
74
|
+
state.appVersion.gitLocalCommit = '--';
|
|
75
|
+
logger.warn(`Unable to retrieve local git commit. ${err}`);
|
|
76
|
+
}
|
|
73
77
|
}
|
|
74
78
|
private checkAll() {
|
|
75
79
|
try {
|
package/controller/Constants.ts
CHANGED
|
@@ -179,8 +179,9 @@ export class Heliotrope {
|
|
|
179
179
|
export class Timestamp {
|
|
180
180
|
private _dt: Date;
|
|
181
181
|
public emitter: EventEmitter;
|
|
182
|
-
constructor(dt?: Date) {
|
|
183
|
-
this._dt =
|
|
182
|
+
constructor(dt?: Date | string) {
|
|
183
|
+
if (typeof dt === 'string') this._dt = new Date(dt);
|
|
184
|
+
else this._dt = dt || new Date();
|
|
184
185
|
this.emitter = new EventEmitter();
|
|
185
186
|
}
|
|
186
187
|
private _isUpdating: boolean = false;
|
|
@@ -265,7 +266,7 @@ export class Timestamp {
|
|
|
265
266
|
let dateJan = new Date(this._dt.getFullYear(), 0, 1, 2);
|
|
266
267
|
let dateJul = new Date(this._dt.getFullYear(), 6, 1, 2);
|
|
267
268
|
obj.tzOffset = dateJan.getTimezoneOffset() / 60 * -1;
|
|
268
|
-
obj.adjustDST = dateJan.getTimezoneOffset() - dateJul.getTimezoneOffset() > 0;
|
|
269
|
+
obj.adjustDST = dateJan.getTimezoneOffset() - dateJul.getTimezoneOffset() > 0;
|
|
269
270
|
return obj;
|
|
270
271
|
}
|
|
271
272
|
public addHours(hours: number, minutes: number = 0, seconds: number = 0, milliseconds: number = 0) {
|
|
@@ -302,10 +303,10 @@ export enum ControllerType {
|
|
|
302
303
|
Virtual = 'virtual',
|
|
303
304
|
Nixie = 'nixie'
|
|
304
305
|
}
|
|
305
|
-
export enum VirtualDeviceType {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
306
|
+
// export enum VirtualDeviceType {
|
|
307
|
+
// Pump = 'pump',
|
|
308
|
+
// Chlorinator = 'chlorinator'
|
|
309
|
+
// }
|
|
309
310
|
//export class Enums {
|
|
310
311
|
// public static Addresses = {
|
|
311
312
|
// 2: { val: 2, name: 'chlorinator', desc: 'Chlorinator' },
|
|
@@ -367,6 +368,94 @@ export class Utils {
|
|
|
367
368
|
if (typeof fn !== 'undefined' && typeof fn[to.toLowerCase()] === 'function') return fn[to.toLowerCase()](val);
|
|
368
369
|
}
|
|
369
370
|
},
|
|
371
|
+
pressure: {
|
|
372
|
+
bar: {
|
|
373
|
+
kpa: (val) => { return val * 100; },
|
|
374
|
+
kilopascal: (val) => { return val * 100; },
|
|
375
|
+
pa: (val) => { return val * 100000; },
|
|
376
|
+
pascal: (val) => { return val * 100000; },
|
|
377
|
+
atm: (val) => { return val * 0.986923; },
|
|
378
|
+
atmosphere: (val) => { return val * 0.986923; },
|
|
379
|
+
psi: (val) => { return val * 14.5038; },
|
|
380
|
+
bar: (val) => { return val; }
|
|
381
|
+
},
|
|
382
|
+
kpa: {
|
|
383
|
+
kpa: (val) => { return val; },
|
|
384
|
+
kilopascal: (val) => { return val; },
|
|
385
|
+
pa: (val) => { return val * 1000; },
|
|
386
|
+
pascal: (val) => { return val * 1000; },
|
|
387
|
+
atm: (val) => { return val / 101.325; },
|
|
388
|
+
atmosphere: (val) => { return val / 101.325; },
|
|
389
|
+
psi: (val) => { return val * 0.145038; },
|
|
390
|
+
bar: (val) => { return val * .01; }
|
|
391
|
+
},
|
|
392
|
+
kilopascal: {
|
|
393
|
+
kpa: (val) => { return val; },
|
|
394
|
+
kilopascal: (val) => { return val; },
|
|
395
|
+
pa: (val) => { return val * 1000; },
|
|
396
|
+
pascal: (val) => { return val * 1000; },
|
|
397
|
+
atm: (val) => { return val / 101.325; },
|
|
398
|
+
atmosphere: (val) => { return val / 101.325; },
|
|
399
|
+
psi: (val) => { return val * 0.145038; },
|
|
400
|
+
bar: (val) => { return val * .01; }
|
|
401
|
+
},
|
|
402
|
+
pa: {
|
|
403
|
+
kpa: (val) => { return val / 1000; },
|
|
404
|
+
kilopascal: (val) => { return val / 1000; },
|
|
405
|
+
pa: (val) => { return val; },
|
|
406
|
+
pascal: (val) => { return val; },
|
|
407
|
+
atm: (val) => { return val / 101325; },
|
|
408
|
+
atmosphere: (val) => { return val / 101325; },
|
|
409
|
+
psi: (val) => { return val * 0.000145038; },
|
|
410
|
+
bar: (val) => { return val / 100000; }
|
|
411
|
+
},
|
|
412
|
+
pascal: {
|
|
413
|
+
kpa: (val) => { return val / 1000; },
|
|
414
|
+
kilopascal: (val) => { return val / 1000; },
|
|
415
|
+
pa: (val) => { return val; },
|
|
416
|
+
pascal: (val) => { return val; },
|
|
417
|
+
atm: (val) => { return val / 101325; },
|
|
418
|
+
atmosphere: (val) => { return val / 101325; },
|
|
419
|
+
psi: (val) => { return val * 0.000145038; },
|
|
420
|
+
bar: (val) => { return val / 100000; }
|
|
421
|
+
},
|
|
422
|
+
atm: {
|
|
423
|
+
kpa: (val) => { return val * 101.325; },
|
|
424
|
+
kilopascal: (val) => { return val * 101.325; },
|
|
425
|
+
pa: (val) => { return val * 101325; },
|
|
426
|
+
pascal: (val) => { return val * 101325; },
|
|
427
|
+
atm: (val) => { return val; },
|
|
428
|
+
atmosphere: (val) => { return val; },
|
|
429
|
+
psi: (val) => { return val * 14.6959; },
|
|
430
|
+
bar: (val) => { return val * 1.01325; }
|
|
431
|
+
},
|
|
432
|
+
atmosphere: {
|
|
433
|
+
kpa: (val) => { return val * 101.325; },
|
|
434
|
+
kilopascal: (val) => { return val * 101.325; },
|
|
435
|
+
pa: (val) => { return val * 101325; },
|
|
436
|
+
pascal: (val) => { return val * 101325; },
|
|
437
|
+
atm: (val) => { return val; },
|
|
438
|
+
atmosphere: (val) => { return val; },
|
|
439
|
+
psi: (val) => { return val * 14.6959; },
|
|
440
|
+
bar: (val) => { return val * 1.01325; }
|
|
441
|
+
},
|
|
442
|
+
psi: {
|
|
443
|
+
kpa: (val) => { return val * 6.89476; },
|
|
444
|
+
kilopascal: (val) => { return val * 6.89476; },
|
|
445
|
+
pa: (val) => { return val * 6894.76; },
|
|
446
|
+
pascal: (val) => { return val * 6894.76; },
|
|
447
|
+
atm: (val) => { return val * 0.068046; },
|
|
448
|
+
atmosphere: (val) => { return 0.068046; },
|
|
449
|
+
psi: (val) => { return val; },
|
|
450
|
+
bar: (val) => { return val * 0.0689476; }
|
|
451
|
+
},
|
|
452
|
+
convertUnits: (val: number, from: string, to: string) => {
|
|
453
|
+
if (typeof val !== 'number') return null;
|
|
454
|
+
let fn = this.convert.pressure[from.toLowerCase()];
|
|
455
|
+
if (typeof fn !== 'undefined' && typeof fn[to.toLowerCase()] === 'function') return fn[to.toLowerCase()](val);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
},
|
|
370
459
|
volume: {
|
|
371
460
|
gal: {
|
|
372
461
|
l: (val) => { return val * 3.78541; },
|
|
@@ -444,7 +533,7 @@ export class Utils {
|
|
|
444
533
|
var fmt = '';
|
|
445
534
|
let hrs = Math.floor(seconds / 3600);
|
|
446
535
|
let min = Math.floor((seconds - (hrs * 3600)) / 60);
|
|
447
|
-
let sec = seconds - ((hrs * 3600) + (min * 60));
|
|
536
|
+
let sec = Math.round(seconds) - ((hrs * 3600) + (min * 60));
|
|
448
537
|
if (hrs > 1) fmt += (hrs.toString() + 'hrs');
|
|
449
538
|
else if (hrs > 0) fmt += (hrs.toString() + 'hr');
|
|
450
539
|
|
|
@@ -479,7 +568,7 @@ export class Utils {
|
|
|
479
568
|
}
|
|
480
569
|
return seconds;
|
|
481
570
|
}
|
|
482
|
-
public isNullOrEmpty(val: any) {
|
|
571
|
+
public isNullOrEmpty(val: any) { return (typeof val === 'string') ? val === null || val === '' : typeof val === 'undefined' || val === null; }
|
|
483
572
|
public sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
|
484
573
|
// Use this method to get around the circular references for the toJSON function.
|
|
485
574
|
public serialize(obj, fn?: (key, value) => any): string {
|
|
@@ -514,6 +603,73 @@ export class Utils {
|
|
|
514
603
|
}
|
|
515
604
|
return o;
|
|
516
605
|
}
|
|
606
|
+
public findLineByLeastSquares(values_x: number[], values_y: number[]): number[][] {
|
|
607
|
+
var x_sum = 0;
|
|
608
|
+
var y_sum = 0;
|
|
609
|
+
var xy_sum = 0;
|
|
610
|
+
var xx_sum = 0;
|
|
611
|
+
var count = 0;
|
|
612
|
+
|
|
613
|
+
/*
|
|
614
|
+
* The above is just for quick access, makes the program faster
|
|
615
|
+
*/
|
|
616
|
+
var x = 0;
|
|
617
|
+
var y = 0;
|
|
618
|
+
var values_length = values_x.length;
|
|
619
|
+
|
|
620
|
+
if (values_length != values_y.length) {
|
|
621
|
+
throw new Error('The parameters values_x and values_y need to have same size!');
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/*
|
|
625
|
+
* Above and below cover edge cases
|
|
626
|
+
*/
|
|
627
|
+
if (values_length === 0) {
|
|
628
|
+
return [[], []];
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/*
|
|
632
|
+
* Calculate the sum for each of the parts necessary.
|
|
633
|
+
*/
|
|
634
|
+
for (let i = 0; i < values_length; i++) {
|
|
635
|
+
x = values_x[i];
|
|
636
|
+
y = values_y[i];
|
|
637
|
+
x_sum += x;
|
|
638
|
+
y_sum += y;
|
|
639
|
+
xx_sum += x * x;
|
|
640
|
+
xy_sum += x * y;
|
|
641
|
+
count++;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/*
|
|
645
|
+
* Calculate m and b for the line equation:
|
|
646
|
+
* y = x * m + b
|
|
647
|
+
*/
|
|
648
|
+
var m = (count * xy_sum - x_sum * y_sum) / (count * xx_sum - x_sum * x_sum);
|
|
649
|
+
var b = (y_sum / count) - (m * x_sum) / count;
|
|
650
|
+
|
|
651
|
+
/*
|
|
652
|
+
* We then return the x and y data points according to our fit
|
|
653
|
+
*/
|
|
654
|
+
var result_values_x: number[] = [];
|
|
655
|
+
var result_values_y: number[] = [];
|
|
656
|
+
|
|
657
|
+
for (let i = 0; i < values_length; i++) {
|
|
658
|
+
x = values_x[i];
|
|
659
|
+
y = x * m + b;
|
|
660
|
+
result_values_x.push(x);
|
|
661
|
+
result_values_y.push(y);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
return [result_values_x, result_values_y];
|
|
665
|
+
}
|
|
666
|
+
public slopeOfLeastSquares(values_x: number[], values_y: number[]): number {
|
|
667
|
+
let points = utils.findLineByLeastSquares(values_x, values_y);
|
|
668
|
+
let points_x = points[0];
|
|
669
|
+
let points_y = points[1];
|
|
670
|
+
let slope = (points_y[0] - points_y[points_y.length - 1]) / (points_x[0] - points_x[points_x.length - 1]);
|
|
671
|
+
return slope;
|
|
672
|
+
}
|
|
517
673
|
}
|
|
518
674
|
|
|
519
675
|
export const utils = new Utils();
|