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.
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)
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
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.
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.
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?
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