Convert total meter values to current consumption

Hello all,

I have been using volkszaehler.org for a while and wanted to check something more modern, with OH (v5.1) there are many new possibilities, but on the other hand topics, where I think “is that seriously so complicated”?

Specifically, I have a few meters, which I integrate via MQTT (easy so far) but which deliver only total values. For graphing I’d like to calculate a “current consumption”. There are a few topics about that, some pretty old. Example: Calculate periodic consumption of gas based on meter readings

Experimenting I came here:

  • a thing which receives the “total meter value” from MQTT
  • an item “Total value” linked to that thing (not usable for graphing as the value is continuously increasing)
  • an item “Current value” which I want to use for graphing
  • a JS rule, which fires on change of “Total value” and shall calculate delta, then update “Current value”
  • DB persistence enabled

This all makes sense and works to some extent, but … :slight_smile: with all the articles I found on the WWW, I was not able access “previous value” (and time) of “Total Value” in the JS rule (I spare you the mess of commented code snippets with everything I tried). Is there an up-to-date example anywhere or any other hints?

Important: I (believe I) was using “Total Value”.previousState but that did not change, only if “Total Value” really changed - however this results in continuously the same value, but never 0 as I’d expect. However, in the graph there must also be 0 values, otherwise there is a continuous non-zero line.

Example:

22:18:00 Total = 1111
22:18:30 Total = 1112 → Rule fires, calculates 1 → update “Current value” (OK)
22:19:00 Total = 1112 → Rule fires, calculates 1 → update “Current value” (wrong, because previousState is still 1111, which is actually not true)

Somewhere sbd wrote that previousState is wrong because it takes the value from the DB - makes sense, but then how can I get the prev state of “Total Value” in a JS rule?

Does that make sense?

BTW: I also tried as rule trigger “thing state changed” but that did not work at all - possibly that fires only, if the thing changes from “offline” to “online” or so?

Many thx!!!

Welcome to our community!
You might checkout my rule templates on the marketplace

There is another one for historical data.

1 Like

If I understand correctly, you are looking for a way to have an Item to show the delta between the previous reading and the current reading for charting.

This is your biggest problem. If the Item updates to the same state, there is no change. You need to trigger the rule using updates, not changes.

Firstly, you almost certainly do not need a rule for this. You could use a script transformation profile instead.

Next, it’s important to understand the difference between an Update and a Change in OH, as hinted above. All Changes are Updates but not all Updates are Changes. That’s why we have two events. If you want to know when the Item was “touched” even if the state didn’t change, you need to focus on the Updates.

I don’t know if MyItem.previousState is driven by Changes only or, whether it takes account of updates. I’m not in a position to test it right now. Because you only look at it in your rule when the Item changes, you are essentially skipping the rule every time there was an update to the same state, so the rule isn’t even running when you want the 0 values.

Let’s assume MyItem.previousState works correctly. Then you can rely on the previousState. In a JS script transformation that would look something like:

(function(input, itemName) {
  if(input == 'NULL' || 'UNDEF') return input;

  // if the value has units
  if (input.includes(' ')) {
    const curr = Quantity(input);
    return curr.subtract(items[itemName].previousQuantityState);
  }

  // just a plain number
  else {
    const curr = parseFloat(input);
    return curr - items[itemName].previousNumericState);
  }
})(input, itemName)

If previousState only gets updated on changes, you’ll have to keep track of the previous state yourself. But that’s not hard when using the cache.

The overall approach would be:

  1. calculate the delta using the value stored in the cache and the new value in the update
  2. record the new value
  3. return the delta

In JS the transformation would look something like this (works for both UoM updates or plain numbers):

(function(input) {
  if(input == 'NULL' || 'UNDEF') return input;

  // if the value has units
  if (input.includes(' ')) {
    const unit = input.split(' ')[1];
    const prev = cache.private.get('delta', () => Quantity('0 ' + unit)); // returns 0 if no value is in the cache
    const curr = Quantity(input);
    cache.private.put('delta', curr);
    return curr.subtract(prev);
  }
  // just a plain number
  else {
    const prev = cache.private.get('delta', () => 0); // returns 0 if no value is in the cache
    const curr = parseFloat(input);
    cache.private.put('delta', curr);
    return curr - prev;
  }
})(input)

Of course, the first time the Item is updated after OH is restarted will treat the current state as the first value which is probably not what you’d want. Therefore, you can either assume 0 for that first update or pass in the name of the Item and use it’s previousState which will be updated from persistence on startup.

