]> git.basschouten.com Git - openhab-addons.git/blob
66a9f0be1116cc3bdc95945c614f563d96cb8bd2
[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.dsmr.internal.device.cosem;
14
15 import java.text.ParseException;
16 import java.util.regex.Matcher;
17 import java.util.regex.Pattern;
18
19 import javax.measure.Quantity;
20 import javax.measure.Unit;
21 import javax.measure.quantity.ElectricCurrent;
22 import javax.measure.quantity.ElectricPotential;
23 import javax.measure.quantity.Energy;
24 import javax.measure.quantity.Power;
25 import javax.measure.quantity.Volume;
26
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.openhab.core.library.types.QuantityType;
30 import org.openhab.core.library.unit.MetricPrefix;
31 import org.openhab.core.library.unit.SIUnits;
32 import org.openhab.core.library.unit.Units;
33
34 /**
35  * {@link CosemQuantity} represents a value with a unit.
36  *
37  * @author Hilbrand Bouwkamp - Initial contribution
38  *
39  * @param <Q> The {@link Quantity} type of the unit of this class
40  */
41 @NonNullByDefault
42 class CosemQuantity<Q extends @Nullable Quantity<Q>> extends CosemValueDescriptor<QuantityType<Q>> {
43
44     public static final CosemQuantity<ElectricCurrent> AMPERE = new CosemQuantity<>(Units.AMPERE);
45     public static final CosemQuantity<Volume> CUBIC_METRE = new CosemQuantity<>(SIUnits.CUBIC_METRE);
46     public static final CosemQuantity<Energy> GIGA_JOULE = new CosemQuantity<>(MetricPrefix.GIGA(Units.JOULE));
47     public static final CosemQuantity<Power> KILO_WATT = new CosemQuantity<>(MetricPrefix.KILO(Units.WATT));
48     public static final CosemQuantity<Energy> KILO_WATT_HOUR = new CosemQuantity<>(Units.KILOWATT_HOUR);
49     public static final CosemQuantity<ElectricPotential> VOLT = new CosemQuantity<>(Units.VOLT);
50     public static final CosemQuantity<Power> WATT = new CosemQuantity<>(Units.WATT);
51     public static final CosemQuantity<Power> KILO_VAR = new CosemQuantity<>(Units.KILOVAR);
52     public static final CosemQuantity<Energy> KILO_VAR_HOUR = new CosemQuantity<>(Units.KILOVAR_HOUR);
53
54     /**
55      * Pattern to convert a cosem value to a value that can be parsed by {@link QuantityType}.
56      * The specification states that the delimiter between the value and the unit is a '*'-character.
57      * We have seen on the Kaifa 0025 meter that both '*' and the '_' character are used.
58      *
59      * On the Kampstrup 162JxC in some CosemValues the separator is missing
60      *
61      * The above quirks are supported
62      *
63      * We also support unit that do not follow the exact case.
64      */
65     private static final Pattern COSEM_VALUE_WITH_UNIT_PATTERN = Pattern.compile("^([\\d\\.]+)[\\*_]?(.+)$",
66             Pattern.CASE_INSENSITIVE);
67
68     /**
69      * Unit of this CosemValue
70      */
71     private final Unit<Q> unit;
72
73     /**
74      * Creates a new {@link CosemDouble}.
75      *
76      * @param unit the unit of the value
77      */
78     private CosemQuantity(Unit<Q> unit) {
79         this(unit, "");
80     }
81
82     /**
83      * Constructor.
84      *
85      * @param unit Unit of this CosemQuantity instance
86      * @param channelId the channel for this CosemValueDescriptor
87      */
88     public CosemQuantity(Unit<Q> unit, String channelId) {
89         super(channelId);
90         this.unit = unit;
91     }
92
93     /**
94      * Parses a String value (that represents a value with a unit) to a {@link QuantityType} object.
95      *
96      * @param cosemValue the value to parse
97      * @return {@link QuanitytType} on success
98      * @throws ParseException in case unit doesn't match.
99      */
100     @Override
101     protected QuantityType<Q> getStateValue(String cosemValue) throws ParseException {
102         try {
103             QuantityType<Q> qt = new QuantityType<>(prepare(cosemValue));
104
105             if (!unit.equals(qt.getUnit())) {
106                 throw new ParseException("Failed to parse value '" + cosemValue + "' as unit " + unit, 0);
107             }
108             return qt;
109         } catch (IllegalArgumentException nfe) {
110             throw new ParseException("Failed to parse value '" + cosemValue + "' as unit " + unit, 0);
111         }
112     }
113
114     /**
115      * Check if COSEM value has a unit, check and parse the value. We assume here numbers (float or integers)
116      * The specification states that the delimiter between the value and the unit is a '*'-character.
117      * We have seen on the Kaifa 0025 meter that both '*' and the '_' character are used.
118      *
119      * On the Kampstrup 162JxC in some CosemValues the separator is missing. This
120      *
121      * The above quirks are supported
122      *
123      * We also support unit that do not follow the exact case.
124      */
125     private String prepare(String cosemValue) {
126         Matcher matcher = COSEM_VALUE_WITH_UNIT_PATTERN.matcher(cosemValue.replace("m3", "m³"));
127
128         return matcher.find() ? matcher.group(1) + ' ' + matcher.group(2) : cosemValue;
129     }
130 }