2 * Copyright (c) 2010-2024 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.mercedesme.internal.utils;
15 import static org.openhab.binding.mercedesme.internal.Constants.*;
17 import java.util.HashMap;
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;
34 * The {@link Mapper} maps a given Json Object towards a channel, group and state
36 * @author Bernd Weymann - Initial contribution
40 private static final Logger LOGGER = LoggerFactory.getLogger(Mapper.class);
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";
47 public static ChannelStateMap getChannelStateMap(JSONObject jo) {
48 if (CHANNELS.isEmpty()) {
51 Set<String> s = jo.keySet();
53 String id = s.toArray()[0].toString();
54 String[] ch = CHANNELS.get(id);
62 state = getKilometers((JSONObject) jo.get(id));
63 return new ChannelStateMap(ch[0], ch[1], state, getTimestamp((JSONObject) jo.get(id)));
67 case "tanklevelpercent":
68 state = getPercentage((JSONObject) jo.get(id));
69 return new ChannelStateMap(ch[0], ch[1], state, getTimestamp((JSONObject) jo.get(id)));
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)));
81 case "lightswitchposition":
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)));
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)));
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)));
106 case "positionHeading":
107 state = getAngle((JSONObject) jo.get(id));
108 return new ChannelStateMap(ch[0], ch[1], state, getTimestamp((JSONObject) jo.get(id)));
110 LOGGER.trace("No mapping available for {}", id);
113 LOGGER.trace("No mapping available for {}", id);
116 LOGGER.debug("More than one key found {}", s);
121 private static long getTimestamp(JSONObject jo) {
122 if (jo.has(TIMESTAMP)) {
123 return jo.getLong(TIMESTAMP);
128 private static State getOnOffType(JSONObject jo) {
130 String value = jo.get(VALUE).toString();
131 boolean b = Boolean.valueOf(value);
132 return OnOffType.from(b);
134 LOGGER.warn("JSONObject contains no value {}", jo);
135 return UnDefType.UNDEF;
139 private static State getOnOffTypeLock(JSONObject jo) {
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);
147 LOGGER.warn("JSONObject contains no value {}", jo);
148 return UnDefType.UNDEF;
152 private static State getAngle(JSONObject jo) {
154 String value = jo.get(VALUE).toString();
155 return QuantityType.valueOf(Double.valueOf(value), Units.DEGREE_ANGLE);
157 LOGGER.warn("JSONObject contains no value {}", jo);
158 return UnDefType.UNDEF;
162 private static State getDecimal(JSONObject jo) {
164 String value = jo.get(VALUE).toString();
165 return DecimalType.valueOf(value);
167 LOGGER.warn("JSONObject contains no value {}", jo);
168 return UnDefType.UNDEF;
172 private static State getContact(JSONObject jo) {
174 String value = jo.get(VALUE).toString();
175 boolean b = Boolean.valueOf(value);
177 return OpenClosedType.CLOSED;
179 return OpenClosedType.OPEN;
182 LOGGER.warn("JSONObject contains no value {}", jo);
183 return UnDefType.UNDEF;
187 private static State getKilometers(JSONObject jo) {
189 String value = jo.get(VALUE).toString();
190 return QuantityType.valueOf(Integer.valueOf(value), KILOMETRE_UNIT);
192 LOGGER.warn("JSONObject contains no value {}", jo);
193 return UnDefType.UNDEF;
197 private static State getPercentage(JSONObject jo) {
199 String value = jo.get(VALUE).toString();
200 return QuantityType.valueOf(Integer.valueOf(value), Units.PERCENT);
202 LOGGER.warn("JSONObject contains no value {}", jo);
203 return UnDefType.UNDEF;
208 * Mapping of json id towards channel group and id
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 });