appChart.js 41.4 KB
Newer Older
1001
1002
1003
  } catch (err) {
    console.error(err);
  }
1004
};
1005
1006
1007
1008

/**
 * Retrieve all the Observations from an array of Observations promises
 * @async
1009
 * @param {Promise} observationPromiseArray An array that contains N observation promises
1010
1011
1012
1013
1014
 * @returns {Promise} A promise that contains an array of Observations from multiple Datastreams when fulfilled
 */
const getObservationsFromMultipleDatastreams = async function (
  observationPromiseArray
) {
1015
1016
1017
  try {
    // Array to store our final result
    const observationsAllDatastreamsArr = [];
1018

1019
1020
    // Use for/of loop - we need to maintain the order of execution of the async operations
    for (const observationPromise of observationPromiseArray) {
1021
1022
1023
1024
      // Observations from a single Datastream
      const observations = await observationPromise;
      observationsAllDatastreamsArr.push(observations);
    }
1025
1026
1027
1028

    return observationsAllDatastreamsArr;
  } catch (err) {
    console.error(err);
1029
1030
  }
};
1031

1032
/**
1033
1034
1035
1036
1037
 * Retrieve the metadata from a single Datastream or multiple Datastreams and the Observations corresponding to the Datastream(s)
 * @param {String} baseUrl Base URL of the STA server
 * @param {Object} urlParamObj The URL parameters to be sent together with the GET request
 * @param {Array} bldgSensorSamplingRateArr A N*1 array (where N >= 1) containing a nested array of buildings, sensors & sampling rates as strings, i.e. [["101", "rl", "15min"]] or [["101", "rl", "15min"], ["102", "vl", "60min"]] or [["101", "rl", "15min"], ["102", "vl", "60min"], ["225", "vl", "60min"]], etc
 * @returns {Promise} A promise that contains a 1*2 array (the first element is an array that contans N Observations arrays; and the second element is an array of N Datastream metadata objects) when fulfilled
1038
 */
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
const getMetadataPlusObservationsFromSingleOrMultipleDatastreams =
  async function (baseUrl, urlParamObj, bldgSensorSamplingRateArr) {
    try {
      if (!bldgSensorSamplingRateArr) return;

      // Datastreams IDs
      const datastreamsIdsArr = bldgSensorSamplingRateArr.map(
        (bldgSensorSamplingRate) =>
          getDatastreamIdFromBuildingNumber(...bldgSensorSamplingRate)
      );
1049

1050
1051
1052
1053
      // Observations URLs
      const observationsUrlArr = datastreamsIdsArr.map((datastreamId) =>
        createObservationsUrl(baseUrl, datastreamId)
      );
1054

1055
1056
1057
1058
      // Datastreams URLs
      const datastreamsUrlArr = datastreamsIdsArr.map((datastreamId) =>
        createDatastreamUrl(baseUrl, datastreamId)
      );
1059

1060
1061
1062
1063
1064
1065
      // Promise objects - Observations
      const observationsPromisesArr = observationsUrlArr.map((obsUrl) =>
        extractCombinedObservationsFromAllPages(
          performGetRequestUsingAxios(obsUrl, urlParamObj)
        )
      );
1066

1067
1068
1069
1070
      // Observations array
      const observationsArr = await getObservationsFromMultipleDatastreams(
        observationsPromisesArr
      );
1071

1072
1073
1074
1075
      // Metadata array
      const metadataArr = await getMetadataFromMultipleDatastreams(
        datastreamsUrlArr
      );
1076

1077
1078
1079
1080
1081
      return [observationsArr, metadataArr];
    } catch (err) {
      console.error(err);
    }
  };
1082

Pithon Kabiro's avatar
Pithon Kabiro committed
1083
1084
1085
1086
1087
/**
 * Calculates the temperature difference, dT, between Vorlauf temperature [VL] and Rücklauf temperature [RL] (i.e., dT = VL - RL)
 * @async
 * @param {String} buildingId The building ID as a string
 * @param {String} samplingRate The sampling rate as a string
1088
 * @returns {Promise} A promise that contains an array (that is made up of a temperature difference array and a metadata object) when fulfilled
Pithon Kabiro's avatar
Pithon Kabiro committed
1089
1090
1091
1092
1093
 */
