]> git.basschouten.com Git - openhab-addons.git/blob
91c691d9beefce2fe093f88cedf86ea959fb54e8
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.smartmeter.internal.conformity;
14
15 import java.util.function.Supplier;
16
17 import javax.measure.Quantity;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.smartmeter.SmartMeterBindingConstants;
22 import org.openhab.binding.smartmeter.internal.MeterDevice;
23 import org.openhab.binding.smartmeter.internal.MeterValue;
24 import org.openhab.binding.smartmeter.internal.ObisCode;
25 import org.openhab.binding.smartmeter.internal.conformity.negate.NegateHandler;
26 import org.openhab.core.library.types.QuantityType;
27 import org.openhab.core.library.unit.SmartHomeUnits;
28 import org.openhab.core.thing.Channel;
29 import org.openhab.core.thing.Thing;
30 import org.openhab.core.types.State;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 /**
35  * Some meters have specific semantics on how to interpret the values which are sent from the meter.
36  * This class handles all such known special cases.
37  *
38  * @author Matthias Steigenberger - Initial contribution
39  *
40  */
41 @NonNullByDefault
42 public enum Conformity {
43
44     NONE {
45         @Override
46         public <Q extends Quantity<Q>> State apply(Channel channel, QuantityType<Q> currentState, Thing thing,
47                 MeterDevice<?> device) {
48             return retrieveOverwrittenNegate(channel, currentState, thing, device, null);
49         }
50     },
51     /**
52      * See
53      * https://www.vde.com/resource/blob/951000/252eb3cdf1c7f6cdea10847be399da0d/fnn-lastenheft-edl-1-0-2010-01-13-data.pdf
54      */
55     EDL_FNN {
56         /*
57          * (non-Javadoc)
58          *
59          * @see org.openhab.binding.smartmeter.internal.Conformity#apply(org.openhab.core.thing.Channel,
60          * org.openhab.core.library.types.QuantityType, org.openhab.core.thing.Thing,
61          * org.openhab.binding.smartmeter.internal.MeterDevice)
62          */
63         @Override
64         public <Q extends Quantity<Q>> QuantityType<?> apply(Channel channel, QuantityType<Q> currentState, Thing thing,
65                 MeterDevice<?> device) {
66             return retrieveOverwrittenNegate(channel, currentState, thing, device, () -> {
67                 // Negate if this channel has the unit "Watt" and the negate bit is set. Read from all other
68                 // channels the state and check if there is a negate bit.
69                 String channelObis = channel.getProperties().get(SmartMeterBindingConstants.CHANNEL_PROPERTY_OBIS);
70                 MeterValue<?> value = device.getMeterValue(channelObis);
71                 if (value != null && SmartHomeUnits.WATT.isCompatible(value.getUnit())) {
72                     for (String obis : device.getObisCodes()) {
73                         try {
74                             MeterValue<?> otherValue = device.getMeterValue(obis);
75                             ObisCode obisCode = ObisCode.from(obis);
76                             if (otherValue != null) {
77                                 if (obisCode.matches((byte) 0x60, (byte) 0x05, (byte) 0x05)) {
78                                     // we found status status obis 96.5.5
79                                     if (NegateHandler.isNegateSet(otherValue.getValue(), 5)) {
80                                         return currentState.negate();
81                                     }
82                                 } else if (obisCode.matches((byte) 0x01, (byte) 0x08, (byte) 0x00)) {
83                                     // check obis 1.8.0 for status if status has negate bit set.
84                                     String status = otherValue.getStatus();
85                                     if (status != null && NegateHandler.isNegateSet(status, 5)) {
86                                         return currentState.negate();
87                                     }
88                                 }
89                             }
90                         } catch (Exception e) {
91                             logger.warn("Failed to check negate status for obis {}", obis, e);
92                         }
93                     }
94                 }
95                 return currentState;
96             });
97         }
98     };
99
100     private static final Logger logger = LoggerFactory.getLogger(Conformity.class);
101
102     /**
103      * Applies the overwritten negation setting for the channel.
104      *
105      * @param currentState The current value.
106      * @param thing The {@link Thing}
107      * @param device The {@link MeterDevice}.
108      * @param negateProperty The negate property.
109      * @return The negated value.
110      */
111     private static <Q extends Quantity<Q>> QuantityType<Q> applyNegation(QuantityType<Q> currentState, Thing thing,
112             MeterDevice<?> device, String negateProperty) {
113         boolean shouldNegateState = NegateHandler.shouldNegateState(negateProperty, channelId -> {
114             Channel negateChannel = thing.getChannel(channelId);
115             if (negateChannel != null) {
116                 String property = negateChannel.getProperties().get(SmartMeterBindingConstants.CHANNEL_PROPERTY_OBIS);
117                 return property != null ? device.getMeterValue(property) : null;
118             }
119             return null;
120         });
121
122         if (shouldNegateState) {
123             return currentState.negate();
124         }
125         return currentState;
126     }
127
128     /**
129      *
130      * @param channel
131      * @param currentState
132      * @param thing
133      * @param device
134      * @param elseDo If negate property was not overwritten call the given supplier.
135      * @return
136      */
137     protected <Q extends Quantity<Q>> QuantityType<?> retrieveOverwrittenNegate(Channel channel,
138             QuantityType<Q> currentState, Thing thing, MeterDevice<?> device,
139             @Nullable Supplier<QuantityType<Q>> elseDo) {
140         // Negate setting
141         String negateProperty = (String) channel.getConfiguration()
142                 .get(SmartMeterBindingConstants.CONFIGURATION_CHANNEL_NEGATE);
143         if (negateProperty != null && !negateProperty.trim().isEmpty()) {
144             return applyNegation(currentState, thing, device, negateProperty);
145         } else {
146             if (elseDo != null) {
147                 return elseDo.get();
148             }
149             return currentState;
150         }
151     }
152
153     /**
154      * Applies any changes according to the conformity and returns the new value.
155      *
156      * @param channel The {@link Channel} for which the conformity should be applied to.
157      * @param currentState The current state of that {@link Channel}
158      * @param thing The {@link Thing} where the channel belongs to.
159      * @param device The {@link MeterDevice} for the Thing.
160      * @return The applied state.
161      */
162     public abstract <Q extends Quantity<Q>> State apply(Channel channel, QuantityType<Q> currentState, Thing thing,
163             MeterDevice<?> device);
164 }