Repository: openhab/openhab-js
Pull request #401: Extend Persistence Extensions with Riemann Sums
Author: login: mherwege
Labels: name: enhancement
description: New feature or request
Created: 2024-12-01T17:19:12Z | Merged: 2025-03-27T17:04:16Z

Depends on https://github.com/openhab/openhab-core/pull/4461

This is not fully tested as I am still not sure about the Java RiemannType enum. It is hard to test without the core PR merged first.


Diff:
diff --git a/README.md b/README.md
index 1dc7de66..e9245f5e 100644
--- a/README.md
+++ b/README.md
@@ -496,9 +496,9 @@ See [openhab-js : ItemConfig](https://openhab.github.io/openhab-js/global.html#I
 Calling `Item.persistence` returns an `ItemPersistence` object with the following functions:
 
 - ItemPersistence :`object`
-  - .averageSince(timestamp, serviceId) ⇒ `PersistedState | null`
-  - .averageUntil(timestamp, serviceId) ⇒ `PersistedState | null`
-  - .averageBetween(begin, end, serviceId) ⇒ `PersistedState | null`
+  - .averageSince(timestamp, riemannType, serviceId) ⇒ `PersistedState | null`
+  - .averageUntil(timestamp, riemannType, serviceId) ⇒ `PersistedState | null`
+  - .averageBetween(begin, end, riemannType, serviceId) ⇒ `PersistedState | null`
   - .changedSince(timestamp, serviceId) ⇒ `boolean`
   - .changedUntil(timestamp, serviceId) ⇒ `boolean`
   - .changedBetween(begin, end, serviceId) ⇒ `boolean`
@@ -511,12 +511,12 @@ Calling `Item.persistence` returns an `ItemPersistence` object with the followin
   - .deltaSince(timestamp, serviceId) ⇒ `PersistedState | null`
   - .deltaUntil(timestamp, serviceId) ⇒ `PersistedState | null`
   - .deltaBetween(begin, end, serviceId) ⇒ `PersistedState | null`
-  - .deviationSince(timestamp, serviceId) ⇒ `PersistedState | null`
-  - .deviationUntil(timestamp, serviceId) ⇒ `PersistedState | null`
-  - .deviationBetween(begin, end, serviceId) ⇒ `PersistedState | null`
-  - .evolutionRateSince(timestamp, serviceId) ⇒ `number | null`
-  - .evolutionRateUntil(timestamp, serviceId) ⇒ `number | null`
-  - .evolutionRateBetween(begin, end, serviceId) ⇒ `number | null`
+  - .deviationSince(timestamp, riemannType, serviceId) ⇒ `PersistedState | null`
+  - .deviationUntil(timestamp, riemannType, serviceId) ⇒ `PersistedState | null`
+  - .deviationBetween(begin, end, riemannType, serviceId) ⇒ `PersistedState | null`
+  - .evolutionRateSince(timestamp, riemannType, serviceId) ⇒ `number | null`
+  - .evolutionRateUntil(timestamp, riemannType, serviceId) ⇒ `number | null`
+  - .evolutionRateBetween(begin, end, riemannType, serviceId) ⇒ `number | null`
   - .getAllStatesSince(timestamp, serviceId)  ⇒ `Array[PersistedItem]`
   - .getAllStatesUntil(timestamp, serviceId)  ⇒ `Array[PersistedItem]`
   - .getAllStatesBetween(begin, end, serviceId)  ⇒ `Array[PersistedItem]`
@@ -540,6 +540,9 @@ Calling `Item.persistence` returns an `ItemPersistence` object with the followin
   - .persistedState(timestamp, serviceId) ⇒ `PersistedItem | null`
   - .previousState(skipEqual, serviceId) ⇒ `PersistedItem | null`
   - .nextState(skipEqual, serviceId) ⇒ `PersistedItem | null`
+  - .riemannSumSince(timestamp, riemannType, serviceId)  ⇒ `PersistedState | null`
+  - .riemannSumUntil(timestamp, riemannType, serviceId)  ⇒ `PersistedState | null`
+  - .riemannSumBetween(begin, end, riemannType, serviceId)  ⇒ `PersistedState | null`
   - .sumSince(timestamp, serviceId) ⇒ `PersistedState | null`
   - .sumUntil(timestamp, serviceId) ⇒ `PersistedState | null`
   - .sumBetween(begin, end, serviceId) ⇒ `PersistedState | null`
@@ -550,6 +553,15 @@ Calling `Item.persistence` returns an `ItemPersistence` object with the followin
   - .varianceUntil(timestamp, serviceId) ⇒ `PersistedState | null`
   - .varianceBetween(begin, end, serviceId) ⇒ `PersistedState | null`
 
+`riemannType` is an optional argument for methods that require calculating an approximation of the integral value.
+The approximation is calculated using a Riemann sum, with left, right, trapezoidal or midpoint value approximations.
+The argument is a Java RiemannType enum with possible values: `RiemannType.LEFT`, `RiemannType.RIGHT`, `RiemannType.TRAPEZOIDAL` or `RiemannType.MIDPOINT`. If ommitted, `RiemannType.LEFT` is used.
+
+A Riemann sum is always calculated using seconds as unit for time.
+As an example, the Riemann sum of power values in `kW` will result in an energy measurement in `kWs`.
+You can rely on framework functionality to convert to the appropriate unit (e.g. `kWh`), or do an explicit conversion.
+If you don't use units, be aware of this time factor.
+
 Note: `serviceId` is optional, if omitted, the default persistence service will be used.
 
 ```javascript
diff --git a/src/items/item-persistence.js b/src/items/item-persistence.js
index 96c2474f..cfae65f5 100644
--- a/src/items/item-persistence.js
+++ b/src/items/item-persistence.js
@@ -6,6 +6,7 @@ const { _toOpenhabPrimitiveType, _isTimeSeries } = require('../helpers');
 const PersistenceExtensions = Java.type('org.openhab.core.persistence.extensions.PersistenceExtensions');
 const TimeSeries = Java.type('org.openhab.core.types.TimeSeries');
 const TypeParser = Java.type('org.openhab.core.types.TypeParser');
+const RiemannType = Java.type('org.openhab.core.persistence.extensions.PersistenceExtensions.RiemannType');
 
 /**
  * @typedef {import('@js-joda/core').ZonedDateTime} time.ZonedDateTime
@@ -166,6 +167,8 @@ class ItemPersistence {
     this.rawItem = rawItem;
   }
 
+  static RiemannType = RiemannType;
+
   /**
    * Persists a state of a given Item.
    *
@@ -509,12 +512,15 @@ class ItemPersistence {
    * Gets the variance of the state of the given Item since a certain point in time.
    *
    * @param {(time.ZonedDateTime | Date)} timestamp the point in time from which to compute the variance
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
    * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
    * @returns {(PersistedState | null)} the variance between then and now as {@link items.PersistedState}, or <code>null</code> if
    *                            <code>timestamp</code> is in the future, or if there is no persisted state for the given
    *                            Item at the given <code>timestamp</code>
    */
-  varianceSince (timestamp, serviceId) {
+  varianceSince (timestamp, riemannType, serviceId) {
     return _persistedStateOrNull(PersistenceExtensions.varianceSince(this.rawItem, ...arguments));
   }
 
@@ -522,12 +528,15 @@ class ItemPersistence {
    * Gets the variance of the state of the given Item until a certain point in time.
    *
    * @param {(time.ZonedDateTime | Date)} timestamp the point in time to which to compute the variance
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
    * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
    * @returns {(PersistedState | null)} the variance between now and then as {@link items.PersistedState}, or <code>null</code> if
    *                            <code>timestamp</code> is in the past, or if there is no persisted state for the given
    *                            Item at the given <code>timestamp</code>
    */
-  varianceUntil (timestamp, serviceId) {
+  varianceUntil (timestamp, riemannType, serviceId) {
     return _persistedStateOrNull(PersistenceExtensions.varianceUntil(this.rawItem, ...arguments));
   }
 
@@ -536,12 +545,15 @@ class ItemPersistence {
    *
    * @param {(time.ZonedDateTime | Date)} begin the point in time from which to compute the variance
    * @param {(time.ZonedDateTime | Date)} end the end time for the computation
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
    * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
    * @returns {(PersistedState | null)} the variance between both points of time as {@link items.PersistedState}, or <code>null</code> if
    *                            <code>begin</code> is after <code>end</code>, or if there is no persisted state for the given
    *                            Item between <code>begin</code> and <code>end</code>
    */
-  varianceBetween (begin, end, serviceId) {
+  varianceBetween (begin, end, riemannType, serviceId) {
     return _persistedStateOrNull(PersistenceExtensions.varianceBetween(this.rawItem, ...arguments));
   }
 
@@ -549,12 +561,15 @@ class ItemPersistence {
    * Gets the standard deviation of the state of the given Item since a certain point in time.
    *
    * @param {(time.ZonedDateTime | Date)} timestamp the point in time from which to compute the standard deviation
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
    * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
    * @returns {(PersistedState | null)} the standard deviation between then and now as {@link items.PersistedState}, or <code>null</code>
    *                            if <code>timestamp</code> is in the future, or if there is no persisted state for the given Item
    *                            at the given <code>timestamp</code>
    */
-  deviationSince (timestamp, serviceId) {
+  deviationSince (timestamp, riemannType, serviceId) {
     return _persistedStateOrNull(PersistenceExtensions.deviationSince(this.rawItem, ...arguments));
   }
 
@@ -562,12 +577,15 @@ class ItemPersistence {
    * Gets the standard deviation of the state of the given Item until a certain point in time.
    *
    * @param {(time.ZonedDateTime | Date)} timestamp the point in time to which to compute the standard deviation
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
    * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
    * @returns {(PersistedState | null)} the standard deviation between now and then as {@link items.PersistedState}, or <code>null</code>
    *                            if <code>timestamp</code> is in the past, or if there is no persisted state for the given Item
    *                            at the given <code>timestamp</code>
    */
-  deviationUntil (timestamp, serviceId) {
+  deviationUntil (timestamp, riemannType, serviceId) {
     return _persistedStateOrNull(PersistenceExtensions.deviationUntil(this.rawItem, ...arguments));
   }
 
@@ -576,12 +594,15 @@ class ItemPersistence {
    *
    * @param {(time.ZonedDateTime | Date)} begin the point in time from which to compute
    * @param {(time.ZonedDateTime | Date)} end the end time for the computation
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
    * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
    * @returns {(PersistedState | null)} the standard deviation between both points of time as {@link items.PersistedState}, or <code>null</code>
    *                            if <code>begin</code> is after <code>end</code>, or if there is no persisted state for the given Item
    *                            between <code>begin</code> and <code>end</code>
    */
-  deviationBetween (begin, end, serviceId) {
+  deviationBetween (begin, end, riemannType, serviceId) {
     return _persistedStateOrNull(PersistenceExtensions.deviationBetween(this.rawItem, ...arguments));
   }
 
@@ -594,10 +615,13 @@ class ItemPersistence {
    * console.log('KitchenDimmer average since yesterday', item.persistence.averageSince(yesterday));
    *
    * @param {(time.ZonedDateTime | Date)} timestamp the point in time from which to search for the average value
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
    * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
    * @returns {(PersistedState | null)} the average value since <code>timestamp</code> as {@link items.PersistedState} or <code>null</code> if no previous states could be found
    */
-  averageSince (timestamp, serviceId) {
+  averageSince (timestamp, riemannType, serviceId) {
     return _persistedStateOrNull(PersistenceExtensions.averageSince(this.rawItem, ...arguments));
   }
 
@@ -605,10 +629,13 @@ class ItemPersistence {
    * Gets the average value of the state of a given Item until a certain point in time.
    *
    * @param {(time.ZonedDateTime | Date)} timestamp the point in time to which to search for the average value
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
    * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
    * @returns {(PersistedState | null)} the average value until <code>timestamp</code> as {@link items.PersistedState} or <code>null</code> if no future states could be found
    */
-  averageUntil (timestamp, serviceId) {
+  averageUntil (timestamp, riemannType, serviceId) {
     return _persistedStateOrNull(PersistenceExtensions.averageUntil(this.rawItem, ...arguments));
   }
 
@@ -617,13 +644,64 @@ class ItemPersistence {
    *
    * @param {(time.ZonedDateTime | Date)} begin the point in time from which to start the average
    * @param {(time.ZonedDateTime | Date)} end the point in time to which to start the average
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
    * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
    * @returns {(PersistedState | null)} the average value between <code>begin</code> and <code>end</code> as {@link items.PersistedState} or <code>null</code> if no states could be found
    */
-  averageBetween (begin, end, serviceId) {
+  averageBetween (begin, end, riemannType, serviceId) {
     return _persistedStateOrNull(PersistenceExtensions.averageBetween(this.rawItem, ...arguments));
   }
 
+  /**
+   * Gets the Riemann sum of the states of a given Item since a certain point in time, time is calculated in seconds.
+   *
+   * @example
+   * var yesterday = time.toZDT().minusDays(1);
+   * var item = items.getItem('SolarPower');
+   * console.log('Solar energy production since yesterday', item.persistence.riemannSumSince(yesterday));
+   *
+   * @param {(time.ZonedDateTime | Date)} timestamp the point in time from which to search for the Riemann sum
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
+   * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
+   * @returns {(PersistedState | null)} the Riemann sum since <code>timestamp</code> as {@link items.PersistedState} or <code>null</code> if no previous states could be found, time is calculated in seconds
+   */
+  riemannSumSince (timestamp, riemannType, serviceId) {
+    return _persistedStateOrNull(PersistenceExtensions.riemannSumSince(this.rawItem, ...arguments));
+  }
+
+  /**
+  * Gets the Riemann sum of the states of a given Item until a certain point in time, time is calculated in seconds.
+  *
+  * @param {(time.ZonedDateTime | Date)} timestamp the point in time to which to search for the Riemann sum
+  * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+  *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+  *                                    default <code>LEFT</code>
+  * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
+  * @returns {(PersistedState | null)} the Riemann sum until <code>timestamp</code> as {@link items.PersistedState} or <code>null</code> if no future states could be found, time is calculated in seconds
+  */
+  riemannSumUntil (timestamp, riemannType, serviceId) {
+    return _persistedStateOrNull(PersistenceExtensions.riemannSumUntil(this.rawItem, ...arguments));
+  }
+
+  /**
+  * Gets the Riemann sum of the states of a given Item between two certain points in time, time is calculated in seconds.
+  *
+  * @param {(time.ZonedDateTime | Date)} begin the point in time from which to start the Riemann sum
+  * @param {(time.ZonedDateTime | Date)} end the point in time to which to start the Riemann sum
+  * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+  *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+  *                                    default <code>LEFT</code>
+  * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
+  * @returns {(PersistedState | null)} the Riemann sum between <code>begin</code> and <code>end</code> as {@link items.PersistedState} or <code>null</code> if no states could be found, time is calculated in seconds
+  */
+  riemannSumBetween (begin, end, riemannType, serviceId) {
+    return _persistedStateOrNull(PersistenceExtensions.riemannSumBetween(this.rawItem, ...arguments));
+  }
+
   /**
    * Gets the median value of the state of a given Item since a certain point in time.
    *
diff --git a/types/items/item-persistence.d.ts b/types/items/item-persistence.d.ts
index 2d01e372..2acf5b4f 100644
--- a/types/items/item-persistence.d.ts
+++ b/types/items/item-persistence.d.ts
@@ -12,6 +12,7 @@ export = ItemPersistence;
  * @hideconstructor
  */
 declare class ItemPersistence {
+    static RiemannType: any;
     constructor(rawItem: any);
     rawItem: any;
     /**
@@ -217,64 +218,82 @@ declare class ItemPersistence {
      * Gets the variance of the state of the given Item since a certain point in time.
      *
      * @param {(time.ZonedDateTime | Date)} timestamp the point in time from which to compute the variance
+     * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+     *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+     *                                    default <code>LEFT</code>
      * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
      * @returns {(PersistedState | null)} the variance between then and now as {@link items.PersistedState}, or <code>null</code> if
      *                            <code>timestamp</code> is in the future, or if there is no persisted state for the given
      *                            Item at the given <code>timestamp</code>
      */
-    varianceSince(timestamp: (time.ZonedDateTime | Date), serviceId?: string, ...args: any[]): (PersistedState | null);
+    varianceSince(timestamp: (time.ZonedDateTime | Date), riemannType?: any, serviceId?: string, ...args: any[]): (PersistedState | null);
     /**
      * Gets the variance of the state of the given Item until a certain point in time.
      *
      * @param {(time.ZonedDateTime | Date)} timestamp the point in time to which to compute the variance
+     * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+     *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+     *                                    default <code>LEFT</code>
      * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
      * @returns {(PersistedState | null)} the variance between now and then as {@link items.PersistedState}, or <code>null</code> if
      *                            <code>timestamp</code> is in the past, or if there is no persisted state for the given
      *                            Item at the given <code>timestamp</code>
      */
-    varianceUntil(timestamp: (time.ZonedDateTime | Date), serviceId?: string, ...args: any[]): (PersistedState | null);
+    varianceUntil(timestamp: (time.ZonedDateTime | Date), riemannType?: any, serviceId?: string, ...args: any[]): (PersistedState | null);
     /**
      * Gets the variance of the state of the given Item between two certain points in time.
      *
      * @param {(time.ZonedDateTime | Date)} begin the point in time from which to compute the variance
      * @param {(time.ZonedDateTime | Date)} end the end time for the computation
+     * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+     *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+     *                                    default <code>LEFT</code>
      * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
      * @returns {(PersistedState | null)} the variance between both points of time as {@link items.PersistedState}, or <code>null</code> if
      *                            <code>begin</code> is after <code>end</code>, or if there is no persisted state for the given
      *                            Item between <code>begin</code> and <code>end</code>
      */
-    varianceBetween(begin: (time.ZonedDateTime | Date), end: (time.ZonedDateTime | Date), serviceId?: string, ...args: any[]): (PersistedState | null);
+    varianceBetween(begin: (time.ZonedDateTime | Date), end: (time.ZonedDateTime | Date), riemannType?: any, serviceId?: string, ...args: any[]): (PersistedState | null);
     /**
      * Gets the standard deviation of the state of the given Item since a certain point in time.
      *
      * @param {(time.ZonedDateTime | Date)} timestamp the point in time from which to compute the standard deviation
+     * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+     *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+     *                                    default <code>LEFT</code>
      * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
      * @returns {(PersistedState | null)} the standard deviation between then and now as {@link items.PersistedState}, or <code>null</code>
      *                            if <code>timestamp</code> is in the future, or if there is no persisted state for the given Item
      *                            at the given <code>timestamp</code>
      */
-    deviationSince(timestamp: (time.ZonedDateTime | Date), serviceId?: string, ...args: any[]): (PersistedState | null);
+    deviationSince(timestamp: (time.ZonedDateTime | Date), riemannType?: any, serviceId?: string, ...args: any[]): (PersistedState | null);
     /**
      * Gets the standard deviation of the state of the given Item until a certain point in time.
      *
      * @param {(time.ZonedDateTime | Date)} timestamp the point in time to which to compute the standard deviation
+     * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+     *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+     *                                    default <code>LEFT</code>
      * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
      * @returns {(PersistedState | null)} the standard deviation between now and then as {@link items.PersistedState}, or <code>null</code>
      *                            if <code>timestamp</code> is in the past, or if there is no persisted state for the given Item
      *                            at the given <code>timestamp</code>
      */
-    deviationUntil(timestamp: (time.ZonedDateTime | Date), serviceId?: string, ...args: any[]): (PersistedState | null);
+    deviationUntil(timestamp: (time.ZonedDateTime | Date), riemannType?: any, serviceId?: string, ...args: any[]): (PersistedState | null);
     /**
      * Gets the standard deviation of the state of the given Item between two certain points in time.
      *
      * @param {(time.ZonedDateTime | Date)} begin the point in time from which to compute
      * @param {(time.ZonedDateTime | Date)} end the end time for the computation
+     * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+     *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+     *                                    default <code>LEFT</code>
      * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
      * @returns {(PersistedState | null)} the standard deviation between both points of time as {@link items.PersistedState}, or <code>null</code>
      *                            if <code>begin</code> is after <code>end</code>, or if there is no persisted state for the given Item
      *                            between <code>begin</code> and <code>end</code>
      */
-    deviationBetween(begin: (time.ZonedDateTime | Date), end: (time.ZonedDateTime | Date), serviceId?: string, ...args: any[]): (PersistedState | null);
+    deviationBetween(begin: (time.ZonedDateTime | Date), end: (time.ZonedDateTime | Date), riemannType?: any, serviceId?: string, ...args: any[]): (PersistedState | null);
     /**
      * Gets the average value of the state of a given Item since a certain point in time.
      *
@@ -284,27 +303,75 @@ declare class ItemPersistence {
      * console.log('KitchenDimmer average since yesterday', item.persistence.averageSince(yesterday));
      *
      * @param {(time.ZonedDateTime | Date)} timestamp the point in time from which to search for the average value
+     * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+     *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+     *                                    default <code>LEFT</code>
      * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
      * @returns {(PersistedState | null)} the average value since <code>timestamp</code> as {@link items.PersistedState} or <code>null</code> if no previous states could be found
      */
-    averageSince(timestamp: (time.ZonedDateTime | Date), serviceId?: string, ...args: any[]): (PersistedState | null);
+    averageSince(timestamp: (time.ZonedDateTime | Date), riemannType?: any, serviceId?: string, ...args: any[]): (PersistedState | null);
     /**
      * Gets the average value of the state of a given Item until a certain point in time.
      *
      * @param {(time.ZonedDateTime | Date)} timestamp the point in time to which to search for the average value
+     * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+     *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+     *                                    default <code>LEFT</code>
      * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
      * @returns {(PersistedState | null)} the average value until <code>timestamp</code> as {@link items.PersistedState} or <code>null</code> if no future states could be found
      */
-    averageUntil(timestamp: (time.ZonedDateTime | Date), serviceId?: string, ...args: any[]): (PersistedState | null);
+    averageUntil(timestamp: (time.ZonedDateTime | Date), riemannType?: any, serviceId?: string, ...args: any[]): (PersistedState | null);
     /**
      * Gets the average value of the state of a given Item between two certain points in time.
      *
      * @param {(time.ZonedDateTime | Date)} begin the point in time from which to start the average
      * @param {(time.ZonedDateTime | Date)} end the point in time to which to start the average
+     * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+     *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+     *                                    default <code>LEFT</code>
      * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
      * @returns {(PersistedState | null)} the average value between <code>begin</code> and <code>end</code> as {@link items.PersistedState} or <code>null</code> if no states could be found
      */
-    averageBetween(begin: (time.ZonedDateTime | Date), end: (time.ZonedDateTime | Date), serviceId?: string, ...args: any[]): (PersistedState | null);
+    averageBetween(begin: (time.ZonedDateTime | Date), end: (time.ZonedDateTime | Date), riemannType?: any, serviceId?: string, ...args: any[]): (PersistedState | null);
+    /**
+     * Gets the Riemann sum of the states of a given Item since a certain point in time, time is calculated in seconds.
+     *
+     * @example
+     * var yesterday = time.toZDT().minusDays(1);
+     * var item = items.getItem('SolarPower');
+     * console.log('Solar energy production since yesterday', item.persistence.riemannSumSince(yesterday));
+     *
+     * @param {(time.ZonedDateTime | Date)} timestamp the point in time from which to search for the Riemann sum
+     * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+     *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+     *                                    default <code>LEFT</code>
+     * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
+     * @returns {(PersistedState | null)} the Riemann sum since <code>timestamp</code> as {@link items.PersistedState} or <code>null</code> if no previous states could be found, time is calculated in seconds
+     */
+    riemannSumSince(timestamp: (time.ZonedDateTime | Date), riemannType?: any, serviceId?: string, ...args: any[]): (PersistedState | null);
+    /**
+    * Gets the Riemann sum of the states of a given Item until a certain point in time, time is calculated in seconds.
+    *
+    * @param {(time.ZonedDateTime | Date)} timestamp the point in time to which to search for the Riemann sum
+    * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+    *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+    *                                    default <code>LEFT</code>
+    * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
+    * @returns {(PersistedState | null)} the Riemann sum until <code>timestamp</code> as {@link items.PersistedState} or <code>null</code> if no future states could be found, time is calculated in seconds
+    */
+    riemannSumUntil(timestamp: (time.ZonedDateTime | Date), riemannType?: any, serviceId?: string, ...args: any[]): (PersistedState | null);
+    /**
+    * Gets the Riemann sum of the states of a given Item between two certain points in time, time is calculated in seconds.
+    *
+    * @param {(time.ZonedDateTime | Date)} begin the point in time from which to start the Riemann sum
+    * @param {(time.ZonedDateTime | Date)} end the point in time to which to start the Riemann sum
+    * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+    *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+    *                                    default <code>LEFT</code>
+    * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
+    * @returns {(PersistedState | null)} the Riemann sum between <code>begin</code> and <code>end</code> as {@link items.PersistedState} or <code>null</code> if no states could be found, time is calculated in seconds
+    */
+    riemannSumBetween(begin: (time.ZonedDateTime | Date), end: (time.ZonedDateTime | Date), riemannType?: any, serviceId?: string, ...args: any[]): (PersistedState | null);
     /**
      * Gets the median value of the state of a given Item since a certain point in time.
      *
diff --git a/types/items/item-persistence.d.ts.map b/types/items/item-persistence.d.ts.map
index f8b37633..e611b1d4 100644
--- a/types/items/item-persistence.d.ts.map
+++ b/types/items/item-persistence.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"item-persistence.d.ts","sourceRoot":"","sources":["../../src/items/item-persistence.js"],"names":[],"mappings":";AAuJA;;;;;;;;;;;GAWG;AACH;IACE,0BAEC;IADC,aAAsB;IAGxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,oBALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,UAC3B,MAAM,GAAC,MAAM,GAAC,KAAK,aAAa,GAAC,QAAQ,YAAU,eACnD,gBAAgB,cAChB,MAAM,wBAiChB;IAqDD;;;;;;OAMG;IACH,0BAJW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,aAAa,GAAG,IAAI,CAAC,CAIlC;IAED;;;;;;MAME;IACF,uBAJW,MAAM,mBACJ,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,CAKvC;IAED;;;;;OAKG;IACH,uBAHW,MAAM,mBACJ,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,CAIvC;IAED;;;;;;OAMG;IACH,uBAJW,MAAM,mBACJ,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,CAKvC;IAED;;;;;OAKG;IACH,uBAHW,MAAM,mBACJ,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,CAIvC;IAED;;;;;;OAMG;IACH,0BAJW,OAAO,cACP,MAAM,mBACJ,CAAC,aAAa,GAAG,IAAI,CAAC,CAIlC;IAED;;;;;;OAMG;IACH,sBAJW,OAAO,cACP,MAAM,mBACJ,CAAC,aAAa,GAAG,IAAI,CAAC,CAIlC;IAED;;;;;;;OAOG;IACH,wBALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,OAAO,CAKnB;IAED;;;;;;;OAOG;IACH,wBALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,OAAO,CAKnB;IAED;;;;;;;;OAQG;IACH,sBANW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,OAC3B,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,OAAO,CAKnB;IAED;;;;;;;OAOG;IACH,wBALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,OAAO,CAKnB;IAED;;;;;;;OAOG;IACH,wBALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,OAAO,CAKnB;IAED;;;;;;;;OAQG;IACH,sBANW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,OAC3B,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,OAAO,CAKnB;IAED;;;;;;;OAOG;IACH,wBALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,aAAa,GAAG,IAAI,CAAC,CAKlC;IAED;;;;;;;OAOG;IACH,wBALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,aAAa,GAAG,IAAI,CAAC,CAKlC;IAED;;;;;;;;OAQG;IACH,sBANW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,OAC3B,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,aAAa,GAAG,IAAI,CAAC,CAKlC;IAED;;;;;;;OAOG;IACH,wBALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,aAAa,GAAG,IAAI,CAAC,CAKlC;IAED;;;;;;;OAOG;IACH,wBALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,aAAa,GAAG,IAAI,CAAC,CAKlC;IAED;;;;;;;;OAQG;IACH,sBANW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,OAC3B,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,aAAa,GAAG,IAAI,CAAC,CAKlC;IAED;;;;;;;;OAQG;IACH,yBANW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAMnC;IAED;;;;;;;;OAQG;IACH,yBANW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAMnC;IAED;;;;;;;;;OASG;IACH,uBAPW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,OAC3B,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAMnC;IAED;;;;;;;;OAQG;IACH,0BANW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAMnC;IAED;;;;;;;;OAQG;IACH,0BANW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAMnC;IAED;;;;;;;;;OASG;IACH,wBAPW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,OAC3B,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAMnC;IAED;;;;;;;;;;;OAWG;IACH,wBAJW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAInC;IAED;;;;;;OAMG;IACH,wBAJW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAInC;IAED;;;;;;;OAOG;IACH,sBALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,OAC3B,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAInC;IAED;;;;;;;;;;;OAWG;IACH,uBAJW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAInC;IAED;;;;;;OAMG;IACH,uBAJW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAInC;IAED;;;;;;;OAOG;IACH,qBALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,OAC3B,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAInC;IAED;;;;;;OAMG;IACH,oBAJW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAInC;IAED;;;;;;OAMG;IACH,oBAJW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAInC;IAED;;;;;;;;OAQG;IACH,kBANW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,OAC3B,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAKnC;IAED;;;;;;;OAOG;IACH,sBALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAKnC;IAED;;;;;;;OAOG;IACH,sBALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAKnC;IAED;;;;;;;;OAQG;IACH,oBANW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,OAC3B,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,cAAc,GAAG,IAAI,CAAC,CAKnC;IAED;;;;;;;;OAQG;IACH,8BANW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,MAAM,GAAG,IAAI,CAAC,CAM3B;IAED;;;;;;;;OAQG;IACH,8BANW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,MAAM,GAAG,IAAI,CAAC,CAM3B;IAED;;;;;;;;;OASG;IACH,4BAPW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,OAC3B,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,CAAC,MAAM,GAAG,IAAI,CAAC,CAM3B;IAED;;;;;;OAMG;IACH,sBAJW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,MAAM,CAIlB;IAED;;;;;;OAMG;IACH,sBAJW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,MAAM,CAIlB;IAED;;;;;;;OAOG;IACH,oBALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,OAC3B,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,MAAM,CAIlB;IAED;;;;;;OAMG;IACH,kCAJW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,MAAM,CAIlB;IAED;;;;;;OAMG;IACH,kCAJW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,MAAM,CAIlB;IAED;;;;;;;OAOG;IACH,gCALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,OAC3B,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,MAAM,CAIlB;IAED;;;;;;OAMG;IACH,6BAJW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,aAAa,EAAE,CAI3B;IAED;;;;;;OAMG;IACH,6BAJW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,aAAa,EAAE,CAI3B;IAED;;;;;;;OAOG;IACH,2BALW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,OAC3B,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,mBACJ,aAAa,EAAE,CAI3B;IAED;;;;;;OAMG;IACH,gCAHW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,uBAIhB;IAED;;;;;;OAMG;IACH,gCAHW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,uBAIhB;IAED;;;;;;;OAOG;IACH,8BAJW,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,OAC3B,CAAC,KAAK,aAAa,GAAG,IAAI,CAAC,cAC3B,MAAM,uBAIhB;;CACF;;;;;yBAt4BY,OAAO,eAAe,EAAE,aAAa;mBAIrC,OAAO,eAAe,EAAE,OAAO;;;gBAI/B,OAAO,aAAa,EAAE,QAAQ;;;;AAZ3C,8BAAkE;AA2ElE;;;;;;;GAOG;AACH;IAQI,qBAAsC;IAGxC;;;;;OAKG;IACH,sCAEC;IAED;;;OAGG;IACH,8BAEC;CAKF;AAhHD;;;GAGG;AACH;;;GAGG;AACH;;;GAGG;AACH;;;GAGG;AAEH;;;;;GAKG;AACH;IACE;;;;OAIG;IACH,mCAEC;IADC,cAAgC;IAGlC;;;OAGG;IACH,oBAEC;IAED;;;OAGG;IACH,2BAGC;IAED;;;OAGG;IACH,oDAWC;IAED,mBAEC;CACF"}
\ No newline at end of file
+{"version":3,"file":"item-persistence.d.ts","sourceRoot":"","sources":["../../src/items/item-persistence.js"],"names":[],"mappings":"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"}
\ No newline at end of file


Reviews:
user: login: florian-h05
body: Overall LGTM, please have a look at my comments.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T19:56:12Z
user: login: mherwege
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T08:03:53Z
user: login: florian-h05
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T13:14:07Z
user: login: mherwege
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T13:27:26Z
user: login: florian-h05
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T13:31:22Z
user: login: mherwege
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T13:51:02Z
user: login: florian-h05
body: LGTM, thanks!
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T17:02:46Z

Review comments:
diff_hunk: @@ -540,6 +540,9 @@ Calling `Item.persistence` returns an `ItemPersistence` object with the followin
   - .persistedState(timestamp, serviceId) ⇒ `PersistedItem | null`
   - .previousState(skipEqual, serviceId) ⇒ `PersistedItem | null`
   - .nextState(skipEqual, serviceId) ⇒ `PersistedItem | null`
+  - .riemannSumSince(timestamp, riemannType, serviceId)  ⇒ `PersistedState | null`: Time is considered in seconds.
path: README.md
user: login: florian-h05
body: What is meant by this "Time is considered in seconds."?
created_at: 2025-03-25T19:50:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -550,6 +553,8 @@ Calling `Item.persistence` returns an `ItemPersistence` object with the followin
   - .varianceUntil(timestamp, serviceId) ⇒ `PersistedState | null`
   - .varianceBetween(begin, end, serviceId) ⇒ `PersistedState | null`
 
+`riemannType` is an optional argument for methods that require calculating an approximation of the integral value. The approximation is calculated using a Riemann sum, with left, right, trapezoidal or midpoint value approximations. The argument is a Java RiemannType enum with possible values: `RiemannType.LEFT`, `RiemannType.RIGHT`, `RiemannType.TRAPEZOIDAL` or `RiemannType.MIDPOINT`. If ommitted, `RiemannType.LEFT` is used.
path: README.md
user: login: florian-h05
body: Please use newlines for each sentence:

```suggestion
`riemannType` is an optional argument for methods that require calculating an approximation of the integral value.
The approximation is calculated using a Riemann sum, with left, right, trapezoidal or midpoint value approximations.
The argument is a Java `RiemannType` enum with possible values: `RiemannType.LEFT`, `RiemannType.RIGHT`, `RiemannType.TRAPEZOIDAL` or `RiemannType.MIDPOINT`. If ommitted, `RiemannType.LEFT` is used.
```
created_at: 2025-03-25T19:51:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6,6 +6,7 @@ const { _toOpenhabPrimitiveType, _isTimeSeries } = require('../helpers');
 const PersistenceExtensions = Java.type('org.openhab.core.persistence.extensions.PersistenceExtensions');
 const TimeSeries = Java.type('org.openhab.core.types.TimeSeries');
 const TypeParser = Java.type('org.openhab.core.types.TypeParser');
+const RiemannType = Java.type('org.openhab..core.persistence.extensions.PersistenceExtensions.RiemannType');
path: src/items/item-persistence.js
user: login: florian-h05
body: Typo:

```suggestion
const RiemannType = Java.type('org.openhab.core.persistence.extensions.PersistenceExtensions.RiemannType');
```
created_at: 2025-03-25T19:52:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -617,13 +644,64 @@ class ItemPersistence {
    *
    * @param {(time.ZonedDateTime | Date)} begin the point in time from which to start the average
    * @param {(time.ZonedDateTime | Date)} end the point in time to which to start the average
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
    * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
    * @returns {(PersistedState | null)} the average value between <code>begin</code> and <code>end</code> as {@link items.PersistedState} or <code>null</code> if no states could be found
    */
-  averageBetween (begin, end, serviceId) {
+  averageBetween (begin, end, riemannType, serviceId) {
     return _persistedStateOrNull(PersistenceExtensions.averageBetween(this.rawItem, ...arguments));
   }
 
+  /**
+   * Gets the RiemannSum of the states of a given Item since a certain point in time, time is calculated in seconds.
path: src/items/item-persistence.js
user: login: florian-h05
body: ```suggestion
   * Gets the Riemann sum of the states of a given Item since a certain point in time, time is calculated in seconds.
```
created_at: 2025-03-25T19:53:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -617,13 +644,64 @@ class ItemPersistence {
    *
    * @param {(time.ZonedDateTime | Date)} begin the point in time from which to start the average
    * @param {(time.ZonedDateTime | Date)} end the point in time to which to start the average
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
    * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
    * @returns {(PersistedState | null)} the average value between <code>begin</code> and <code>end</code> as {@link items.PersistedState} or <code>null</code> if no states could be found
    */
-  averageBetween (begin, end, serviceId) {
+  averageBetween (begin, end, riemannType, serviceId) {
     return _persistedStateOrNull(PersistenceExtensions.averageBetween(this.rawItem, ...arguments));
   }
 
+  /**
+   * Gets the RiemannSum of the states of a given Item since a certain point in time, time is calculated in seconds.
+   *
+   * @example
path: src/items/item-persistence.js
user: login: florian-h05
body: I would rather have an example with power measurement and energy consumption calculation, 
this example IMO is not really "meaningful".
created_at: 2025-03-25T19:55:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -617,13 +644,64 @@ class ItemPersistence {
    *
    * @param {(time.ZonedDateTime | Date)} begin the point in time from which to start the average
    * @param {(time.ZonedDateTime | Date)} end the point in time to which to start the average
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
    * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
    * @returns {(PersistedState | null)} the average value between <code>begin</code> and <code>end</code> as {@link items.PersistedState} or <code>null</code> if no states could be found
    */
-  averageBetween (begin, end, serviceId) {
+  averageBetween (begin, end, riemannType, serviceId) {
     return _persistedStateOrNull(PersistenceExtensions.averageBetween(this.rawItem, ...arguments));
   }
 
+  /**
+   * Gets the RiemannSum of the states of a given Item since a certain point in time, time is calculated in seconds.
+   *
+   * @example
+   * var yesterday = time.toZDT().minusDays(1);
+   * var item = items.getItem('KitchenDimmer');
+   * console.log('KitchenDimmer Riemann sum since yesterday', item.persistence.riemannSumSince(yesterday));
+   *
+   * @param {(time.ZonedDateTime | Date)} timestamp the point in time from which to search for the Riemann sum
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
+   * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
+   * @returns {(PersistedState | null)} the Riemann sum since <code>timestamp</code> as {@link items.PersistedState} or <code>null</code> if no previous states could be found, time is calculated in seconds
+   */
+  riemannSumSince (timestamp, riemannType, serviceId) {
+    return _persistedStateOrNull(PersistenceExtensions.riemannSumSince(this.rawItem, ...arguments));
+  }
+
+  /**
+  * Gets the RiemannSum of the states of a given Item until a certain point in time, time is calculated in seconds.
path: src/items/item-persistence.js
user: login: florian-h05
body: ```suggestion
  * Gets the Riemann sum of the states of a given Item until a certain point in time, time is calculated in seconds.
```
created_at: 2025-03-25T19:55:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -617,13 +644,64 @@ class ItemPersistence {
    *
    * @param {(time.ZonedDateTime | Date)} begin the point in time from which to start the average
    * @param {(time.ZonedDateTime | Date)} end the point in time to which to start the average
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
    * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
    * @returns {(PersistedState | null)} the average value between <code>begin</code> and <code>end</code> as {@link items.PersistedState} or <code>null</code> if no states could be found
    */
-  averageBetween (begin, end, serviceId) {
+  averageBetween (begin, end, riemannType, serviceId) {
     return _persistedStateOrNull(PersistenceExtensions.averageBetween(this.rawItem, ...arguments));
   }
 
+  /**
+   * Gets the RiemannSum of the states of a given Item since a certain point in time, time is calculated in seconds.
+   *
+   * @example
+   * var yesterday = time.toZDT().minusDays(1);
+   * var item = items.getItem('KitchenDimmer');
+   * console.log('KitchenDimmer Riemann sum since yesterday', item.persistence.riemannSumSince(yesterday));
+   *
+   * @param {(time.ZonedDateTime | Date)} timestamp the point in time from which to search for the Riemann sum
+   * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+   *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+   *                                    default <code>LEFT</code>
+   * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
+   * @returns {(PersistedState | null)} the Riemann sum since <code>timestamp</code> as {@link items.PersistedState} or <code>null</code> if no previous states could be found, time is calculated in seconds
+   */
+  riemannSumSince (timestamp, riemannType, serviceId) {
+    return _persistedStateOrNull(PersistenceExtensions.riemannSumSince(this.rawItem, ...arguments));
+  }
+
+  /**
+  * Gets the RiemannSum of the states of a given Item until a certain point in time, time is calculated in seconds.
+  *
+  * @param {(time.ZonedDateTime | Date)} timestamp the point in time to which to search for the Riemann sum
+  * @param {RiemannType} [riemannType] optional Riemann approximation type to calculate the integral approximation
+  *                                    (<code>LEFT</code>, <code>RIGHT</code>, <code>TRAPEZOIDAL</code>, <code>MIDPOINT</code>),
+  *                                    default <code>LEFT</code>
+  * @param {string} [serviceId] optional persistence service ID, if omitted, the default persistence service will be used
+  * @returns {(PersistedState | null)} the Riemann sum until <code>timestamp</code> as {@link items.PersistedState} or <code>null</code> if no future states could be found, time is calculated in seconds
+  */
+  riemannSumUntil (timestamp, riemannType, serviceId) {
+    return _persistedStateOrNull(PersistenceExtensions.riemannSumUntil(this.rawItem, ...arguments));
+  }
+
+  /**
+  * Gets the RiemannSum of the states of a given Item between two certain points in time, time is calculated in seconds.
path: src/items/item-persistence.js
user: login: florian-h05
body: ```suggestion
  * Gets the Riemann sum of the states of a given Item between two certain points in time, time is calculated in seconds.
```
created_at: 2025-03-25T19:55:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -540,6 +540,9 @@ Calling `Item.persistence` returns an `ItemPersistence` object with the followin
   - .persistedState(timestamp, serviceId) ⇒ `PersistedItem | null`
   - .previousState(skipEqual, serviceId) ⇒ `PersistedItem | null`
   - .nextState(skipEqual, serviceId) ⇒ `PersistedItem | null`
+  - .riemannSumSince(timestamp, riemannType, serviceId)  ⇒ `PersistedState | null`: Time is considered in seconds.
path: README.md
user: login: mherwege
body: A Riemann sum will sum value * time by bucket. If the item type is a straight Number (no dimension, no unit), it is important to know the unit of the time dimension as the result will also be a straight Number. Calculation is always done in seconds for time.
created_at: 2025-03-26T08:03:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -540,6 +540,9 @@ Calling `Item.persistence` returns an `ItemPersistence` object with the followin
   - .persistedState(timestamp, serviceId) ⇒ `PersistedItem | null`
   - .previousState(skipEqual, serviceId) ⇒ `PersistedItem | null`
   - .nextState(skipEqual, serviceId) ⇒ `PersistedItem | null`
+  - .riemannSumSince(timestamp, riemannType, serviceId)  ⇒ `PersistedState | null`: Time is considered in seconds.
path: README.md
user: login: florian-h05
body: So if my Item is `Number:Power` with unit `kW` I will receive `kWs`?
created_at: 2025-03-26T13:14:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -540,6 +540,9 @@ Calling `Item.persistence` returns an `ItemPersistence` object with the followin
   - .persistedState(timestamp, serviceId) ⇒ `PersistedItem | null`
   - .previousState(skipEqual, serviceId) ⇒ `PersistedItem | null`
   - .nextState(skipEqual, serviceId) ⇒ `PersistedItem | null`
+  - .riemannSumSince(timestamp, riemannType, serviceId)  ⇒ `PersistedState | null`: Time is considered in seconds.
path: README.md
user: login: mherwege
body: Yes, it will. But that gets converted automatically to kWh depending on the unit setting of the item if you persist, or the state description anyway.
created_at: 2025-03-26T13:27:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -540,6 +540,9 @@ Calling `Item.persistence` returns an `ItemPersistence` object with the followin
   - .persistedState(timestamp, serviceId) ⇒ `PersistedItem | null`
   - .previousState(skipEqual, serviceId) ⇒ `PersistedItem | null`
   - .nextState(skipEqual, serviceId) ⇒ `PersistedItem | null`
+  - .riemannSumSince(timestamp, riemannType, serviceId)  ⇒ `PersistedState | null`: Time is considered in seconds.
path: README.md
user: login: florian-h05
body: Do you think it would make sense to somehow improve the note in the README so the questions I asked won't come up if you just read this?
created_at: 2025-03-26T13:31:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -540,6 +540,9 @@ Calling `Item.persistence` returns an `ItemPersistence` object with the followin
   - .persistedState(timestamp, serviceId) ⇒ `PersistedItem | null`
   - .previousState(skipEqual, serviceId) ⇒ `PersistedItem | null`
   - .nextState(skipEqual, serviceId) ⇒ `PersistedItem | null`
+  - .riemannSumSince(timestamp, riemannType, serviceId)  ⇒ `PersistedState | null`: Time is considered in seconds.
path: README.md
user: login: mherwege
body: Done
created_at: 2025-03-26T13:51:02Z
author_association: CONTRIBUTOR

PR comments:
user: login: holgerfriedrich
created_at: 2025-03-24T18:51:16Z
body: @florian-h05 FYI: PR in core is now merged and will be available after next core build.
author_association: MEMBER
user: login: dandjo
created_at: 2025-03-27T17:20:14Z
body: @florian-h05 just to be sure how to use this. How do we pass the Enum in scripts? Just via string or is there a Enum type for that? Can you provide an example? Is it just like follows?

```
items.getItem('my_item').persistence.averageBetween(time.toZDT('00:00'), time.toZDT(), 'TRAPEZOIDAL')
```
author_association: NONE
user: login: florian-h05
created_at: 2025-03-27T17:22:53Z
body: The enum should be available through someItem.persistence.RiemannType … maybe we should add a static export for persistence on the items namespace.
author_association: CONTRIBUTOR
user: login: dandjo
created_at: 2025-03-27T17:27:47Z
body: @florian-h05 I see, this is what confused me. Yes, would be intuitive to export it somewhere static for usage. Maybe even in global scope? Are there other enums somewhere? Something like...

```
items.getItem('my_item').persistence.averageBetween(time.toZDT('00:00'), time.toZDT(), enums.RiemannType.TRAPEZOIDAL)
```

This feels a bit clumsy...

```
items.getItem('my_item').persistence.averageBetween(time.toZDT('00:00'), time.toZDT(), items.getItem('my_item').persistence.RiemannType.TRAPEZOIDAL)
```
author_association: NONE