(function(input) {
  if(input == 'NULL' || 'UNDEF') return input;

  // if the value has units
  if (input.includes(' ')) {
    const unit = input.split(' ')[1];
    const prev = cache.private.get('delta', () => Quantity('0 ' + unit)); // returns 0 if no value is in the cache
    const curr = Quantity(input);
    cache.private.put('delta', curr);
    return (prev.equals('0 ' + unit)) ? 0 : curr.subtract(prev);
  }
  // just a plain number
  else {
    const prev = cache.private.get('delta', () => 0); // returns 0 if no value is in the cache
    const curr = parseFloat(input);
    cache.private.put('delta', curr);
    return (prev == 0) ? 0 : curr - prev;
  }
})(input)
(function(input, itemName) {
  if(input == 'NULL' || 'UNDEF') return input;

  // if the value has units
  if (input.includes(' ')) {
    const unit = input.split(' ')[1];
    const prev = cache.private.get('delta', () => Quantity('0 ' + unit)); // returns 0 if no value is in the cache
    const curr = Quantity(input);
    cache.private.put('delta', curr);
    return (prev.equals('0 ' + unit)) ? items[itemName].previousQuantityState : curr.subtract(prev);
  }
  // just a plain number
  else {
    const prev = cache.private.get('delta', () => 0); // returns 0 if no value is in the cache
    const curr = parseFloat(input);
    cache.private.put('delta', curr);
    return (prev == 0) ? items[itemName].previousNumericState : curr - prev;
  }
})(input, itemName)

Create one of the transformations from the above. On the link between the Channel and the Item add a JS transformation and use the transformation you created. Use URL arguments to pass in the ItemName to the transformations that need it. See the JS Scripting docs for details.

Note I just typed in the above. There likely are errors.

Note 2 if you have more than one Item that needs this transformation, you’ll need to pass in a unique key to use in place of 'delta' into the transformation each place you use it. There is only one instance of the transformation so if you use it in more than one place each use will overwrite the entry in the cache for the others.

This is how I solved it for me (similar situation than Volkszähler): Use case: Convert cumulative meter reading (e.g. for heat/energy (kWh) or water (l)) into daily / hourly consumptions (W or l/h) - #13 by stonke

Hello all,

first of all many thanks for your responses!!! One apology: I tried to phrase everything as precise as possible, but failed when describing what I did: My rule is triggered by an update of the “Total” item, so @Rich - thx for explaining, but this is what I understood/guessed already. The trigger actually works as expected, the problem is rather the “prev value”.

Nonetheless I will try, what you suggested. I also saw somewhere the solution with a cache var.

@Cplant - I also found your article and admittedly, did not try it yet, because I was asking myself, whether this is still (with OH5) up to date.

Especially I was/am really surprised that this (probably) common scenario requires such a complex solution with a lot of custom scripting.

Maybe this is a enhancement for next OH versions? With volkszaehler, this scenario is extremely simple - just choose the right “channel” type (something like “Energy (total meter values)” and that’s it. There are three types of “Energy” (total, current reading and impulses) and the summing up etc happens under the hood (same for water etc).
In OH terminology, maybe the “Current” item could be then of “semantic point” not “calculation” (as I used it right now) but rather a sub-class like “calculation →total meter values” and the three types as in VZ are supported … (?)

Many thx again, I will experiment further … :slight_smile: Thomas

It’s not super common. Most of the time there’s a binding that actually talks to the device instead of going through an intermediary like MQTT. And in those cases there usually is a Channel with the instantaneous usage in addition to a cumulative total. And if there isn’t, one can file an issue on that binding to have it added.

Perhaps you could do the same with what ever is publishing the MQTT messages in the first place. Maybe it already does. :person_shrugging:

Mmmm, hard to tell … what seems to be very popular is e.g. wmbusmeters, and our water meter and heat meters all only tell the total value - so it does not matter which protocol you are using to talk to it (actually wmbusmeters is very flexible), at some point a conversion has to take place. Actually, our electricity meter - same thing.

In addition, we have some old Ferraris electricity meters and some old water meters (with the half-mirrored disk) and gas meters, which all yield impulses using some little adapter ( Stromzähler - German only :frowning: ) which btw works fine, because the number of impulses represents a quantity of water/electricity/gas, so it can be graphed right away.
If somebody cares: I have configured a vzlogger to listen at a few GPIO ports for those impulses (one for each such adapter/meter) on an old RPi, sum the up over e.g. 1min and then publish the results via MQTT again.

But anyway, back to the actual challenge … :slight_smile: I did not have the time to try anything out yet, but will do. Still I’d ask “OH designers” (if any are here) whether that concept of a “built-in” conversion might be a useful enhancement …

Many thx again!!!

I still do not really understand what you are trying to achieve and therefore do not see what openHAB should convert.

My Heimann water meter and Pipersbeg gas meter are read by ESP32 readers with camera using „AI-On-The-Edge“ projekt, pushing the total meter values via MQTT to openHAB.
My two rules (I already posted the link to the templates) then calculate todays (actual)/yesterdays/this week/last week and so on values.

From what I remember I did not change the script since I first wrote it.

Exactly.

@hmerk, I believe the thought (which I can understand is that OH does the conversion out of the box. Though with the new blockly blocks I‘m sure there’s an easier way to do what I did via my script.

There is no conversion, it is a calculation :wink:
Anyway, my rule templates are using Blockly….
What new blocks are you referring to ?