]> git.basschouten.com Git - openhab-addons.git/blob
51e559ea420a5206369b5b45fa499aaafbddd179
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.plugwise.internal.protocol.field;
14
15 import java.time.Duration;
16 import java.time.LocalDateTime;
17 import java.time.ZoneId;
18 import java.time.ZonedDateTime;
19 import java.time.temporal.ChronoUnit;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23
24 /**
25  * A simple class to represent energy usage, converting between Plugwise data representations.
26  *
27  * @author Wouter Born, Karel Goderis - Initial contribution
28  */
29 @NonNullByDefault
30 public class Energy {
31
32     private static final int WATTS_PER_KILOWATT = 1000;
33     private static final double PULSES_PER_KW_SECOND = 468.9385193;
34     private static final double PULSES_PER_W_SECOND = PULSES_PER_KW_SECOND / WATTS_PER_KILOWATT;
35
36     private @Nullable ZonedDateTime utcStart; // using UTC resolves wrong local start/end timestamps when DST changes
37                                               // occur
38     private ZonedDateTime utcEnd;
39     private long pulses;
40     private @Nullable Duration interval;
41
42     public Energy(ZonedDateTime utcEnd, long pulses) {
43         this.utcEnd = utcEnd;
44         this.pulses = pulses;
45     }
46
47     public Energy(ZonedDateTime utcEnd, long pulses, Duration interval) {
48         this.utcEnd = utcEnd;
49         this.pulses = pulses;
50         this.interval = interval;
51         updateStart(interval);
52     }
53
54     private double correctPulses(double pulses, PowerCalibration calibration) {
55         double gainA = calibration.getGainA();
56         double gainB = calibration.getGainB();
57         double offsetNoise = calibration.getOffsetNoise();
58         double offsetTotal = calibration.getOffsetTotal();
59
60         double correctedPulses = Math.pow(pulses + offsetNoise, 2) * gainB + (pulses + offsetNoise) * gainA
61                 + offsetTotal;
62         if ((pulses > 0 && correctedPulses < 0) || (pulses < 0 && correctedPulses > 0)) {
63             return 0;
64         }
65         return correctedPulses;
66     }
67
68     public LocalDateTime getEnd() {
69         return utcEnd.withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime();
70     }
71
72     public @Nullable Duration getInterval() {
73         return interval;
74     }
75
76     public long getPulses() {
77         return pulses;
78     }
79
80     public @Nullable LocalDateTime getStart() {
81         ZonedDateTime localUtcStart = utcStart;
82         if (localUtcStart == null) {
83             return null;
84         }
85         return localUtcStart.withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime();
86     }
87
88     private double intervalSeconds() {
89         Duration localInterval = interval;
90         if (localInterval == null) {
91             throw new IllegalStateException("Failed to calculate seconds because interval is null");
92         }
93
94         double seconds = localInterval.getSeconds();
95         seconds += localInterval.getNano() / ChronoUnit.SECONDS.getDuration().toNanos();
96         return seconds;
97     }
98
99     public void setInterval(Duration interval) {
100         this.interval = interval;
101         updateStart(interval);
102     }
103
104     public double tokWh(PowerCalibration calibration) {
105         return toWatt(calibration) * intervalSeconds()
106                 / (ChronoUnit.HOURS.getDuration().getSeconds() * WATTS_PER_KILOWATT);
107     }
108
109     @Override
110     public String toString() {
111         return "Energy [utcStart=" + utcStart + ", utcEnd=" + utcEnd + ", pulses=" + pulses + ", interval=" + interval
112                 + "]";
113     }
114
115     public double toWatt(PowerCalibration calibration) {
116         double averagePulses = pulses / intervalSeconds();
117         return correctPulses(averagePulses, calibration) / PULSES_PER_W_SECOND;
118     }
119
120     private void updateStart(Duration interval) {
121         utcStart = utcEnd.minus(interval);
122     }
123 }