S0 counter from power meter - how to get kwh?

I have same strange things now - but only when the heatinpump is running…

The power from the compressor of my heatingpump ist about 1,1 kW (electrical). The rule shows 1,1 - then it counts in short intervals to 2,2 and falls down to 1,1 … and so on.

I think, i get the counter value 1 minute before, then this is the given value to calculate the watt. The real time counter gets higher - but the counter 1 minute ago is still the same in the rule…

So short time before the next minute beginns, i get the watt calculated from nearly 2 minutes shown in my sitemap.

I hope you can follow my explanations…

Persistence service is rrd4j with strategy every change and every minute. So i think, rrd4j stores a new value every 1-2 second, when heatingpump is running. But the rule only uses the values from every minute…

If heatingpump is in standby (only 30 watt) all is shown correctly, but in this case i only get a impulse from the s0 counter every 1-2 minutes - so there can´t be a big error.

I had sort of the same problem with the rule depending on previous values - granularity. 5 Ticks from my counter mean 300W up or down in a minute for my calculation, so i decided to go another way (as outlined above): Measuring time between 5 ticks coming in and evaluating power from there:

import org.joda.time.DateTime

var lastUpdate = null
var lastCount = 0
var ticksBetween = 5

var smoothingSamples = 5
var total = 0.0d
var average = 0.0d
val samples = newLinkedList()
rule "Stromzaehler_Gesamt_Berechnung"
when
  Item Stromzaehler_Gesamt received command
then
  /*
   * Take 2: React on every input, get the time inbetween and calculate power based
   * on time passed.
   * Very granular, calculation takes about 20ms on Raspi3B
   */
  var newCommand = (receivedCommand as DecimalType).intValue 
  var tickDiff = newCommand - lastCount
  if (lastUpdate != null && lastCount > 0) {
  	if (tickDiff == ticksBetween) {
	  	var startMillis = now().millis
	  	var nowMillis = now().millis
	  	var lastUpdateMillis = (lastUpdate as DateTime).millis
	  	var diff = nowMillis - lastUpdateMillis
	  	var watt = ((3600.0 / diff) * 1000.0 * ticksBetween) as Double

	  	// Calculate moving average
	  	if (samples.size == smoothingSamples) {
	  		total -= (samples.first as Double).doubleValue
	  		samples.removeFirst
	  	}
	  	total += watt
	  	samples.addLast(watt)
	  	average = total / samples.size
	  	
	  	var endMillis = now().millis
		logInfo("Stromzaehler_Gesamt_Berechnung", "Timediff since last update: " + diff.toString() + " ms, posting average: " + average.toString() + " W, calculated "+ watt.toString() + " W")
		logInfo("Stromzaehler_Gesamt_Berechnung", "Calculation took " + (endMillis - startMillis).toString() + " ms")
		Stromzaehler_Gesamt_Watt.postUpdate(average)
	} else {
		logInfo("Stromzaehler_Gesamt_Berechnung", "Tick difference not what we expected: " + tickDiff)
	}
  }
  
  lastUpdate = now()
  lastCount = newCommand
  
  /*
   * Take 1:
   * 
   * Get last historicState from the counter from DB and compare to current Value
   * Yields correct values, but granularity is quite coarse (300W for 5 ticks)
   * 
   */
  //var cur = Stromzaehler_Gesamt.state as DecimalType
  //var prev = Stromzaehler_Gesamt.historicState(now()).state as DecimalType
  //var diff = cur - prev
  //logInfo("Stromzaehler_Gesamt_Berechnung", "Current state: " + cur + ", Previous State: " + prev + ", Difference: " + diff)
  //logInfo("Stromzaehler_Gesamt_Berechnung", "Posting Update to Stromzaehler_Gesamt_Watt: " + (diff * 60).toString()) 
  //Stromzaehler_Gesamt_Watt.postUpdate(diff*60)
end