const calculateVorlaufMinusRuecklaufTemperature = async function (
  buildingId,
  samplingRate
) {
1094
1095
1096
1097
1098
  try {
    const bldgSensorSamplingRateArr = [
      [buildingId, "vl", samplingRate],
      [buildingId, "rl", samplingRate],
    ];
Pithon Kabiro's avatar
Pithon Kabiro committed
1099

1100
1101
    const BUILDING_ID = buildingId;
    const SAMPLING_RATE = samplingRate;
Pithon Kabiro's avatar
Pithon Kabiro committed
1102

1103
    const observationsPlusMetadata =
1104
1105
1106
      await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
        BASE_URL,
        QUERY_PARAMS_COMBINED,
1107
1108
        bldgSensorSamplingRateArr
      );
Pithon Kabiro's avatar
Pithon Kabiro committed
1109

1110
1111
1112
    // Extract Vorlauf temperature, Ruecklauf temperature and metadata
    const [[vorlaufTemp, ruecklaufTemp], [metadataVorlauf, metadataRuecklauf]] =
      observationsPlusMetadata;
Pithon Kabiro's avatar
Pithon Kabiro committed
1113

1114
1115
1116
    // Extract the temperature values
    const vorlaufTempValues = vorlaufTemp.map((obs) => obs[1]);
    const ruecklaufTempValues = ruecklaufTemp.map((obs) => obs[1]);
Pithon Kabiro's avatar
Pithon Kabiro committed
1117

1118
1119
1120
1121
1122
1123
    // The arrays have equal length, we need only use one of them for looping
    // Resulting array contains the following pairs (timestamp + dT)
    const vorlaufMinusRuecklaufTemp = vorlaufTemp.map((obs, i) => [
      obs[0],
      vorlaufTempValues[i] - ruecklaufTempValues[i],
    ]);
Pithon Kabiro's avatar
Pithon Kabiro committed
1124

1125
1126
1127
1128
1129
    // From Vorlauf metadata, extract `name` and `unitOfMeasurement`
    const {
      name: datastreamNameVorlauf,
      unitOfMeasurement: unitOfMeasurementVorlauf,
    } = metadataVorlauf;
Pithon Kabiro's avatar
Pithon Kabiro committed
1130

1131
1132
    // From Ruecklauf metadata, extract `name`
    const { name: datastreamNameRuecklauf } = metadataRuecklauf;
Pithon Kabiro's avatar
Pithon Kabiro committed
1133

1134
1135
1136
1137
1138
1139
1140
    // Extract the phenomenon names from the Datastream names
    const phenomenonNameVorlauf = extractPhenomenonNameFromDatastreamName(
      datastreamNameVorlauf
    );
    const phenomenonNameRuecklauf = extractPhenomenonNameFromDatastreamName(
      datastreamNameRuecklauf
    );
Pithon Kabiro's avatar
Pithon Kabiro committed
1141

1142
1143
1144
1145
1146
1147
1148
1149
    // Create our custom datastream description text
    // The resulting datastream description string has two `temperature` substrings;
    // replace the first occurence with an empty string
    const descriptionTempDifference =
      `Computed dT: ${phenomenonNameVorlauf} minus ${phenomenonNameRuecklauf}`.replace(
        "temperature",
        ""
      );
Pithon Kabiro's avatar
Pithon Kabiro committed
1150

1151
1152
    // Create our custom datastream name text
    const nameTempDifference = `BOSCH_${BUILDING_ID} / dT Temperature difference (VL-RL) DS:${SAMPLING_RATE}`;
Pithon Kabiro's avatar
Pithon Kabiro committed
1153

1154
1155
1156
1157
    // The datastream object that we return needs to have these property names
    const description = descriptionTempDifference;
    const name = nameTempDifference;
    const unitOfMeasurement = unitOfMeasurementVorlauf;
Pithon Kabiro's avatar
Pithon Kabiro committed
1158

1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
    return [
      vorlaufMinusRuecklaufTemp,
      {
        description,
        name,
        unitOfMeasurement,
      },
    ];
  } catch (err) {
    console.error(err);
  }
Pithon Kabiro's avatar
Pithon Kabiro committed
1170
1171
1172
1173
1174
1175
1176
1177
1178
};

/**
 * Test plotting of temp difference (dT) using heatmap
 */
const drawHeatmapHCUsingTempDifference = async function () {
  const [tempDifferenceObsArrBau225, tempDifferenceMetadataBau225] =
    await calculateVorlaufMinusRuecklaufTemperature("225", "60min");

1179
1180
  drawHeatMapHighcharts(
    formatSensorThingsApiResponseForHeatMap(tempDifferenceObsArrBau225),
Pithon Kabiro's avatar
Pithon Kabiro committed
1181
1182
1183
1184
    formatDatastreamMetadataForChart(tempDifferenceMetadataBau225)
  );
};

1185
1186
1187
/**
 * Test drawing of scatter plot chart
 */
1188
const drawScatterPlotHCTest2 = async function () {
1189
1190
  const sensorsOfInterestArr = [
    ["225", "vl", "60min"],
1191
1192
    // ["125", "rl", "60min"],
    ["weather_station_521", "outside_temp", "60min"],
1193
1194
1195
  ];

  const observationsPlusMetadata =
1196
1197
1198
    await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
      BASE_URL,
      QUERY_PARAMS_COMBINED,
1199
      sensorsOfInterestArr
1200
1201
    );

1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
  // Extract the combined arrays for observations and metadata
  const [observationsArr, metadataArr] = observationsPlusMetadata;

  // Create formatted array(s) for observations
  // This function expects two arguments, these are unpacked using the spread operator
  const formattedObsScatterPlotArr =
    formatSensorThingsApiResponseForScatterPlot(...observationsArr);

  // Create formatted array(s) for metadata
  const formattedMetadataArr = metadataArr.map((metadata) =>
    formatDatastreamMetadataForChart(metadata)
  );
1214

1215
  // This function expects three arguments, the second and third are unpacked using the spread operator
1216
  drawScatterPlotHighcharts(
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
    formattedObsScatterPlotArr,
    ...formattedMetadataArr
  );
};

/**
 * Test drawing of line chart with multiple series
 */
const testLineChartMultipleSeries = async function () {
  const sensorsOfInterestArr = [
    ["225", "vl", "60min"],
    ["125", "rl", "60min"],
    ["weather_station_521", "outside_temp", "60min"],
  ];

  const observationsPlusMetadata =
    await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
      BASE_URL,
      QUERY_PARAMS_COMBINED,
      sensorsOfInterestArr
    );

  // Extract the observations and metadata arrays
  const [observationsArr, metadataArr] = observationsPlusMetadata;

  // Format the observations and metadata
  const formattedObservationsArr = observationsArr.map((observations) =>
    formatSensorThingsApiResponseForLineChart(observations)
1245
  );
1246
1247
1248
1249
1250
1251

  const formattedMetadataArr = metadataArr.map((metadata) =>
    formatDatastreamMetadataForChart(metadata)
  );

  drawLineChartHighcharts(formattedObservationsArr, formattedMetadataArr);
1252
1253
};

1254
1255
1256
// drawScatterPlotHCTest2();
// drawHeatmapHCUsingTempDifference();
// testLineChartMultipleSeries()
1257

1258
1259
1260
1261
export {
  BASE_URL,
  QUERY_PARAMS_COMBINED,
  formatDatastreamMetadataForChart,
1262
1263
1264
1265
  formatSensorThingsApiResponseForHeatMap,
  drawHeatMapHighcharts,
  formatSensorThingsApiResponseForLineChart,
  drawLineChartHighcharts,
1266
  getMetadataPlusObservationsFromSingleOrMultipleDatastreams,
1267
};
For faster browsing, not all history is shown. View entire blame