[renault] Improve handling of HTTP 502 responses. (#14586)

Signed-off-by: Doug Culnane <doug@culnane.net>
This commit is contained in:
Doug Culnane 2023-03-13 07:51:27 +01:00 committed by GitHub
parent 9aa72abd82
commit b3d3d20b8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 29 deletions

View File

@ -26,6 +26,7 @@ import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Fields;
import org.openhab.binding.renault.internal.RenaultConfiguration; import org.openhab.binding.renault.internal.RenaultConfiguration;
import org.openhab.binding.renault.internal.api.Car.ChargingMode; import org.openhab.binding.renault.internal.api.Car.ChargingMode;
import org.openhab.binding.renault.internal.api.exceptions.RenaultAPIGatewayException;
import org.openhab.binding.renault.internal.api.exceptions.RenaultActionException; import org.openhab.binding.renault.internal.api.exceptions.RenaultActionException;
import org.openhab.binding.renault.internal.api.exceptions.RenaultException; import org.openhab.binding.renault.internal.api.exceptions.RenaultException;
import org.openhab.binding.renault.internal.api.exceptions.RenaultForbiddenException; import org.openhab.binding.renault.internal.api.exceptions.RenaultForbiddenException;
@ -202,8 +203,8 @@ public class MyRenaultHttpSession {
} }
} }
public void getVehicle(Car car) public void getVehicle(Car car) throws RenaultForbiddenException, RenaultUpdateException,
throws RenaultForbiddenException, RenaultUpdateException, RenaultNotImplementedException { RenaultNotImplementedException, RenaultAPIGatewayException {
JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId + "/vehicles/" JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId + "/vehicles/"
+ config.vin + "/details?country=" + getCountry(config)); + config.vin + "/details?country=" + getCountry(config));
if (responseJson != null) { if (responseJson != null) {
@ -211,8 +212,8 @@ public class MyRenaultHttpSession {
} }
} }
public void getBatteryStatus(Car car) public void getBatteryStatus(Car car) throws RenaultForbiddenException, RenaultUpdateException,
throws RenaultForbiddenException, RenaultUpdateException, RenaultNotImplementedException { RenaultNotImplementedException, RenaultAPIGatewayException {
JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId
+ "/kamereon/kca/car-adapter/v2/cars/" + config.vin + "/battery-status?country=" + getCountry(config)); + "/kamereon/kca/car-adapter/v2/cars/" + config.vin + "/battery-status?country=" + getCountry(config));
if (responseJson != null) { if (responseJson != null) {
@ -220,8 +221,8 @@ public class MyRenaultHttpSession {
} }
} }
public void getHvacStatus(Car car) public void getHvacStatus(Car car) throws RenaultForbiddenException, RenaultUpdateException,
throws RenaultForbiddenException, RenaultUpdateException, RenaultNotImplementedException { RenaultNotImplementedException, RenaultAPIGatewayException {
JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId
+ "/kamereon/kca/car-adapter/v1/cars/" + config.vin + "/hvac-status?country=" + getCountry(config)); + "/kamereon/kca/car-adapter/v1/cars/" + config.vin + "/hvac-status?country=" + getCountry(config));
if (responseJson != null) { if (responseJson != null) {
@ -229,8 +230,8 @@ public class MyRenaultHttpSession {
} }
} }
public void getCockpit(Car car) public void getCockpit(Car car) throws RenaultForbiddenException, RenaultUpdateException,
throws RenaultForbiddenException, RenaultUpdateException, RenaultNotImplementedException { RenaultNotImplementedException, RenaultAPIGatewayException {
JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId
+ "/kamereon/kca/car-adapter/v2/cars/" + config.vin + "/cockpit?country=" + getCountry(config)); + "/kamereon/kca/car-adapter/v2/cars/" + config.vin + "/cockpit?country=" + getCountry(config));
if (responseJson != null) { if (responseJson != null) {
@ -238,8 +239,8 @@ public class MyRenaultHttpSession {
} }
} }
public void getLocation(Car car) public void getLocation(Car car) throws RenaultForbiddenException, RenaultUpdateException,
throws RenaultForbiddenException, RenaultUpdateException, RenaultNotImplementedException { RenaultNotImplementedException, RenaultAPIGatewayException {
JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId
+ "/kamereon/kca/car-adapter/v1/cars/" + config.vin + "/location?country=" + getCountry(config)); + "/kamereon/kca/car-adapter/v1/cars/" + config.vin + "/location?country=" + getCountry(config));
if (responseJson != null) { if (responseJson != null) {
@ -247,8 +248,8 @@ public class MyRenaultHttpSession {
} }
} }
public void getLockStatus(Car car) public void getLockStatus(Car car) throws RenaultForbiddenException, RenaultUpdateException,
throws RenaultForbiddenException, RenaultUpdateException, RenaultNotImplementedException { RenaultNotImplementedException, RenaultAPIGatewayException {
JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId
+ "/kamereon/kca/car-adapter/v1/cars/" + config.vin + "/lock-status?country=" + getCountry(config)); + "/kamereon/kca/car-adapter/v1/cars/" + config.vin + "/lock-status?country=" + getCountry(config));
if (responseJson != null) { if (responseJson != null) {
@ -256,8 +257,8 @@ public class MyRenaultHttpSession {
} }
} }
public void actionHvacOn(double hvacTargetTemperature) public void actionHvacOn(double hvacTargetTemperature) throws RenaultForbiddenException,
throws RenaultForbiddenException, RenaultNotImplementedException, RenaultActionException { RenaultNotImplementedException, RenaultActionException, RenaultAPIGatewayException {
final String path = "/commerce/v1/accounts/" + kamereonaccountId + "/kamereon/kca/car-adapter/v1/cars/" final String path = "/commerce/v1/accounts/" + kamereonaccountId + "/kamereon/kca/car-adapter/v1/cars/"
+ config.vin + "/actions/hvac-start?country=" + getCountry(config); + config.vin + "/actions/hvac-start?country=" + getCountry(config);
postKamereonRequest(path, postKamereonRequest(path,
@ -265,8 +266,8 @@ public class MyRenaultHttpSession {
+ hvacTargetTemperature + "\"}}}"); + hvacTargetTemperature + "\"}}}");
} }
public void actionChargeMode(ChargingMode mode) public void actionChargeMode(ChargingMode mode) throws RenaultForbiddenException, RenaultNotImplementedException,
throws RenaultForbiddenException, RenaultNotImplementedException, RenaultActionException { RenaultActionException, RenaultAPIGatewayException {
final String apiMode = ChargingMode.SCHEDULE_MODE.equals(mode) ? CHARGING_MODE_SCHEDULE : CHARGING_MODE_ALWAYS; final String apiMode = ChargingMode.SCHEDULE_MODE.equals(mode) ? CHARGING_MODE_SCHEDULE : CHARGING_MODE_ALWAYS;
final String path = "/commerce/v1/accounts/" + kamereonaccountId + "/kamereon/kca/car-adapter/v1/cars/" final String path = "/commerce/v1/accounts/" + kamereonaccountId + "/kamereon/kca/car-adapter/v1/cars/"
+ config.vin + "/actions/charge-mode?country=" + getCountry(config); + config.vin + "/actions/charge-mode?country=" + getCountry(config);
@ -274,8 +275,8 @@ public class MyRenaultHttpSession {
"{\"data\":{\"type\":\"ChargeMode\",\"attributes\":{\"action\":\"" + apiMode + "\"}}}"); "{\"data\":{\"type\":\"ChargeMode\",\"attributes\":{\"action\":\"" + apiMode + "\"}}}");
} }
public void actionPause(boolean mode) public void actionPause(boolean mode) throws RenaultForbiddenException, RenaultNotImplementedException,
throws RenaultForbiddenException, RenaultNotImplementedException, RenaultActionException { RenaultActionException, RenaultAPIGatewayException {
final String apiMode = mode ? "pause" : "resume"; final String apiMode = mode ? "pause" : "resume";
final String path = "/commerce/v1/accounts/" + kamereonaccountId + "/kamereon/kcm/v1/vehicles/" + config.vin final String path = "/commerce/v1/accounts/" + kamereonaccountId + "/kamereon/kcm/v1/vehicles/" + config.vin
@ -284,8 +285,8 @@ public class MyRenaultHttpSession {
"{\"data\":{\"type\":\"ChargePauseResume\",\"attributes\":{\"action\":\"" + apiMode + "\"}}}"); "{\"data\":{\"type\":\"ChargePauseResume\",\"attributes\":{\"action\":\"" + apiMode + "\"}}}");
} }
private void postKamereonRequest(final String path, final String content) private void postKamereonRequest(final String path, final String content) throws RenaultForbiddenException,
throws RenaultForbiddenException, RenaultNotImplementedException, RenaultActionException { RenaultNotImplementedException, RenaultActionException, RenaultAPIGatewayException {
Request request = httpClient.newRequest(this.constants.getKamereonRootUrl() + path).method(HttpMethod.POST) Request request = httpClient.newRequest(this.constants.getKamereonRootUrl() + path).method(HttpMethod.POST)
.header("Content-type", "application/vnd.api+json").header("apikey", this.config.kamereonApiKey) .header("Content-type", "application/vnd.api+json").header("apikey", this.config.kamereonApiKey)
.header("x-kamereon-authorization", "Bearer " + kamereonToken).header("x-gigya-id_token", jwt) .header("x-kamereon-authorization", "Bearer " + kamereonToken).header("x-gigya-id_token", jwt)
@ -302,8 +303,8 @@ public class MyRenaultHttpSession {
} }
} }
private @Nullable JsonObject getKamereonResponse(String path) private @Nullable JsonObject getKamereonResponse(String path) throws RenaultForbiddenException,
throws RenaultForbiddenException, RenaultNotImplementedException, RenaultUpdateException { RenaultNotImplementedException, RenaultUpdateException, RenaultAPIGatewayException {
Request request = httpClient.newRequest(this.constants.getKamereonRootUrl() + path).method(HttpMethod.GET) Request request = httpClient.newRequest(this.constants.getKamereonRootUrl() + path).method(HttpMethod.GET)
.header("Content-type", "application/vnd.api+json").header("apikey", this.config.kamereonApiKey) .header("Content-type", "application/vnd.api+json").header("apikey", this.config.kamereonApiKey)
.header("x-kamereon-authorization", "Bearer " + kamereonToken).header("x-gigya-id_token", jwt); .header("x-kamereon-authorization", "Bearer " + kamereonToken).header("x-gigya-id_token", jwt);
@ -336,7 +337,7 @@ public class MyRenaultHttpSession {
} }
private void checkResponse(ContentResponse response) private void checkResponse(ContentResponse response)
throws RenaultForbiddenException, RenaultNotImplementedException { throws RenaultForbiddenException, RenaultNotImplementedException, RenaultAPIGatewayException {
switch (response.getStatus()) { switch (response.getStatus()) {
case HttpStatus.FORBIDDEN_403: case HttpStatus.FORBIDDEN_403:
throw new RenaultForbiddenException( throw new RenaultForbiddenException(
@ -346,7 +347,7 @@ public class MyRenaultHttpSession {
case HttpStatus.NOT_IMPLEMENTED_501: case HttpStatus.NOT_IMPLEMENTED_501:
throw new RenaultNotImplementedException("Kamereon request not implemented"); throw new RenaultNotImplementedException("Kamereon request not implemented");
case HttpStatus.BAD_GATEWAY_502: case HttpStatus.BAD_GATEWAY_502:
throw new RenaultNotImplementedException("Kamereon request failed"); throw new RenaultAPIGatewayException("Kamereon request failed");
default: default:
break; break;
} }

View File

@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.renault.internal.api.exceptions;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Exception thrown while trying to access the My Renault service which
* is unavailable temporarily
*
* @author Doug Culnane - Initial contribution
*/
@NonNullByDefault
public class RenaultAPIGatewayException extends RenaultException {
private static final long serialVersionUID = 1L;
public RenaultAPIGatewayException(String message) {
super(message);
}
}

View File

@ -37,6 +37,7 @@ import org.openhab.binding.renault.internal.RenaultConfiguration;
import org.openhab.binding.renault.internal.api.Car; import org.openhab.binding.renault.internal.api.Car;
import org.openhab.binding.renault.internal.api.Car.ChargingMode; import org.openhab.binding.renault.internal.api.Car.ChargingMode;
import org.openhab.binding.renault.internal.api.MyRenaultHttpSession; import org.openhab.binding.renault.internal.api.MyRenaultHttpSession;
import org.openhab.binding.renault.internal.api.exceptions.RenaultAPIGatewayException;
import org.openhab.binding.renault.internal.api.exceptions.RenaultActionException; import org.openhab.binding.renault.internal.api.exceptions.RenaultActionException;
import org.openhab.binding.renault.internal.api.exceptions.RenaultException; import org.openhab.binding.renault.internal.api.exceptions.RenaultException;
import org.openhab.binding.renault.internal.api.exceptions.RenaultForbiddenException; import org.openhab.binding.renault.internal.api.exceptions.RenaultForbiddenException;
@ -292,7 +293,7 @@ public class RenaultHandler extends BaseThingHandler {
} catch (RenaultNotImplementedException e) { } catch (RenaultNotImplementedException e) {
logger.warn("Disabling unsupported HVAC status update."); logger.warn("Disabling unsupported HVAC status update.");
car.setDisableHvac(true); car.setDisableHvac(true);
} catch (RenaultForbiddenException | RenaultUpdateException e) { } catch (RenaultForbiddenException | RenaultUpdateException | RenaultAPIGatewayException e) {
logger.warn("Error updating HVAC status.", e); logger.warn("Error updating HVAC status.", e);
} }
} }
@ -315,7 +316,8 @@ public class RenaultHandler extends BaseThingHandler {
} catch (RenaultNotImplementedException e) { } catch (RenaultNotImplementedException e) {
logger.warn("Disabling unsupported location update."); logger.warn("Disabling unsupported location update.");
car.setDisableLocation(true); car.setDisableLocation(true);
} catch (IllegalArgumentException | RenaultForbiddenException | RenaultUpdateException e) { } catch (IllegalArgumentException | RenaultForbiddenException | RenaultUpdateException
| RenaultAPIGatewayException e) {
logger.warn("Error updating location.", e); logger.warn("Error updating location.", e);
} }
} }
@ -332,7 +334,7 @@ public class RenaultHandler extends BaseThingHandler {
} catch (RenaultNotImplementedException e) { } catch (RenaultNotImplementedException e) {
logger.warn("Disabling unsupported cockpit status update."); logger.warn("Disabling unsupported cockpit status update.");
car.setDisableCockpit(true); car.setDisableCockpit(true);
} catch (RenaultForbiddenException | RenaultUpdateException e) { } catch (RenaultForbiddenException | RenaultUpdateException | RenaultAPIGatewayException e) {
logger.warn("Error updating cockpit status.", e); logger.warn("Error updating cockpit status.", e);
} }
} }
@ -370,7 +372,7 @@ public class RenaultHandler extends BaseThingHandler {
} catch (RenaultNotImplementedException e) { } catch (RenaultNotImplementedException e) {
logger.warn("Disabling unsupported battery update."); logger.warn("Disabling unsupported battery update.");
car.setDisableBattery(true); car.setDisableBattery(true);
} catch (RenaultForbiddenException | RenaultUpdateException e) { } catch (RenaultForbiddenException | RenaultUpdateException | RenaultAPIGatewayException e) {
logger.warn("Error updating battery status.", e); logger.warn("Error updating battery status.", e);
} }
} }
@ -391,7 +393,8 @@ public class RenaultHandler extends BaseThingHandler {
updateState(CHANNEL_LOCKED, UnDefType.UNDEF); updateState(CHANNEL_LOCKED, UnDefType.UNDEF);
break; break;
} }
} catch (RenaultNotImplementedException e) { } catch (RenaultNotImplementedException | RenaultAPIGatewayException e) {
// If not supported API returns a Bad Gateway for this call.
updateState(CHANNEL_LOCKED, UnDefType.UNDEF); updateState(CHANNEL_LOCKED, UnDefType.UNDEF);
logger.warn("Disabling unsupported lock status update."); logger.warn("Disabling unsupported lock status update.");
car.setDisableLockStatus(true); car.setDisableLockStatus(true);