Code’s a bit of a mess, but i get constant (and very precise) readings from it. You only have to consider that your counter sends 2000 ticks per kWh - adjust my 3600 to your 1800 and you should be ok.

Best regards,
Alex

Super! Thanks a lot. It is working good.

A few questions to your rule:

var ticksBetween = 5

var smoothingSamples = 5

If i want to have a higher resolution with less average values, i have to change this two things to maybe “2” ? Then i measure the time between 2 impulses only and i get the real power of the last time without any average values?

var total = 0.0d
var average = 0.0d

What is this “d” ? Is this 0.0d only 1 decimal behind the point?

Can i calculate the power with this rule with only 1 decimal (= x.x kW --> 100 Watt)?

Can i calculate the power with 3 decimals also? (= x.xxx kW --> 1 Watt)?

ticksBetween is set according to the setting on my binary actuator, which posts the current counter value to be bus every 5 ticks.

smothingSamples is purely for smoothing the value in this rule, you can set it to anything you like - and since it’s a linked list which is not iterated, it should work out in O(1) and only consumes a little bit more memory for each smoothing value.

0.0d tells openhab, that this is to be taken as a double value, so i can neglect casting and/or autoboxing.

The result of this calculation will always be a double, you can set the shown decimal digits in your UI afterwards, somethings like this (that’s my item definition for the power value):

Number  Stromzaehler_Gesamt_Watt   "Stromzähler Gesamt Leistung [%.0f W]"   (gTest,gStromzaehler)

Actually setting smothingSamples to 1 will average over just the current sample, so there will be no averaging.

Yesterday i forgot to remove the old rule, so i did only get my old values. The new rule wasn´t working. Today i removed the old rule but now i always get error messages about this rule:

