Commit 6e518409 authored by Pithon Kabiro's avatar Pithon Kabiro
Browse files

Merge branch 'wip_aggregate' into 'master'

Add logic for performing basic aggregation

See merge request !4
parents 0270f869 0ef2781e
...@@ -73,6 +73,7 @@ ...@@ -73,6 +73,7 @@
<script defer type="module" src="js/appCesium.js"></script> <script defer type="module" src="js/appCesium.js"></script>
<script defer type="module" src="js/appChart.js"></script> <script defer type="module" src="js/appChart.js"></script>
<script defer type="module" src="js/dropDownList.js"></script> <script defer type="module" src="js/dropDownList.js"></script>
<script defer type="module" src="js/aggregate.js"></script>
</head> </head>
<body class="sb-nav-fixed"> <body class="sb-nav-fixed">
<nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark"> <nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
......
"use strict";
import {
BASE_URL,
QUERY_PARAMS_COMBINED,
getDatastreamIdFromBuildingNumber,
createObservationsUrl,
performGetRequestUsingAxios,
extractCombinedObservationsFromAllPages,
} from "./appChart.js";
/**
* Create 24-hour time strings for a time interval delimited by a start time and an end time. It is assumed that the start time is at "00:00:00" and the end time is at "23:45:00" (when the sampling rate of observations is 15 min) or "23:00:00" (when the sampling rate of observations is 60 min)
* @param {String} phenomenonSamplingRate The sampling rate of the phenomenon of interest represented as a string, e.g. "15 min", "60 min"
* @returns {Array} An array of two 24-hour strings representing the start time and end time
*/
const createTimeStringsForInterval = function (phenomenonSamplingRate) {
const fifteenMinutes = "15 min";
const sixtyMinutes = "60 min";
const startTime = "00:00:00";
const endTimeFifteenMinutes = "23:45:00";
const endTimeSixtyMinutes = "23:00:00";
if (
phenomenonSamplingRate !== fifteenMinutes &&
phenomenonSamplingRate !== sixtyMinutes
)
return;
// 15 min sampling rate
if (phenomenonSamplingRate === fifteenMinutes) {
return [startTime, endTimeFifteenMinutes];
}
// 60 min sampling rate
if (phenomenonSamplingRate === sixtyMinutes) {
return [startTime, endTimeSixtyMinutes];
}
};
/**
* Create an ISO 8601 date and time string
* @param {String} inputCalendarDate Calendar date string in "YYYY-MM-DD" format
* @param {String} inputTwentyFourHourTime 24-hour time string in "hh:mm:ss" format
* @returns {String} An ISO 8601 date and time string
*/
const createIso8601DateTimeString = function (
inputCalendarDate,
inputTwentyFourHourTime
) {
return `${inputCalendarDate}T${inputTwentyFourHourTime}.000Z`;
};
/**
* Calculate the index of a timestamp in an array of timestamps
* @param {Array} inputTimestampArr An array of timestamps, extracted from an array of observations
* @param {String} timestampOfInterest A string representing the timestamp of interest in ISO 8601 format
* @returns {Number} An integer representing the index of the timestamp of interest in the array of timestamps
*/
const getIndexOfTimestamp = function (inputTimestampArr, timestampOfInterest) {
const timestampIndex = inputTimestampArr.findIndex(
(timestamp) => timestamp === timestampOfInterest
);
// If the timestamp does not exist in the timestamp array
if (timestampIndex === -1)
throw new Error(
"A start or end timestamp could not be found in the timestamp array"
);
// If the timestamp exists in the timestamp array
return timestampIndex;
};
/**
* Aggregate observations within a time interval delimited by a start date and end date. The start date may be the same as the end date.
* @param {Array} obsArray An array of observations (timestamp + value) that is response from SensorThings API
* @param {String} samplingRate The sampling rate of observations as a string, e.g. "15 min", "60 min"
* @param {String} startDate A 24-hour date string representing the start date
* @param {String} endDate A 24-hour date string representing the end date
* @returns {Number} A floating-point number representing the aggregated observation value
*/
const aggregateObservationsWithinTimeInterval = function (
obsArray,
samplingRate,
startDate,
endDate
) {
// Extract the timestamps and values from the observations
const obsTimestampArr = obsArray.map((obs) => obs[0]);
const obsValuesArr = obsArray.map((obs) => obs[1]);
// Create array of 24-hour strings for the start and end of interval
const startPlusEndTimeStrings = createTimeStringsForInterval(samplingRate);
// Extract 24-hour strings for the start and end of interval
const [startTimeString, endTimeString] = startPlusEndTimeStrings;
// Create ISO 8601 strings for the start and end of interval
const startIso8601DateTimeString = createIso8601DateTimeString(
startDate,
startTimeString
);
const endIso8601DateTimeString = createIso8601DateTimeString(
endDate,
endTimeString
);
// Calculate the indexes of the timestamps for the start and end of interval
const indexStartTimestamp = getIndexOfTimestamp(
obsTimestampArr,
startIso8601DateTimeString
);
const indexEndTimestamp = getIndexOfTimestamp(
obsTimestampArr,
endIso8601DateTimeString
);
// Extract the observations that fall within our time interval
const obsValuesForTimeIntervalArr = obsValuesArr.slice(
indexStartTimestamp,
indexEndTimestamp + 1
);
// Calculate the aggregated observation value
const aggregatedObsValue = obsValuesForTimeIntervalArr.reduce(
(accumulator, currentValue) => accumulator + currentValue
);
return aggregatedObsValue;
};
/**
* Test aggregation of observations from a single datastream
*/
const testAggregation = async function () {
// Datastream ID
const datastreamIdBau225VL = getDatastreamIdFromBuildingNumber(
"225",
"vl",
"60min"
);
// Observations URL
const observationsUrlBau225VL = createObservationsUrl(
BASE_URL,
datastreamIdBau225VL
);
// Observations array
const observationsBau225VL = await extractCombinedObservationsFromAllPages(
performGetRequestUsingAxios(observationsUrlBau225VL, QUERY_PARAMS_COMBINED)
);
// Aggregated observations
const observationsBau225VLAggregated =
aggregateObservationsWithinTimeInterval(
observationsBau225VL,
"60 min",
"2020-02-01",
"2020-03-31"
);
// console.log(observationsBau225VLAggregated);
};
// testAggregation();
...@@ -104,7 +104,7 @@ const getDatastreamIdFromBuildingNumber = function ( ...@@ -104,7 +104,7 @@ const getDatastreamIdFromBuildingNumber = function (
* @param {Number} datastreamID Integer representing the Datastream ID * @param {Number} datastreamID Integer representing the Datastream ID
* @returns {String} URL string for fetching a single Datastream * @returns {String} URL string for fetching a single Datastream
*/ */
const getDatastreamUrl = function (baseUrl, datastreamID) { const createDatastreamUrl = function (baseUrl, datastreamID) {
if (!datastreamID) return; if (!datastreamID) return;
const fullDatastreamURL = `${baseUrl}/Datastreams(${datastreamID})`; const fullDatastreamURL = `${baseUrl}/Datastreams(${datastreamID})`;
return fullDatastreamURL; return fullDatastreamURL;
...@@ -116,7 +116,7 @@ const getDatastreamUrl = function (baseUrl, datastreamID) { ...@@ -116,7 +116,7 @@ const getDatastreamUrl = function (baseUrl, datastreamID) {
* @param {Number} datastreamID Integer representing the Datastream ID * @param {Number} datastreamID Integer representing the Datastream ID
* @returns {String} URL string for fetching Observations * @returns {String} URL string for fetching Observations
*/ */
const getObservationsUrl = function (baseUrl, datastreamID) { const createObservationsUrl = function (baseUrl, datastreamID) {
if (!datastreamID) return; if (!datastreamID) return;
const fullObservationsURL = `${baseUrl}/Datastreams(${datastreamID})/Observations`; const fullObservationsURL = `${baseUrl}/Datastreams(${datastreamID})/Observations`;
return fullObservationsURL; return fullObservationsURL;
...@@ -134,7 +134,6 @@ const createTemporalFilterString = function (dateStart, dateStop) { ...@@ -134,7 +134,6 @@ const createTemporalFilterString = function (dateStart, dateStop) {
return filterString; return filterString;
}; };
// const BASE_URL_OBSERVATIONS = getObservationsUrl(80);
const QUERY_PARAM_RESULT_FORMAT = "dataArray"; const QUERY_PARAM_RESULT_FORMAT = "dataArray";
const QUERY_PARAM_ORDER_BY = "phenomenonTime asc"; const QUERY_PARAM_ORDER_BY = "phenomenonTime asc";
const QUERY_PARAM_FILTER = createTemporalFilterString( const QUERY_PARAM_FILTER = createTemporalFilterString(
...@@ -155,7 +154,7 @@ const QUERY_PARAMS_COMBINED = { ...@@ -155,7 +154,7 @@ const QUERY_PARAMS_COMBINED = {
* @param {Object} urlParamObj The URL parameters to be sent together with the GET request * @param {Object} urlParamObj The URL parameters to be sent together with the GET request
* @returns {Promise} A promise that contains the first page of results when fulfilled * @returns {Promise} A promise that contains the first page of results when fulfilled
*/ */
const axiosGetRequest = function (urlObservations, urlParamObj) { const performGetRequestUsingAxios = function (urlObservations, urlParamObj) {
return axios.get(urlObservations, { return axios.get(urlObservations, {
params: urlParamObj, params: urlParamObj,
}); });
...@@ -172,7 +171,7 @@ const getMetadataFromSingleDatastream = async function (urlDatastream) { ...@@ -172,7 +171,7 @@ const getMetadataFromSingleDatastream = async function (urlDatastream) {
// Extract properties of interest // Extract properties of interest
const { const {
data: { description, name, unitOfMeasurement }, data: { description, name, unitOfMeasurement },
} = await axiosGetRequest(urlDatastream); } = await performGetRequestUsingAxios(urlDatastream);
return { description, name, unitOfMeasurement }; return { description, name, unitOfMeasurement };
} catch (err) { } catch (err) {
...@@ -267,11 +266,11 @@ const formatDatastreamMetadataForChart = function (datastreamMetadata) { ...@@ -267,11 +266,11 @@ const formatDatastreamMetadataForChart = function (datastreamMetadata) {
}; };
/** /**
* Format the response from SensorThings API to make it suitable for heatmap * Format the response from SensorThings API to make it suitable for use in a heatmap
* @param {Array} obsArray Array of observations (timestamp + value) that is response from SensorThings API * @param {Array} obsArray Array of observations (timestamp + value) that is response from SensorThings API
* @returns {Array} Array of formatted observations suitable for use in a heatmap * @returns {Array} Array of formatted observations suitable for use in a heatmap
*/ */
const formatSTAResponseForHeatMap = function (obsArray) { const formatSensorThingsApiResponseForHeatMap = function (obsArray) {
if (!obsArray) return; if (!obsArray) return;
const dataSTAFormatted = obsArray.map((obs) => { const dataSTAFormatted = obsArray.map((obs) => {
...@@ -322,7 +321,7 @@ const calculateMinMaxValuesForHeatmapColorAxis = function ( ...@@ -322,7 +321,7 @@ const calculateMinMaxValuesForHeatmapColorAxis = function (
* @param {Object} formattedDatastreamMetadata Object containing Datastream metadata * @param {Object} formattedDatastreamMetadata Object containing Datastream metadata
* @returns {undefined} undefined * @returns {undefined} undefined
*/ */
const drawHeatMapHC = function ( const drawHeatMapHighcharts = function (
formattedObsArrayForHeatmap, formattedObsArrayForHeatmap,
formattedDatastreamMetadata formattedDatastreamMetadata
) { ) {
...@@ -431,11 +430,11 @@ const drawHeatMapHC = function ( ...@@ -431,11 +430,11 @@ const drawHeatMapHC = function (
}; };
/** /**
* Format the response from SensorThings API to make it suitable for line chart * Format the response from SensorThings API to make it suitable for use in a line chart
* @param {Array} obsArray Response from SensorThings API as array * @param {Array} obsArray Response from SensorThings API as array
* @returns {Array} Array of formatted observations suitable for use in a line chart * @returns {Array} Array of formatted observations suitable for use in a line chart
*/ */
const formatSTAResponseForLineChart = function (obsArray) { const formatSensorThingsApiResponseForLineChart = function (obsArray) {
if (!obsArray) return; if (!obsArray) return;
const dataSTAFormatted = obsArray.map((result) => { const dataSTAFormatted = obsArray.map((result) => {
...@@ -453,7 +452,7 @@ const formatSTAResponseForLineChart = function (obsArray) { ...@@ -453,7 +452,7 @@ const formatSTAResponseForLineChart = function (obsArray) {
* @param {Object} formattedDatastreamMetadata Object containing Datastream metadata * @param {Object} formattedDatastreamMetadata Object containing Datastream metadata
* @returns {undefined} undefined * @returns {undefined} undefined
*/ */
const drawLineChartHC = function ( const drawLineChartHighcharts = function (
formattedObsArrayForLineChart, formattedObsArrayForLineChart,
formattedDatastreamMetadata formattedDatastreamMetadata
) { ) {
...@@ -537,21 +536,26 @@ const getIndexesOfUniqueObservations = function ( ...@@ -537,21 +536,26 @@ const getIndexesOfUniqueObservations = function (
/** /**
* Removes observations (by modifying array in place) that are unique to a larger set of observations. Based on the comparison of two observation arrays, where one array is larger than the other * Removes observations (by modifying array in place) that are unique to a larger set of observations. Based on the comparison of two observation arrays, where one array is larger than the other
* @param {Array} uniqueIndexesArr An array of the indexes unique to the larger set of observations * @param {Array} uniqueIndexesArr An array of the indexes unique to the larger set of observations
* @param {Array} largerObsArr The larger array of observations (timestamp + value) which is modified in place * @param {Array} largerObsArr The larger array of observations (timestamp + value)
* @returns {undefined} * @returns {Array} The larger array with the unique indexes removed
*/ */
const removeUniqueObservationsFromLargerArray = function ( const removeUniqueObservationsFromLargerArray = function (
uniqueIndexesArr, uniqueIndexesArr,
largerObsArr largerObsArr
) { ) {
// Reverse the indexes array so that the larger index is removed first // Create a reversed copy of the indexes array, so that the larger index is removed first
uniqueIndexesArr.reverse(); const reversedUniqueIndexesArr = uniqueIndexesArr.reverse();
// Create a copy the larger observation array, will be modified in place
const processedLargerObsArr = largerObsArr;
uniqueIndexesArr.forEach((index) => { reversedUniqueIndexesArr.forEach((index) => {
if (index > -1) { if (index > -1) {
largerObsArr.splice(index, 1); processedLargerObsArr.splice(index, 1);
} }
}); });
return processedLargerObsArr;
}; };
/** /**
...@@ -630,10 +634,12 @@ const deleteUniqueObservationsFromLargerArray = function ( ...@@ -630,10 +634,12 @@ const deleteUniqueObservationsFromLargerArray = function (
); );
// Remove the missing observation from the larger array of observations // Remove the missing observation from the larger array of observations
// Modifies the array in place const modifiedBiggerObsArr = removeUniqueObservationsFromLargerArray(
removeUniqueObservationsFromLargerArray(indexesMissingObsArr, biggerObsArr); indexesMissingObsArr,
biggerObsArr
);
return [biggerObsArr, smallerObsArr]; return [modifiedBiggerObsArr, smallerObsArr];
}; };
/** /**
...@@ -661,7 +667,7 @@ const checkForAndDeleteUniqueObservationsFromLargerArray = function ( ...@@ -661,7 +667,7 @@ const checkForAndDeleteUniqueObservationsFromLargerArray = function (
}; };
/** /**
* Extracts and combines observation values from two imput observation arrays of equal length * Extracts and combines observation values from two input observation arrays of equal length
* @param {Array} obsArrayOne First set of N observations (timestamp + value) * @param {Array} obsArrayOne First set of N observations (timestamp + value)
* @param {Array} obsArrayTwo Second set of N observations (timestamp + value) * @param {Array} obsArrayTwo Second set of N observations (timestamp + value)
* @returns {Array} A 2*N array of observation values from both input observation arrays * @returns {Array} A 2*N array of observation values from both input observation arrays
...@@ -680,12 +686,15 @@ const createCombinedObservationValues = function (obsArrayOne, obsArrayTwo) { ...@@ -680,12 +686,15 @@ const createCombinedObservationValues = function (obsArrayOne, obsArrayTwo) {
}; };
/** /**
* Format the response from SensorThings API to make it suitable for scatter plot * Format the response from SensorThings API to make it suitable for use in a scatter plot
* @param {Array} obsArrayOne Array of observations (timestamp + value) that is response from SensorThings API * @param {Array} obsArrayOne Array of observations (timestamp + value) that is response from SensorThings API
* @param {Array} obsArrayTwo Array of observations (timestamp + value) that is response from SensorThings API * @param {Array} obsArrayTwo Array of observations (timestamp + value) that is response from SensorThings API
* @returns {Array} Array of formatted observations suitable for use in a scatter plot * @returns {Array} Array of formatted observations suitable for use in a scatter plot
*/ */
const formatSTAResponseForScatterPlot = function (obsArrayOne, obsArrayTwo) { const formatSensorThingsApiResponseForScatterPlot = function (
obsArrayOne,
obsArrayTwo
) {
// When our observation arrays have DIFFERENT lengths // When our observation arrays have DIFFERENT lengths
if (obsArrayOne.length !== obsArrayTwo.length) { if (obsArrayOne.length !== obsArrayTwo.length) {
const [obsArrayOneFinal, obsArrayTwoFinal] = const [obsArrayOneFinal, obsArrayTwoFinal] =
...@@ -708,7 +717,7 @@ const formatSTAResponseForScatterPlot = function (obsArrayOne, obsArrayTwo) { ...@@ -708,7 +717,7 @@ const formatSTAResponseForScatterPlot = function (obsArrayOne, obsArrayTwo) {
* @param {*} formattedDatastreamMetadataSeriesTwo Object containing Datastream metadata for the second chart series * @param {*} formattedDatastreamMetadataSeriesTwo Object containing Datastream metadata for the second chart series
* @returns {undefined} * @returns {undefined}
*/ */
const drawScatterPlotHC = function ( const drawScatterPlotHighcharts = function (
formattedObsArrayForSeriesOnePlusSeriesTwo, formattedObsArrayForSeriesOnePlusSeriesTwo,
formattedDatastreamMetadataSeriesOne, formattedDatastreamMetadataSeriesOne,
formattedDatastreamMetadataSeriesTwo formattedDatastreamMetadataSeriesTwo
...@@ -830,61 +839,67 @@ const drawScatterPlotHC = function ( ...@@ -830,61 +839,67 @@ const drawScatterPlotHC = function (
}; };
/** /**
* Follows "@iot.nextLink" links in SensorThingsAPI's response * Traverses all the pages that make up the response from a SensorThingsAPI instance. The link to the next page, if present, is denoted by the presence of a "@iot.nextLink" property in the response object. This function concatenates all the values so that the complete results are returned in one array.
* Appends new results to existing results
* @async * @async
* @param {Promise} responsePromise Promise object resulting from an Axios GET request * @param {Promise} httpGetRequestPromise Promise object resulting from an Axios GET request
* @returns {Object} Object containing results from all the "@iot.nextLink" links * @returns {Promise} A promise that contains an object containing results from all the pages when fulfilled
*/ */
const followNextLink = function (responsePromise) { const combineResultsFromAllPages = async function (httpGetRequestPromise) {
if (!responsePromise) return; try {
return responsePromise if (!httpGetRequestPromise) return;
.then((lastSuccess) => {
if (lastSuccess.data["@iot.nextLink"]) { const lastSuccess = await httpGetRequestPromise;
return followNextLink( if (lastSuccess.data["@iot.nextLink"]) {
axios.get(lastSuccess.data["@iot.nextLink"]) const nextLinkSuccess = await combineResultsFromAllPages(
).then((nextLinkSuccess) => { axios.get(lastSuccess.data["@iot.nextLink"])
nextLinkSuccess.data.value = lastSuccess.data.value.concat( );
nextLinkSuccess.data.value nextLinkSuccess.data.value = lastSuccess.data.value.concat(
); nextLinkSuccess.data.value
return nextLinkSuccess; );
}); return nextLinkSuccess;
} else { } else {
return lastSuccess; return lastSuccess;
} }
}) } catch (err) {
.catch((err) => { console.error(err);
console.error(err); }
});
}; };
/** /**
* Retrieve all the Observations from a Datastream after traversing all the "@iot.nextLink" links * Traverses all the pages that make up the response from a SensorThingsAPI instance and extracts the combined Observations
* @async * @async
* @param {Promise} httpGetRequestPromise Promise object resulting from an Axios GET request * @param {Promise} httpGetRequestPromise Promise object resulting from an Axios GET request
* @returns {Promise} A promise that contains an array of Observations from a single Datastream when fulfilled * @returns {Promise} A promise that contains an array of Observations when fulfilled
*/ */
const getCombinedObservationsFromAllNextLinks = function ( const extractCombinedObservationsFromAllPages = async function (
httpGetRequestPromise httpGetRequestPromise
) { ) {
return followNextLink(httpGetRequestPromise) try {
.then((success) => { const successResponse = await combineResultsFromAllPages(
const successValue = success.data.value; httpGetRequestPromise
// Array that will hold the combined observations );
const combinedObservations = [];
successValue.forEach((dataObj) => { // Extract value array from the success response object
// Each page of results will have a dataArray that holds the observations const {
const dataArrays = dataObj.dataArray; data,
combinedObservations.push(...dataArrays); data: { value: valueArr },
}); } = successResponse;
return new Promise((resolve, reject) => { // Array that will hold the combined observations
resolve(combinedObservations); const combinedObservations = [];
});
}) valueArr.forEach((val) => {
.catch((err) => { // Each page of results will have a dataArray that holds the observations
console.error(err); const { dataArray } = val;
combinedObservations.push(...dataArray);
});
return new Promise((resolve, reject) => {
resolve(combinedObservations);
}); });
} catch (err) {
console.error(err);
}
}; };
/** /**
...@@ -959,18 +974,18 @@ const getMetadataPlusObservationsFromMultipleDatastreams = async function ( ...@@ -959,18 +974,18 @@ const getMetadataPlusObservationsFromMultipleDatastreams = async function (
// Observations URLs // Observations URLs
const observationsUrlArr = datastreamsIdsArr.map((datastreamId) => const observationsUrlArr = datastreamsIdsArr.map((datastreamId) =>
getObservationsUrl(BASE_URL, datastreamId) createObservationsUrl(BASE_URL, datastreamId)
); );
// Datastreams URLs // Datastreams URLs
const datastreamsUrlArr = datastreamsIdsArr.map((datastreamId) => const datastreamsUrlArr = datastreamsIdsArr.map((datastreamId) =>
getDatastreamUrl(BASE_URL, datastreamId) createDatastreamUrl(BASE_URL, datastreamId)
); );
// Promise objects - Observations // Promise objects - Observations
const observationsPromisesArr = observationsUrlArr.map((obsUrl) => const observationsPromisesArr = observationsUrlArr.map((obsUrl) =>
getCombinedObservationsFromAllNextLinks( extractCombinedObservationsFromAllPages(
axiosGetRequest(obsUrl, QUERY_PARAMS_COMBINED) performGetRequestUsingAxios(obsUrl, QUERY_PARAMS_COMBINED)
) )
); );
...@@ -995,73 +1010,86 @@ const getMetadataPlusObservationsFromMultipleDatastreams = async function ( ...@@ -995,73 +1010,86 @@ const getMetadataPlusObservationsFromMultipleDatastreams = async function (
* @async * @async
* @param {String} buildingId The building ID as a string * @param {String} buildingId The building ID as a string
* @param {String} samplingRate The sampling rate as a string * @param {String} samplingRate The sampling rate as a string
* @returns A promise that contains an array (that is made up of a temperature difference array and a metadata object) when fulfilled * @returns {Promise} A promise that contains an array (that is made up of a temperature difference array and a metadata object) when fulfilled
*/ */
const calculateVorlaufMinusRuecklaufTemperature = async function ( const calculateVorlaufMinusRuecklaufTemperature = async function (
buildingId, buildingId,
samplingRate samplingRate
) { ) {
const bldgSensorSamplingRateArr = [ try {
[buildingId, "vl", samplingRate], const bldgSensorSamplingRateArr = [
[buildingId, "rl", samplingRate], [buildingId, "vl", samplingRate],
]; [buildingId, "rl", samplingRate],
];
const BUILDING_ID = buildingId;
const SAMPLING_RATE = samplingRate;
const observationsPlusMetadata = const BUILDING_ID = buildingId;
await getMetadataPlusObservationsFromMultipleDatastreams( const SAMPLING_RATE = samplingRate;
bldgSensorSamplingRateArr
);
// Extract Vorlauf temperature and Ruecklauf temperature const observationsPlusMetadata =
const [[vorlaufTemp, ruecklaufTemp], [metadataVorlauf, metadataRuecklauf]] = await getMetadataPlusObservationsFromMultipleDatastreams(
observationsPlusMetadata; bldgSensorSamplingRateArr
);
const vorlaufTempValues = vorlaufTemp.map((obs) => obs[1]); // Extract Vorlauf temperature, Ruecklauf temperature and metadata
const ruecklaufTempValues = ruecklaufTemp.map((obs) => obs[1]); const [[vorlaufTemp, ruecklaufTemp], [metadataVorlauf, metadataRuecklauf]] =
observationsPlusMetadata;
// The arrays have equal length, we need only use one of them for looping // Extract the temperature values
// Resulting array contains the following pairs (timestamp + dT) const vorlaufTempValues = vorlaufTemp.map((obs) => obs[1]);
const vorlaufMinusRuecklaufTemp = vorlaufTemp.map((obs, i) => [ const ruecklaufTempValues = ruecklaufTemp.map((obs) => obs[1]);
obs[0],
vorlaufTempValues[i] - ruecklaufTempValues[i],
]);
// From Vorlauf metadata, extract `name` and `unitOfMeasurement` // The arrays have equal length, we need only use one of them for looping
const { name: datastreamNameVorlauf, unitOfMeasurement } = metadataVorlauf; // Resulting array contains the following pairs (timestamp + dT)
const vorlaufMinusRuecklaufTemp = vorlaufTemp.map((obs, i) => [
obs[0],
vorlaufTempValues[i] - ruecklaufTempValues[i],
]);
// From Ruecklauf metadata, extract `name` // From Vorlauf metadata, extract `name` and `unitOfMeasurement`
const { name: datastreamNameRuecklauf } = metadataRuecklauf; const {
name: datastreamNameVorlauf,
unitOfMeasurement: unitOfMeasurementVorlauf,
} = metadataVorlauf;
// Extract the phenomenon names from Datastream names // From Ruecklauf metadata, extract `name`
const phenomenonNameVorlauf = extractPhenomenonNameFromDatastreamName( const { name: datastreamNameRuecklauf } = metadataRuecklauf;
datastreamNameVorlauf
);
const phenomenonNameRuecklauf = extractPhenomenonNameFromDatastreamName(
datastreamNameRuecklauf
);
// Create our custom datastream description text // Extract the phenomenon names from the Datastream names
const descriptionCombined = `Computed dT: ${phenomenonNameVorlauf} minus ${phenomenonNameRuecklauf}`; const phenomenonNameVorlauf = extractPhenomenonNameFromDatastreamName(
datastreamNameVorlauf
);
const phenomenonNameRuecklauf = extractPhenomenonNameFromDatastreamName(
datastreamNameRuecklauf
);
// The resulting datastream description string has two `temperature` substrings; // Create our custom datastream description text
// replace the first occurence with an empty string // The resulting datastream description string has two `temperature` substrings;
const description = descriptionCombined.replace("temperature", ""); // replace the first occurence with an empty string
const descriptionTempDifference =
`Computed dT: ${phenomenonNameVorlauf} minus ${phenomenonNameRuecklauf}`.replace(
"temperature",
""
);
// Create our custom datastream name text // Create our custom datastream name text
const name = `BOSCH_${BUILDING_ID} / dT Temperature difference (VL-RL) DS:${SAMPLING_RATE}`; const nameTempDifference = `BOSCH_${BUILDING_ID} / dT Temperature difference (VL-RL) DS:${SAMPLING_RATE}`;
return [ // The datastream object that we return needs to have these property names
vorlaufMinusRuecklaufTemp, const description = descriptionTempDifference;
const name = nameTempDifference;
const unitOfMeasurement = unitOfMeasurementVorlauf;
// The datastream metadata object needs to have these property names return [
{ vorlaufMinusRuecklaufTemp,
description, {
name, description,
unitOfMeasurement, name,
}, unitOfMeasurement,
]; },
];
} catch (err) {
console.error(err);
}
}; };
/** /**
...@@ -1071,8 +1099,8 @@ const drawHeatmapHCUsingTempDifference = async function () { ...@@ -1071,8 +1099,8 @@ const drawHeatmapHCUsingTempDifference = async function () {
const [tempDifferenceObsArrBau225, tempDifferenceMetadataBau225] = const [tempDifferenceObsArrBau225, tempDifferenceMetadataBau225] =
await calculateVorlaufMinusRuecklaufTemperature("225", "60min"); await calculateVorlaufMinusRuecklaufTemperature("225", "60min");
drawHeatMapHC( drawHeatMapHighcharts(
formatSTAResponseForHeatMap(tempDifferenceObsArrBau225), formatSensorThingsApiResponseForHeatMap(tempDifferenceObsArrBau225),
formatDatastreamMetadataForChart(tempDifferenceMetadataBau225) formatDatastreamMetadataForChart(tempDifferenceMetadataBau225)
); );
}; };
...@@ -1099,8 +1127,11 @@ const drawScatterPlotHCTest2 = async function () { ...@@ -1099,8 +1127,11 @@ const drawScatterPlotHCTest2 = async function () {
[metadataSensorOne, metadataSensorTwo], [metadataSensorOne, metadataSensorTwo],
] = observationsPlusMetadata; ] = observationsPlusMetadata;
drawScatterPlotHC( drawScatterPlotHighcharts(
formatSTAResponseForScatterPlot(obsSensorOneArr, obsSensorTwoArr), formatSensorThingsApiResponseForScatterPlot(
obsSensorOneArr,
obsSensorTwoArr
),
formatDatastreamMetadataForChart(metadataSensorOne), formatDatastreamMetadataForChart(metadataSensorOne),
formatDatastreamMetadataForChart(metadataSensorTwo) formatDatastreamMetadataForChart(metadataSensorTwo)
); );
...@@ -1115,16 +1146,16 @@ export { ...@@ -1115,16 +1146,16 @@ export {
BASE_URL, BASE_URL,
QUERY_PARAMS_COMBINED, QUERY_PARAMS_COMBINED,
getDatastreamIdFromBuildingNumber, getDatastreamIdFromBuildingNumber,
getDatastreamUrl, createDatastreamUrl,
getObservationsUrl, createObservationsUrl,
createTemporalFilterString, createTemporalFilterString,
axiosGetRequest, performGetRequestUsingAxios,
getMetadataFromSingleDatastream, getMetadataFromSingleDatastream,
formatDatastreamMetadataForChart, formatDatastreamMetadataForChart,
formatSTAResponseForHeatMap, formatSensorThingsApiResponseForHeatMap,
drawHeatMapHC, drawHeatMapHighcharts,
formatSTAResponseForLineChart, formatSensorThingsApiResponseForLineChart,
drawLineChartHC, drawLineChartHighcharts,
getCombinedObservationsFromAllNextLinks, extractCombinedObservationsFromAllPages,
getMetadataPlusObservationsFromSingleDatastream, getMetadataPlusObservationsFromSingleDatastream,
}; };
...@@ -4,16 +4,16 @@ import { ...@@ -4,16 +4,16 @@ import {
BASE_URL, BASE_URL,
QUERY_PARAMS_COMBINED, QUERY_PARAMS_COMBINED,
getDatastreamIdFromBuildingNumber, getDatastreamIdFromBuildingNumber,
getDatastreamUrl, createDatastreamUrl,
getObservationsUrl, createObservationsUrl,
axiosGetRequest, performGetRequestUsingAxios,
getMetadataFromSingleDatastream, getMetadataFromSingleDatastream,
formatDatastreamMetadataForChart, formatDatastreamMetadataForChart,
formatSTAResponseForHeatMap, formatSensorThingsApiResponseForHeatMap,
drawHeatMapHC, drawHeatMapHighcharts,
formatSTAResponseForLineChart, formatSensorThingsApiResponseForLineChart,
drawLineChartHC, drawLineChartHighcharts,
getCombinedObservationsFromAllNextLinks, extractCombinedObservationsFromAllPages,
getMetadataPlusObservationsFromSingleDatastream, getMetadataPlusObservationsFromSingleDatastream,
} from "./appChart.js"; } from "./appChart.js";
...@@ -285,14 +285,17 @@ const selectChartTypeFromDropDown = async function () { ...@@ -285,14 +285,17 @@ const selectChartTypeFromDropDown = async function () {
// Display the loading indicator // Display the loading indicator
showLoadingSpinner(); showLoadingSpinner();
const URL_DATASTREAM = getDatastreamUrl(BASE_URL, selectedDatastream); const URL_DATASTREAM = createDatastreamUrl(BASE_URL, selectedDatastream);
const URL_OBSERVATIONS = getObservationsUrl(BASE_URL, selectedDatastream); const URL_OBSERVATIONS = createObservationsUrl(
BASE_URL,
selectedDatastream
);
// Create promises // Create promises
const promiseDatastreamMetadata = const promiseDatastreamMetadata =
getMetadataFromSingleDatastream(URL_DATASTREAM); getMetadataFromSingleDatastream(URL_DATASTREAM);
const promiseCombinedObservations = getCombinedObservationsFromAllNextLinks( const promiseCombinedObservations = extractCombinedObservationsFromAllPages(
axiosGetRequest(URL_OBSERVATIONS, QUERY_PARAMS_COMBINED) performGetRequestUsingAxios(URL_OBSERVATIONS, QUERY_PARAMS_COMBINED)
); );
// Pass promises to our async function // Pass promises to our async function
...@@ -307,13 +310,13 @@ const selectChartTypeFromDropDown = async function () { ...@@ -307,13 +310,13 @@ const selectChartTypeFromDropDown = async function () {
const datastreamMetadata = metadataPlusObservations[1]; const datastreamMetadata = metadataPlusObservations[1];
if (selectedChartType === "Line") { if (selectedChartType === "Line") {
drawLineChartHC( drawLineChartHighcharts(
formatSTAResponseForLineChart(combinedObs), formatSensorThingsApiResponseForLineChart(combinedObs),
formatDatastreamMetadataForChart(datastreamMetadata) formatDatastreamMetadataForChart(datastreamMetadata)
); );
} else if (selectedChartType === "Heatmap") { } else if (selectedChartType === "Heatmap") {
drawHeatMapHC( drawHeatMapHighcharts(
formatSTAResponseForHeatMap(combinedObs), formatSensorThingsApiResponseForHeatMap(combinedObs),
formatDatastreamMetadataForChart(datastreamMetadata) formatDatastreamMetadataForChart(datastreamMetadata)
); );
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment