diff --git a/public/js/aggregate.js b/public/js/aggregate.js
index 5157411fcb364409b7cfce5908cd4a0f88cba29b..53148985a0498409e00b3d80e0b2f7f009b74d41 100644
--- a/public/js/aggregate.js
+++ b/public/js/aggregate.js
@@ -3,10 +3,7 @@
 import {
   BASE_URL,
   QUERY_PARAMS_COMBINED,
-  getDatastreamIdFromBuildingNumber,
-  createObservationsUrl,
-  performGetRequestUsingAxios,
-  extractCombinedObservationsFromAllPages,
+  getMetadataPlusObservationsFromSingleOrMultipleDatastreams,
 } from "./appChart.js";
 
 /**
@@ -135,28 +132,23 @@ const aggregateObservationsWithinTimeInterval = function (
  * Test aggregation of observations from a single datastream
  */
 const testAggregation = async function () {
-  // Datastream ID
-  const datastreamIdBau225VL = getDatastreamIdFromBuildingNumber(
-    "225",
-    "vl",
-    "60min"
-  );
+  const sensorOfInterestNestedArr = [["225", "vl", "60min"]];
 
-  // Observations URL
-  const observationsUrlBau225VL = createObservationsUrl(
-    BASE_URL,
-    datastreamIdBau225VL
-  );
+  const observationsPlusMetadata =
+    await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
+      BASE_URL,
+      QUERY_PARAMS_COMBINED,
+      sensorOfInterestNestedArr
+    );
 
-  // Observations array
-  const observationsBau225VL = await extractCombinedObservationsFromAllPages(
-    performGetRequestUsingAxios(observationsUrlBau225VL, QUERY_PARAMS_COMBINED)
-  );
+  // Extract the observations and metadata for each sensor
+  // Array elements in same order as input array
+  const [[obsSensorOneArr], [metadataSensorOne]] = observationsPlusMetadata;
 
   // Aggregated observations
   const observationsBau225VLAggregated =
     aggregateObservationsWithinTimeInterval(
-      observationsBau225VL,
+      obsSensorOneArr,
       "60 min",
       "2020-02-01",
       "2020-03-31"
diff --git a/public/js/appChart.js b/public/js/appChart.js
index 3b3a6754ed79b6f6ddfbd813dd37d85ceea77066..181efd4e0907057aa476b5dd8b25aa49291fb15a 100644
--- a/public/js/appChart.js
+++ b/public/js/appChart.js
@@ -91,11 +91,9 @@ const getDatastreamIdFromBuildingNumber = function (
   )
     return;
 
-  const datastreamIdMatched = Number(
+  return Number(
     buildingToDatastreamMapping[buildingNumber][phenomenon][samplingRate]
   );
-
-  return datastreamIdMatched;
 };
 
 /**
@@ -106,8 +104,7 @@ const getDatastreamIdFromBuildingNumber = function (
  */
 const createDatastreamUrl = function (baseUrl, datastreamID) {
   if (!datastreamID) return;
-  const fullDatastreamURL = `${baseUrl}/Datastreams(${datastreamID})`;
-  return fullDatastreamURL;
+  return `${baseUrl}/Datastreams(${datastreamID})`;
 };
 
 /**
@@ -118,8 +115,7 @@ const createDatastreamUrl = function (baseUrl, datastreamID) {
  */
 const createObservationsUrl = function (baseUrl, datastreamID) {
   if (!datastreamID) return;
-  const fullObservationsURL = `${baseUrl}/Datastreams(${datastreamID})/Observations`;
-  return fullObservationsURL;
+  return `${baseUrl}/Datastreams(${datastreamID})/Observations`;
 };
 
 /**
@@ -130,23 +126,33 @@ const createObservationsUrl = function (baseUrl, datastreamID) {
  */
 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;
+  return `resultTime ge ${dateStart}T00:00:00.000Z and resultTime le ${dateStop}T00:00:00.000Z`;
+};
+
+/**
+ * Create a query parameter object that should be sent together with a HTTP GET request using the Axios library
+ * @param {String} dateStart Start date (for temporal filter) in YYYY-MM-DD format
+ * @param {String} dateStop Stop date (for temporal filter) in YYYY-MM-DD format
+ * @returns {Object} A query parameter object
+ */
+const createUrlParametersForGetRequest = function (dateStart, dateStop) {
+  const QUERY_PARAM_RESULT_FORMAT = "dataArray";
+  const QUERY_PARAM_ORDER_BY = "phenomenonTime asc";
+  const QUERY_PARAM_FILTER = createTemporalFilterString(dateStart, dateStop);
+  const QUERY_PARAM_SELECT = "result,phenomenonTime";
+
+  return {
+    "$resultFormat": QUERY_PARAM_RESULT_FORMAT,
+    "$orderBy": QUERY_PARAM_ORDER_BY,
+    "$filter": QUERY_PARAM_FILTER,
+    "$select": QUERY_PARAM_SELECT,
+  };
 };
 
