]> git.basschouten.com Git - openhab-addons.git/blob
3bbf4e934b946c901e7a94682d0dd739731f5163
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.renault.internal.handler;
14
15 import static org.openhab.binding.renault.internal.RenaultBindingConstants.*;
16 import static org.openhab.core.library.unit.MetricPrefix.KILO;
17 import static org.openhab.core.library.unit.SIUnits.METRE;
18
19 import java.util.concurrent.ScheduledFuture;
20 import java.util.concurrent.TimeUnit;
21
22 import javax.measure.quantity.Length;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.eclipse.jetty.client.HttpClient;
27 import org.openhab.binding.renault.internal.RenaultConfiguration;
28 import org.openhab.binding.renault.internal.api.Car;
29 import org.openhab.binding.renault.internal.api.MyRenaultHttpSession;
30 import org.openhab.binding.renault.internal.api.exceptions.RenaultForbiddenException;
31 import org.openhab.binding.renault.internal.api.exceptions.RenaultNotImplementedException;
32 import org.openhab.binding.renault.internal.api.exceptions.RenaultUpdateException;
33 import org.openhab.core.library.types.DecimalType;
34 import org.openhab.core.library.types.OnOffType;
35 import org.openhab.core.library.types.PointType;
36 import org.openhab.core.library.types.QuantityType;
37 import org.openhab.core.library.types.StringType;
38 import org.openhab.core.thing.ChannelUID;
39 import org.openhab.core.thing.Thing;
40 import org.openhab.core.thing.ThingStatus;
41 import org.openhab.core.thing.ThingStatusDetail;
42 import org.openhab.core.thing.binding.BaseThingHandler;
43 import org.openhab.core.types.Command;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48  * The {@link RenaultHandler} is responsible for handling commands, which are
49  * sent to one of the channels.
50  *
51  * @author Doug Culnane - Initial contribution
52  */
53 @NonNullByDefault
54 public class RenaultHandler extends BaseThingHandler {
55
56     private final Logger logger = LoggerFactory.getLogger(RenaultHandler.class);
57
58     private RenaultConfiguration config = new RenaultConfiguration();
59
60     private @Nullable ScheduledFuture<?> pollingJob;
61
62     private HttpClient httpClient;
63
64     private Car car;
65
66     public RenaultHandler(Thing thing, HttpClient httpClient) {
67         super(thing);
68         this.car = new Car();
69         this.httpClient = httpClient;
70     }
71
72     @Override
73     public void handleCommand(ChannelUID channelUID, Command command) {
74         // This binding only polls status data automatically.
75     }
76
77     @Override
78     public void initialize() {
79         // reset the car on initialize
80         this.car = new Car();
81         this.config = getConfigAs(RenaultConfiguration.class);
82
83         // Validate configuration
84         if (this.config.myRenaultUsername.isBlank()) {
85             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "MyRenault Username is empty!");
86             return;
87         }
88         if (this.config.myRenaultPassword.isBlank()) {
89             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "MyRenault Password is empty!");
90             return;
91         }
92         if (this.config.locale.isBlank()) {
93             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Location is empty!");
94             return;
95         }
96         if (this.config.vin.isBlank()) {
97             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "VIN is empty!");
98             return;
99         }
100         if (this.config.refreshInterval < 1) {
101             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
102                     "The refresh interval mush to be larger than 1");
103             return;
104         }
105         updateStatus(ThingStatus.UNKNOWN);
106
107         // Background initialization:
108         ScheduledFuture<?> job = pollingJob;
109         if (job == null || job.isCancelled()) {
110             pollingJob = scheduler.scheduleWithFixedDelay(this::getStatus, 0, config.refreshInterval, TimeUnit.MINUTES);
111         }
112     }
113
114     @Override
115     public void dispose() {
116         ScheduledFuture<?> job = pollingJob;
117         if (job != null) {
118             job.cancel(true);
119             pollingJob = null;
120         }
121         super.dispose();
122     }
123
124     private void getStatus() {
125         MyRenaultHttpSession httpSession = new MyRenaultHttpSession(this.config, httpClient);
126         try {
127             httpSession.initSesssion(car);
128             updateStatus(ThingStatus.ONLINE);
129         } catch (Exception e) {
130             httpSession = null;
131             logger.warn("Error My Renault Http Session.", e);
132             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
133         }
134         if (httpSession != null) {
135             String imageURL = car.getImageURL();
136             if (imageURL != null && !imageURL.isEmpty()) {
137                 updateState(CHANNEL_IMAGE, new StringType(imageURL));
138             }
139             updateHvacStatus(httpSession);
140             updateCockpit(httpSession);
141             updateLocation(httpSession);
142             updateBattery(httpSession);
143         }
144     }
145
146     private void updateHvacStatus(MyRenaultHttpSession httpSession) {
147         if (!car.isDisableHvac()) {
148             try {
149                 httpSession.getHvacStatus(car);
150                 Boolean hvacstatus = car.getHvacstatus();
151                 if (hvacstatus != null) {
152                     updateState(CHANNEL_HVAC_STATUS, OnOffType.from(hvacstatus.booleanValue()));
153                 }
154             } catch (RenaultNotImplementedException e) {
155                 car.setDisableHvac(true);
156             } catch (RenaultForbiddenException | RenaultUpdateException e) {
157             }
158         }
159     }
160
161     private void updateLocation(MyRenaultHttpSession httpSession) {
162         if (!car.isDisableLocation()) {
163             try {
164                 httpSession.getLocation(car);
165                 Double latitude = car.getGpsLatitude();
166                 Double longitude = car.getGpsLongitude();
167                 if (latitude != null && longitude != null) {
168                     updateState(CHANNEL_LOCATION, new PointType(new DecimalType(latitude.doubleValue()),
169                             new DecimalType(longitude.doubleValue())));
170                 }
171             } catch (RenaultNotImplementedException e) {
172                 car.setDisableLocation(true);
173             } catch (RenaultForbiddenException | RenaultUpdateException e) {
174             }
175         }
176     }
177
178     private void updateCockpit(MyRenaultHttpSession httpSession) {
179         if (!car.isDisableCockpit()) {
180             try {
181                 httpSession.getCockpit(car);
182                 Double odometer = car.getOdometer();
183                 if (odometer != null) {
184                     updateState(CHANNEL_ODOMETER, new QuantityType<Length>(odometer.doubleValue(), KILO(METRE)));
185                 }
186             } catch (RenaultNotImplementedException e) {
187                 car.setDisableCockpit(true);
188             } catch (RenaultForbiddenException | RenaultUpdateException e) {
189             }
190         }
191     }
192
193     private void updateBattery(MyRenaultHttpSession httpSession) {
194         if (!car.isDisableBattery()) {
195             try {
196                 httpSession.getBatteryStatus(car);
197                 Double batteryLevel = car.getBatteryLevel();
198                 if (batteryLevel != null) {
199                     updateState(CHANNEL_BATTERY_LEVEL, new DecimalType(batteryLevel.doubleValue()));
200                 }
201             } catch (RenaultNotImplementedException e) {
202                 car.setDisableBattery(true);
203             } catch (RenaultForbiddenException | RenaultUpdateException e) {
204             }
205         }
206     }
207 }