2017-01-18 09:57:24.280 [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule 'Stromzaehler Waermepumpe Berechnung Watt': The name 'lastCount' cannot be resolved to an item or type.

Here is the top of my rule-file:

//
import org.openhab.core.library.types.*   
import org.openhab.core.types.Command
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import org.joda.time.*
import java.lang.Math
//
import java.util.concurrent.locks.ReentrantLock

// Variablen Waschmaschine + Trockner
val Number MODE_OFF = 0
val Number MODE_STANDBY = 1
val Number MODE_ACTIVE = 2
val Number MODE_FINISHED = 3
var java.util.concurrent.locks.ReentrantLock finishLock  = new java.util.concurrent.locks.ReentrantLock()

// Variablen Stromzähler Wärmepumpe
var lastUpdate = null
var lastCount = 0
var ticksBetween = 1

var smoothingSamples = 2
var total = 0.0d
var average = 0.0d
val samples = newLinkedList()


rule "Stromzaehler Waermepumpe Berechnung Watt"
when
  Item HeatPump_Stromzaehler received command
then
  /*
   * Take 2: React on every input, get the time inbetween and calculate power based
   * on time passed.
   * Very granular, calculation takes about 20ms on Raspi3B
   */
  var newCommand = (receivedCommand as DecimalType).intValue 
  var tickDiff = newCommand - lastCount
  if (lastUpdate != null && lastCount > 0) {
  	if (tickDiff == ticksBetween) {
	  	var startMillis = now().millis
	  	var nowMillis = now().millis
	  	var lastUpdateMillis = (lastUpdate as DateTime).millis
	  	var diff = nowMillis - lastUpdateMillis
	  	var watt = ((1800.0 / diff) * 1000.0 * ticksBetween) as Double

	  	// Calculate moving average
	  	if (samples.size == smoothingSamples) {
	  		total -= (samples.first as Double).doubleValue
	  		samples.removeFirst
	  	}
	  	total += watt
	  	samples.addLast(watt)
	  	average = total / samples.size
	  	
	  	var endMillis = now().millis
		logInfo("Stromzaehler Waermepumpe Berechnung Watt", "Timediff since last update: " + diff.toString() + " ms, posting average: " + average.toString() + " W, calculated "+ watt.toString() + " W")
		logInfo("Stromzaehler Waermepumpe Berechnung Watt", "Calculation took " + (endMillis - startMillis).toString() + " ms")
		Heatpump_Stromzaehler_Watt.postUpdate(average)
	} else {
		logInfo("Stromzaehler Waermepumpe Berechnung Watt", "Tick difference not what we expected: " + tickDiff)
	}
  }
  lastUpdate = now()
  lastCount = newCommand
end

Here is my items-file:

Number	HeatPump_Stromzaehler			"Wärmepumpe Stromzaehler [%d Impulse]"				<energy>		(gHeatpump_Strom,gMapDB)								{knx="12.001:4/3/1"}
Number	HeatPump_Stromzaehler_kwh		"Wärmepumpenzaehler [%.1f kWh]"						<energy>		(gMapDB)										//Calculated via rule
Number	HeatPump_Stromzaehler_Watt		"Wärmepumpe [%.3f kW]"								<energy>														//Calculated via rule
Number	HeatPump_Stromzaehler_kwh_today	"Wärmepumpenzaehler heute [%.1f kWh]"				<energy>		(gMapDB)										//Calculated via rule

Is there something missing???

Can this be a problem of openhab 1.8.3?

Are the imports in my rule file the right ones?

Can i use lastCount in my rule?

Do i have to persist some of the items?

You have some stuff in your rule that i don’t have and you don’t need it for my rule to run:

Replace that with

import org.joda.time.DateTime

and you should be fine.

My rule does not rely on persistence, only that the counter gets posted to the item from knx, but i do persist the calculated value each minute for graphing later on.

This things are for other rules in this rule file…
Ok, i make a new rule file only for my power meter things.

I tend to put everything in seperate rulefiles, makes mantainability and readability better for me :slight_smile:

I did so, but now i get the following error:

2017-01-18 21:37:35.126 [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule 'Stromzaehler Waermepumpe Berechnung Watt': Cannot cast org.openhab.core.library.types.DecimalType to void
2017-01-18 21:38:44.419 [INFO ] [c.internal.ModelRepositoryImpl] - Refreshing model 'powermeter.rules'
2017-01-18 21:39:27.950 [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule 'Stromzaehler Waermepumpe Berechnung Watt': The name 'lastCount' cannot be resolved to an item or type.

First error i removed with adding of import org.openhab.core.library.types.* on top of my rule-file. Then you can see the refreshing and after that, still the old error message.

I don’t quite get it, try to copy / paste my rule from above and only replace all occurences from my items with your corresponding items - restart openhab to be sure.

Ok, i will do this.

But i did a test the last minutes:

I changed

var lastCount = 0

to

var Number lastCount = 0

Now old error is gone but i get an error message for the next thing in the rule: lastUpdate

I didn’t mention i’m using this rule on OH2 - what version are you on? Maybe there are some syntactical differences that i’m not aware of when it comes to variable initialization?

I told you some postings before…

OH 1.8.3

Maybe @rlkoshak knows something about that???

Oops, must have overread… Let me see -

ticksBetween is an int, as is smoothingSamples and lastCount
lastUpdate is org.joda.time.DateTime
total and average are decimal (already declared by the d at the initialization)

I’m actually not sure if newLinkedList() is available in OH1, but samples is of type java.util.LinkedList

I see no reason why you would be getting that error. lastCount is defined as a var where it is supposed to be.

Try giving a hint by defining lastUpdate as an int.

var int lastUpdate = 0

Similarly give the same hint when you define newCommand:

var int newCommand = ...

The imports look OH for OH 1.8

Persistence would neither solve nor explain this problem.

With this changes i get “pointer exception null …” very much lines of errors…

Has to do with lastUpdate i think.

When removing the “int” from lastUpdate, i get the single error like before… cannot resolve lastUpdate to item or type.

Does Designer highlight anything as an error?

I don’t use it, have first to learn how to install it.