]> git.basschouten.com Git - openhab-addons.git/blob
cdd2218098636ee8bd14b843000c4c0ea2b1ae9b
[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.dsmr.internal.device.cosem;
14
15 import java.text.ParseException;
16 import java.time.LocalDateTime;
17 import java.time.ZoneId;
18 import java.time.ZonedDateTime;
19 import java.time.format.DateTimeFormatter;
20 import java.time.format.DateTimeParseException;
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.openhab.core.library.types.DateTimeType;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * CosemDate represents a datetime value and will try to autodetect the format
31  *
32  * @author M. Volaart - Initial contribution
33  * @author Hilbrand Bouwkamp - Class now a factory instead of data containing class
34  */
35 @NonNullByDefault
36 class CosemDate extends CosemValueDescriptor<DateTimeType> {
37
38     public static final CosemDate INSTANCE = new CosemDate("timestamp");
39     /*
40      * Some meters can return the following value when something is wrong.
41      */
42     public static final String INVALID_METER_VALUE = "632525252525W";
43
44     private final Logger logger = LoggerFactory.getLogger(CosemDate.class);
45
46     public CosemDate(String ohChannelId) {
47         super(ohChannelId);
48     }
49
50     /**
51      * This enum contains the known date formats for the DSMR-specification
52      */
53     private enum CosemDateFormat {
54         /*
55          * Ignore DST setting for general format. We use local time that is already DST
56          */
57         COSEM_DATE_GENERAL("(\\d{12})([S,W]?)", "yyMMddHHmmss"),
58         COSEM_DATE_DSMR_V2("(\\d{2}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})", "yy-MM-dd HH:mm:ss");
59
60         /**
61          * Cached compiled pattern
62          */
63         private final Pattern pattern;
64
65         /**
66          * Cached java date formatter
67          */
68         private final DateTimeFormatter formatter;
69
70         /**
71          * Constructs a new CosemDateFormat
72          *
73          * @param regex String containing the regular expression to check the value against (the date format
74          *            should at least contain 1 regex group
75          * @param javaDateFormat String containing the datetime format to use for parsing
76          */
77         private CosemDateFormat(String regex, String javaDateFormat) {
78             pattern = Pattern.compile(regex);
79             formatter = DateTimeFormatter.ofPattern(javaDateFormat);
80         }
81     }
82
83     /**
84      * Parses a String value to an openHAB DateTimeType
85      * <p>
86      * The input string must be in the format yyMMddHHmmssX
87      * <p>
88      * Based on the DSMR specification X is:
89      * <p>
90      * <ul>
91      * <li>''. Valid for DSMR v3 specification
92      * <li>'S'. Specifies a summer time (DST = 1) datetime
93      * <li>'W'. Specifies a winter time (DST = 0) datetime
94      * </ul>
95      *
96      * @param cosemValue the value to parse
97      * @return {@link DateTimeType} representing the value the cosem value
98      * @throws ParseException if parsing failed
99      */
100     @Override
101     protected DateTimeType getStateValue(String cosemValue) throws ParseException {
102         for (CosemDateFormat cosemDateFormat : CosemDateFormat.values()) {
103             logger.trace("Trying pattern: {}", cosemDateFormat.pattern);
104
105             Matcher m = cosemDateFormat.pattern.matcher(cosemValue);
106
107             if (m.matches()) {
108                 logger.trace("{} matches pattern: {}", cosemValue, cosemDateFormat.pattern);
109
110                 try {
111                     LocalDateTime localDateTime = LocalDateTime.parse(m.group(1), cosemDateFormat.formatter);
112                     return new DateTimeType(ZonedDateTime.of(localDateTime, ZoneId.systemDefault()));
113                 } catch (DateTimeParseException e) {
114                     if (INVALID_METER_VALUE.equals(cosemValue)) {
115                         throw new ParseException(
116                                 "Cosem value: '" + cosemValue + "' might indicate something is wrong with the meter.",
117                                 0);
118                     }
119                 }
120             }
121         }
122         throw new ParseException("Cosem value: '" + cosemValue + "' is not a known CosemDate string", 0);
123     }
124 }