created AddReportFutureVersion dbus method

New method will support CollectionTimeScope, CollectionDuration

In order to make not breaking interface changes bmcweb will switch to
AddReportFutureVersion, then AddReport will be changed to match
AddReportFutureVersion, then redfish will switch back to use AddReport,
then AddReportFutureVersion will be removed.

Tested:
  - Verified that current version of bmcweb works fine with old API

Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
Change-Id: I51a9b7fb2f4da5b8d2f688ccd5e93710352b1ac7
diff --git a/src/discrete_threshold.cpp b/src/discrete_threshold.cpp
index a93f682..efec549 100644
--- a/src/discrete_threshold.cpp
+++ b/src/discrete_threshold.cpp
@@ -3,12 +3,10 @@
 #include <phosphor-logging/log.hpp>
 
 DiscreteThreshold::DiscreteThreshold(
-    boost::asio::io_context& ioc,
-    std::vector<std::shared_ptr<interfaces::Sensor>> sensorsIn,
+    boost::asio::io_context& ioc, Sensors sensorsIn,
     std::vector<std::string> sensorNames,
     std::vector<std::unique_ptr<interfaces::TriggerAction>> actionsIn,
-    std::chrono::milliseconds dwellTimeIn, double thresholdValueIn,
-    std::string name) :
+    Milliseconds dwellTimeIn, double thresholdValueIn, std::string name) :
     ioc(ioc),
     sensors(std::move(sensorsIn)), actions(std::move(actionsIn)),
     dwellTime(dwellTimeIn), thresholdValue(thresholdValueIn), name(name)
@@ -65,7 +63,7 @@
                                    uint64_t timestamp, double value)
 {
     auto& [sensorName, dwell, timer] = getDetails(sensor);
-    if (dwellTime == std::chrono::milliseconds::zero())
+    if (dwellTime == Milliseconds::zero())
     {
         commit(sensorName, timestamp, value);
     }
diff --git a/src/discrete_threshold.hpp b/src/discrete_threshold.hpp
index 100b88d..70b2a6a 100644
--- a/src/discrete_threshold.hpp
+++ b/src/discrete_threshold.hpp
@@ -4,7 +4,8 @@
 #include "interfaces/sensor_listener.hpp"
 #include "interfaces/threshold.hpp"
 #include "interfaces/trigger_action.hpp"
-#include "interfaces/trigger_types.hpp"
+#include "types/milliseconds.hpp"
+#include "types/trigger_types.hpp"
 
 #include <boost/asio/steady_timer.hpp>
 
@@ -19,12 +20,10 @@
 {
   public:
     DiscreteThreshold(
-        boost::asio::io_context& ioc,
-        std::vector<std::shared_ptr<interfaces::Sensor>> sensors,
+        boost::asio::io_context& ioc, Sensors sensors,
         std::vector<std::string> sensorNames,
         std::vector<std::unique_ptr<interfaces::TriggerAction>> actions,
-        std::chrono::milliseconds dwellTime, double thresholdValue,
-        std::string name);
+        Milliseconds dwellTime, double thresholdValue, std::string name);
     DiscreteThreshold(const DiscreteThreshold&) = delete;
     DiscreteThreshold(DiscreteThreshold&&) = delete;
     ~DiscreteThreshold()
@@ -37,9 +36,9 @@
 
   private:
     boost::asio::io_context& ioc;
-    const std::vector<std::shared_ptr<interfaces::Sensor>> sensors;
+    const Sensors sensors;
     const std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
-    const std::chrono::milliseconds dwellTime;
+    const Milliseconds dwellTime;
     const double thresholdValue;
     const std::string name;
 
diff --git a/src/interfaces/metric.hpp b/src/interfaces/metric.hpp
index deb3ed6..3279fd7 100644
--- a/src/interfaces/metric.hpp
+++ b/src/interfaces/metric.hpp
@@ -1,7 +1,7 @@
 #pragma once
 
-#include "interfaces/types.hpp"
 #include "metric_value.hpp"
+#include "types/report_types.hpp"
 
 #include <nlohmann/json.hpp>
 
@@ -16,7 +16,7 @@
     virtual ~Metric() = default;
 
     virtual void initialize() = 0;
-    virtual const MetricValue& getReading() const = 0;
+    virtual const std::vector<MetricValue>& getReadings() const = 0;
     virtual LabeledMetricParameters dumpConfiguration() const = 0;
 };
 
diff --git a/src/interfaces/report_factory.hpp b/src/interfaces/report_factory.hpp
index 237ae7b..182973d 100644
--- a/src/interfaces/report_factory.hpp
+++ b/src/interfaces/report_factory.hpp
@@ -3,7 +3,7 @@
 #include "interfaces/json_storage.hpp"
 #include "interfaces/report.hpp"
 #include "interfaces/report_manager.hpp"
-#include "interfaces/types.hpp"
+#include "types/report_types.hpp"
 
 #include <boost/asio/spawn.hpp>
 
@@ -19,17 +19,15 @@
   public:
     virtual ~ReportFactory() = default;
 
-    virtual std::unique_ptr<interfaces::Report> make(
-        boost::asio::yield_context& yield, const std::string& name,
-        const std::string& reportingType, bool emitsReadingsSignal,
-        bool logToMetricReportsCollection, std::chrono::milliseconds period,
-        const ReadingParameters& metricParams, ReportManager& reportManager,
-        JsonStorage& reportStorage) const = 0;
+    virtual std::vector<LabeledMetricParameters>
+        convertMetricParams(boost::asio::yield_context& yield,
+                            const ReadingParameters& metricParams) const = 0;
+
     virtual std::unique_ptr<interfaces::Report> make(
         const std::string& name, const std::string& reportingType,
         bool emitsReadingsSignal, bool logToMetricReportsCollection,
-        std::chrono::milliseconds period, const ReadingParameters& metricParams,
-        ReportManager& reportManager, JsonStorage& reportStorage,
+        Milliseconds period, ReportManager& reportManager,
+        JsonStorage& reportStorage,
         std::vector<LabeledMetricParameters> labeledMetricParams) const = 0;
 };
 
diff --git a/src/interfaces/sensor.hpp b/src/interfaces/sensor.hpp
index 07c7897..3e46317 100644
--- a/src/interfaces/sensor.hpp
+++ b/src/interfaces/sensor.hpp
@@ -6,6 +6,7 @@
 #include <string>
 #include <string_view>
 #include <tuple>
+#include <vector>
 
 namespace interfaces
 {
@@ -46,3 +47,5 @@
 };
 
 } // namespace interfaces
+
+using Sensors = std::vector<std::shared_ptr<interfaces::Sensor>>;
diff --git a/src/interfaces/trigger_factory.hpp b/src/interfaces/trigger_factory.hpp
index b84ce73..a9eb55b 100644
--- a/src/interfaces/trigger_factory.hpp
+++ b/src/interfaces/trigger_factory.hpp
@@ -3,7 +3,7 @@
 #include "interfaces/json_storage.hpp"
 #include "interfaces/trigger.hpp"
 #include "interfaces/trigger_manager.hpp"
