]> git.basschouten.com Git - openhab-addons.git/blob
55c66b5b44afaec66bfc161652d806be31b38f93
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.bmwconnecteddrive.internal.discovery;
14
15 import static org.openhab.binding.bmwconnecteddrive.internal.ConnectedDriveConstants.SUPPORTED_THING_SET;
16
17 import java.lang.reflect.Field;
18 import java.util.HashMap;
19 import java.util.Map;
20 import java.util.Optional;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.bmwconnecteddrive.internal.ConnectedDriveConstants;
25 import org.openhab.binding.bmwconnecteddrive.internal.dto.discovery.VehiclesContainer;
26 import org.openhab.binding.bmwconnecteddrive.internal.handler.ConnectedDriveBridgeHandler;
27 import org.openhab.binding.bmwconnecteddrive.internal.utils.Constants;
28 import org.openhab.binding.bmwconnecteddrive.internal.utils.Converter;
29 import org.openhab.core.config.core.Configuration;
30 import org.openhab.core.config.discovery.AbstractDiscoveryService;
31 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
32 import org.openhab.core.config.discovery.DiscoveryService;
33 import org.openhab.core.thing.ThingUID;
34 import org.openhab.core.thing.binding.ThingHandler;
35 import org.openhab.core.thing.binding.ThingHandlerService;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 /**
40  * The {@link VehicleDiscovery} requests data from ConnectedDrive and is identifying the Vehicles after response
41  *
42  * @author Bernd Weymann - Initial contribution
43  */
44 @NonNullByDefault
45 public class VehicleDiscovery extends AbstractDiscoveryService implements DiscoveryService, ThingHandlerService {
46
47     private final Logger logger = LoggerFactory.getLogger(VehicleDiscovery.class);
48     private static final int DISCOVERY_TIMEOUT = 10;
49     private Optional<ConnectedDriveBridgeHandler> bridgeHandler = Optional.empty();
50
51     public VehicleDiscovery() {
52         super(SUPPORTED_THING_SET, DISCOVERY_TIMEOUT, false);
53     }
54
55     public void onResponse(VehiclesContainer container) {
56         bridgeHandler.ifPresent(bridge -> {
57             final ThingUID bridgeUID = bridge.getThing().getUID();
58             container.vehicles.forEach(vehicle -> {
59                 // the DriveTrain field in the delivered json is defining the Vehicle Type
60                 String vehicleType = vehicle.driveTrain.toLowerCase();
61                 SUPPORTED_THING_SET.forEach(entry -> {
62                     if (entry.getId().equals(vehicleType)) {
63                         ThingUID uid = new ThingUID(entry, vehicle.vin, bridgeUID.getId());
64                         Map<String, String> properties = new HashMap<>();
65                         // Dealer
66                         if (vehicle.dealer != null) {
67                             properties.put("dealer", vehicle.dealer.name);
68                             properties.put("dealerAddress", vehicle.dealer.street + " " + vehicle.dealer.country + " "
69                                     + vehicle.dealer.postalCode + " " + vehicle.dealer.city);
70                             properties.put("dealerPhone", vehicle.dealer.phone);
71                         }
72
73                         // Services & Support
74                         properties.put("servicesActivated", getObject(vehicle, Constants.ACTIVATED));
75                         String servicesSupported = getObject(vehicle, Constants.SUPPORTED);
76                         String servicesNotSupported = getObject(vehicle, Constants.NOT_SUPPORTED);
77                         if (vehicle.statisticsAvailable) {
78                             servicesSupported += Constants.STATISTICS;
79                         } else {
80                             servicesNotSupported += Constants.STATISTICS;
81                         }
82                         properties.put(Constants.SERVICES_SUPPORTED, servicesSupported);
83                         properties.put("servicesNotSupported", servicesNotSupported);
84                         properties.put("supportBreakdownNumber", vehicle.breakdownNumber);
85
86                         // Vehicle Properties
87                         if (vehicle.supportedChargingModes != null) {
88                             properties.put("vehicleChargeModes",
89                                     String.join(Constants.SPACE, vehicle.supportedChargingModes));
90                         }
91                         if (vehicle.hasAlarmSystem) {
92                             properties.put("vehicleAlarmSystem", "Available");
93                         } else {
94                             properties.put("vehicleAlarmSystem", "Not Available");
95                         }
96                         properties.put("vehicleBrand", vehicle.brand);
97                         properties.put("vehicleBodytype", vehicle.bodytype);
98                         properties.put("vehicleColor", vehicle.color);
99                         properties.put("vehicleConstructionYear", Short.toString(vehicle.yearOfConstruction));
100                         properties.put("vehicleDriveTrain", vehicle.driveTrain);
101                         properties.put("vehicleModel", vehicle.model);
102                         if (vehicle.chargingControl != null) {
103                             properties.put("vehicleChargeControl", Converter.toTitleCase(vehicle.model));
104                         }
105
106                         // Update Properties for already created Things
107                         bridge.getThing().getThings().forEach(vehicleThing -> {
108                             Configuration c = vehicleThing.getConfiguration();
109                             if (c.containsKey(ConnectedDriveConstants.VIN)) {
110                                 String thingVIN = c.get(ConnectedDriveConstants.VIN).toString();
111                                 if (vehicle.vin.equals(thingVIN)) {
112                                     vehicleThing.setProperties(properties);
113                                 }
114                             }
115                         });
116
117                         // Properties needed for functional THing
118                         properties.put(ConnectedDriveConstants.VIN, vehicle.vin);
119                         properties.put("refreshInterval",
120                                 Integer.toString(ConnectedDriveConstants.DEFAULT_REFRESH_INTERVAL_MINUTES));
121                         properties.put("units", ConnectedDriveConstants.UNITS_AUTODETECT);
122                         properties.put("imageSize", Integer.toString(ConnectedDriveConstants.DEFAULT_IMAGE_SIZE_PX));
123                         properties.put("imageViewport", ConnectedDriveConstants.DEFAULT_IMAGE_VIEWPORT);
124
125                         String vehicleLabel = vehicle.brand + " " + vehicle.model;
126                         Map<String, Object> convertedProperties = new HashMap<String, Object>(properties);
127                         thingDiscovered(DiscoveryResultBuilder.create(uid).withBridge(bridgeUID)
128                                 .withRepresentationProperty(ConnectedDriveConstants.VIN).withLabel(vehicleLabel)
129                                 .withProperties(convertedProperties).build());
130                     }
131                 });
132             });
133         });
134     };
135
136     /**
137      * Get all field names from a DTO with a specific value
138      * Used to get e.g. all services which are "ACTIVATED"
139      *
140      * @param DTO Object
141      * @param compare String which needs to map with the value
142      * @return String with all field names matching this value separated with Spaces
143      */
144     public String getObject(Object dto, String compare) {
145         StringBuilder buf = new StringBuilder();
146         for (Field field : dto.getClass().getDeclaredFields()) {
147             try {
148                 Object value = field.get(dto);
149                 if (compare.equals(value)) {
150                     buf.append(Converter.capitalizeFirst(field.getName()) + Constants.SPACE);
151                 }
152             } catch (IllegalArgumentException | IllegalAccessException e) {
153                 logger.debug("Field {} not found {}", compare, e.getMessage());
154             }
155         }
156         return buf.toString();
157     }
158
159     @Override
160     public void setThingHandler(ThingHandler handler) {
161         if (handler instanceof ConnectedDriveBridgeHandler) {
162             bridgeHandler = Optional.of((ConnectedDriveBridgeHandler) handler);
163             bridgeHandler.get().setDiscoveryService(this);
164         }
165     }
166
167     @Override
168     public @Nullable ThingHandler getThingHandler() {
169         return bridgeHandler.orElse(null);
170     }
171
172     @Override
173     protected void startScan() {
174         bridgeHandler.ifPresent(ConnectedDriveBridgeHandler::requestVehicles);
175     }
176
177     @Override
178     public void deactivate() {
179         super.deactivate();
180     }
181 }