]> git.basschouten.com Git - openhab-addons.git/blob
be2f83e7bfe6bd7893a371870778c49c8032665d
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.mercedesme.internal.utils;
14
15 import static org.openhab.binding.mercedesme.internal.Constants.*;
16
17 import java.util.HashMap;
18 import java.util.Map;
19 import java.util.Set;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.json.JSONObject;
23 import org.openhab.core.library.types.DecimalType;
24 import org.openhab.core.library.types.OnOffType;
25 import org.openhab.core.library.types.OpenClosedType;
26 import org.openhab.core.library.types.QuantityType;
27 import org.openhab.core.library.unit.Units;
28 import org.openhab.core.types.State;
29 import org.openhab.core.types.UnDefType;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 /**
34  * The {@link Mapper} maps a given Json Object towards a channel, group and state
35  *
36  * @author Bernd Weymann - Initial contribution
37  */
38 @NonNullByDefault
39 public class Mapper {
40     private static final Logger LOGGER = LoggerFactory.getLogger(Mapper.class);
41
42     public static final ChannelStateMap INVALID_MAP = new ChannelStateMap(EMPTY, EMPTY, UnDefType.UNDEF, -1);
43     public static final Map<String, String[]> CHANNELS = new HashMap<String, String[]>();
44     public static final String TIMESTAMP = "timestamp";
45     public static final String VALUE = "value";
46
47     public static ChannelStateMap getChannelStateMap(JSONObject jo) {
48         if (CHANNELS.isEmpty()) {
49             init();
50         }
51         Set<String> s = jo.keySet();
52         if (s.size() == 1) {
53             String id = s.toArray()[0].toString();
54             String[] ch = CHANNELS.get(id);
55             if (ch != null) {
56                 State state;
57                 switch (id) {
58                     // Kilometer values
59                     case "odo":
60                     case "rangeelectric":
61                     case "rangeliquid":
62                         state = getKilometers((JSONObject) jo.get(id));
63                         return new ChannelStateMap(ch[0], ch[1], state, getTimestamp((JSONObject) jo.get(id)));
64
65                     // Percentages
66                     case "soc":
67                     case "tanklevelpercent":
68                         state = getPercentage((JSONObject) jo.get(id));
69                         return new ChannelStateMap(ch[0], ch[1], state, getTimestamp((JSONObject) jo.get(id)));
70
71                     // Contacts
72                     case "decklidstatus":
73                     case "doorstatusfrontleft":
74                     case "doorstatusfrontright":
75                     case "doorstatusrearleft":
76                     case "doorstatusrearright":
77                         state = getContact((JSONObject) jo.get(id));
78                         return new ChannelStateMap(ch[0], ch[1], state, getTimestamp((JSONObject) jo.get(id)));
79
80                     // Number Status
81                     case "lightswitchposition":
82                     case "rooftopstatus":
83                     case "sunroofstatus":
84                     case "windowstatusfrontleft":
85                     case "windowstatusfrontright":
86                     case "windowstatusrearleft":
87                     case "windowstatusrearright":
88                     case "doorlockstatusvehicle":
89                         state = getDecimal((JSONObject) jo.get(id));
90                         return new ChannelStateMap(ch[0], ch[1], state, getTimestamp((JSONObject) jo.get(id)));
91
92                     // Switches
93                     case "interiorLightsFront":
94                     case "interiorLightsRear":
95                     case "readingLampFrontLeft":
96                     case "readingLampFrontRight":
97                         state = getOnOffType((JSONObject) jo.get(id));
98                         return new ChannelStateMap(ch[0], ch[1], state, getTimestamp((JSONObject) jo.get(id)));
99
100                     case "doorlockstatusdecklid":
101                     case "doorlockstatusgas":
102                         state = getOnOffTypeLock((JSONObject) jo.get(id));
103                         return new ChannelStateMap(ch[0], ch[1], state, getTimestamp((JSONObject) jo.get(id)));
104
105                     // Angle
106                     case "positionHeading":
107                         state = getAngle((JSONObject) jo.get(id));
108                         return new ChannelStateMap(ch[0], ch[1], state, getTimestamp((JSONObject) jo.get(id)));
109                     default:
110                         LOGGER.trace("No mapping available for {}", id);
111                 }
112             } else {
113                 LOGGER.trace("No mapping available for {}", id);
114             }
115         } else {
116             LOGGER.debug("More than one key found {}", s);
117         }
118         return INVALID_MAP;
119     }
120
121     private static long getTimestamp(JSONObject jo) {
122         if (jo.has(TIMESTAMP)) {
123             return jo.getLong(TIMESTAMP);
124         }
125         return -1;
126     }
127
128     private static State getOnOffType(JSONObject jo) {
129         if (jo.has(VALUE)) {
130             String value = jo.get(VALUE).toString();
131             boolean b = Boolean.valueOf(value);
132             return OnOffType.from(b);
133         } else {
134             LOGGER.warn("JSONObject contains no value {}", jo);
135             return UnDefType.UNDEF;
136         }
137     }
138
139     private static State getOnOffTypeLock(JSONObject jo) {
140         if (jo.has(VALUE)) {
141             String value = jo.get(VALUE).toString();
142             boolean b = Boolean.valueOf(value);
143             // Yes, false is locked and true unlocked
144             // https://developer.mercedes-benz.com/products/vehicle_lock_status/specifications/vehicle_lock_status_api
145             return OnOffType.from(!b);
146         } else {
147             LOGGER.warn("JSONObject contains no value {}", jo);
148             return UnDefType.UNDEF;
149         }
150     }
151
152     private static State getAngle(JSONObject jo) {
153         if (jo.has(VALUE)) {
154             String value = jo.get(VALUE).toString();
155             return QuantityType.valueOf(Double.valueOf(value), Units.DEGREE_ANGLE);
156         } else {
157             LOGGER.warn("JSONObject contains no value {}", jo);
158             return UnDefType.UNDEF;
159         }
160     }
161
162     private static State getDecimal(JSONObject jo) {
163         if (jo.has(VALUE)) {
164             String value = jo.get(VALUE).toString();
165             return DecimalType.valueOf(value);
166         } else {
167             LOGGER.warn("JSONObject contains no value {}", jo);
168             return UnDefType.UNDEF;
169         }
170     }
171
172     private static State getContact(JSONObject jo) {
173         if (jo.has(VALUE)) {
174             String value = jo.get(VALUE).toString();
175             boolean b = Boolean.valueOf(value);
176             if (!b) {
177                 return OpenClosedType.CLOSED;
178             } else {
179                 return OpenClosedType.OPEN;
180             }
181         } else {
182             LOGGER.warn("JSONObject contains no value {}", jo);
183             return UnDefType.UNDEF;
184         }
185     }
186
187     private static State getKilometers(JSONObject jo) {
188         if (jo.has(VALUE)) {
189             String value = jo.get(VALUE).toString();
190             return QuantityType.valueOf(Integer.valueOf(value), KILOMETRE_UNIT);
191         } else {
192             LOGGER.warn("JSONObject contains no value {}", jo);
193             return UnDefType.UNDEF;
194         }
195     }
196
197     private static State getPercentage(JSONObject jo) {
198         if (jo.has(VALUE)) {
199             String value = jo.get(VALUE).toString();
200             return QuantityType.valueOf(Integer.valueOf(value), Units.PERCENT);
201         } else {
202             LOGGER.warn("JSONObject contains no value {}", jo);
203             return UnDefType.UNDEF;
204         }
205     }
206
207     /**
208      * Mapping of json id towards channel group and id
209      */
210     private static void init() {
211         CHANNELS.put("odo", new String[] { "mileage", GROUP_RANGE });
212         CHANNELS.put("rangeelectric", new String[] { "range-electric", GROUP_RANGE });
213         CHANNELS.put("soc", new String[] { "soc", GROUP_RANGE });
214         CHANNELS.put("rangeliquid", new String[] { "range-fuel", GROUP_RANGE });
215         CHANNELS.put("tanklevelpercent", new String[] { "fuel-level", GROUP_RANGE });
216         CHANNELS.put("decklidstatus", new String[] { "deck-lid", GROUP_DOORS });
217         CHANNELS.put("doorstatusfrontleft", new String[] { "driver-front", GROUP_DOORS });
218         CHANNELS.put("doorstatusfrontright", new String[] { "passenger-front", GROUP_DOORS });
219         CHANNELS.put("doorstatusrearleft", new String[] { "driver-rear", GROUP_DOORS });
220         CHANNELS.put("doorstatusrearright", new String[] { "passenger-rear", GROUP_DOORS });
221         CHANNELS.put("interiorLightsFront", new String[] { "interior-front", GROUP_LIGHTS });
222         CHANNELS.put("interiorLightsRear", new String[] { "interior-rear", GROUP_LIGHTS });
223         CHANNELS.put("lightswitchposition", new String[] { "light-switch", GROUP_LIGHTS });
224         CHANNELS.put("readingLampFrontLeft", new String[] { "reading-left", GROUP_LIGHTS });
225         CHANNELS.put("readingLampFrontRight", new String[] { "reading-right", GROUP_LIGHTS });
226         CHANNELS.put("rooftopstatus", new String[] { "rooftop", GROUP_DOORS });
227         CHANNELS.put("sunroofstatus", new String[] { "sunroof", GROUP_DOORS });
228         CHANNELS.put("windowstatusfrontleft", new String[] { "driver-front", GROUP_WINDOWS });
229         CHANNELS.put("windowstatusfrontright", new String[] { "passenger-front", GROUP_WINDOWS });
230         CHANNELS.put("windowstatusrearleft", new String[] { "driver-rear", GROUP_WINDOWS });
231         CHANNELS.put("windowstatusrearright", new String[] { "passenger-rear", GROUP_WINDOWS });
232         CHANNELS.put("doorlockstatusvehicle", new String[] { "doors", GROUP_LOCK });
233         CHANNELS.put("doorlockstatusdecklid", new String[] { "deck-lid", GROUP_LOCK });
234         CHANNELS.put("doorlockstatusgas", new String[] { "flap", GROUP_LOCK });
235         CHANNELS.put("positionHeading", new String[] { "heading", GROUP_LOCATION });
236     }
237 }