-#include "interfaces/trigger_types.hpp"
+#include "types/trigger_types.hpp"
 
 #include <boost/asio/spawn.hpp>
 #include <sdbusplus/message/types.hpp>
diff --git a/src/interfaces/types.hpp b/src/interfaces/types.hpp
deleted file mode 100644
index a3a1b1c..0000000
--- a/src/interfaces/types.hpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#pragma once
-
-#include "operation_type.hpp"
-#include "utils/labeled_tuple.hpp"
-#include "utils/tstring.hpp"
-
-#include <sdbusplus/message/types.hpp>
-
-#include <string>
-#include <tuple>
-#include <type_traits>
-#include <vector>
-
-using ReadingParameters =
-    std::vector<std::tuple<sdbusplus::message::object_path, std::string,
-                           std::string, std::string>>;
-
-using LabeledSensorParameters =
-    utils::LabeledTuple<std::tuple<std::string, std::string>,
-                        utils::tstring::Service, utils::tstring::Path>;
-
-using LabeledMetricParameters =
-    utils::LabeledTuple<std::tuple<LabeledSensorParameters, OperationType,
-                                   std::string, std::string>,
-                        utils::tstring::SensorPath,
-                        utils::tstring::OperationType, utils::tstring::Id,
-                        utils::tstring::MetricMetadata>;
-
-using Readings = std::tuple<
-    uint64_t,
-    std::vector<std::tuple<std::string, std::string, double, uint64_t>>>;
\ No newline at end of file
diff --git a/src/metric.cpp b/src/metric.cpp
index 2a73536..6734d28 100644
--- a/src/metric.cpp
+++ b/src/metric.cpp
@@ -1,27 +1,36 @@
 #include "metric.hpp"
 
-#include "interfaces/types.hpp"
+#include "types/report_types.hpp"
+#include "utils/json.hpp"
 #include "utils/transform.hpp"
 
 #include <algorithm>
 
-Metric::Metric(std::shared_ptr<interfaces::Sensor> sensor,
-               OperationType operationType, std::string id,
-               std::string metadata) :
-    sensor(std::move(sensor)),
-    operationType(std::move(operationType)), reading{std::move(id),
-                                                     std::move(metadata), 0.,
-                                                     0u}
-{}
+Metric::Metric(Sensors sensorsIn, OperationType operationTypeIn,
+               std::string idIn, std::string metadataIn,
+               CollectionTimeScope timeScopeIn,
+               CollectionDuration collectionDurationIn) :
+    id(idIn),
+    metadata(metadataIn),
+    readings(sensorsIn.size(),
+             MetricValue{std::move(idIn), std::move(metadataIn), 0., 0u}),
+    sensors(std::move(sensorsIn)), operationType(operationTypeIn),
+    timeScope(timeScopeIn), collectionDuration(collectionDurationIn)
+{
+    tryUnpackJsonMetadata();
+}
 
 void Metric::initialize()
 {
-    sensor->registerForUpdates(weak_from_this());
+    for (const auto& sensor : sensors)
+    {
+        sensor->registerForUpdates(weak_from_this());
+    }
 }
 
-const MetricValue& Metric::getReading() const
+const std::vector<MetricValue>& Metric::getReadings() const
 {
-    return reading;
+    return readings;
 }
 
 void Metric::sensorUpdated(interfaces::Sensor& notifier, uint64_t timestamp)
@@ -40,17 +49,41 @@
 
 MetricValue& Metric::findMetric(interfaces::Sensor& notifier)
 {
-    if (sensor.get() != &notifier)
-    {
-        throw std::out_of_range("unknown sensor");
-    }
-    return reading;
+    auto it = std::find_if(
+        sensors.begin(), sensors.end(),
+        [&notifier](const auto& sensor) { return sensor.get() == &notifier; });
+    auto index = std::distance(sensors.begin(), it);
+    return readings.at(index);
 }
 
 LabeledMetricParameters Metric::dumpConfiguration() const
 {
-    auto sensorPath =
-        LabeledSensorParameters(sensor->id().service, sensor->id().path);
-    return LabeledMetricParameters(std::move(sensorPath), operationType,
-                                   reading.id, reading.metadata);
+    auto sensorPath = utils::transform(sensors, [this](const auto& sensor) {
+        return LabeledSensorParameters(sensor->id().service, sensor->id().path);
+    });
+
+    return LabeledMetricParameters(std::move(sensorPath), operationType, id,
+                                   metadata, timeScope, collectionDuration);
+}
+
+void Metric::tryUnpackJsonMetadata()
+{
+    try
+    {
+        const nlohmann::json parsedMetadata = nlohmann::json::parse(metadata);
+        if (const auto metricProperties =
+                utils::readJson<std::vector<std::string>>(parsedMetadata,
+                                                          "MetricProperties"))
+        {
+            if (readings.size() == metricProperties->size())
+            {
+                for (size_t i = 0; i < readings.size(); ++i)
+                {
+                    readings[i].metadata = (*metricProperties)[i];
+                }
+            }
+        }
+    }
+    catch (const nlohmann::json::parse_error& e)
+    {}
 }
diff --git a/src/metric.hpp b/src/metric.hpp
index aab4d15..08684da 100644
--- a/src/metric.hpp
+++ b/src/metric.hpp
@@ -10,19 +10,25 @@
     public std::enable_shared_from_this<Metric>
 {
   public:
-    Metric(std::shared_ptr<interfaces::Sensor> sensor,
-           OperationType operationType, std::string id, std::string metadata);
+    Metric(Sensors sensors, OperationType operationType, std::string id,
+           std::string metadata, CollectionTimeScope, CollectionDuration);
 
     void initialize() override;
-    const MetricValue& getReading() const override;
+    const std::vector<MetricValue>& getReadings() const override;
     void sensorUpdated(interfaces::Sensor&, uint64_t) override;
     void sensorUpdated(interfaces::Sensor&, uint64_t, double value) override;
     LabeledMetricParameters dumpConfiguration() const override;
 
   private:
+    void tryUnpackJsonMetadata();
+
     MetricValue& findMetric(interfaces::Sensor&);
 
-    std::shared_ptr<interfaces::Sensor> sensor;
+    std::string id;
+    std::string metadata;
+    std::vector<MetricValue> readings;
+    Sensors sensors;
     OperationType operationType;
-    MetricValue reading;
+    CollectionTimeScope timeScope;
+    CollectionDuration collectionDuration;
 };
diff --git a/src/numeric_threshold.cpp b/src/numeric_threshold.cpp
index 5cc2be5..ebb7826 100644
--- a/src/numeric_threshold.cpp
+++ b/src/numeric_threshold.cpp
@@ -3,11 +3,10 @@
 #include <phosphor-logging/log.hpp>
 
 NumericThreshold::NumericThreshold(
-    boost::asio::io_context& ioc,
-    std::vector<std::shared_ptr<interfaces::Sensor>> sensorsIn,
+    boost::asio::io_context& ioc, Sensors sensorsIn,
     std::vector<std::string> sensorNames,
     std::vector<std::unique_ptr<interfaces::TriggerAction>> actionsIn,
-    std::chrono::milliseconds dwellTimeIn, numeric::Direction direction,
+    Milliseconds dwellTimeIn, numeric::Direction direction,
     double thresholdValueIn) :
     ioc(ioc),
     sensors(std::move(sensorsIn)), actions(std::move(actionsIn)),
