frost-event-detector 2.0.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/.env +10 -0
- package/.eslintrc.js +14 -0
- package/.husky/pre-commit +4 -0
- package/.husky/pre-push +4 -0
- package/.prettierrc.js +12 -0
- package/.vscode/launch.json.example +28 -0
- package/README.md +29 -0
- package/bitbucket-pipelines.yml +48 -0
- package/context.json +1 -0
- package/dev.env +10 -0
- package/dist/src/calculate.js +195 -0
- package/dist/src/calculate.js.map +1 -0
- package/dist/src/constants.js +10 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/db.js +79 -0
- package/dist/src/db.js.map +1 -0
- package/dist/src/evaluate.js +170 -0
- package/dist/src/evaluate.js.map +1 -0
- package/dist/src/index.js +75 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/repository/coldstore.repository.js +215 -0
- package/dist/src/repository/coldstore.repository.js.map +1 -0
- package/dist/src/repository/timeseries.repository.js +248 -0
- package/dist/src/repository/timeseries.repository.js.map +1 -0
- package/dist/src/timeSeries.js +233 -0
- package/dist/src/timeSeries.js.map +1 -0
- package/dist/src/utils.js +33 -0
- package/dist/src/utils.js.map +1 -0
- package/dist/test/int/lambda.test.js +36 -0
- package/dist/test/int/lambda.test.js.map +1 -0
- package/dist/test/unit/db.test.js +154 -0
- package/dist/test/unit/db.test.js.map +1 -0
- package/dist/test/unit/evaluate.test.js +76 -0
- package/dist/test/unit/evaluate.test.js.map +1 -0
- package/dist/test/unit/fps.test.js +84 -0
- package/dist/test/unit/fps.test.js.map +1 -0
- package/dist/test/unit/runtime.test.js +84 -0
- package/dist/test/unit/runtime.test.js.map +1 -0
- package/dist/test/unit/timeSeries.test.js +81 -0
- package/dist/test/unit/timeSeries.test.js.map +1 -0
- package/dist/test/unit/utils.test.js +64 -0
- package/dist/test/unit/utils.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/event.json +6 -0
- package/jest-int.config.ts +18 -0
- package/jest-unit.config.ts +25 -0
- package/jest.config.ts +30 -0
- package/lint-staged.config.js +10 -0
- package/package.json +61 -0
- package/prod.env +10 -0
- package/src/calculate.ts +389 -0
- package/src/constants.ts +15 -0
- package/src/db.ts +134 -0
- package/src/evaluate.ts +272 -0
- package/src/index.ts +104 -0
- package/src/repository/coldstore.repository.ts +238 -0
- package/src/repository/timeseries.repository.ts +273 -0
- package/src/types.d.ts +68 -0
- package/src/utils.ts +47 -0
- package/test/int/lambda.test.ts +46 -0
- package/test/unit/db.test.ts +188 -0
- package/test/unit/evaluate.test.ts +85 -0
- package/test/unit/fps.test.ts +97 -0
- package/test/unit/json/currentCandidates.json +44 -0
- package/test/unit/json/dayEvent.json +169 -0
- package/test/unit/json/eventCandidates.json +68 -0
- package/test/unit/json/eventDay.json +891 -0
- package/test/unit/json/frost_protection_score.json +800 -0
- package/test/unit/json/frost_protection_score_2_fans.json +1615 -0
- package/test/unit/json/runtime_high.json +458 -0
- package/test/unit/json/runtime_negative.json +772 -0
- package/test/unit/runtime.test.ts +96 -0
- package/test/unit/timeSeries.test.ts +88 -0
- package/test/unit/utils.test.ts +76 -0
- package/tsconfig.json +32 -0
package/.env
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
AWS_ROLE_ARN=arn:aws:iam::045197510462:role/lambda_basic_vpc_execution
|
|
2
|
+
AWS_REGION=ap-southeast-2
|
|
3
|
+
AWS_FUNCTION_NAME=frost-event-detector
|
|
4
|
+
AWS_HANDLER=dist/src/index.handler
|
|
5
|
+
AWS_MEMORY_SIZE=512
|
|
6
|
+
AWS_TIMEOUT=900
|
|
7
|
+
AWS_DESCRIPTION=Function to find frost events
|
|
8
|
+
AWS_RUNTIME=nodejs20.x
|
|
9
|
+
AWS_VPC_SUBNETS=subnet-03d05ce3d18cdcc6e,subnet-01d335c6dde9a6cbf,subnet-0413bf072d758981a
|
|
10
|
+
AWS_VPC_SECURITY_GROUPS=sg-0ef60c0fcc95b260f
|
package/.eslintrc.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
"extends": ["@frostsmart/eslint-config-loncel/node-config-ts"],
|
|
3
|
+
"parser": "@typescript-eslint/parser",
|
|
4
|
+
"settings": {
|
|
5
|
+
"import/resolver": {
|
|
6
|
+
"node": {
|
|
7
|
+
"extensions": [".js", ".json", ".d.ts"]
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"rules": {
|
|
12
|
+
// Rules that you want to override or new ones
|
|
13
|
+
}
|
|
14
|
+
};
|
package/.husky/pre-push
ADDED
package/.prettierrc.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.2.0",
|
|
3
|
+
"configurations": [
|
|
4
|
+
{
|
|
5
|
+
"type": "node",
|
|
6
|
+
"request": "launch",
|
|
7
|
+
"name": "Debug with node-lambda",
|
|
8
|
+
"program": "${workspaceFolder}/node_modules/node-lambda/bin/node-lambda",
|
|
9
|
+
"args": ["run", "--handler", "dist/src/index.handler"],
|
|
10
|
+
"sourceMaps": true,
|
|
11
|
+
"cwd": "${workspaceFolder}",
|
|
12
|
+
"console": "integratedTerminal",
|
|
13
|
+
"internalConsoleOptions": "neverOpen",
|
|
14
|
+
"disableOptimisticBPs": true
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"type": "node",
|
|
18
|
+
"request": "launch",
|
|
19
|
+
"name": "Debug with jest",
|
|
20
|
+
"program": "${workspaceFolder}/node_modules/jest/bin/jest",
|
|
21
|
+
"args": ["--runInBand", "test/unit/fps.test.ts"],
|
|
22
|
+
"cwd": "${workspaceFolder}",
|
|
23
|
+
"console": "integratedTerminal",
|
|
24
|
+
"internalConsoleOptions": "neverOpen",
|
|
25
|
+
"disableOptimisticBPs": true
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# README
|
|
2
|
+
|
|
3
|
+
## What is this repository for?
|
|
4
|
+
|
|
5
|
+
This lambda function usually runs a part of a step function and is designed to run from scratch, meaning going through all the history of data and determine all frost events for an area. Once it has established the history, it always starts from the last recorded event.
|
|
6
|
+
And to be current and expand on currently happening events, there is a current mode, that only picks up on todays events.
|
|
7
|
+
|
|
8
|
+
### What is actually a frost event
|
|
9
|
+
|
|
10
|
+
This is actually not as trivial as it sounds. The most basic condition is, that it needs to be cold and the fan is running at the time.
|
|
11
|
+
Only running is not enough, as fans can also run for cooling operations in summer. So it must be cold at the same time.
|
|
12
|
+
But even then you have the so called ice bucket tests, done by installers. They prove that a fan is actually automatically starting once the temperature drops
|
|
13
|
+
below a certain threshold. These tests are usually performed during the day.
|
|
14
|
+
|
|
15
|
+
So this leaves the following conditions that determine a frost event:
|
|
16
|
+
|
|
17
|
+
- Fan(s) must be running
|
|
18
|
+
- The temperature must be below 2.5 degrees while the fan is running
|
|
19
|
+
- An event is only recorded from 6pm in the evening to 10am in the morning
|
|
20
|
+
|
|
21
|
+
### What is recorded for a frost event
|
|
22
|
+
|
|
23
|
+
Per event we record:
|
|
24
|
+
|
|
25
|
+
- Area of the event
|
|
26
|
+
- Start and stop time of the event
|
|
27
|
+
- ids of the fans involved
|
|
28
|
+
- min temperature recorded
|
|
29
|
+
- Total hrs of run time amoung all fans
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
image: sleavely/node-awscli:20.x
|
|
2
|
+
|
|
3
|
+
definitions:
|
|
4
|
+
scripts:
|
|
5
|
+
- script:
|
|
6
|
+
&build
|
|
7
|
+
npm config set @${NPM_SCOPE}:registry https://registry.npmjs.org/ &&
|
|
8
|
+
npm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}" &&
|
|
9
|
+
npm i --location=global @frostsmart/devops node-lambda ts-node typescript husky &&
|
|
10
|
+
npm install &&
|
|
11
|
+
npx tsc &&
|
|
12
|
+
node-lambda package -A .lambda
|
|
13
|
+
pipelines:
|
|
14
|
+
pull-requests:
|
|
15
|
+
'**':
|
|
16
|
+
- step:
|
|
17
|
+
name: Build and test
|
|
18
|
+
script:
|
|
19
|
+
- apt-get update
|
|
20
|
+
- *build
|
|
21
|
+
- npm run test:unit
|
|
22
|
+
branches:
|
|
23
|
+
master:
|
|
24
|
+
- step:
|
|
25
|
+
caches:
|
|
26
|
+
- node
|
|
27
|
+
name: Deploy to loncel, frost environment
|
|
28
|
+
script:
|
|
29
|
+
- *build
|
|
30
|
+
# deploy into frost_dev
|
|
31
|
+
- devops deploy-direct -e dev -p FROST_DEV
|
|
32
|
+
# unit test
|
|
33
|
+
- npm run test:unit
|
|
34
|
+
# deploy into frost_stage
|
|
35
|
+
- devops deploy-direct -e dev -p FROST_STAGE
|
|
36
|
+
# run the int test
|
|
37
|
+
- export aws_role="arn:aws:iam::$FROST_STAGE_ACCOUNT:role/$AWS_CI_ROLE_NAME"
|
|
38
|
+
- export creds=$(aws sts assume-role --role-arn $aws_role --role-session-name "bitbucket" --external-id $FROST_STAGE_EXTERNAL_ID)
|
|
39
|
+
- export AWS_ACCESS_KEY_ID=$(echo $creds | jq -r .Credentials.AccessKeyId)
|
|
40
|
+
- export AWS_SECRET_ACCESS_KEY=$(echo $creds | jq -r .Credentials.SecretAccessKey)
|
|
41
|
+
- export AWS_SESSION_TOKEN=$(echo $creds | jq -r .Credentials.SessionToken)
|
|
42
|
+
- npm run test:int
|
|
43
|
+
- step:
|
|
44
|
+
name: Deploy to frost prod environment
|
|
45
|
+
script:
|
|
46
|
+
- *build
|
|
47
|
+
# deploy into frost_prod
|
|
48
|
+
- devops deploy-direct -e prod -p FROST_PROD
|
package/context.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"invokedFunctionArn":"arn:aws:lambda:ap-southeast-2:045197510462:function:dummy"}
|
package/dev.env
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
AWS_ROLE_ARN='arn:aws:iam::221392187604:role/lambda_basic_vpc_execution'
|
|
2
|
+
AWS_REGION=us-west-2
|
|
3
|
+
AWS_FUNCTION_NAME=frost-event-detector
|
|
4
|
+
AWS_HANDLER=dist/src/index.handler
|
|
5
|
+
AWS_MEMORY_SIZE=200
|
|
6
|
+
AWS_TIMEOUT=600
|
|
7
|
+
AWS_DESCRIPTION="Function to find frost events"
|
|
8
|
+
AWS_RUNTIME=nodejs20.x
|
|
9
|
+
AWS_VPC_SUBNETS=subnet-5845de3c,subnet-de46ddba,subnet-7d45de19
|
|
10
|
+
AWS_VPC_SECURITY_GROUPS=sg-cbcd25ad
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.calculateFPS = exports.calculateDurationBelowThreshold = exports.calculateFPSInput = exports.calculateFansStartTemp = exports.calculateInversion = exports.calculateTripHours = exports.calculatesMinTemperature = void 0;
|
|
7
|
+
const underscore_1 = require("underscore");
|
|
8
|
+
const moment_1 = __importDefault(require("moment"));
|
|
9
|
+
const binary_search_1 = __importDefault(require("binary-search"));
|
|
10
|
+
const constants_1 = __importDefault(require("./constants"));
|
|
11
|
+
const db_1 = require("./db");
|
|
12
|
+
const calculatesMinTemperature = (eventDay, startTime, endTime, fans) => {
|
|
13
|
+
const { tempSeries } = eventDay;
|
|
14
|
+
const minTemp = (0, underscore_1.reduce)(tempSeries, (memo, tempGroup) => {
|
|
15
|
+
if (tempGroup.group_by &&
|
|
16
|
+
(0, underscore_1.find)(fans, (id) => id === Number(tempGroup.group_by[0].group.section)))
|
|
17
|
+
return Math.min(memo, (0, underscore_1.min)((0, underscore_1.map)(tempGroup.values, (value) => value[0] >= startTime && value[0] <= endTime ? value[1] : memo)));
|
|
18
|
+
return memo;
|
|
19
|
+
}, constants_1.default.MAX_TEMPERATURE);
|
|
20
|
+
return minTemp;
|
|
21
|
+
};
|
|
22
|
+
exports.calculatesMinTemperature = calculatesMinTemperature;
|
|
23
|
+
const calculateTripHours = (eventDay, frostStartTime, frostEndTime, fans) => {
|
|
24
|
+
const oneHour = 60;
|
|
25
|
+
const timeBetweenIntervals = 5;
|
|
26
|
+
const intervalsPerHour = oneHour / timeBetweenIntervals;
|
|
27
|
+
const { engineSeries, runSeries } = eventDay;
|
|
28
|
+
const tripHours = runSeries.reduce((memo, runGroup) => {
|
|
29
|
+
if (runGroup.group_by && fans.find((id) => id === Number(runGroup.group_by[0].group.section))) {
|
|
30
|
+
const engineGroup = engineSeries.find((engineGroup) => engineGroup.group_by &&
|
|
31
|
+
engineGroup.group_by[0].group.section === runGroup.group_by[0].group.section);
|
|
32
|
+
if (!engineGroup) {
|
|
33
|
+
return memo + Math.max(runGroup.values.length - 1, 1) / intervalsPerHour;
|
|
34
|
+
}
|
|
35
|
+
const startIndex = (0, underscore_1.findIndex)(engineGroup.values, (value) => value[0] >= frostStartTime);
|
|
36
|
+
const endIndex = Math.max((0, underscore_1.findIndex)(engineGroup.values, (value) => value[0] >= frostEndTime), engineGroup.values.length - 1);
|
|
37
|
+
if (startIndex > -1 &&
|
|
38
|
+
-1 < endIndex &&
|
|
39
|
+
endIndex < engineGroup.values.length &&
|
|
40
|
+
engineGroup.values[startIndex][0] <= engineGroup.values[endIndex][0]) {
|
|
41
|
+
if (engineGroup.values[engineGroup.values.length - 1][1] === 0) {
|
|
42
|
+
return memo + Math.max(runGroup.values.length - 1, 1) / intervalsPerHour;
|
|
43
|
+
}
|
|
44
|
+
const lastEngineHoursValue = engineGroup.values[Math.min(endIndex + 1, engineGroup.values.length - 1)][1];
|
|
45
|
+
const firstEngineHoursValue = engineGroup.values[Math.max(startIndex - 1, 0)][1];
|
|
46
|
+
const engineHoursDelta = lastEngineHoursValue - firstEngineHoursValue;
|
|
47
|
+
const hoursOfEngineEvent = (0, moment_1.default)(engineGroup.values[endIndex][0]).diff((0, moment_1.default)(engineGroup.values[startIndex][0]), 'minutes') / 60;
|
|
48
|
+
if (engineHoursDelta < 0 || engineHoursDelta > hoursOfEngineEvent) {
|
|
49
|
+
return memo + Math.max(runGroup.values.length - 1, 1) / 12;
|
|
50
|
+
}
|
|
51
|
+
return memo + engineHoursDelta;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return memo;
|
|
55
|
+
}, 0);
|
|
56
|
+
return tripHours;
|
|
57
|
+
};
|
|
58
|
+
exports.calculateTripHours = calculateTripHours;
|
|
59
|
+
const calculateInversion = async (client, eventDay, startTime) => {
|
|
60
|
+
const { tempSeries, towerSeries } = eventDay;
|
|
61
|
+
const fans = (0, underscore_1.compact)(tempSeries.map((tempGroup) => {
|
|
62
|
+
if (tempGroup.group_by && Number(tempGroup.group_by[0].group.section)) {
|
|
63
|
+
return Number(tempGroup.group_by[0].group.section);
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}));
|
|
67
|
+
const fansWithTowerTemp = await (0, db_1.fetchFansWithTowerTempFor)(client, fans);
|
|
68
|
+
if (!fansWithTowerTemp.length)
|
|
69
|
+
return null;
|
|
70
|
+
const inversionDeltas = (0, underscore_1.reduce)(fansWithTowerTemp, (memo, fanId) => {
|
|
71
|
+
const tempGroup = (0, underscore_1.find)(tempSeries, (_series) => _series.group_by && Number(_series.group_by[0].group.section) === fanId);
|
|
72
|
+
const towerGroup = (0, underscore_1.find)(towerSeries, (_series) => _series.group_by && Number(_series.group_by[0].group.section) === fanId);
|
|
73
|
+
if (!tempGroup || !towerGroup)
|
|
74
|
+
return memo;
|
|
75
|
+
const canopy = (0, underscore_1.find)(tempGroup.values, (value) => {
|
|
76
|
+
const ts = new Date(value[0]).getTime();
|
|
77
|
+
return ts <= startTime && ts >= startTime - 5 * 60 * 1000;
|
|
78
|
+
});
|
|
79
|
+
const tower = (0, underscore_1.find)(towerGroup.values, (value) => {
|
|
80
|
+
const ts = new Date(value[0]).getTime();
|
|
81
|
+
return ts <= startTime && ts >= startTime - 5 * 60 * 1000;
|
|
82
|
+
});
|
|
83
|
+
if (canopy && tower)
|
|
84
|
+
memo.push(tower[1] - canopy[1]);
|
|
85
|
+
return memo;
|
|
86
|
+
}, []);
|
|
87
|
+
const percentageToRemove = 0.05;
|
|
88
|
+
const elementsToRemove = Math.ceil(inversionDeltas.length * percentageToRemove);
|
|
89
|
+
const inversionDeltasSorted = (0, underscore_1.sortBy)(inversionDeltas);
|
|
90
|
+
const trimmedResult = inversionDeltasSorted.length > 2
|
|
91
|
+
? inversionDeltasSorted.slice(elementsToRemove, -elementsToRemove)
|
|
92
|
+
: inversionDeltasSorted;
|
|
93
|
+
return trimmedResult.length
|
|
94
|
+
? (0, underscore_1.reduce)(inversionDeltas, (memo, value) => memo + value, 0) / inversionDeltas.length
|
|
95
|
+
: null;
|
|
96
|
+
};
|
|
97
|
+
exports.calculateInversion = calculateInversion;
|
|
98
|
+
const calculateFansStartTemp = (startTempSeries, fans) => {
|
|
99
|
+
const fanStartTemp = fans.reduce((memo, fanId) => {
|
|
100
|
+
const fanStartTempGroup = startTempSeries.find((tempGroup) => tempGroup?.group_by && Number(tempGroup?.group_by[0]?.group?.section) === fanId);
|
|
101
|
+
if (fanStartTempGroup?.values?.length) {
|
|
102
|
+
const startTempValue = fanStartTempGroup.values[fanStartTempGroup.values.length - 1][1];
|
|
103
|
+
if (startTempValue != null) {
|
|
104
|
+
return Math.min(memo, startTempValue);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return memo;
|
|
108
|
+
}, constants_1.default.MAX_TEMPERATURE);
|
|
109
|
+
if (fanStartTemp < constants_1.default.MAX_TEMPERATURE) {
|
|
110
|
+
return fanStartTemp;
|
|
111
|
+
}
|
|
112
|
+
const seriesStartTemp = startTempSeries.reduce((memo, startTempGroup) => {
|
|
113
|
+
if (startTempGroup?.values?.length) {
|
|
114
|
+
const startTempValue = startTempGroup.values[startTempGroup.values.length - 1][1];
|
|
115
|
+
if (startTempValue != null) {
|
|
116
|
+
return Math.min(memo, startTempValue);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return memo;
|
|
120
|
+
}, constants_1.default.MAX_TEMPERATURE);
|
|
121
|
+
return seriesStartTemp < constants_1.default.MAX_TEMPERATURE ? seriesStartTemp : null;
|
|
122
|
+
};
|
|
123
|
+
exports.calculateFansStartTemp = calculateFansStartTemp;
|
|
124
|
+
const calculateFPSInput = (event, fans, tempThreshold) => {
|
|
125
|
+
const { tempSeries, runSeries } = event;
|
|
126
|
+
return runSeries.reduce((memo, runGroup) => {
|
|
127
|
+
if (runGroup.values.length === 0) {
|
|
128
|
+
return memo;
|
|
129
|
+
}
|
|
130
|
+
if (runGroup.group_by &&
|
|
131
|
+
(0, underscore_1.find)(fans, (id) => id === Number(runGroup.group_by[0].group.section))) {
|
|
132
|
+
const tempGroup = (0, underscore_1.find)(tempSeries, (_series) => _series?.group_by[0].group.section === runGroup.group_by[0].group.section);
|
|
133
|
+
if (!tempGroup) {
|
|
134
|
+
return memo;
|
|
135
|
+
}
|
|
136
|
+
let timeBelowThreshold = 0;
|
|
137
|
+
const temperatures = [];
|
|
138
|
+
runGroup.values.forEach((run) => {
|
|
139
|
+
const index = (0, binary_search_1.default)(tempGroup.values, run, (element, needle) => element[0] - needle[0]);
|
|
140
|
+
if (index > -1) {
|
|
141
|
+
const currentTemp = tempGroup.values[index][1];
|
|
142
|
+
const tempDelta = currentTemp - tempThreshold;
|
|
143
|
+
temperatures.push(tempDelta);
|
|
144
|
+
if (currentTemp < tempThreshold)
|
|
145
|
+
timeBelowThreshold += 5;
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
memo = {
|
|
149
|
+
tempValues: [...memo.tempValues, ...temperatures],
|
|
150
|
+
totalTimeBelow: memo.totalTimeBelow + timeBelowThreshold,
|
|
151
|
+
maxFanBelow: Math.max(memo.maxFanBelow, timeBelowThreshold),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return memo;
|
|
155
|
+
}, {
|
|
156
|
+
tempValues: [],
|
|
157
|
+
totalTimeBelow: 0,
|
|
158
|
+
maxFanBelow: 0,
|
|
159
|
+
});
|
|
160
|
+
};
|
|
161
|
+
exports.calculateFPSInput = calculateFPSInput;
|
|
162
|
+
const calculateDurationBelowThreshold = (event, startTime, endTime, threshold) => {
|
|
163
|
+
const { tempSeries } = event;
|
|
164
|
+
let totalBelowThresholdDurationMs = 0;
|
|
165
|
+
let validGroupCount = 0;
|
|
166
|
+
for (const tempGroup of tempSeries) {
|
|
167
|
+
let groupDuration = 0;
|
|
168
|
+
let prevTimestamp = null;
|
|
169
|
+
let prevTemp = null;
|
|
170
|
+
if (!tempGroup.values.length) {
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
for (const [timestamp, temp] of tempGroup.values) {
|
|
174
|
+
if (timestamp >= startTime && timestamp <= endTime) {
|
|
175
|
+
if (prevTimestamp !== null && prevTemp < threshold && temp < threshold) {
|
|
176
|
+
groupDuration += timestamp - prevTimestamp;
|
|
177
|
+
}
|
|
178
|
+
prevTimestamp = timestamp;
|
|
179
|
+
prevTemp = temp;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
totalBelowThresholdDurationMs += groupDuration;
|
|
183
|
+
validGroupCount++;
|
|
184
|
+
}
|
|
185
|
+
const avgBelowThresholdMinutes = validGroupCount > 0 ? totalBelowThresholdDurationMs / validGroupCount / (1000 * 60) : 0;
|
|
186
|
+
return avgBelowThresholdMinutes;
|
|
187
|
+
};
|
|
188
|
+
exports.calculateDurationBelowThreshold = calculateDurationBelowThreshold;
|
|
189
|
+
const calculateFPS = (cat, totalTimeBelow, maxFanBelow, totalFans) => {
|
|
190
|
+
const avgCriticalScore = totalTimeBelow / totalFans / 60;
|
|
191
|
+
const maxImpactScore = (maxFanBelow - totalTimeBelow / totalFans) / totalFans / 60;
|
|
192
|
+
return cat - avgCriticalScore - maxImpactScore;
|
|
193
|
+
};
|
|
194
|
+
exports.calculateFPS = calculateFPS;
|
|
195
|
+
//# sourceMappingURL=calculate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculate.js","sourceRoot":"","sources":["../../src/calculate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const constants = {
|
|
4
|
+
MAX_TEMPERATURE: 5.0,
|
|
5
|
+
MIN_TEMPERATURE: -30.0,
|
|
6
|
+
EVENT_WINDOW_START_HOUR: 18,
|
|
7
|
+
EVENT_WINDOW_END_HOUR: 10,
|
|
8
|
+
};
|
|
9
|
+
exports.default = constants;
|
|
10
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":";;AAOA,MAAM,SAAS,GAAG;IAChB,eAAe,EAAE,GAAG;IACpB,eAAe,EAAE,CAAC,IAAI;IACtB,uBAAuB,EAAE,EAAE;IAC3B,qBAAqB,EAAE,EAAE;CACjB,CAAC;AAEX,kBAAe,SAAS,CAAC"}
|
package/dist/src/db.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.recordFor = exports.fetchFansWithTowerTempFor = exports.fetchFrostAreasFor = void 0;
|
|
7
|
+
const moment_timezone_1 = __importDefault(require("moment-timezone"));
|
|
8
|
+
const getFrostTableName = (useReplica) => {
|
|
9
|
+
return useReplica ? 'lcloud.frost_event_replica' : 'lcloud.frost_event';
|
|
10
|
+
};
|
|
11
|
+
const fetchFrostAreasFor = async (client, siteId, useReplica = false) => {
|
|
12
|
+
const result = await client.raw(`
|
|
13
|
+
SELECT area.id, COALESCE(site.config->>'timezone','Pacific/Auckland') as timezone,
|
|
14
|
+
(SELECT json_build_object('id', id, 'startTime', start_time, 'endTime', end_time, 'fans', fans)
|
|
15
|
+
FROM ${getFrostTableName(useReplica)}
|
|
16
|
+
WHERE area = area.id
|
|
17
|
+
ORDER BY start_time DESC
|
|
18
|
+
LIMIT 1) AS "lastEvent"
|
|
19
|
+
FROM lcloud.area INNER JOIN lcloud.site on site.id = area.site
|
|
20
|
+
WHERE site = ? AND (site.tags ->> 'internal' IS NULL OR site.tags ->> 'internal' = 'false')
|
|
21
|
+
AND application_type = 'frost'`, [siteId]);
|
|
22
|
+
return result.rows;
|
|
23
|
+
};
|
|
24
|
+
exports.fetchFrostAreasFor = fetchFrostAreasFor;
|
|
25
|
+
const fetchFansWithTowerTempFor = async (client, fans) => {
|
|
26
|
+
const { rows } = await client.raw(`
|
|
27
|
+
SELECT area, array_agg(section) as fans
|
|
28
|
+
FROM lcloud.sensor WHERE section = ANY(?) AND type = 'frostFan' and (config->>'ntc2')::boolean IS NOT TRUE
|
|
29
|
+
GROUP BY area
|
|
30
|
+
`, [fans]);
|
|
31
|
+
return rows.length ? rows[0].fans : [];
|
|
32
|
+
};
|
|
33
|
+
exports.fetchFansWithTowerTempFor = fetchFansWithTowerTempFor;
|
|
34
|
+
const recordFor = async (client, area, event, useReplica = false) => {
|
|
35
|
+
const tableName = getFrostTableName(useReplica);
|
|
36
|
+
const { lastEvent } = area;
|
|
37
|
+
const { startTime, endTime, fans, minTemp, tripHours, inversion, cat, totalTimeBelow, maxFanBelow, startTemp, fps, durationBelowThreshold, } = event;
|
|
38
|
+
const eventStart = (0, moment_timezone_1.default)(startTime).tz('Pacific/Auckland');
|
|
39
|
+
if (lastEvent &&
|
|
40
|
+
(0, moment_timezone_1.default)(lastEvent.startTime)
|
|
41
|
+
.tz('Pacific/Auckland')
|
|
42
|
+
.isBetween(eventStart, eventStart.clone().add(1, 'day'), null, '[]')) {
|
|
43
|
+
if (endTime !== (0, moment_timezone_1.default)(lastEvent.endTime).valueOf()) {
|
|
44
|
+
await client.raw(`UPDATE ${tableName} SET end_time = ?, fans = ?, min_temp = ?, runtime = ?, inversion = ?, cat = ?, total_time_below = ?, max_fan_below = ?, start_temp = ?, fps = ?, duration_below_start = ? WHERE id = ? returning id`, [
|
|
45
|
+
(0, moment_timezone_1.default)(endTime).tz('Pacific/Auckland').format(),
|
|
46
|
+
fans,
|
|
47
|
+
minTemp,
|
|
48
|
+
tripHours,
|
|
49
|
+
inversion,
|
|
50
|
+
cat,
|
|
51
|
+
totalTimeBelow,
|
|
52
|
+
maxFanBelow,
|
|
53
|
+
startTemp,
|
|
54
|
+
fps,
|
|
55
|
+
durationBelowThreshold ?? [0, 0, 0, 0, 0, 0],
|
|
56
|
+
lastEvent.id,
|
|
57
|
+
]);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else if (!lastEvent || eventStart > (0, moment_timezone_1.default)(lastEvent.startTime).tz('Pacific/Auckland')) {
|
|
61
|
+
await client.raw(`INSERT INTO ${tableName} (start_time, end_time, fans, min_temp, runtime, inversion, area, cat, total_time_below, max_fan_below, start_temp, fps, duration_below_start) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) returning id`, [
|
|
62
|
+
(0, moment_timezone_1.default)(startTime).tz('Pacific/Auckland').format(),
|
|
63
|
+
(0, moment_timezone_1.default)(endTime).tz('Pacific/Auckland').format(),
|
|
64
|
+
fans,
|
|
65
|
+
minTemp,
|
|
66
|
+
tripHours,
|
|
67
|
+
inversion,
|
|
68
|
+
area.id,
|
|
69
|
+
cat,
|
|
70
|
+
totalTimeBelow,
|
|
71
|
+
maxFanBelow,
|
|
72
|
+
startTemp,
|
|
73
|
+
fps,
|
|
74
|
+
durationBelowThreshold ?? [0, 0, 0, 0, 0, 0],
|
|
75
|
+
]);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
exports.recordFor = recordFor;
|
|
79
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/db.ts"],"names":[],"mappings":"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"}
|