-const QUERY_PARAM_RESULT_FORMAT = "dataArray";
-const QUERY_PARAM_ORDER_BY = "phenomenonTime asc";
-const QUERY_PARAM_FILTER = createTemporalFilterString(
+const QUERY_PARAMS_COMBINED = createUrlParametersForGetRequest(
   "2020-01-01",
   "2021-01-01"
 );
-const QUERY_PARAM_SELECT = "result,phenomenonTime";
-const QUERY_PARAMS_COMBINED = {
-  "$resultFormat": QUERY_PARAM_RESULT_FORMAT,
-  "$orderBy": QUERY_PARAM_ORDER_BY,
-  "$filter": QUERY_PARAM_FILTER,
-  "$select": QUERY_PARAM_SELECT,
-};
 
 /**
  * Perform a GET request using the Axios library
@@ -446,22 +452,113 @@ const formatSensorThingsApiResponseForLineChart = function (obsArray) {
   return dataSTAFormatted;
 };
 
+/**
+ * Extract the properties that make up the formatted datastream metadata object(s)
+ * @param {Array} formattedDatastreamsMetadataArr An array of formatted metadata object(s) from one or more datastreams
+ * @returns {Object} An object that contains array(s) of formatted datastream metadata properties
+ */
+const extractPropertiesFromDatastreamMetadata = function (
+  formattedDatastreamsMetadataArr
+) {
+  // Create arrays from the properties of the formatted datastream metadata
+  const datastreamDescriptionsArr = formattedDatastreamsMetadataArr.map(
+    (datastreamMetadata) => datastreamMetadata.datastreamDescription
+  );
+
+  const datastreamNamesArr = formattedDatastreamsMetadataArr.map(
+    (datastreamMetadata) => datastreamMetadata.datastreamName
+  );
+
+  const phenomenonNamesArr = formattedDatastreamsMetadataArr.map(
+    (datastreamMetadata) => datastreamMetadata.phenomenonName
+  );
+
+  const unitOfMeasurementSymbolsArr = formattedDatastreamsMetadataArr.map(
+    (datastreamMetadata) => datastreamMetadata.unitOfMeasurementSymbol
+  );
+
+  return {
+    datastreamDescriptionsArr,
+    datastreamNamesArr,
+    phenomenonNamesArr,
+    unitOfMeasurementSymbolsArr,
+  };
+};
+
+/**
+ * Extracts the sampling rate substring from a datastream name string
+ * @param {Array} datastreamNamesArr An array of datastream name(s)
+ * @returns {Array} An array containing the sampling rate substring(s)
+ */
+const extractSamplingRateFromDatastreamName = function (datastreamNamesArr) {
+  // The sampling rate string is the last word in the Datastream name string
+  return datastreamNamesArr.map((datastreamName) =>
+    datastreamName.split(" ").pop()
+  );
+};
+
+/**
+ * Concatenates metadata properties to create a string for either the title or subtitle of a line chart
+ * @param {Array} datastreamMetadataPropArr An array of metadata property strings
+ * @returns {String} A string of comma separated metadata property strings
+ */
+const createCombinedTextForLineChartTitles = function (
+  datastreamMetadataPropArr
+) {
+  return datastreamMetadataPropArr.join(", ");
+};
+
+/**
+ * Creates an options object for each series drawn in the line chart
+ * @param {Array} formattedObsArraysForLineChart An array of formatted observation array(s) from one or more datastreams
+ * @param {Array} phenomenonNamesArr An array of phenomenon name(s)
+ * @param {Array} phenomenonSymbolsArr An array of phenomenon symbol(s)
+ * @returns {Array} An array made up of series options object(s)
+ */
+const createSeriesOptionsForLineChart = function (
+  formattedObsArraysForLineChart,
+  phenomenonNamesArr,
+  phenomenonSymbolsArr
+) {
+  // An array of colors provided by the Highcharts object
+  const seriesColors = Highcharts.getOptions().colors;
+
+  // Create an array of seriesOptions objects
+  // Assumes that the observation array of arrays, phenomenon names array and phenomenon symbols array are of equal length
+  // Use one of the arrays for looping
+  return formattedObsArraysForLineChart.map((formattedObsArray, i) => {
+    return {
+      name: `${phenomenonNamesArr[i]} (${phenomenonSymbolsArr[i]})`,
+      data: formattedObsArray,
+      color: seriesColors[i],
+      turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release
+    };
+  });
+};
+
 /**
  * Draw a line chart using Highcharts library
- * @param {Array} formattedObsArrayForLineChart Response from SensorThings API formatted for use in a line chart
- * @param {Object} formattedDatastreamMetadata Object containing Datastream metadata
+ * @param {Array} formattedObsArraysForLineChart An array made up of formatted observation array(s) suitable for use in a line chart
+ * @param {Object} formattedDatastreamMetadataArr An array made up of object(s) containing Datastream metadata
  * @returns {undefined} undefined
  */
 const drawLineChartHighcharts = function (
-  formattedObsArrayForLineChart,
-  formattedDatastreamMetadata
+  formattedObsArraysForLineChart,
+  formattedDatastreamMetadataArr
 ) {
+  // Arrays of datastream properties
   const {
-    datastreamDescription: DATASTREAM_DESCRIPTION,
-    datastreamName: DATASTREAM_NAME,
-    phenomenonName: PHENOMENON_NAME,
-    unitOfMeasurementSymbol: PHENOMENON_SYMBOL,
-  } = formattedDatastreamMetadata;
+    datastreamNamesArr,
+    phenomenonNamesArr,
+    unitOfMeasurementSymbolsArr,
+  } = extractPropertiesFromDatastreamMetadata(formattedDatastreamMetadataArr);
+
+  // Create the array of series options object(s)
+  const seriesOptionsArr = createSeriesOptionsForLineChart(
+    formattedObsArraysForLineChart,
+    phenomenonNamesArr,
+    unitOfMeasurementSymbolsArr
+  );
 
   Highcharts.stockChart("chart-line", {
     chart: {
@@ -473,25 +570,24 @@ const drawLineChartHighcharts = function (
     },
 
     title: {
-      text: DATASTREAM_DESCRIPTION,
+      text: createCombinedTextForLineChartTitles(phenomenonNamesArr),
       "align": "left",
     },
 
     subtitle: {
-      text: DATASTREAM_NAME,
+      text: `Sampling rate(s): ${createCombinedTextForLineChartTitles(
+        extractSamplingRateFromDatastreamName(datastreamNamesArr)
+      )}`,
       align: "left",
     },
 
-    series: [
-      {
-        name: `${PHENOMENON_NAME} (${PHENOMENON_SYMBOL})`,
-        data: formattedObsArrayForLineChart,
-        tooltip: {
-          valueDecimals: 2,
-        },
-        turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release
-      },
-    ],
+    tooltip: {
+      pointFormat:
+        '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> <br/>',
+      valueDecimals: 2,
+    },
+
+    series: seriesOptionsArr,
   });
 };
 
@@ -670,7 +766,7 @@ const checkForAndDeleteUniqueObservationsFromLargerArray = function (
  * 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} 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 N*2 array of observation values from both input observation arrays
  */
 const createCombinedObservationValues = function (obsArrayOne, obsArrayTwo) {
   // Extract the values from the two observation arrays
@@ -712,9 +808,9 @@ const formatSensorThingsApiResponseForScatterPlot = function (
 
 /**
  * Draw a scatter plot using Highcharts library
- * @param {*} formattedObsArrayForSeriesOnePlusSeriesTwo Response from SensorThings API formatted for use in a scatter plot
- * @param {*} formattedDatastreamMetadataSeriesOne Object containing Datastream metadata for the first chart series
- * @param {*} formattedDatastreamMetadataSeriesTwo Object containing Datastream metadata for the second chart series
+ * @param {Array} formattedObsArrayForSeriesOnePlusSeriesTwo Response from SensorThings API formatted for use in a scatter plot
+ * @param {Object} formattedDatastreamMetadataSeriesOne Object containing Datastream metadata for the first chart series
+ * @param {Object} formattedDatastreamMetadataSeriesTwo Object containing Datastream metadata for the second chart series
  * @returns {undefined}
  */
 const drawScatterPlotHighcharts = function (
@@ -849,10 +945,15 @@ const combineResultsFromAllPages = async function (httpGetRequestPromise) {
     if (!httpGetRequestPromise) return;
 
     const lastSuccess = await httpGetRequestPromise;
+
+    // The "success" objects contain a "data" object which in turn has a "value" property
+    // If the "data" object in turn has a "@iot.nextLink" property, then a next page exists
     if (lastSuccess.data["@iot.nextLink"]) {
       const nextLinkSuccess = await combineResultsFromAllPages(
         axios.get(lastSuccess.data["@iot.nextLink"])
       );
+      // The "data" object in turn has a "value" property
+      // The "value" property's value is an array
       nextLinkSuccess.data.value = lastSuccess.data.value.concat(
         nextLinkSuccess.data.value
       );
@@ -902,32 +1003,6 @@ const extractCombinedObservationsFromAllPages = async function (
   }
 };
 
-/**
- * Retrieve the metadata for a Datastream as well as the Observations corresponding to it
- * @async
- * @param {Promise} metadataPlusObsPromiseArray An array that contains two promises, one for datastream metadata, the other for observations
- * @returns {Promise} A promise that contains two arrays when fulfilled, one for datastream metadata and the other for observations
- */
-const getMetadataPlusObservationsFromSingleDatastream = async function (
-  metadataPlusObsPromiseArray
-) {
-  try {
-    // Array to store our final result
-    const combinedResolvedPromises = [];
-
-    // Use for/of loop - we need to maintain the order of execution of the async operations
-    for (const promise of metadataPlusObsPromiseArray) {
-      // Resolved value of a single promise
-      const resolvedPromise = await promise;
-      combinedResolvedPromises.push(resolvedPromise);
-    }
-
-    return combinedResolvedPromises;
-  } catch (err) {
-    console.error(err);
-  }
-};
-
 /**
  * Retrieve all the Observations from an array of Observations promises
  * @async
@@ -955,55 +1030,55 @@ const getObservationsFromMultipleDatastreams = async function (
 };
 
 /**
- * Retrieve the metadata from multiple Datastreams and the Observations corresponding to these Datastreams
- * @async
- * @param {Array} bldgSensorSamplingRateArr A 3*N array containing buildings, sensors & sampling rates as strings, e.g. ["101", "rl", "60min"]
- * @returns {Promise} A promise that contains a N*2 array (the first element is an array of Observations and the second element is an array of Datastream metadata objects) when fulfilled
+ * 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
  */
-const getMetadataPlusObservationsFromMultipleDatastreams = async function (
-  bldgSensorSamplingRateArr
-) {
-  try {
-    if (!bldgSensorSamplingRateArr) return;
-
-    // Datastreams IDs
-    const datastreamsIdsArr = bldgSensorSamplingRateArr.map(
-      (bldgSensorSamplingRate) =>
-        getDatastreamIdFromBuildingNumber(...bldgSensorSamplingRate)
-    );
+const getMetadataPlusObservationsFromSingleOrMultipleDatastreams =
+  async function (baseUrl, urlParamObj, bldgSensorSamplingRateArr) {
+    try {
+      if (!bldgSensorSamplingRateArr) return;
+
+      // Datastreams IDs
+      const datastreamsIdsArr = bldgSensorSamplingRateArr.map(
+        (bldgSensorSamplingRate) =>
+          getDatastreamIdFromBuildingNumber(...bldgSensorSamplingRate)
+      );
 
-    // Observations URLs
-    const observationsUrlArr = datastreamsIdsArr.map((datastreamId) =>
-      createObservationsUrl(BASE_URL, datastreamId)
-    );
+      // Observations URLs
+      const observationsUrlArr = datastreamsIdsArr.map((datastreamId) =>
+        createObservationsUrl(baseUrl, datastreamId)
+      );
 
-    // Datastreams URLs
-    const datastreamsUrlArr = datastreamsIdsArr.map((datastreamId) =>
-      createDatastreamUrl(BASE_URL, datastreamId)
-    );
+      // Datastreams URLs
+      const datastreamsUrlArr = datastreamsIdsArr.map((datastreamId) =>
+        createDatastreamUrl(baseUrl, datastreamId)
+      );
 
-    // Promise objects - Observations
-    const observationsPromisesArr = observationsUrlArr.map((obsUrl) =>
-      extractCombinedObservationsFromAllPages(
-        performGetRequestUsingAxios(obsUrl, QUERY_PARAMS_COMBINED)
-      )
-    );
+      // Promise objects - Observations
+      const observationsPromisesArr = observationsUrlArr.map((obsUrl) =>
+        extractCombinedObservationsFromAllPages(
+          performGetRequestUsingAxios(obsUrl, urlParamObj)
+        )
+      );
 
-    // Observations array
-    const observationsArr = await getObservationsFromMultipleDatastreams(
-      observationsPromisesArr
-    );
+      // Observations array
+      const observationsArr = await getObservationsFromMultipleDatastreams(
+        observationsPromisesArr
+      );
 
-    // Metadata array
-    const metadataArr = await getMetadataFromMultipleDatastreams(
-      datastreamsUrlArr
-    );
+      // Metadata array
+      const metadataArr = await getMetadataFromMultipleDatastreams(
+        datastreamsUrlArr
+      );
 
-    return [observationsArr, metadataArr];
-  } catch (err) {
-    console.error(err);
-  }
-};
+      return [observationsArr, metadataArr];
+    } catch (err) {
+      console.error(err);
+    }
+  };
 
 /**
  * Calculates the temperature difference, dT, between Vorlauf temperature [VL] and Rücklauf temperature [RL] (i.e., dT = VL - RL)
@@ -1026,7 +1101,9 @@ const calculateVorlaufMinusRuecklaufTemperature = async function (
     const SAMPLING_RATE = samplingRate;
 
     const observationsPlusMetadata =
-      await getMetadataPlusObservationsFromMultipleDatastreams(
+      await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
+        BASE_URL,
+        QUERY_PARAMS_COMBINED,
         bldgSensorSamplingRateArr
       );
 
@@ -1116,46 +1193,75 @@ const drawScatterPlotHCTest2 = async function () {
   ];
 
   const observationsPlusMetadata =
-    await getMetadataPlusObservationsFromMultipleDatastreams(
+    await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
+      BASE_URL,
+      QUERY_PARAMS_COMBINED,
       sensorsOfInterestArr
     );
 
-  // Extract the observations and metadata for each sensor
-  // Array elements in same order as input array
-  const [
-    [obsSensorOneArr, obsSensorTwoArr],
-    [metadataSensorOne, metadataSensorTwo],
-  ] = observationsPlusMetadata;
+  // 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)
+  );
 
+  // This function expects three arguments, the second and third are unpacked using the spread operator
   drawScatterPlotHighcharts(
-    formatSensorThingsApiResponseForScatterPlot(
-      obsSensorOneArr,
-      obsSensorTwoArr
-    ),
-    formatDatastreamMetadataForChart(metadataSensorOne),
-    formatDatastreamMetadataForChart(metadataSensorTwo)
+    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)
   );
+
+  const formattedMetadataArr = metadataArr.map((metadata) =>
+    formatDatastreamMetadataForChart(metadata)
+  );
+
+  drawLineChartHighcharts(formattedObservationsArr, formattedMetadataArr);
 };
 
-(async () => {
-  // await drawScatterPlotHCTest2();
-  await drawHeatmapHCUsingTempDifference();
-})();
+// drawScatterPlotHCTest2();
+// drawHeatmapHCUsingTempDifference();
+// testLineChartMultipleSeries()
 
 export {
   BASE_URL,
   QUERY_PARAMS_COMBINED,
-  getDatastreamIdFromBuildingNumber,
-  createDatastreamUrl,
-  createObservationsUrl,
-  createTemporalFilterString,
-  performGetRequestUsingAxios,
-  getMetadataFromSingleDatastream,
   formatDatastreamMetadataForChart,
   formatSensorThingsApiResponseForHeatMap,
   drawHeatMapHighcharts,
   formatSensorThingsApiResponseForLineChart,
   drawLineChartHighcharts,
-  extractCombinedObservationsFromAllPages,
-  getMetadataPlusObservationsFromSingleDatastream,
+  getMetadataPlusObservationsFromSingleOrMultipleDatastreams,
 };
diff --git a/public/js/dropDownList.js b/public/js/dropDownList.js
index e069f2b8b21bd1278a0211ba206afcc2bcd69398..44428a511095493510a9bfb001784744c98126d1 100644
--- a/public/js/dropDownList.js
+++ b/public/js/dropDownList.js
@@ -3,18 +3,12 @@
 import {
   BASE_URL,
   QUERY_PARAMS_COMBINED,
-  getDatastreamIdFromBuildingNumber,
-  createDatastreamUrl,
-  createObservationsUrl,
-  performGetRequestUsingAxios,
-  getMetadataFromSingleDatastream,
   formatDatastreamMetadataForChart,
   formatSensorThingsApiResponseForHeatMap,
   drawHeatMapHighcharts,
   formatSensorThingsApiResponseForLineChart,
   drawLineChartHighcharts,
-  extractCombinedObservationsFromAllPages,
-  getMetadataPlusObservationsFromSingleDatastream,
+  getMetadataPlusObservationsFromSingleOrMultipleDatastreams,
 } from "./appChart.js";
 
 const buildingsAvailableSensorsArr = [
@@ -268,13 +262,8 @@ const selectChartTypeFromDropDown = async function () {
 
     if (selectedOptions === undefined) return;
 
-    const abbreviationsArr = getBuildingSensorSamplingRateAbbreviation(
-      ...selectedOptions
-    );
-
-    const selectedDatastream = getDatastreamIdFromBuildingNumber(
-      ...abbreviationsArr
-    );
+    const selectedOptionsAbbreviationsArr =
+      getBuildingSensorSamplingRateAbbreviation(...selectedOptions);
 
     const selectedChartType = document.querySelector(
       "#drop-down--chart-type"
@@ -285,40 +274,39 @@ const selectChartTypeFromDropDown = async function () {
     // Display the loading indicator
     showLoadingSpinner();
 
-    const URL_DATASTREAM = createDatastreamUrl(BASE_URL, selectedDatastream);
-    const URL_OBSERVATIONS = createObservationsUrl(
-      BASE_URL,
-      selectedDatastream
-    );
+    // The `getMetadataPlusObservationsFromSingleOrMultipleDatastreams` function expects a nested array structure
+    const abbreviationsNestedArr = [selectedOptionsAbbreviationsArr];
+
+    const observationsPlusMetadata =
+      await getMetadataPlusObservationsFromSingleOrMultipleDatastreams(
+        BASE_URL,
+        QUERY_PARAMS_COMBINED,
+        abbreviationsNestedArr
+      );
 
-    // Create promises
-    const promiseDatastreamMetadata =
-      getMetadataFromSingleDatastream(URL_DATASTREAM);
-    const promiseCombinedObservations = extractCombinedObservationsFromAllPages(
-      performGetRequestUsingAxios(URL_OBSERVATIONS, QUERY_PARAMS_COMBINED)
+    // Extract the combined arrays for observations and metadata
+    const [observationsArr, metadataArr] = observationsPlusMetadata;
+
+    // Create formatted array(s) for observations - line chart
+    const formattedObsLineChartArr = observationsArr.map((observations) =>
+      formatSensorThingsApiResponseForLineChart(observations)
     );
 
-    // Pass promises to our async function
-    const metadataPlusObservations =
-      await getMetadataPlusObservationsFromSingleDatastream([
-        promiseCombinedObservations,
-        promiseDatastreamMetadata,
-      ]);
+    // Create formatted array(s) for observations - heatmap
+    const formattedObsHeatMapArr = observationsArr.map((observations) =>
+      formatSensorThingsApiResponseForHeatMap(observations)
+    );
 
-    // Extract the metadata and the observations from resulting array
-    const combinedObs = metadataPlusObservations[0];
-    const datastreamMetadata = metadataPlusObservations[1];
+    // Create formatted array(s) for metadata - same for both chart types
+    const formattedMetadataArr = metadataArr.map((metadata) =>
+      formatDatastreamMetadataForChart(metadata)
+    );
 
     if (selectedChartType === "Line") {
-      drawLineChartHighcharts(
-        formatSensorThingsApiResponseForLineChart(combinedObs),
-        formatDatastreamMetadataForChart(datastreamMetadata)
-      );
+      drawLineChartHighcharts(formattedObsLineChartArr, formattedMetadataArr);
     } else if (selectedChartType === "Heatmap") {
-      drawHeatMapHighcharts(
-        formatSensorThingsApiResponseForHeatMap(combinedObs),
-        formatDatastreamMetadataForChart(datastreamMetadata)
-      );
+      // First need to extract the nested arrays for the formatted observations and metadata
+      drawHeatMapHighcharts(...formattedObsHeatMapArr, ...formattedMetadataArr);
     }
   } catch (err) {
     console.error(err);