@@ -72,7 +71,7 @@
                                   uint64_t timestamp, double value, bool& dwell,
                                   boost::asio::steady_timer& timer)
 {
-    if (dwellTime == std::chrono::milliseconds::zero())
+    if (dwellTime == Milliseconds::zero())
     {
         commit(sensorName, timestamp, value);
     }
diff --git a/src/numeric_threshold.hpp b/src/numeric_threshold.hpp
index 0951956..338d00b 100644
--- a/src/numeric_threshold.hpp
+++ b/src/numeric_threshold.hpp
@@ -4,7 +4,8 @@
 #include "interfaces/sensor_listener.hpp"
 #include "interfaces/threshold.hpp"
 #include "interfaces/trigger_action.hpp"
-#include "interfaces/trigger_types.hpp"
+#include "types/milliseconds.hpp"
+#include "types/trigger_types.hpp"
 
 #include <boost/asio/steady_timer.hpp>
 
@@ -19,11 +20,10 @@
 {
   public:
     NumericThreshold(
-        boost::asio::io_context& ioc,
-        std::vector<std::shared_ptr<interfaces::Sensor>> sensors,
+        boost::asio::io_context& ioc, Sensors sensors,
         std::vector<std::string> sensorNames,
         std::vector<std::unique_ptr<interfaces::TriggerAction>> actions,
-        std::chrono::milliseconds dwellTime, numeric::Direction direction,
+        Milliseconds dwellTime, numeric::Direction direction,
         double thresholdValue);
     ~NumericThreshold();
 
@@ -33,9 +33,9 @@
 
   private:
     boost::asio::io_context& ioc;
-    const std::vector<std::shared_ptr<interfaces::Sensor>> sensors;
+    const Sensors sensors;
     const std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
-    const std::chrono::milliseconds dwellTime;
+    const Milliseconds dwellTime;
     const numeric::Direction direction;
     const double thresholdValue;
 
diff --git a/src/on_change_threshold.cpp b/src/on_change_threshold.cpp
index 0365ef4..5285ee3 100644
--- a/src/on_change_threshold.cpp
+++ b/src/on_change_threshold.cpp
@@ -3,8 +3,7 @@
 #include <phosphor-logging/log.hpp>
 
 OnChangeThreshold::OnChangeThreshold(
-    std::vector<std::shared_ptr<interfaces::Sensor>> sensorsIn,
-    std::vector<std::string> sensorNamesIn,
+    Sensors sensorsIn, std::vector<std::string> sensorNamesIn,
     std::vector<std::unique_ptr<interfaces::TriggerAction>> actionsIn) :
     sensors(std::move(sensorsIn)),
     sensorNames(std::move(sensorNamesIn)), actions(std::move(actionsIn))
diff --git a/src/on_change_threshold.hpp b/src/on_change_threshold.hpp
index 0d0f841..7eb1f6d 100644
--- a/src/on_change_threshold.hpp
+++ b/src/on_change_threshold.hpp
@@ -4,7 +4,7 @@
 #include "interfaces/sensor_listener.hpp"
 #include "interfaces/threshold.hpp"
 #include "interfaces/trigger_action.hpp"
-#include "interfaces/trigger_types.hpp"
+#include "types/trigger_types.hpp"
 
 #include <boost/asio/steady_timer.hpp>
 
@@ -19,8 +19,7 @@
 {
   public:
     OnChangeThreshold(
-        std::vector<std::shared_ptr<interfaces::Sensor>> sensors,
-        std::vector<std::string> sensorNames,
+        Sensors sensors, std::vector<std::string> sensorNames,
         std::vector<std::unique_ptr<interfaces::TriggerAction>> actions);
     ~OnChangeThreshold()
     {}
@@ -30,7 +29,7 @@
     void sensorUpdated(interfaces::Sensor&, uint64_t, double) override;
 
   private:
-    const std::vector<std::shared_ptr<interfaces::Sensor>> sensors;
+    const Sensors sensors;
     const std::vector<std::string> sensorNames;
     const std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
 
diff --git a/src/report.cpp b/src/report.cpp
index 7aef423..8a7297e 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -14,20 +14,30 @@
                const std::string& reportingTypeIn,
                const bool emitsReadingsUpdateIn,
                const bool logToMetricReportsCollectionIn,
-               const std::chrono::milliseconds intervalIn,
-               const ReadingParameters& readingParametersIn,
+               const Milliseconds intervalIn,
                interfaces::ReportManager& reportManager,
                interfaces::JsonStorage& reportStorageIn,
-               std::vector<std::shared_ptr<interfaces::Metric>> metrics) :
+               std::vector<std::shared_ptr<interfaces::Metric>> metricsIn) :
     name(reportName),
     path(reportDir + name), reportingType(reportingTypeIn),
     interval(intervalIn), emitsReadingsUpdate(emitsReadingsUpdateIn),
     logToMetricReportsCollection(logToMetricReportsCollectionIn),
-    readingParameters(readingParametersIn), objServer(objServer),
-    metrics(std::move(metrics)), timer(ioc),
+    objServer(objServer), metrics(std::move(metricsIn)), timer(ioc),
     fileName(std::to_string(std::hash<std::string>{}(name))),
     reportStorage(reportStorageIn)
 {
+    readingParameters =
+        toReadingParameters(utils::transform(metrics, [](const auto& metric) {
+            return metric->dumpConfiguration();
+        }));
+
+    readingParametersPastVersion =
+        utils::transform(readingParameters, [](const auto& item) {
+            return ReadingParametersPastVersion::value_type(
+                std::get<0>(item).front(), std::get<1>(item), std::get<2>(item),
+                std::get<3>(item));
+        });
+
     deleteIface = objServer->add_unique_interface(
         path, deleteIfaceName, [this, &ioc, &reportManager](auto& dbusIface) {
             dbusIface.register_method("Delete", [this, &ioc, &reportManager] {
@@ -59,10 +69,10 @@
 {
     auto dbusIface = objServer->add_unique_interface(path, reportIfaceName);
     dbusIface->register_property_rw(
-        "Interval", static_cast<uint64_t>(interval.count()),
+        "Interval", interval.count(),
         sdbusplus::vtable::property_::emits_change,
         [this](uint64_t newVal, auto&) {
-            std::chrono::milliseconds newValT(newVal);
+            Milliseconds newValT(newVal);
             if (newValT < ReportManager::minInterval)
             {
                 return false;
@@ -70,9 +80,7 @@
             interval = newValT;
             return true;
         },
-        [this](const auto&) {
-            return static_cast<uint64_t>(interval.count());
-        });
+        [this](const auto&) { return interval.count(); });
     dbusIface->register_property_rw(
         "Persistency", persistency, sdbusplus::vtable::property_::emits_change,
         [this](bool newVal, const auto&) {
@@ -104,7 +112,11 @@
         "ReportingType", reportingType, sdbusplus::vtable::property_::const_,
         [this](const auto&) { return reportingType; });
     dbusIface->register_property_r(
-        "ReadingParameters", readingParameters,
+        "ReadingParameters", readingParametersPastVersion,
+        sdbusplus::vtable::property_::const_,
+        [this](const auto&) { return readingParametersPastVersion; });
+    dbusIface->register_property_r(
+        "ReadingParametersFutureVersion", readingParameters,
         sdbusplus::vtable::property_::const_,
         [this](const auto&) { return readingParameters; });
     dbusIface->register_property_r(
@@ -137,7 +149,7 @@
     self.scheduleTimer(self.interval);
 }
 
-void Report::scheduleTimer(std::chrono::milliseconds timerInterval)
+void Report::scheduleTimer(Milliseconds timerInterval)
 {
     timer.expires_after(timerInterval);
     timer.async_wait(
@@ -146,17 +158,23 @@
 
 void Report::updateReadings()
 {
-    std::tuple_element_t<1, Readings> readingsCache(metrics.size());
+    using ReadingsValue = std::tuple_element_t<1, Readings>;
+    std::get<ReadingsValue>(cachedReadings).clear();
 
-    std::transform(std::begin(metrics), std::end(metrics),
-                   std::begin(readingsCache), [](const auto& metric) {
-                       const auto& reading = metric->getReading();
-                       return std::make_tuple(reading.id, reading.metadata,
-                                              reading.value, reading.timestamp);
-                   });
+    for (const auto& metric : metrics)
+    {
+        for (const auto& reading : metric->getReadings())
+        {
+            std::get<1>(cachedReadings)
+                .emplace_back(reading.id, reading.metadata, reading.value,
+                              reading.timestamp);
+        }
+    }
 
-    std::get<0>(readings) = std::time(0);
-    std::get<1>(readings) = std::move(readingsCache);
+    using ReadingsTimestamp = std::tuple_element_t<0, Readings>;
+    std::get<ReadingsTimestamp>(cachedReadings) = std::time(0);
+
+    std::swap(readings, cachedReadings);
 
     reportIface->signal_property("Readings");
 }
diff --git a/src/report.hpp b/src/report.hpp
index d9ecb33..92293a0 100644
--- a/src/report.hpp
+++ b/src/report.hpp
@@ -4,7 +4,7 @@
 #include "interfaces/metric.hpp"
 #include "interfaces/report.hpp"
 #include "interfaces/report_manager.hpp"
-#include "interfaces/types.hpp"
+#include "types/report_types.hpp"
 
 #include <boost/asio/io_context.hpp>
 #include <boost/asio/steady_timer.hpp>
@@ -20,9 +20,7 @@
            const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
            const std::string& reportName, const std::string& reportingType,
            const bool emitsReadingsSignal,
-           const bool logToMetricReportsCollection,
-           const std::chrono::milliseconds period,
-           const ReadingParameters& metricParams,
+           const bool logToMetricReportsCollection, const Milliseconds period,
            interfaces::ReportManager& reportManager,
            interfaces::JsonStorage& reportStorage,
            std::vector<std::shared_ptr<interfaces::Metric>> metrics);
@@ -49,16 +47,18 @@
   private:
     std::unique_ptr<sdbusplus::asio::dbus_interface> makeReportInterface();
     static void timerProc(boost::system::error_code, Report& self);
-    void scheduleTimer(std::chrono::milliseconds interval);
+    void scheduleTimer(Milliseconds interval);
 
     const std::string name;
     const std::string path;
     std::string reportingType;
-    std::chrono::milliseconds interval;
+    Milliseconds interval;
     bool emitsReadingsUpdate;
     bool logToMetricReportsCollection;
+    ReadingParametersPastVersion readingParametersPastVersion;
     ReadingParameters readingParameters;
     bool persistency = false;
+    Readings cachedReadings = {};
     Readings readings = {};
     std::shared_ptr<sdbusplus::asio::object_server> objServer;
     std::unique_ptr<sdbusplus::asio::dbus_interface> reportIface;
@@ -76,5 +76,5 @@
         "/xyz/openbmc_project/Telemetry/Reports/";
     static constexpr const char* deleteIfaceName =
         "xyz.openbmc_project.Object.Delete";
-    static constexpr size_t reportVersion = 3;
+    static constexpr size_t reportVersion = 4;
 };
diff --git a/src/report_factory.cpp b/src/report_factory.cpp
index 9dfdbb0..fb6edf9 100644
--- a/src/report_factory.cpp
+++ b/src/report_factory.cpp
@@ -16,24 +16,9 @@
 {}
 
 std::unique_ptr<interfaces::Report> ReportFactory::make(
-    boost::asio::yield_context& yield, const std::string& name,
-    const std::string& reportingType, bool emitsReadingsSignal,
-    bool logToMetricReportsCollection, std::chrono::milliseconds period,
-    const ReadingParameters& metricParams,
-    interfaces::ReportManager& reportManager,
-    interfaces::JsonStorage& reportStorage) const
-{
-    return make(name, reportingType, emitsReadingsSignal,
-                logToMetricReportsCollection, period, metricParams,
-                reportManager, reportStorage,
-                convertMetricParams(yield, metricParams));
-}
-
-std::unique_ptr<interfaces::Report> ReportFactory::make(
     const std::string& name, const std::string& reportingType,
     bool emitsReadingsSignal, bool logToMetricReportsCollection,
-    std::chrono::milliseconds period, const ReadingParameters& metricParams,
-    interfaces::ReportManager& reportManager,
+    Milliseconds period, interfaces::ReportManager& reportManager,
     interfaces::JsonStorage& reportStorage,
     std::vector<LabeledMetricParameters> labeledMetricParams) const
 {
@@ -41,25 +26,35 @@
         labeledMetricParams,
         [this](const LabeledMetricParameters& param)
             -> std::shared_ptr<interfaces::Metric> {
+            namespace ts = utils::tstring;
+
             return std::make_shared<Metric>(
-                getSensor(param.at_index<0>()), param.at_index<1>(),
-                param.at_index<2>(), param.at_index<3>());
+                getSensors(param.at_label<ts::SensorPath>()),
+                param.at_label<ts::OperationType>(), param.at_label<ts::Id>(),
+                param.at_label<ts::MetricMetadata>(),
+                param.at_label<ts::CollectionTimeScope>(),
+                param.at_label<ts::CollectionDuration>());
         });
 
     return std::make_unique<Report>(
         bus->get_io_context(), objServer, name, reportingType,
-        emitsReadingsSignal, logToMetricReportsCollection, period, metricParams,
+        emitsReadingsSignal, logToMetricReportsCollection, period,
         reportManager, reportStorage, std::move(metrics));
 }
 
-std::shared_ptr<interfaces::Sensor>
-    ReportFactory::getSensor(const LabeledSensorParameters& sensorPath) const
+Sensors ReportFactory::getSensors(
+    const std::vector<LabeledSensorParameters>& sensorPaths) const
 {
     using namespace utils::tstring;
 
-    return sensorCache.makeSensor<Sensor>(sensorPath.at_label<Service>(),
-                                          sensorPath.at_label<Path>(),
-                                          bus->get_io_context(), bus);
+    return utils::transform(sensorPaths,
+                            [this](const LabeledSensorParameters& sensorPath)
+                                -> std::shared_ptr<interfaces::Sensor> {
+                                return sensorCache.makeSensor<Sensor>(
+                                    sensorPath.at_label<Service>(),
+                                    sensorPath.at_label<Path>(),
+                                    bus->get_io_context(), bus);
+                            });
 }
 
 std::vector<LabeledMetricParameters> ReportFactory::convertMetricParams(
@@ -69,22 +64,35 @@
     auto tree = utils::getSubTreeSensors(yield, bus);
 
     return utils::transform(metricParams, [&tree](const auto& item) {
-        const auto& [sensorPath, operationType, id, metadata] = item;
+        const auto& [sensorPaths, operationType, id, metadata,
+                     collectionTimeScope, collectionDuration] = item;
 
-        auto it = std::find_if(
-            tree.begin(), tree.end(),
-            [&sensorPath](const auto& v) { return v.first == sensorPath; });
+        std::vector<LabeledSensorParameters> sensorParameters;
 
-        if (it != tree.end() && it->second.size() == 1)
+        for (const auto& sensorPath : sensorPaths)
         {
-            const auto& [service, ifaces] = it->second.front();
-            return LabeledMetricParameters(
-                LabeledSensorParameters(service, sensorPath),
-                utils::stringToOperationType(operationType), id, metadata);
+            auto it = std::find_if(
+                tree.begin(), tree.end(),
+                [&sensorPath](const auto& v) { return v.first == sensorPath; });
+
+            if (it != tree.end() && it->second.size() == 1)
+            {
+                const auto& [service, ifaces] = it->second.front();
+                sensorParameters.emplace_back(service, sensorPath);
+            }
         }
 
-        throw sdbusplus::exception::SdBusError(
-            static_cast<int>(std::errc::invalid_argument),
-            "Could not find service for provided sensors");
+        if (sensorParameters.size() != sensorPaths.size())
+        {
+            throw sdbusplus::exception::SdBusError(
+                static_cast<int>(std::errc::invalid_argument),
+                "Could not find service for provided sensors");
+        }
+
+        return LabeledMetricParameters(
+            std::move(sensorParameters),
+            utils::stringToOperationType(operationType), id, metadata,
+            utils::stringToCollectionTimeScope(collectionTimeScope),
+            CollectionDuration(Milliseconds(collectionDuration)));
     });
 }
diff --git a/src/report_factory.hpp b/src/report_factory.hpp
index 550eb81..1160a6f 100644
--- a/src/report_factory.hpp
+++ b/src/report_factory.hpp
@@ -15,30 +15,21 @@
         const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
         SensorCache& sensorCache);
 
-    std::unique_ptr<interfaces::Report>
-        make(boost::asio::yield_context& yield, const std::string& name,
-             const std::string& reportingType, bool emitsReadingsSignal,
-             bool logToMetricReportsCollection,
-             std::chrono::milliseconds period,
-             const ReadingParameters& metricParams,
-             interfaces::ReportManager& reportManager,
-             interfaces::JsonStorage& reportStorage) const override;
+    std::vector<LabeledMetricParameters> convertMetricParams(
+        boost::asio::yield_context& yield,
+        const ReadingParameters& metricParams) const override;
+
     std::unique_ptr<interfaces::Report>
         make(const std::string& name, const std::string& reportingType,
              bool emitsReadingsSignal, bool logToMetricReportsCollection,
-             std::chrono::milliseconds period,
-             const ReadingParameters& metricParams,
-             interfaces::ReportManager& reportManager,
+             Milliseconds period, interfaces::ReportManager& reportManager,
              interfaces::JsonStorage& reportStorage,
              std::vector<LabeledMetricParameters> labeledMetricParams)
             const override;
 
   private:
-    std::shared_ptr<interfaces::Sensor>
-        getSensor(const LabeledSensorParameters& sensorPath) const;
-    std::vector<LabeledMetricParameters>
-        convertMetricParams(boost::asio::yield_context& yield,
-                            const ReadingParameters& metricParams) const;
+    Sensors getSensors(
+        const std::vector<LabeledSensorParameters>& sensorPaths) const;
 
     std::shared_ptr<sdbusplus::asio::connection> bus;
     std::shared_ptr<sdbusplus::asio::object_server> objServer;
diff --git a/src/report_manager.cpp b/src/report_manager.cpp
index 24087c3..e40d9a4 100644
--- a/src/report_manager.cpp
+++ b/src/report_manager.cpp
@@ -1,7 +1,7 @@
 #include "report_manager.hpp"
 
-#include "interfaces/types.hpp"
 #include "report.hpp"
+#include "types/report_types.hpp"
 #include "utils/conversion.hpp"
 #include "utils/transform.hpp"
 
@@ -11,6 +11,19 @@
 #include <stdexcept>
 #include <system_error>
 
+ReadingParameters
+    convertToReadingParameters(ReadingParametersPastVersion params)
+{
+    return utils::transform(params, [](const auto& param) {
+        using namespace std::chrono_literals;
+
+        return ReadingParameters::value_type(
+            std::vector{{std::get<0>(param)}}, std::get<1>(param),
+            std::get<2>(param), std::get<3>(param),
+            utils::enumToString(CollectionTimeScope::point), 0u);
+    });
+}
+
 ReportManager::ReportManager(
     std::unique_ptr<interfaces::ReportFactory> reportFactoryIn,
     std::unique_ptr<interfaces::JsonStorage> reportStorageIn,
@@ -42,11 +55,29 @@
                                     const bool emitsReadingsUpdate,
                                     const bool logToMetricReportsCollection,
                                     const uint64_t interval,
-                                    ReadingParameters metricParams) {
+                                    ReadingParametersPastVersion metricParams) {
                     return addReport(yield, reportName, reportingType,
                                      emitsReadingsUpdate,
                                      logToMetricReportsCollection,
-                                     std::chrono::milliseconds(interval),
+                                     Milliseconds(interval),
+                                     convertToReadingParameters(
+                                         std::move(metricParams)))
+                        .getPath();
+                });
+
+            dbusIface.register_method(
+                "AddReportFutureVersion",
+                [this](boost::asio::yield_context& yield,
+                       const std::string& reportName,
+                       const std::string& reportingType,
+                       const bool emitsReadingsUpdate,
+                       const bool logToMetricReportsCollection,
+                       const uint64_t interval,
+                       ReadingParameters metricParams) {
+                    return addReport(yield, reportName, reportingType,
+                                     emitsReadingsUpdate,
+                                     logToMetricReportsCollection,
+                                     Milliseconds(interval),
                                      std::move(metricParams))
                         .getPath();
                 });
@@ -71,10 +102,10 @@
     }
 }
 
-void ReportManager::verifyAddReport(const std::string& reportName,
-                                    const std::string& reportingType,
-                                    std::chrono::milliseconds interval,
-                                    const ReadingParameters& readingParams)
+void ReportManager::verifyAddReport(
+    const std::string& reportName, const std::string& reportingType,
+    Milliseconds interval,
+    const std::vector<LabeledMetricParameters>& readingParams)
 {
     if (reports.size() >= maxReports)
     {
@@ -119,9 +150,12 @@
 
     try
     {
-        for (const auto& item : readingParams)
+        namespace ts = utils::tstring;
+
+        for (const LabeledMetricParameters& item : readingParams)
         {
-            utils::stringToOperationType(std::get<1>(item));
+            utils::toOperationType(
+                utils::toUnderlying(item.at_label<ts::OperationType>()));
         }
     }
     catch (const std::exception& e)
@@ -134,41 +168,29 @@
 interfaces::Report& ReportManager::addReport(
     boost::asio::yield_context& yield, const std::string& reportName,
     const std::string& reportingType, const bool emitsReadingsUpdate,
-    const bool logToMetricReportsCollection, std::chrono::milliseconds interval,
+    const bool logToMetricReportsCollection, Milliseconds interval,
     ReadingParameters metricParams)
 {
-    verifyAddReport(reportName, reportingType, interval, metricParams);
+    auto labeledMetricParams =
+        reportFactory->convertMetricParams(yield, metricParams);
 
-    reports.emplace_back(reportFactory->make(
-        yield, reportName, reportingType, emitsReadingsUpdate,
-        logToMetricReportsCollection, interval, std::move(metricParams), *this,
-        *reportStorage));
-    return *reports.back();
+    return addReport(reportName, reportingType, emitsReadingsUpdate,
+                     logToMetricReportsCollection, interval,
+                     std::move(labeledMetricParams));
 }
 
 interfaces::Report& ReportManager::addReport(
     const std::string& reportName, const std::string& reportingType,
     const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
-    std::chrono::milliseconds interval,
+    Milliseconds interval,
     std::vector<LabeledMetricParameters> labeledMetricParams)
 {
-    auto metricParams = utils::transform(
-        labeledMetricParams, [](const LabeledMetricParameters& param) {
-            using namespace utils::tstring;
+    verifyAddReport(reportName, reportingType, interval, labeledMetricParams);
 
-            return ReadingParameters::value_type(
-                sdbusplus::message::object_path(
-                    param.at_index<0>().at_label<Path>()),
-                utils::enumToString(param.at_index<1>()), param.at_index<2>(),
-                param.at_index<3>());
-        });
-
-    verifyAddReport(reportName, reportingType, interval, metricParams);
-
-    reports.emplace_back(reportFactory->make(
-        reportName, reportingType, emitsReadingsUpdate,
-        logToMetricReportsCollection, interval, std::move(metricParams), *this,
-        *reportStorage, labeledMetricParams));
+    reports.emplace_back(
+        reportFactory->make(reportName, reportingType, emitsReadingsUpdate,
+                            logToMetricReportsCollection, interval, *this,
+                            *reportStorage, labeledMetricParams));
     return *reports.back();
 }
 
@@ -200,8 +222,7 @@
                     .get<std::vector<LabeledMetricParameters>>();
 
             addReport(name, reportingType, emitsReadingsSignal,
-                      logToMetricReportsCollection,
-                      std::chrono::milliseconds(interval),
+                      logToMetricReportsCollection, Milliseconds(interval),
                       std::move(readingParameters));
         }
         catch (const std::exception& e)
diff --git a/src/report_manager.hpp b/src/report_manager.hpp
index e66a614..1e6e15d 100644
--- a/src/report_manager.hpp
+++ b/src/report_manager.hpp
@@ -39,21 +39,21 @@
     std::vector<std::unique_ptr<interfaces::Report>> reports;
 
     void verifyReportNameLength(const std::string& reportName);
-    void verifyAddReport(const std::string& reportName,
-                         const std::string& reportingType,
-                         std::chrono::milliseconds interval,
-                         const ReadingParameters& readingParams);
+    void verifyAddReport(
+        const std::string& reportName, const std::string& reportingType,
+        Milliseconds interval,
+        const std::vector<LabeledMetricParameters>& readingParams);
     interfaces::Report& addReport(boost::asio::yield_context& yield,
                                   const std::string& reportName,
                                   const std::string& reportingType,
                                   const bool emitsReadingsUpdate,
                                   const bool logToMetricReportsCollection,
-                                  std::chrono::milliseconds interval,
+                                  Milliseconds interval,
                                   ReadingParameters metricParams);
     interfaces::Report& addReport(
         const std::string& reportName, const std::string& reportingType,
         const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
-        std::chrono::milliseconds interval,
+        Milliseconds interval,
         std::vector<LabeledMetricParameters> metricParams);
     void loadFromPersistent();
 
@@ -62,8 +62,7 @@
     static constexpr size_t maxReadingParams{TELEMETRY_MAX_READING_PARAMS};
     static constexpr size_t maxReportNameLength{
         TELEMETRY_MAX_REPORT_NAME_LENGTH};
-    static constexpr std::chrono::milliseconds minInterval{
-        TELEMETRY_MIN_INTERVAL};
+    static constexpr Milliseconds minInterval{TELEMETRY_MIN_INTERVAL};
     static constexpr const char* reportManagerIfaceName =
         "xyz.openbmc_project.Telemetry.ReportManager";
     static constexpr const char* reportManagerPath =
diff --git a/src/sensor.hpp b/src/sensor.hpp
index 1374c54..e3334a0 100644
--- a/src/sensor.hpp
+++ b/src/sensor.hpp
@@ -2,6 +2,7 @@
 
 #include "interfaces/sensor.hpp"
 #include "interfaces/sensor_listener.hpp"
+#include "types/milliseconds.hpp"
 #include "utils/unique_call.hpp"
 
 #include <boost/asio/high_resolution_timer.hpp>
@@ -41,7 +42,7 @@
     interfaces::Sensor::Id sensorId;
     boost::asio::io_context& ioc;
     std::shared_ptr<sdbusplus::asio::connection> bus;
-    std::chrono::milliseconds timerInterval = std::chrono::milliseconds(0);
+    Milliseconds timerInterval = Milliseconds(0);
     std::optional<boost::asio::high_resolution_timer> timer;
 
     utils::UniqueCall uniqueCall;
diff --git a/src/trigger.cpp b/src/trigger.cpp
index 6289a05..d6ee3be 100644
--- a/src/trigger.cpp
+++ b/src/trigger.cpp
@@ -1,7 +1,7 @@
 #include "trigger.hpp"
 
-#include "interfaces/trigger_types.hpp"
-#include "interfaces/types.hpp"
+#include "types/report_types.hpp"
+#include "types/trigger_types.hpp"
 #include "utils/conversion_trigger.hpp"
 #include "utils/transform.hpp"
 
diff --git a/src/trigger.hpp b/src/trigger.hpp
index a108caf..09b5dc8 100644
--- a/src/trigger.hpp
+++ b/src/trigger.hpp
@@ -4,7 +4,7 @@
 #include "interfaces/threshold.hpp"
 #include "interfaces/trigger.hpp"
 #include "interfaces/trigger_manager.hpp"
-#include "interfaces/trigger_types.hpp"
+#include "types/trigger_types.hpp"
 
 #include <boost/asio/io_context.hpp>
 #include <sdbusplus/asio/object_server.hpp>
diff --git a/src/trigger_actions.hpp b/src/trigger_actions.hpp
index 408bcb5..2b126e0 100644
--- a/src/trigger_actions.hpp
+++ b/src/trigger_actions.hpp
@@ -2,7 +2,7 @@
 
 #include "interfaces/report_manager.hpp"
 #include "interfaces/trigger_action.hpp"
-#include "interfaces/trigger_types.hpp"
+#include "types/trigger_types.hpp"
 
 namespace action
 {
diff --git a/src/trigger_factory.cpp b/src/trigger_factory.cpp
index 6e2ad21..bdfc163 100644
--- a/src/trigger_factory.cpp
+++ b/src/trigger_factory.cpp
@@ -45,8 +45,8 @@
                 labeledThresholdParam.at_label<ts::UserId>();
             discrete::Severity severity =
                 labeledThresholdParam.at_label<ts::Severity>();
-            std::chrono::milliseconds dwellTime = std::chrono::milliseconds(
-                labeledThresholdParam.at_label<ts::DwellTime>());
+            auto dwellTime =
+                Milliseconds(labeledThresholdParam.at_label<ts::DwellTime>());
             std::string thresholdValue =
                 labeledThresholdParam.at_label<ts::ThresholdValue>();
 
@@ -68,7 +68,7 @@
 
             thresholds.emplace_back(std::make_shared<DiscreteThreshold>(
                 bus->get_io_context(), sensors, sensorNames, std::move(actions),
-                std::chrono::milliseconds(dwellTime), std::stod(thresholdValue),
+                Milliseconds(dwellTime), std::stod(thresholdValue),
                 thresholdName));
         }
         if (labeledDiscreteThresholdParams.empty())
@@ -106,8 +106,8 @@
         {
             std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
             auto type = labeledThresholdParam.at_label<ts::Type>();
-            auto dwellTime = std::chrono::milliseconds(
-                labeledThresholdParam.at_label<ts::DwellTime>());
+            auto dwellTime =
+                Milliseconds(labeledThresholdParam.at_label<ts::DwellTime>());
             auto direction = labeledThresholdParam.at_label<ts::Direction>();
             auto thresholdValue =
                 double{labeledThresholdParam.at_label<ts::ThresholdValue>()};
@@ -145,12 +145,10 @@
         triggerStorage);
 }
 
-std::pair<std::vector<std::shared_ptr<interfaces::Sensor>>,
-          std::vector<std::string>>
-    TriggerFactory::getSensors(
-        const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const
+std::pair<Sensors, std::vector<std::string>> TriggerFactory::getSensors(
+    const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const
 {
-    std::vector<std::shared_ptr<interfaces::Sensor>> sensors;
+    Sensors sensors;
     std::vector<std::string> sensorNames;
 
     for (const auto& labeledSensorInfo : labeledSensorsInfo)
diff --git a/src/trigger_factory.hpp b/src/trigger_factory.hpp
index 7c13e55..4ec273a 100644
--- a/src/trigger_factory.hpp
+++ b/src/trigger_factory.hpp
@@ -35,8 +35,6 @@
     SensorCache& sensorCache;
     interfaces::ReportManager& reportManager;
 
-    std::pair<std::vector<std::shared_ptr<interfaces::Sensor>>,
-              std::vector<std::string>>
-        getSensors(
-            const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const;
+    std::pair<Sensors, std::vector<std::string>> getSensors(
+        const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const;
 };
diff --git a/src/trigger_manager.cpp b/src/trigger_manager.cpp
index d9d04d2..81a0398 100644
--- a/src/trigger_manager.cpp
+++ b/src/trigger_manager.cpp
@@ -1,7 +1,7 @@
 #include "trigger_manager.hpp"
 
-#include "interfaces/trigger_types.hpp"
 #include "trigger.hpp"
+#include "types/trigger_types.hpp"
 #include "utils/conversion_trigger.hpp"
 #include "utils/transform.hpp"
 
diff --git a/src/types/collection_duration.hpp b/src/types/collection_duration.hpp
new file mode 100644
index 0000000..ddeb9cc
--- /dev/null
+++ b/src/types/collection_duration.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "types/milliseconds.hpp"
+
+#include <boost/serialization/strong_typedef.hpp>
+#include <nlohmann/json.hpp>
+
+#include <chrono>
+
+BOOST_STRONG_TYPEDEF(Milliseconds, CollectionDuration)
+
+inline void to_json(nlohmann::json& json, const CollectionDuration& value)
+{
+    json = value.t.count();
+}
+
+inline void from_json(const nlohmann::json& json, CollectionDuration& value)
+{
+    value = CollectionDuration(Milliseconds(json.get<uint64_t>()));
+}
diff --git a/src/types/collection_time_scope.hpp b/src/types/collection_time_scope.hpp
new file mode 100644
index 0000000..d2694d2
--- /dev/null
+++ b/src/types/collection_time_scope.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "utils/conversion.hpp"
+
+#include <array>
+#include <cstdint>
+#include <string_view>
+#include <type_traits>
+
+enum class CollectionTimeScope : uint32_t
+{
+    point,
+    interval,
+    startup
+};
+
+namespace utils
+{
+
+constexpr std::array<std::pair<std::string_view, CollectionTimeScope>, 3>
+    convDataCollectionTimeScope = {
+        {std::make_pair<std::string_view, CollectionTimeScope>(
+             "Point", CollectionTimeScope::point),
+         std::make_pair<std::string_view, CollectionTimeScope>(
+             "Interval", CollectionTimeScope::interval),
+         std::make_pair<std::string_view, CollectionTimeScope>(
+             "StartupInterval", CollectionTimeScope::startup)}};
+
+inline CollectionTimeScope
+    toCollectionTimeScope(std::underlying_type_t<CollectionTimeScope> value)
+{
+    return toEnum<CollectionTimeScope, CollectionTimeScope::point,
+                  CollectionTimeScope::startup>(value);
+}
+
+inline CollectionTimeScope stringToCollectionTimeScope(const std::string& value)
+{
+    return stringToEnum(convDataCollectionTimeScope, value);
+}
+
+inline std::string enumToString(CollectionTimeScope value)
+{
+    return std::string(enumToString(convDataCollectionTimeScope, value));
+}
+
+} // namespace utils
\ No newline at end of file
diff --git a/src/types/milliseconds.hpp b/src/types/milliseconds.hpp
new file mode 100644
index 0000000..6de2c2b
--- /dev/null
+++ b/src/types/milliseconds.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include <chrono>
+
+using Milliseconds = std::chrono::duration<uint64_t, std::milli>;
diff --git a/src/operation_type.hpp b/src/types/operation_type.hpp
similarity index 100%
rename from src/operation_type.hpp
rename to src/types/operation_type.hpp
diff --git a/src/types/report_types.cpp b/src/types/report_types.cpp
new file mode 100644
index 0000000..f6979cc
--- /dev/null
+++ b/src/types/report_types.cpp
@@ -0,0 +1,26 @@
+#include "report_types.hpp"
+
+#include "utils/transform.hpp"
+
+ReadingParameters
+    toReadingParameters(const std::vector<LabeledMetricParameters>& labeled)
+{
+    namespace ts = utils::tstring;
+
+    return utils::transform(
+        labeled, [](const LabeledMetricParameters& metricParams) {
+            return ReadingParameters::value_type(
+                utils::transform(
+                    metricParams.at_label<ts::SensorPath>(),
+                    [](const LabeledSensorParameters& sensorParameters) {
+                        return sdbusplus::message::object_path(
+                            sensorParameters.at_label<ts::Path>());
+                    }),
+                utils::enumToString(metricParams.at_label<ts::OperationType>()),
+                metricParams.at_label<ts::Id>(),
+                metricParams.at_label<ts::MetricMetadata>(),
+                utils::enumToString(
+                    metricParams.at_label<ts::CollectionTimeScope>()),
+                metricParams.at_label<ts::CollectionDuration>().t.count());
+        });
+}
diff --git a/src/types/report_types.hpp b/src/types/report_types.hpp
new file mode 100644
index 0000000..8046df0
--- /dev/null
+++ b/src/types/report_types.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "types/collection_duration.hpp"
+#include "types/collection_time_scope.hpp"
+#include "types/operation_type.hpp"
+#include "utils/labeled_tuple.hpp"
+#include "utils/tstring.hpp"
+
+#include <sdbusplus/message/types.hpp>
+
+#include <chrono>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <vector>
+
+using ReadingParametersPastVersion =
+    std::vector<std::tuple<sdbusplus::message::object_path, std::string,
+                           std::string, std::string>>;
+
+using ReadingParameters = std::vector<
+    std::tuple<std::vector<sdbusplus::message::object_path>, std::string,
+               std::string, std::string, std::string, uint64_t>>;
+
+using LabeledSensorParameters =
+    utils::LabeledTuple<std::tuple<std::string, std::string>,
+                        utils::tstring::Service, utils::tstring::Path>;
+
+using LabeledMetricParameters = utils::LabeledTuple<
+    std::tuple<std::vector<LabeledSensorParameters>, OperationType, std::string,
+               std::string, CollectionTimeScope, CollectionDuration>,
+    utils::tstring::SensorPath, utils::tstring::OperationType,
+    utils::tstring::Id, utils::tstring::MetricMetadata,
+    utils::tstring::CollectionTimeScope, utils::tstring::CollectionDuration>;
+
+using Readings = std::tuple<
+    uint64_t,
+    std::vector<std::tuple<std::string, std::string, double, uint64_t>>>;
+
+ReadingParameters
+    toReadingParameters(const std::vector<LabeledMetricParameters>& labeled);
diff --git a/src/interfaces/trigger_types.hpp b/src/types/trigger_types.hpp
similarity index 100%
rename from src/interfaces/trigger_types.hpp
rename to src/types/trigger_types.hpp
diff --git a/src/utils/conversion_trigger.hpp b/src/utils/conversion_trigger.hpp
index 7ed660f..5229e5e 100644
--- a/src/utils/conversion_trigger.hpp
+++ b/src/utils/conversion_trigger.hpp
@@ -1,7 +1,7 @@
 #pragma once
 
 #include "interfaces/json_storage.hpp"
-#include "interfaces/trigger_types.hpp"
+#include "types/trigger_types.hpp"
 
 namespace utils
 {
diff --git a/src/utils/detached_timer.hpp b/src/utils/detached_timer.hpp
index 224e5a1..636949c 100644
--- a/src/utils/detached_timer.hpp
+++ b/src/utils/detached_timer.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "types/milliseconds.hpp"
+
 #include <boost/asio/io_context.hpp>
 #include <boost/asio/steady_timer.hpp>
 
@@ -9,8 +11,8 @@
 {
 
 template <class F>
-void makeDetachedTimer(boost::asio::io_context& ioc,
-                       std::chrono::milliseconds delay, F&& fun)
+void makeDetachedTimer(boost::asio::io_context& ioc, Milliseconds delay,
+                       F&& fun)
 {
     auto timer = std::make_unique<boost::asio::steady_timer>(ioc);
     timer->expires_after(delay);
diff --git a/src/utils/json.hpp b/src/utils/json.hpp
new file mode 100644
index 0000000..2ae606f
--- /dev/null
+++ b/src/utils/json.hpp
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <nlohmann/json.hpp>
+
+#include <string_view>
+
+namespace utils
+{
+
+template <class T>
+struct is_vector : std::false_type
+{};
+
+template <class T>
+struct is_vector<std::vector<T>> : std::true_type
+{};
+
+template <class T>
+constexpr bool is_vector_v = is_vector<T>::value;
+
+template <class T>
+std::optional<T> readJson(const nlohmann::json& json)
+{
+    if constexpr (is_vector_v<T>)
+    {
+        if (json.is_array())
+        {
+            auto result = T{};
+            for (const auto& item : json.items())
+            {
+                if (auto val = readJson<typename T::value_type>(item.value()))
+                {
+                    result.emplace_back(*val);
+                }
+            }
+            return result;
+        }
+    }
+    else
+    {
+        if (const T* val = json.get_ptr<const T*>())
+        {
+            return *val;
+        }
+    }
+
+    return std::nullopt;
+}
+
+template <class T>
+std::optional<T> readJson(const nlohmann::json& json, std::string_view key)
+{
+    auto it = json.find(key);
+    if (it != json.end())
+    {
+        const nlohmann::json& subJson = *it;
+        return readJson<T>(subJson);
+    }
+
+    return std::nullopt;
+}
+
+} // namespace utils
diff --git a/src/utils/labeled_tuple.hpp b/src/utils/labeled_tuple.hpp
index 795f37f..a224141 100644
--- a/src/utils/labeled_tuple.hpp
+++ b/src/utils/labeled_tuple.hpp
@@ -170,15 +170,15 @@
 };
 
 template <class... Args, class... Labels>
-void to_json(nlohmann::json& json,
-             const LabeledTuple<std::tuple<Args...>, Labels...>& tuple)
+inline void to_json(nlohmann::json& json,
+                    const LabeledTuple<std::tuple<Args...>, Labels...>& tuple)
 {
     json = tuple.to_json();
 }
 
 template <class... Args, class... Labels>
-void from_json(const nlohmann::json& json,
-               LabeledTuple<std::tuple<Args...>, Labels...>& tuple)
+inline void from_json(const nlohmann::json& json,
+                      LabeledTuple<std::tuple<Args...>, Labels...>& tuple)
 {
     tuple.from_json(json);
 }
diff --git a/src/utils/tstring.hpp b/src/utils/tstring.hpp
index 5b17d98..8f9701a 100644
--- a/src/utils/tstring.hpp
+++ b/src/utils/tstring.hpp
@@ -112,5 +112,21 @@
     }
 };
 
+struct CollectionTimeScope
+{
+    static std::string str()
+    {
+        return "collectionTimeScope";
+    }
+};
+
+struct CollectionDuration
+{
+    static std::string str()
+    {
+        return "collectionDuration";
+    }
+};
+
 } // namespace tstring
 } // namespace utils