"use strict"; // DEBUG: // Observations WITHOUT data gap - Bau 225 / Datastream ID = 80 // Observations WITH data gap - Bau 112 / Datastream ID = 78 export const BASE_URL = "http://193.196.39.91:8080/frost-icity-tp31/v1.1"; export const getDatastreamIdFromBuildingNumber = function ( buildingNumber, phenomenon, samplingRate ) { // Ensure that building number passed here is numeric if (!Number.isInteger(buildingNumber)) return; const buildingToDatastreamMapping = { 101: { vl: { "15min": "69", "60min": "75" }, rl: { "15min": "81", "60min": "87" }, flow: { "15min": "93", "60min": "99" }, power: { "15min": "105", "60min": "111" }, energy: { "15min": "117", "60min": "123" }, energy_verb: { "15min": "129", "60min": "135" }, }, 102: { vl: { "15min": "70", "60min": "76" }, rl: { "15min": "82", "60min": "88" }, flow: { "15min": "94", "60min": "100" }, power: { "15min": "106", "60min": "112" }, energy: { "15min": "118", "60min": "124" }, energy_verb: { "15min": "130", "60min": "136" }, }, 107: { vl: { "15min": "71", "60min": "77" }, rl: { "15min": "83", "60min": "89" }, flow: { "15min": "95", "60min": "101" }, power: { "15min": "107", "60min": "113" }, energy: { "15min": "119", "60min": "125" }, energy_verb: { "15min": "131", "60min": "137" }, }, "112_118": { vl: { "15min": "72", "60min": "78" }, rl: { "15min": "84", "60min": "90" }, flow: { "15min": "96", "60min": "102" }, power: { "15min": "108", "60min": "114" }, energy: { "15min": "120", "60min": "126" }, energy_verb: { "15min": "132", "60min": "138" }, }, 125: { vl: { "15min": "73", "60min": "79" }, rl: { "15min": "85", "60min": "91" }, flow: { "15min": "97", "60min": "103" }, power: { "15min": "109", "60min": "115" }, energy: { "15min": "121", "60min": "127" }, energy_verb: { "15min": "133", "60min": "139" }, }, 225: { vl: { "15min": "74", "60min": "80" }, rl: { "15min": "86", "60min": "92" }, flow: { "15min": "98", "60min": "104" }, power: { "15min": "110", "60min": "116" }, energy: { "15min": "122", "60min": "128" }, energy_verb: { "15min": "134", "60min": "140" }, }, }; const datastreamIdMatched = Number( buildingToDatastreamMapping[buildingNumber][phenomenon][samplingRate] ); return datastreamIdMatched; }; /** * Create URL to fetch the Observations corresponding to a provided Datastream * @param {Number} datastreamID - Integer representing the Datastream ID * @returns {String} URL string for fetching the Observations corresponding to a Datastream */ export const getObservationsUrl = function (baseUrl, datastreamID) { if (!datastreamID) return; const fullDatastreamURL = `${baseUrl}/Datastreams(${datastreamID})/Observations`; return fullDatastreamURL; }; /** * Create a temporal filter string for the fetched Observations * @param {String} dateStart Start date in YYYY-MM-DD format * @param {String} dateStop Stop date in YYYY-MM-DD format * @returns {String} Temporal filter string */ export const createTemporalFilterString = function (dateStart, dateStop) { if (!dateStart || !dateStop) return; const filterString = `resultTime ge ${dateStart}T00:00:00.000Z and resultTime le ${dateStop}T00:00:00.000Z`; return filterString; }; // const BASE_URL_OBSERVATIONS = getObservationsUrl(80); export const PARAM_RESULT_FORMAT = "dataArray"; export const PARAM_ORDER_BY = "phenomenonTime asc"; // const PARAM_FILTER = createTemporalFilterString("2020-01-01", "2021-01-01"); export const PARAM_SELECT = "result,phenomenonTime"; // const axiosGetRequest = axios.get(BASE_URL_OBSERVATIONS, { // params: { // "$resultFormat": PARAM_RESULT_FORMAT, // "$orderBy": PARAM_ORDER_BY, // "$filter": PARAM_FILTER, // "$select": PARAM_SELECT, // }, // }); /** * Format the response from SensorThings API to make it suitable for heatmap * @param {Array} obsArray Response from SensorThings API as array * @returns {Array} Array of formatted observations suitable for use in a heatmap */ export const formatSTAResponseForHeatMap = function (obsArray) { const dataSTAFormatted = []; obsArray.forEach((obs) => { // Get the date/time string; first element in input array; remove trailing "Z" const obsDateTimeInput = obs[0].slice(0, -1); // Get the "date" part of an observation const obsDateInput = obs[0].slice(0, 10); // Create Date objects const obsDateTime = new Date(obsDateTimeInput); const obsDate = new Date(obsDateInput); // x-axis -> timestamp; will be the same for observations from the same date const timestamp = Date.parse(obsDate); // y-axis -> hourOfDay const hourOfDay = obsDateTime.getHours(); // value -> the observation's value; second element in input array const value = obs[1]; dataSTAFormatted.push([timestamp, hourOfDay, value]); }); return dataSTAFormatted; }; /** * Draw a heatmap using Highcharts library * @param {Array} obsArray Response from SensorThings API * @returns {Object} Highcharts library heatmap object */ export const drawHeatMapHC = function (formattedObsArrayForHeatmap) { Highcharts.chart("chart-heatmap", { chart: { type: "heatmap", zoomType: "x", }, boost: { useGPUTranslations: true, }, title: { text: "Inlet flow (Vorlauf)", align: "left", x: 40, }, subtitle: { text: "Temperature variation by day and hour in 2020", align: "left", x: 40, }, xAxis: { type: "datetime", // min: Date.UTC(2017, 0, 1), // max: Date.UTC(2017, 11, 31, 23, 59, 59), labels: { align: "left", x: 5, y: 14, format: "{value:%B}", // long month }, showLastLabel: false, tickLength: 16, }, yAxis: { title: { text: null, }, labels: { format: "{value}:00", }, minPadding: 0, maxPadding: 0, startOnTick: false, endOnTick: false, // tickPositions: [0, 6, 12, 18, 24], tickPositions: [0, 3, 6, 9, 12, 15, 18, 21, 24], tickWidth: 1, min: 0, max: 23, reversed: true, }, colorAxis: { stops: [ [0, "#3060cf"], [0.5, "#fffbbc"], [0.9, "#c4463a"], [1, "#c4463a"], ], min: 60, max: 85, startOnTick: false, endOnTick: false, labels: { format: "{value}℃", }, }, series: [ { data: formattedObsArrayForHeatmap, boostThreshold: 100, borderWidth: 0, nullColor: "#525252", colsize: 24 * 36e5, // one day tooltip: { headerFormat: "Temperature
", pointFormat: "{point.x:%e %b, %Y} {point.y}:00: {point.value} ℃", }, turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release }, ], }); }; /** * Convert the observations' phenomenonTime from an ISO 8601 string to Unix epoch * @param {Array} obsArray Response from SensorThings API as array * @returns {Array} Array of formatted observations suitable for use in a line chart */ export const formatSTAResponseForLineChart = function (obsArray) { const dataSTAFormatted = []; obsArray.forEach((result) => { const timestampObs = new Date(result[0].slice(0, -1)).getTime(); // slice() removes trailing "Z" character in timestamp const valueObs = result[1]; dataSTAFormatted.push([timestampObs, valueObs]); }); return dataSTAFormatted; }; /** * Draw a line chart using Highcharts library * @param {Array} obsArray - Response from SensorThings API * @returns {Object} Highcharts library line chart object */ export const drawLineChartHC = function (formattedObsArrayForLineChart) { // Create the chart Highcharts.stockChart("chart-line", { chart: { zoomType: "x", }, rangeSelector: { selected: 1, }, title: { text: "AAPL Stock Price", }, series: [ { name: "AAPL", data: formattedObsArrayForLineChart, tooltip: { valueDecimals: 2, }, turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release }, ], }); }; /** * Follows "@iot.nextLink" links in SensorThingsAPI's response * Appends new results to existing results * @async * @param {Object} responsePromise Promise object * @returns {Object} - Object containing results from all the "@iot.nextLink" links */ export const followNextLink = function (responsePromise) { return responsePromise .then(function (lastSuccess) { if (lastSuccess.data["@iot.nextLink"]) { return followNextLink( axios.get(lastSuccess.data["@iot.nextLink"]) ).then(function (nextLinkSuccess) { nextLinkSuccess.data.value = lastSuccess.data.value.concat( nextLinkSuccess.data.value ); return nextLinkSuccess; }); } else { return lastSuccess; } }) .catch(function (err) { console.log(err); }); }; // Get "ALL" the Observations that satisfy our query // followNextLink(axiosGetRequest) // .then((success) => { // const successValue = success.data.value; // // Array that will hold the combined observations // const combinedObservations = []; // successValue.forEach((dataObj) => { // // Each page of results will have a dataArray that holds the observations // const dataArrays = dataObj.dataArray; // combinedObservations.push(...dataArrays); // }); // // DEBUG: Check total number of observations // console.log(combinedObservations.length); // // DEBUG: Print the array of observations // console.log(combinedObservations); // return combinedObservations; // }) // .catch((err) => { // console.log(err); // }) // .then((observationArr) => { // drawHeatMapHC(observationArr); // drawLineChartHC(observationArr); // });