diff --git a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/Circle.java b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/Circle.java index 4f733b3847d..19370b7df39 100644 --- a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/Circle.java +++ b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/Circle.java @@ -35,8 +35,7 @@ * Circles maintain current energy usage by counting 'pulses' in a one or eight-second interval. Furthermore, they * store hourly energy usage as well in a buffer. Each entry in the buffer contains usage for the last 4 full hours * of consumption. In order to convert pulses to power (Watt) or KWh you need to apply a formula that uses some - * calibration - * information + * calibration information. * * @author Karel Goderis * @since 1.1.0 @@ -45,7 +44,9 @@ public class Circle extends PlugwiseDevice { private static Logger logger = LoggerFactory.getLogger(Circle.class); - private static final float PULSE_FACTOR = 2.1324759f; + private static final double PULSES_PER_KW_SECOND = 468.9385193; + + private static final double PULSES_PER_W_SECOND = (PULSES_PER_KW_SECOND / 1000); private static final int POWER_STATE_RETRIES = 3; @@ -67,10 +68,10 @@ public String getStateAsString() { // Calibration data, required to calculate energy consumption protected boolean calibrated; - protected float gaina; - protected float gainb; - protected float offtot; - protected float offruis; + protected double gainA; + protected double gainB; + protected double offsetTotal; + protected double offsetNoise; // System variables as kept/maintained by the Circle hardware protected DateTime stamp; @@ -82,6 +83,7 @@ public String getStateAsString() { protected String hardwareVersion; protected DateTime firmwareVersion; protected Energy one; + protected Energy lastHour; // Pending power state changes are tracked for retries and temporarily // ignoring an outdated result of an InformationJob @@ -155,15 +157,14 @@ public void updateEnergy(boolean completeHistory) { } else { previousLogAddress = 0; } - while (previousLogAddress < recentLogAddress) { + while (previousLogAddress <= recentLogAddress) { PowerBufferRequestMessage message = new PowerBufferRequestMessage(MAC, previousLogAddress); previousLogAddress = previousLogAddress + 1; stick.sendMessage(message); } - } - public float getCurrentWatt() { + public double getCurrentWatt() { if (one != null) { return pulseToWatt(one); } else { @@ -171,32 +172,22 @@ public float getCurrentWatt() { } } - private float pulseToWatt(Energy energy) { - float averagePulses; - float correctedPulses; - - if (energy.getInterval() != 0) { - averagePulses = energy.getPulses() / energy.getInterval(); - } else { + private double correctPulses(double pulses) { + double correctedPulses = Math.pow(pulses + offsetNoise, 2) * gainB + (pulses + offsetNoise) * gainA + + offsetTotal; + if ((pulses > 0 && correctedPulses < 0) || (pulses < 0 && correctedPulses > 0)) { return 0; } - correctedPulses = (float) (Math.pow(averagePulses + offruis, 2) * gainb + (averagePulses + offruis) * gaina - + offtot); - - return correctedPulses * PULSE_FACTOR; + return correctedPulses; } - private float pulseTokWh(Energy energy) { - float joule = 0; - if (energy.getInterval() == 0) { - float correctedPulses = (float) (Math.pow(energy.getPulses() + offruis, 2) * gainb - + (energy.getPulses() + offruis) * gaina + offtot); - joule = correctedPulses * PULSE_FACTOR; - } else { - joule = pulseToWatt(energy) * energy.getInterval(); - } + private double pulseToWatt(Energy energy) { + double averagePulses = energy.getPulses() / energy.getInterval(); + return correctPulses(averagePulses) / PULSES_PER_W_SECOND; + } - return joule / (3600 * 1000); + private double pulseTokWh(Energy energy) { + return pulseToWatt(energy) * energy.getInterval() / (3600 * 1000); } @Override @@ -215,10 +206,10 @@ public boolean processMessage(Message message) { case DEVICE_CALIBRATION_RESPONSE: - gaina = ((CalibrationResponseMessage) message).getGaina(); - gainb = ((CalibrationResponseMessage) message).getGainb(); - offtot = ((CalibrationResponseMessage) message).getOfftot(); - offruis = ((CalibrationResponseMessage) message).getOffruis(); + gainA = ((CalibrationResponseMessage) message).getGainA(); + gainB = ((CalibrationResponseMessage) message).getGainB(); + offsetTotal = ((CalibrationResponseMessage) message).getOffsetTotal(); + offsetNoise = ((CalibrationResponseMessage) message).getOffsetNoise(); calibrated = true; return true; @@ -258,6 +249,10 @@ public boolean processMessage(Message message) { postUpdate(MAC, PlugwiseCommandType.CURRENTSTATE, powerState); } + if (lastHour == null) { + updateEnergy(false); + } + return true; case POWER_INFORMATION_RESPONSE: @@ -271,7 +266,7 @@ public boolean processMessage(Message message) { return true; } one = ((PowerInformationResponseMessage) message).getOneSecond(); - float watt = pulseToWatt(one); + double watt = pulseToWatt(one); if (watt > 10000) { logger.debug("{} with name: {} and MAC address: {} is in a kind of error state, " + "skipping power information response", type.name(), name, MAC); @@ -283,21 +278,27 @@ public boolean processMessage(Message message) { case POWER_BUFFER_RESPONSE: - // get the last hour energy consumption - Energy lastHour = ((PowerBufferResponseMessage) message).getEnergy(3); - if (lastHour == null) { - lastHour = ((PowerBufferResponseMessage) message).getEnergy(2); - } - if (lastHour == null) { - lastHour = ((PowerBufferResponseMessage) message).getEnergy(1); + if (!calibrated) { + return true; } - if (lastHour == null) { - lastHour = ((PowerBufferResponseMessage) message).getEnergy(0); + + // get the most recent energy consumption + Energy mostRecentEnergy = null; + for (int i = 0; i < 4; i++) { + Energy energy = ((PowerBufferResponseMessage) message).getEnergy(i); + if (energy != null) { + mostRecentEnergy = energy; + } } - if (lastHour != null) { - postUpdate(MAC, PlugwiseCommandType.LASTHOURCONSUMPTION, pulseTokWh(lastHour)); - postUpdate(MAC, PlugwiseCommandType.LASTHOURCONSUMPTIONSTAMP, lastHour.getTime()); + if (mostRecentEnergy != null) { + // when the current time is '11:44:55.888', the last hour energy has time '10:00:00.000' + boolean isLastHour = mostRecentEnergy.getTime().isAfter(DateTime.now().minusHours(2)); + if (isLastHour) { + lastHour = mostRecentEnergy; + postUpdate(MAC, PlugwiseCommandType.LASTHOURCONSUMPTION, pulseTokWh(lastHour)); + postUpdate(MAC, PlugwiseCommandType.LASTHOURCONSUMPTIONSTAMP, lastHour.getTime()); + } } return true; @@ -342,4 +343,5 @@ public boolean postUpdate(String MAC, PlugwiseCommandType type, Object value) { } } + } diff --git a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/Energy.java b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/Energy.java index 66fead1a3c5..adf55bc614b 100644 --- a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/Energy.java +++ b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/Energy.java @@ -22,9 +22,9 @@ public class Energy { private DateTime time; private long pulses; - private int interval; + private double interval; - public Energy(String logdate, long l, int interval) { + public Energy(String logdate, long l, double interval) { if (logdate.length() == 8) { @@ -56,7 +56,7 @@ public Energy(String logdate, long l, int interval) { } - public Energy(DateTime logdate, long pulses, int interval) { + public Energy(DateTime logdate, long pulses, double interval) { time = logdate; this.interval = interval; this.pulses = pulses; @@ -64,7 +64,7 @@ public Energy(DateTime logdate, long pulses, int interval) { @Override public String toString() { - return time.toString() + "-" + Integer.toString(interval) + "-" + Long.toString(pulses); + return time.toString() + "-" + Double.toString(interval) + "-" + Long.toString(pulses); } public DateTime getTime() { @@ -75,7 +75,7 @@ public long getPulses() { return pulses; } - public int getInterval() { + public double getInterval() { return interval; } diff --git a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseBinding.java b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseBinding.java index e95041bb3df..ebe8ad700fd 100644 --- a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseBinding.java +++ b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseBinding.java @@ -404,6 +404,8 @@ private State createStateForType(PlugwiseCommandType ctype, Object value) throws // the logic below covers all possible command types and value types if (typeClass == DecimalType.class && value instanceof Float) { return new DecimalType((Float) value); + } else if (typeClass == DecimalType.class && value instanceof Double) { + return new DecimalType((Double) value); } else if (typeClass == OnOffType.class && value instanceof Boolean) { return ((Boolean) value).booleanValue() ? OnOffType.ON : OnOffType.OFF; } else if (typeClass == DateTimeType.class && value instanceof Calendar) { diff --git a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/CalibrationResponseMessage.java b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/CalibrationResponseMessage.java index f2451f68787..6632f9aed33 100644 --- a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/CalibrationResponseMessage.java +++ b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/CalibrationResponseMessage.java @@ -21,25 +21,25 @@ public class CalibrationResponseMessage extends Message { private static final Pattern RESPONSE_PATTERN = Pattern.compile("(\\w{16})(\\w{8})(\\w{8})(\\w{8})(\\w{8})"); - private float gaina; - private float gainb; - private float offtot; - private float offruis; + private double gainA; + private double gainB; + private double offsetTotal; + private double offsetNoise; - public float getGaina() { - return gaina; + public double getGainA() { + return gainA; } - public float getGainb() { - return gainb; + public double getGainB() { + return gainB; } - public float getOfftot() { - return offtot; + public double getOffsetTotal() { + return offsetTotal; } - public float getOffruis() { - return offruis; + public double getOffsetNoise() { + return offsetNoise; } public CalibrationResponseMessage(int sequenceNumber, String payLoad) { @@ -58,10 +58,10 @@ protected void parsePayLoad() { if (matcher.matches()) { MAC = matcher.group(1); - gaina = Float.intBitsToFloat((int) (Long.parseLong(matcher.group(2), 16))); - gainb = Float.intBitsToFloat((int) (Long.parseLong(matcher.group(3), 16))); - offtot = Float.intBitsToFloat((int) (Long.parseLong(matcher.group(4), 16))); - offruis = Float.intBitsToFloat((int) (Long.parseLong(matcher.group(5), 16))); + gainA = Float.intBitsToFloat((int) (Long.parseLong(matcher.group(2), 16))); + gainB = Float.intBitsToFloat((int) (Long.parseLong(matcher.group(3), 16))); + offsetTotal = Float.intBitsToFloat((int) (Long.parseLong(matcher.group(4), 16))); + offsetNoise = Float.intBitsToFloat((int) (Long.parseLong(matcher.group(5), 16))); } else { logger.debug("Plugwise protocol RoleCallResponseMessage error: {} does not match", payLoad); } diff --git a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/InformationResponseMessage.java b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/InformationResponseMessage.java index 62c6b2e2dc5..43976b92f86 100644 --- a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/InformationResponseMessage.java +++ b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/InformationResponseMessage.java @@ -96,7 +96,7 @@ protected void parsePayLoad() { year = Integer.parseInt(matcher.group(2), 16) + 2000; month = Integer.parseInt(matcher.group(3), 16); minutes = Integer.parseInt(matcher.group(4), 16); - logAddress = (Integer.parseInt(matcher.group(5), 16) - 278528) / 8; + logAddress = (Integer.parseInt(matcher.group(5), 16) - 278528) / 32; powerState = (matcher.group(6).equals("01")); hertz = Integer.parseInt(matcher.group(7), 16); hardwareVersion = StringUtils.left(matcher.group(8), 4) + "-" + StringUtils.mid(matcher.group(8), 4, 4) diff --git a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/PowerBufferRequestMessage.java b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/PowerBufferRequestMessage.java index ffe2bb0c918..b7a9c141cd5 100644 --- a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/PowerBufferRequestMessage.java +++ b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/PowerBufferRequestMessage.java @@ -26,7 +26,7 @@ public PowerBufferRequestMessage(String MAC, int logAddress) { @Override protected String payLoadToHexString() { - return String.format("%08X", (logAddress * 8 + 278528)); + return String.format("%08X", (logAddress * 32 + 278528)); } @Override diff --git a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/PowerBufferResponseMessage.java b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/PowerBufferResponseMessage.java index d9b4d30ea9c..e0ba26ea332 100644 --- a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/PowerBufferResponseMessage.java +++ b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/PowerBufferResponseMessage.java @@ -62,22 +62,22 @@ protected void parsePayLoad() { datapoints[0] = null; } if (!matcher.group(4).equals("FFFFFFFF")) { - datapoints[1] = new Energy(matcher.group(2), Long.parseLong(matcher.group(5), 16), 3600); + datapoints[1] = new Energy(matcher.group(4), Long.parseLong(matcher.group(5), 16), 3600); } else { datapoints[1] = null; } if (!matcher.group(6).equals("FFFFFFFF")) { - datapoints[2] = new Energy(matcher.group(2), Long.parseLong(matcher.group(7), 16), 3600); + datapoints[2] = new Energy(matcher.group(6), Long.parseLong(matcher.group(7), 16), 3600); } else { datapoints[2] = null; } if (!matcher.group(8).equals("FFFFFFFF")) { - datapoints[3] = new Energy(matcher.group(2), Long.parseLong(matcher.group(9), 16), 3600); + datapoints[3] = new Energy(matcher.group(8), Long.parseLong(matcher.group(9), 16), 3600); } else { datapoints[3] = null; } - logAddress = (Integer.parseInt(matcher.group(10), 16) - 278528) / 8; + logAddress = (Integer.parseInt(matcher.group(10), 16) - 278528) / 32; } else { logger.debug("Plugwise protocol PowerBufferResponseMessage error: {} does not match", payLoad); } diff --git a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/PowerInformationResponseMessage.java b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/PowerInformationResponseMessage.java index dbc1a7eb509..a199387db05 100644 --- a/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/PowerInformationResponseMessage.java +++ b/bundles/binding/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/protocol/PowerInformationResponseMessage.java @@ -24,17 +24,13 @@ public class PowerInformationResponseMessage extends Message { private static final Pattern RESPONSE_PATTERN = Pattern - .compile("(\\w{16})(\\w{4})(\\w{4})(\\w{8})(\\w{4})(\\w{4})(\\w{4})"); + .compile("(\\w{16})(\\w{4})(\\w{4})(\\w{8})(\\w{8})(\\w{4})"); private Energy oneSecond; private Energy eightSecond; - private Energy allSeconds; - @SuppressWarnings("unused") - private int unknown1; - @SuppressWarnings("unused") - private int unknown2; - @SuppressWarnings("unused") - private int unknown3; + private Energy oneHourConsumed; + private Energy oneHourProduced; + private double secondsCorrection; public PowerInformationResponseMessage(int sequenceNumber, String payLoad) { super(sequenceNumber, payLoad); @@ -51,13 +47,11 @@ protected void parsePayLoad() { Matcher matcher = RESPONSE_PATTERN.matcher(payLoad); if (matcher.matches()) { MAC = matcher.group(1); - oneSecond = new Energy(DateTime.now(), Integer.parseInt(matcher.group(2), 16), 1); - eightSecond = new Energy(DateTime.now(), Integer.parseInt(matcher.group(3), 16), 8); - allSeconds = new Energy(DateTime.now(), Integer.parseInt(matcher.group(4), 16), 0); - unknown1 = Integer.parseInt(matcher.group(5), 16); - unknown2 = Integer.parseInt(matcher.group(6), 16); - unknown3 = Integer.parseInt(matcher.group(7), 16); - + secondsCorrection = Integer.parseInt(matcher.group(6), 16) / 46875.0; + oneSecond = new Energy(DateTime.now(), Integer.parseInt(matcher.group(2), 16), 1 + secondsCorrection); + eightSecond = new Energy(DateTime.now(), Integer.parseInt(matcher.group(3), 16), 8 + secondsCorrection); + oneHourConsumed = new Energy(DateTime.now(), Long.parseLong(matcher.group(4), 16), 3600); + oneHourProduced = new Energy(DateTime.now(), Long.parseLong(matcher.group(5), 16), 3600); } else { logger.debug("Plugwise protocol PowerInformationResponseMessage error: {} does not match", payLoad); } @@ -71,7 +65,11 @@ public Energy getEightSecond() { return eightSecond; } - public Energy getAllSeconds() { - return allSeconds; + public Energy getOneHourConsumed() { + return oneHourConsumed; + } + + public Energy getOneHourProduced() { + return oneHourProduced; } }