[groupepsa] Initial Contribution (#10332)
* Initial commit: template only Signed-off-by: Arjan Mels <github@mels.email> * Initial version Signed-off-by: Arjan Mels <github@mels.email> * Minor cleanup after rebase Signed-off-by: Arjan Mels <github@mels.email> * Corrected type "peugot" => "peugeot" Signed-off-by: Arjan Mels <github@mels.email> * Improved Exception messages Corrected URL Signed-off-by: Arjan Mels <github@mels.email> * Switched from vin to id Changed nextDelayedTime from ZonedDateTime to Duration Added vehcile etails and additional info retrieval Signed-off-by: Arjan Mels <github@mels.email> * Before rebase Signed-off-by: Arjan Mels <github@mels.email> * Various fixes Signed-off-by: Arjan Mels <github@mels.email> * Updated tests Signed-off-by: Arjan Mels <github@mels.email> * Changed double to BigDecimal to keep accuracy Added lastupdated channel Small corrections Signed-off-by: Arjan Mels <github@mels.email> * Updated to 3.1.0-SNAPSHOT Signed-off-by: Arjan Mels <github@mels.email> * Added README.md Signed-off-by: Arjan Mels <github@mels.email> * Changed channels to lowerCamelCase Signed-off-by: Arjan Mels <github@mels.email> * Minor corrections Signed-off-by: Arjan Mels <github@mels.email> * Corrected lastUpdated in thing-types.xml Signed-off-by: Arjan Mels <github@mels.email> * Fixed ToStringbuilder Signed-off-by: Arjan Mels <github@mels.email> * corrected capitalization in thing-types.xml and Constants Signed-off-by: Arjan Mels <github@mels.email> * Corrected URL for Citroen Signed-off-by: Arjan Mels <github@mels.email> * Added groupepsa binding to bom pom.xml Signed-off-by: Arjan Mels <github@mels.email> * Updated copyrights Signed-off-by: Arjan Mels <github@mels.email> * Fixed CheckStyle warnings Signed-off-by: Arjan Mels <github@mels.email> * Fixed check style notifications Signed-off-by: Arjan Mels <github@mels.email> * Updated readme Signed-off-by: Arjan Mels <github@mels.email> * Corrected capitalization of thing-types.xml Signed-off-by: Arjan Mels <github@mels.email> * Updated pom. xml to 3.3.0-SNAPSHOT Signed-off-by: Arjan Mels <github@mels.email> * Updated copyright messages Signed-off-by: Arjan Mels <github@mels.email> * Various minor cleanups Cleanup of the README.md Removed unnecessary license header form the feature.xml file Various null annotation corrections Further cleanup of thing-types.xml Cleanup of groupepsa.properties Signed-off-by: Arjan Mels <github@mels.email> * Logging updates Signed-off-by: Arjan Mels <github@mels.email> * Updated dependencies Added dependencies to NOTICE Signed-off-by: Arjan Mels <github@mels.email> * Ignore lastposition for isConnected check Signed-off-by: Arjan Mels <github@mels.email> * Updated to use ThingHandlerService Signed-off-by: Arjan Mels <github@mels.email> * Fixed various review findings Signed-off-by: Arjan Mels <github@mels.email> Co-authored-by: Arjan Mels <github@mels.email>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.groupepsa-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-groupepsa" description="Groupe PSA Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.groupepsa/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link GroupePSABindingConstants} class defines common constants, which
|
||||
* are used across the whole binding.
|
||||
*
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GroupePSABindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "groupepsa";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, "bridge");
|
||||
public static final ThingTypeUID THING_TYPE_VEHICLE = new ThingTypeUID(BINDING_ID, "vehicle");
|
||||
|
||||
// Vehicle properties
|
||||
public static final String VEHICLE_ID = "id";
|
||||
public static final String VEHICLE_VIN = "vin";
|
||||
public static final String VEHICLE_VENDOR = "vendor";
|
||||
public static final String VEHICLE_MODEL = "model";
|
||||
|
||||
// List of all Channel ids
|
||||
public static final String CHANNEL_BATTERY_CURRENT = "battery#current";
|
||||
public static final String CHANNEL_BATTERY_VOLTAGE = "battery#voltage";
|
||||
|
||||
public static final String CHANNEL_TYPE_DOORLOCK = "doorLock";
|
||||
public static final String CHANNEL_TYPE_DOOROPEN = "doorOpen";
|
||||
|
||||
public static final String CHANNEL_GROUP_DOORS = "doors";
|
||||
public static final String CHANNEL_DOORS_LOCK = "doors#locked";
|
||||
|
||||
public static final String CHANNEL_ENVIRONMENT_TEMPERATURE = "environment#temperature";
|
||||
public static final String CHANNEL_ENVIRONMENT_DAYTIME = "environment#daytime";
|
||||
|
||||
public static final String CHANNEL_MOTION_IGNITION = "motion#ignition";
|
||||
public static final String CHANNEL_MOTION_ACCELERATION = "motion#acceleration";
|
||||
public static final String CHANNEL_MOTION_MOVING = "motion#moving";
|
||||
public static final String CHANNEL_MOTION_SPEED = "motion#speed";
|
||||
public static final String CHANNEL_MOTION_MILEAGE = "motion#mileage";
|
||||
|
||||
public static final String CHANNEL_POSITION_POSITION = "position#position";
|
||||
public static final String CHANNEL_POSITION_HEADING = "position#heading";
|
||||
public static final String CHANNEL_POSITION_TYPE = "position#type";
|
||||
public static final String CHANNEL_POSITION_SIGNALSTRENGTH = "position#signal";
|
||||
|
||||
public static final String CHANNEL_VARIOUS_LAST_UPDATED = "various#lastUpdated";
|
||||
public static final String CHANNEL_VARIOUS_PRIVACY = "various#privacy";
|
||||
public static final String CHANNEL_VARIOUS_BELT = "various#belt";
|
||||
public static final String CHANNEL_VARIOUS_EMERGENCY = "various#emergency";
|
||||
public static final String CHANNEL_VARIOUS_SERVICE = "various#service";
|
||||
public static final String CHANNEL_VARIOUS_PRECONDITINING = "various#preconditioning";
|
||||
public static final String CHANNEL_VARIOUS_PRECONDITINING_FAILURE = "various#preconditioningFailure";
|
||||
|
||||
public static final String CHANNEL_FUEL_AUTONOMY = "fuel#autonomy";
|
||||
public static final String CHANNEL_FUEL_CONSUMPTION = "fuel#consumption";
|
||||
public static final String CHANNEL_FUEL_LEVEL = "fuel#level";
|
||||
|
||||
public static final String CHANNEL_ELECTRIC_AUTONOMY = "electric#autonomy";
|
||||
public static final String CHANNEL_ELECTRIC_LEVEL = "electric#level";
|
||||
public static final String CHANNEL_ELECTRIC_RESIDUAL = "electric#residual";
|
||||
|
||||
public static final String CHANNEL_ELECTRIC_BATTERY_CAPACITY = "electric#batteryCapacity";
|
||||
public static final String CHANNEL_ELECTRIC_BATTERY_HEALTH_CAPACITY = "electric#batteryHealthCapacity";
|
||||
public static final String CHANNEL_ELECTRIC_BATTERY_HEALTH_RESISTANCE = "electric#batteryHealthResistance";
|
||||
|
||||
public static final String CHANNEL_ELECTRIC_CHARGING_STATUS = "electric#chargingStatus";
|
||||
public static final String CHANNEL_ELECTRIC_CHARGING_MODE = "electric#chargingMode";
|
||||
public static final String CHANNEL_ELECTRIC_CHARGING_PLUGGED = "electric#chargingPlugged";
|
||||
public static final String CHANNEL_ELECTRIC_CHARGING_RATE = "electric#chargingRate";
|
||||
public static final String CHANNEL_ELECTRIC_CHARGING_REMAININGTIME = "electric#chargingRemainingTime";
|
||||
public static final String CHANNEL_ELECTRIC_CHARGING_NEXTDELAYEDTIME = "electric#chargingNextDelayedTime";
|
||||
|
||||
public enum VendorConstants {
|
||||
PEUGEOT("https://idpcvs.peugeot.com/am/oauth2/access_token", "clientsB2CPeugeot"),
|
||||
CITROEN("https://idpcvs.citroen.com/am/oauth2/access_token", "clientsB2CCitroen"),
|
||||
DS("https://idpcvs.driveds.com/am/oauth2/access_token", "clientsB2CDS"),
|
||||
OPEL("https://idpcvs.opel.com/am/oauth2/access_token", "clientsB2COpel"),
|
||||
VAUXHALL("https://idpcvs.vauxhall.co.uk/am/oauth2/access_token", "clientsB2CVauxhall");
|
||||
|
||||
public final String url;
|
||||
public final String realm;
|
||||
public final String scope;
|
||||
|
||||
VendorConstants(String url, String realm) {
|
||||
this.url = url;
|
||||
this.realm = realm;
|
||||
this.scope = "profile openid";
|
||||
}
|
||||
}
|
||||
|
||||
public static final String API_URL = "https://api.groupe-psa.com/connectedcar/v4";
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal;
|
||||
|
||||
import static org.openhab.binding.groupepsa.internal.GroupePSABindingConstants.*;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.groupepsa.internal.bridge.GroupePSABridgeHandler;
|
||||
import org.openhab.binding.groupepsa.internal.things.GroupePSAHandler;
|
||||
import org.openhab.core.auth.client.oauth2.OAuthFactory;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* The {@link GroupePSAHandlerFactory} is responsible for creating things and
|
||||
* thing handlers.
|
||||
*
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.groupepsa", service = ThingHandlerFactory.class)
|
||||
public class GroupePSAHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_BRIDGE, THING_TYPE_VEHICLE);
|
||||
|
||||
private final OAuthFactory oAuthFactory;
|
||||
protected final HttpClient httpClient;
|
||||
|
||||
@Activate
|
||||
public GroupePSAHandlerFactory(@Reference OAuthFactory oAuthFactory,
|
||||
@Reference HttpClientFactory httpClientFactory) {
|
||||
this.oAuthFactory = oAuthFactory;
|
||||
this.httpClient = httpClientFactory.getCommonHttpClient();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (THING_TYPE_VEHICLE.equals(thingTypeUID)) {
|
||||
return new GroupePSAHandler(thing);
|
||||
} else if (THING_TYPE_BRIDGE.equals(thingTypeUID)) {
|
||||
return new GroupePSABridgeHandler((Bridge) thing, oAuthFactory, httpClient);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link GroupePSABridgeConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public final class GroupePSABridgeConfiguration {
|
||||
private String vendor = "";
|
||||
private String userName = "";
|
||||
private String password = "";
|
||||
private String clientId = "";
|
||||
private String clientSecret = "";
|
||||
|
||||
private Integer pollingInterval = 5;
|
||||
|
||||
/**
|
||||
* @return The polling interval for the groupepsa state in s
|
||||
*/
|
||||
public Integer getPollingInterval() {
|
||||
return pollingInterval;
|
||||
}
|
||||
|
||||
public void setPollingInterval(Integer pollingInterval) {
|
||||
this.pollingInterval = pollingInterval;
|
||||
}
|
||||
|
||||
public String getVendor() {
|
||||
return vendor;
|
||||
}
|
||||
|
||||
public void setVendor(String vendor) {
|
||||
this.vendor = vendor;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public String getClientSecret() {
|
||||
return clientSecret;
|
||||
}
|
||||
|
||||
public void setClientSecret(String clientSecret) {
|
||||
this.clientSecret = clientSecret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.bridge;
|
||||
|
||||
import static org.openhab.binding.groupepsa.internal.GroupePSABindingConstants.THING_TYPE_BRIDGE;
|
||||
import static org.openhab.binding.groupepsa.internal.GroupePSABindingConstants.VendorConstants;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.groupepsa.internal.discovery.GroupePSADiscoveryService;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.GroupePSAConnectApi;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Vehicle;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.VehicleStatus;
|
||||
import org.openhab.binding.groupepsa.internal.rest.exceptions.GroupePSACommunicationException;
|
||||
import org.openhab.core.auth.client.oauth2.AccessTokenResponse;
|
||||
import org.openhab.core.auth.client.oauth2.OAuthClientService;
|
||||
import org.openhab.core.auth.client.oauth2.OAuthException;
|
||||
import org.openhab.core.auth.client.oauth2.OAuthFactory;
|
||||
import org.openhab.core.auth.client.oauth2.OAuthResponseException;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.openhab.core.types.Command;
|
||||
|
||||
/**
|
||||
* The {@link GroupePSABridgeHandler} is responsible for handling commands,
|
||||
* which are sent to one of the channels.
|
||||
*
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GroupePSABridgeHandler extends BaseBridgeHandler {
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_BRIDGE);
|
||||
private static final long DEFAULT_POLLING_INTERVAL_M = TimeUnit.HOURS.toMinutes(1);
|
||||
|
||||
private final OAuthFactory oAuthFactory;
|
||||
|
||||
private @Nullable OAuthClientService oAuthService;
|
||||
private @Nullable ScheduledFuture<?> groupepsaBridgePollingJob;
|
||||
private final HttpClient httpClient;
|
||||
|
||||
private String vendor = "";
|
||||
private @Nullable VendorConstants vendorConstants;
|
||||
private String userName = "";
|
||||
private String password = "";
|
||||
private String clientId = "";
|
||||
private String clientSecret = "";
|
||||
|
||||
private @Nullable GroupePSAConnectApi groupePSAApi;
|
||||
|
||||
public GroupePSABridgeHandler(Bridge bridge, OAuthFactory oAuthFactory, HttpClient httpClient) {
|
||||
super(bridge);
|
||||
this.oAuthFactory = oAuthFactory;
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
private void pollGroupePSAs() {
|
||||
try {
|
||||
List<Vehicle> vehicles = getVehicles();
|
||||
if (vehicles != null) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"@text/comm-error-query-vehicles-failed");
|
||||
}
|
||||
} catch (GroupePSACommunicationException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
stopGroupePSABridgePolling();
|
||||
oAuthFactory.ungetOAuthService(thing.getUID().getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
GroupePSABridgeConfiguration bridgeConfiguration = getConfigAs(GroupePSABridgeConfiguration.class);
|
||||
|
||||
vendor = bridgeConfiguration.getVendor();
|
||||
userName = bridgeConfiguration.getUserName();
|
||||
password = bridgeConfiguration.getPassword();
|
||||
clientId = bridgeConfiguration.getClientId();
|
||||
clientSecret = bridgeConfiguration.getClientSecret();
|
||||
|
||||
final Integer pollingIntervalM = bridgeConfiguration.getPollingInterval();
|
||||
|
||||
if (vendor.isEmpty()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/conf-error-no-vendor");
|
||||
} else if (userName.isEmpty()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/conf-error-no-username");
|
||||
} else if (password.isEmpty()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/conf-error-no-password");
|
||||
} else if (clientId.isEmpty()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/conf-error-no-clientid");
|
||||
} else if (clientSecret.isEmpty()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/conf-error-no-clientsecret");
|
||||
} else if (pollingIntervalM < 1) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/conf-error-invalid-polling-interval");
|
||||
} else {
|
||||
VendorConstants localVendorConstants = VendorConstants.valueOf(vendor);
|
||||
vendorConstants = localVendorConstants;
|
||||
|
||||
oAuthService = oAuthFactory.createOAuthClientService(thing.getUID().getAsString(), localVendorConstants.url,
|
||||
null, clientId, clientSecret, localVendorConstants.scope, true);
|
||||
|
||||
groupePSAApi = new GroupePSAConnectApi(httpClient, this, clientId, localVendorConstants.realm);
|
||||
|
||||
startGroupePSABridgePolling(pollingIntervalM);
|
||||
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
private void startGroupePSABridgePolling(@Nullable Integer pollingIntervalM) {
|
||||
if (groupepsaBridgePollingJob == null) {
|
||||
final long pollingIntervalToUse = pollingIntervalM == null ? DEFAULT_POLLING_INTERVAL_M : pollingIntervalM;
|
||||
groupepsaBridgePollingJob = scheduler.scheduleWithFixedDelay(() -> pollGroupePSAs(), 1,
|
||||
TimeUnit.MINUTES.toSeconds(pollingIntervalToUse), TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void stopGroupePSABridgePolling() {
|
||||
final ScheduledFuture<?> job = groupepsaBridgePollingJob;
|
||||
if (job != null) {
|
||||
job.cancel(true);
|
||||
groupepsaBridgePollingJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
|
||||
static Throwable getRootCause(Throwable e) {
|
||||
Throwable nextE;
|
||||
do {
|
||||
nextE = e.getCause();
|
||||
if (nextE != null) {
|
||||
e = nextE;
|
||||
}
|
||||
} while (nextE != null);
|
||||
return e;
|
||||
}
|
||||
|
||||
public String authenticate() throws GroupePSACommunicationException {
|
||||
OAuthClientService localOAuthService = oAuthService;
|
||||
VendorConstants localVendorConstants = vendorConstants;
|
||||
if (localOAuthService == null) {
|
||||
throw new GroupePSACommunicationException("OAuth service is unexpectedly null");
|
||||
}
|
||||
if (localVendorConstants == null) {
|
||||
throw new GroupePSACommunicationException("Vendor constants are unexpectedly null");
|
||||
}
|
||||
try {
|
||||
AccessTokenResponse result = localOAuthService.getAccessTokenResponse();
|
||||
if (result == null) {
|
||||
result = localOAuthService.getAccessTokenByResourceOwnerPasswordCredentials(userName, password,
|
||||
localVendorConstants.scope);
|
||||
}
|
||||
return result.getAccessToken();
|
||||
} catch (OAuthException | IOException | OAuthResponseException e) {
|
||||
throw new GroupePSACommunicationException("Unable to authenticate: " + getRootCause(e).getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public GroupePSAConnectApi getAPI() throws GroupePSACommunicationException {
|
||||
GroupePSAConnectApi localGroupePSAApi = groupePSAApi;
|
||||
if (localGroupePSAApi == null) {
|
||||
throw new GroupePSACommunicationException("groupePSAApi is unexpectedly null");
|
||||
} else {
|
||||
return localGroupePSAApi;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A list of vehicles
|
||||
* @throws GroupePSACommunicationException In case the query cannot be executed
|
||||
* successfully
|
||||
*/
|
||||
public @Nullable List<Vehicle> getVehicles() throws GroupePSACommunicationException {
|
||||
return getAPI().getVehicles();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id The id of the mower to query
|
||||
* @return A detailed status of the mower with the specified id
|
||||
* @throws GroupePSACommunicationException In case the query cannot be executed
|
||||
* successfully
|
||||
*/
|
||||
public @Nullable VehicleStatus getVehicleStatus(String vin) throws GroupePSACommunicationException {
|
||||
return getAPI().getVehicleStatus(vin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||
return Collections.singleton(GroupePSADiscoveryService.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.groupepsa.internal.GroupePSABindingConstants.THING_TYPE_VEHICLE;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.groupepsa.internal.GroupePSABindingConstants;
|
||||
import org.openhab.binding.groupepsa.internal.bridge.GroupePSABridgeHandler;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Vehicle;
|
||||
import org.openhab.binding.groupepsa.internal.rest.exceptions.GroupePSACommunicationException;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link GroupePSADiscoveryService} is responsible for discovering new
|
||||
* vehicles available for the configured app key.
|
||||
*
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@Component(service = ThingHandlerService.class)
|
||||
@NonNullByDefault
|
||||
public class GroupePSADiscoveryService extends AbstractDiscoveryService implements ThingHandlerService {
|
||||
private final Logger logger = LoggerFactory.getLogger(GroupePSADiscoveryService.class);
|
||||
|
||||
private @Nullable GroupePSABridgeHandler bridgeHandler;
|
||||
|
||||
public GroupePSADiscoveryService() {
|
||||
super(Collections.singleton(THING_TYPE_VEHICLE), 10, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
if (handler instanceof GroupePSABridgeHandler) {
|
||||
bridgeHandler = (GroupePSABridgeHandler) handler;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return bridgeHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
super.deactivate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
try {
|
||||
GroupePSABridgeHandler localBridgeHandler = bridgeHandler;
|
||||
if (localBridgeHandler == null) {
|
||||
return;
|
||||
}
|
||||
List<Vehicle> vehicles = localBridgeHandler.getVehicles();
|
||||
if (vehicles == null || vehicles.isEmpty()) {
|
||||
logger.warn("No vehicles found");
|
||||
return;
|
||||
}
|
||||
for (Vehicle vehicle : vehicles) {
|
||||
ThingUID bridgeUID = localBridgeHandler.getThing().getUID();
|
||||
ThingTypeUID thingTypeUID = THING_TYPE_VEHICLE;
|
||||
String id = vehicle.getId();
|
||||
if (id != null) {
|
||||
ThingUID vehicleThingUid = new ThingUID(THING_TYPE_VEHICLE, bridgeUID, id);
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
putProperty(properties, GroupePSABindingConstants.VEHICLE_ID, id);
|
||||
putProperty(properties, GroupePSABindingConstants.VEHICLE_VIN, vehicle.getVin());
|
||||
putProperty(properties, GroupePSABindingConstants.VEHICLE_VENDOR, vehicle.getBrand());
|
||||
putProperty(properties, GroupePSABindingConstants.VEHICLE_MODEL, vehicle.getLabel());
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(vehicleThingUid)
|
||||
.withThingType(thingTypeUID).withProperties(properties).withBridge(bridgeUID)
|
||||
.withRepresentationProperty(GroupePSABindingConstants.VEHICLE_VIN)
|
||||
.withLabel(vehicle.getBrand() + " (" + vehicle.getVin() + ")").build();
|
||||
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
}
|
||||
} catch (GroupePSACommunicationException e) {
|
||||
logger.warn("No vehicles found", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void putProperty(Map<String, Object> properties, String key, @Nullable String value) {
|
||||
if (value == null) {
|
||||
value = "Unknown";
|
||||
}
|
||||
properties.put(key, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api;
|
||||
|
||||
import static org.openhab.binding.groupepsa.internal.GroupePSABindingConstants.API_URL;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.time.Duration;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.openhab.binding.groupepsa.internal.bridge.GroupePSABridgeHandler;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.ErrorObject;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.User;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Vehicle;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.VehicleStatus;
|
||||
import org.openhab.binding.groupepsa.internal.rest.exceptions.GroupePSACommunicationException;
|
||||
import org.openhab.binding.groupepsa.internal.rest.exceptions.UnauthorizedException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.filosganga.geogson.gson.GeometryAdapterFactory;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* Allows access to the GroupePSAConnectApi
|
||||
*
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GroupePSAConnectApi {
|
||||
private final Logger logger = LoggerFactory.getLogger(GroupePSAConnectApi.class);
|
||||
|
||||
private final HttpClient httpClient;
|
||||
private final GroupePSABridgeHandler bridge;
|
||||
private final String clientId;
|
||||
private final String realm;
|
||||
|
||||
protected final Gson gson;
|
||||
|
||||
public GroupePSAConnectApi(HttpClient httpClient, GroupePSABridgeHandler bridge, String clientId, String realm) {
|
||||
this.httpClient = httpClient;
|
||||
this.bridge = bridge;
|
||||
this.clientId = clientId;
|
||||
this.realm = realm;
|
||||
|
||||
gson = new GsonBuilder().registerTypeAdapterFactory(new GeometryAdapterFactory())
|
||||
.registerTypeAdapter(ZonedDateTime.class, new JsonDeserializer<ZonedDateTime>() {
|
||||
@Override
|
||||
public @Nullable ZonedDateTime deserialize(JsonElement json, Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
return ZonedDateTime.parse(json.getAsJsonPrimitive().getAsString());
|
||||
}
|
||||
}).registerTypeAdapter(Duration.class, new JsonDeserializer<Duration>() {
|
||||
@Override
|
||||
public @Nullable Duration deserialize(JsonElement json, Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
return Duration.parse(json.getAsJsonPrimitive().getAsString());
|
||||
}
|
||||
}).create();
|
||||
}
|
||||
|
||||
protected HttpClient getHttpClient() {
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
protected GroupePSABridgeHandler getBridge() {
|
||||
return bridge;
|
||||
}
|
||||
|
||||
public String getBaseUrl() {
|
||||
return API_URL;
|
||||
}
|
||||
|
||||
private ContentResponse executeRequest(final String uri) throws GroupePSACommunicationException {
|
||||
return executeRequest(uri, "application/hal+json");
|
||||
}
|
||||
|
||||
static Throwable getRootCause(Throwable e) {
|
||||
Throwable nextE;
|
||||
do {
|
||||
nextE = e.getCause();
|
||||
if (nextE != null) {
|
||||
e = nextE;
|
||||
}
|
||||
} while (nextE != null);
|
||||
return e;
|
||||
}
|
||||
|
||||
public ContentResponse executeRequest(final String uri, final String accept)
|
||||
throws GroupePSACommunicationException {
|
||||
Request request = getHttpClient().newRequest(uri);
|
||||
|
||||
String token = getBridge().authenticate();
|
||||
|
||||
request.timeout(10, TimeUnit.SECONDS);
|
||||
|
||||
request.param("client_id", this.clientId);
|
||||
|
||||
request.header("Authorization", "Bearer " + token);
|
||||
request.header("Accept", accept);
|
||||
request.header("x-introspect-realm", this.realm);
|
||||
|
||||
request.method(HttpMethod.GET);
|
||||
|
||||
logger.trace("HttpRequest {}", request.getURI());
|
||||
logger.trace("HttpRequest Headers:\n{}", request.getHeaders());
|
||||
|
||||
try {
|
||||
ContentResponse response = request.send();
|
||||
logger.trace("HttpResponse {}", response);
|
||||
logger.trace("HttpResponse Headers:\n{}", response.getHeaders());
|
||||
logger.trace("HttpResponse Content: {}", response.getContentAsString());
|
||||
return response;
|
||||
} catch (InterruptedException | TimeoutException | ExecutionException e) {
|
||||
throw new GroupePSACommunicationException("Unable to perform Http Request: " + getRootCause(e).getMessage(),
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkForError(ContentResponse response, int statusCode) throws GroupePSACommunicationException {
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (statusCode) {
|
||||
case HttpStatus.NOT_FOUND_404:
|
||||
ErrorObject error = gson.fromJson(response.getContentAsString(), ErrorObject.class);
|
||||
String message = (error != null) ? error.getMessage() : null;
|
||||
if (message == null) {
|
||||
message = "Unknown";
|
||||
}
|
||||
throw new GroupePSACommunicationException(statusCode, message);
|
||||
|
||||
case HttpStatus.FORBIDDEN_403:
|
||||
case HttpStatus.UNAUTHORIZED_401:
|
||||
throw new UnauthorizedException(statusCode, response.getContentAsString());
|
||||
|
||||
default:
|
||||
throw new GroupePSACommunicationException(statusCode, response.getContentAsString());
|
||||
}
|
||||
}
|
||||
|
||||
private <T> @Nullable T parseResponse(ContentResponse response, Class<T> type)
|
||||
throws GroupePSACommunicationException {
|
||||
int statusCode = response.getStatus();
|
||||
|
||||
checkForError(response, statusCode);
|
||||
|
||||
try {
|
||||
return gson.fromJson(response.getContentAsString(), type);
|
||||
} catch (JsonSyntaxException e) {
|
||||
throw new GroupePSACommunicationException("Error in received JSON: " + getRootCause(e).getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable List<Vehicle> getVehicles() throws GroupePSACommunicationException {
|
||||
ContentResponse response = executeRequest(getBaseUrl() + "/user");
|
||||
User user = parseResponse(response, User.class);
|
||||
|
||||
if (user != null) {
|
||||
return user.getVehicles();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable VehicleStatus getVehicleStatus(String vin) throws GroupePSACommunicationException {
|
||||
ContentResponse responseOdometer = executeRequest(getBaseUrl() + "/user/vehicles/" + vin + "/status");
|
||||
VehicleStatus status = parseResponse(responseOdometer, VehicleStatus.class);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Air {
|
||||
|
||||
private @Nullable BigDecimal temp;
|
||||
|
||||
public @Nullable BigDecimal getTemp() {
|
||||
return temp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("temp", temp).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AirConditioning {
|
||||
|
||||
private @Nullable String failureCause;
|
||||
private @Nullable List<Program> programs = null;
|
||||
private @Nullable String status;
|
||||
private @Nullable ZonedDateTime updatedAt;
|
||||
|
||||
public @Nullable String getFailureCause() {
|
||||
return failureCause;
|
||||
}
|
||||
|
||||
public @Nullable List<Program> getPrograms() {
|
||||
return programs;
|
||||
}
|
||||
|
||||
public @Nullable String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public @Nullable ZonedDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("failureCause", failureCause).append("programs", programs)
|
||||
.append("status", status).append("updatedAt", updatedAt).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Battery {
|
||||
|
||||
private @Nullable ZonedDateTime createdAt;
|
||||
private @Nullable BigDecimal current;
|
||||
private @Nullable BigDecimal voltage;
|
||||
|
||||
public @Nullable ZonedDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getVoltage() {
|
||||
return voltage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("createdAt", createdAt).append("current", current)
|
||||
.append("voltage", voltage).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BatteryStatus {
|
||||
|
||||
private @Nullable BigDecimal capacity;
|
||||
private @Nullable Health health;
|
||||
|
||||
public @Nullable BigDecimal getCapacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
public @Nullable Health getHealth() {
|
||||
return health;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("capacity", capacity).append("health", health).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Charging {
|
||||
|
||||
private @Nullable String chargingMode;
|
||||
private @Nullable BigDecimal chargingRate;
|
||||
private @Nullable Duration nextDelayedTime;
|
||||
private @Nullable Boolean plugged;
|
||||
private @Nullable Duration remainingTime;
|
||||
private @Nullable String status;
|
||||
|
||||
public @Nullable String getChargingMode() {
|
||||
return chargingMode;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getChargingRate() {
|
||||
return chargingRate;
|
||||
}
|
||||
|
||||
public void setChargingRate(BigDecimal chargingRate) {
|
||||
this.chargingRate = chargingRate;
|
||||
}
|
||||
|
||||
public @Nullable Duration getNextDelayedTime() {
|
||||
return nextDelayedTime;
|
||||
}
|
||||
|
||||
public @Nullable Boolean isPlugged() {
|
||||
return plugged;
|
||||
}
|
||||
|
||||
public @Nullable Duration getRemainingTime() {
|
||||
return remainingTime;
|
||||
}
|
||||
|
||||
public @Nullable String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("chargingMode", chargingMode).append("chargingRate", chargingRate)
|
||||
.append("nextDelayedTime", nextDelayedTime).append("plugged", plugged)
|
||||
.append("remainingTime", remainingTime).append("status", status).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DoorsState {
|
||||
|
||||
private @Nullable List<String> lockedState = null;
|
||||
private @Nullable List<Opening> opening = null;
|
||||
private @Nullable ZonedDateTime updatedAt;
|
||||
|
||||
public @Nullable List<String> getLockedState() {
|
||||
return lockedState;
|
||||
}
|
||||
|
||||
public @Nullable List<Opening> getOpening() {
|
||||
return opening;
|
||||
}
|
||||
|
||||
public @Nullable ZonedDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("lockedState", lockedState).append("opening", opening)
|
||||
.append("updatedAt", updatedAt).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Energy {
|
||||
|
||||
private @Nullable ZonedDateTime updatedAt;
|
||||
private @Nullable ZonedDateTime createdAt;
|
||||
private @Nullable BigDecimal autonomy;
|
||||
private @Nullable BatteryStatus battery;
|
||||
private @Nullable Charging charging;
|
||||
private @Nullable BigDecimal consumption;
|
||||
private @Nullable BigDecimal level;
|
||||
private @Nullable BigDecimal residual;
|
||||
private @Nullable String type;
|
||||
|
||||
public @Nullable ZonedDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public @Nullable ZonedDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getAutonomy() {
|
||||
return autonomy;
|
||||
}
|
||||
|
||||
public @Nullable BatteryStatus getBattery() {
|
||||
return battery;
|
||||
}
|
||||
|
||||
public @Nullable Charging getCharging() {
|
||||
return charging;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getConsumption() {
|
||||
return consumption;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getResidual() {
|
||||
return residual;
|
||||
}
|
||||
|
||||
public @Nullable String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("updatedAt", updatedAt).append("createdAt", createdAt)
|
||||
.append("autonomy", autonomy).append("battery", battery).append("charging", charging)
|
||||
.append("consumption", consumption).append("level", level).append("residual", residual)
|
||||
.append("type", type).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Engine {
|
||||
@SerializedName("class")
|
||||
private @Nullable String type;
|
||||
private @Nullable String energy;
|
||||
|
||||
public @Nullable String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public @Nullable String getEnergy() {
|
||||
return energy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("type", type).append("energy", energy).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Environment {
|
||||
|
||||
private @Nullable ZonedDateTime updatedAt;
|
||||
private @Nullable ZonedDateTime createdAt;
|
||||
private @Nullable Air air;
|
||||
private @Nullable Luminosity luminosity;
|
||||
|
||||
public @Nullable ZonedDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public @Nullable ZonedDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public @Nullable Air getAir() {
|
||||
return air;
|
||||
}
|
||||
|
||||
public @Nullable Luminosity getLuminosity() {
|
||||
return luminosity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("updatedAt", updatedAt).append("createdAt", createdAt)
|
||||
.append("air", air).append("luminosity", luminosity).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ErrorObject {
|
||||
private @Nullable String uuid;
|
||||
private @Nullable String code;
|
||||
private @Nullable String message;
|
||||
|
||||
public @Nullable String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public @Nullable String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public @Nullable String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("uuid", uuid).append("code", code).append("message", message)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Health {
|
||||
|
||||
private @Nullable BigDecimal capacity;
|
||||
private @Nullable BigDecimal resistance;
|
||||
|
||||
public @Nullable BigDecimal getCapacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getResistance() {
|
||||
return resistance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("capacity", capacity).append("resistance", resistance).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Ignition {
|
||||
|
||||
private @Nullable ZonedDateTime updatedAt;
|
||||
private @Nullable String type;
|
||||
|
||||
public @Nullable ZonedDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public @Nullable String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("updatedAt", updatedAt).append("type", type).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Kinetic {
|
||||
|
||||
private @Nullable ZonedDateTime createdAt;
|
||||
private @Nullable BigDecimal acceleration;
|
||||
private @Nullable Boolean moving;
|
||||
private @Nullable BigDecimal pace;
|
||||
private @Nullable BigDecimal speed;
|
||||
|
||||
public @Nullable ZonedDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getAcceleration() {
|
||||
return acceleration;
|
||||
}
|
||||
|
||||
public @Nullable Boolean isMoving() {
|
||||
return moving;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getPace() {
|
||||
return pace;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getSpeed() {
|
||||
return speed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("createdAt", createdAt).append("acceleration", acceleration)
|
||||
.append("moving", moving).append("pace", pace).append("speed", speed).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Luminosity {
|
||||
|
||||
private @Nullable Boolean day;
|
||||
|
||||
public @Nullable Boolean isDay() {
|
||||
return day;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("day", day).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Occurence {
|
||||
|
||||
private @Nullable List<String> day = null;
|
||||
private @Nullable List<String> week = null;
|
||||
|
||||
public @Nullable List<String> getDay() {
|
||||
return day;
|
||||
}
|
||||
|
||||
public @Nullable List<String> getWeek() {
|
||||
return week;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("day", day).append("week", week).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Odometer {
|
||||
|
||||
private @Nullable ZonedDateTime createdAt;
|
||||
private @Nullable BigDecimal mileage;
|
||||
|
||||
public @Nullable ZonedDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getMileage() {
|
||||
return mileage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("createdAt", createdAt).append("mileage", mileage).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Opening {
|
||||
|
||||
private @Nullable String identifier;
|
||||
private @Nullable String state;
|
||||
|
||||
public @Nullable String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public @Nullable String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("identifier", identifier).append("state", state).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.github.filosganga.geogson.model.Geometry;
|
||||
import com.github.filosganga.geogson.model.positions.SinglePosition;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Position {
|
||||
|
||||
private @Nullable ZonedDateTime updatedAt;
|
||||
private @Nullable ZonedDateTime createdAt;
|
||||
private @Nullable Geometry<SinglePosition> geometry;
|
||||
private @Nullable Properties properties;
|
||||
private @Nullable String type;
|
||||
|
||||
public @Nullable ZonedDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public @Nullable ZonedDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public @Nullable Geometry<SinglePosition> getGeometry() {
|
||||
return geometry;
|
||||
}
|
||||
|
||||
public @Nullable Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public @Nullable String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("updatedAt", updatedAt).append("createdAt", createdAt)
|
||||
.append("geometry", geometry).append("properties", properties).append("type", type).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Preconditionning {
|
||||
|
||||
private @Nullable AirConditioning airConditioning;
|
||||
|
||||
public @Nullable AirConditioning getAirConditioning() {
|
||||
return airConditioning;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("airConditioning", airConditioning).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Privacy {
|
||||
|
||||
private @Nullable ZonedDateTime createdAt;
|
||||
private @Nullable String state;
|
||||
|
||||
public @Nullable ZonedDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public @Nullable String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("createdAt", createdAt).append("state", state).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Program {
|
||||
|
||||
private @Nullable Occurence occurence;
|
||||
private @Nullable String recurrence;
|
||||
private @Nullable String start;
|
||||
private @Nullable Boolean enabled;
|
||||
private @Nullable BigDecimal slot;
|
||||
|
||||
public @Nullable Occurence getOccurence() {
|
||||
return occurence;
|
||||
}
|
||||
|
||||
public @Nullable String getRecurrence() {
|
||||
return recurrence;
|
||||
}
|
||||
|
||||
public @Nullable String getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public @Nullable Boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getSlot() {
|
||||
return slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("occurence", occurence).append("recurrence", recurrence)
|
||||
.append("start", start).append("enabled", enabled).append("slot", slot).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Properties {
|
||||
|
||||
private @Nullable BigDecimal heading;
|
||||
private @Nullable BigDecimal signalQuality;
|
||||
private @Nullable String type;
|
||||
|
||||
public @Nullable BigDecimal getHeading() {
|
||||
return heading;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getSignalQuality() {
|
||||
return signalQuality;
|
||||
}
|
||||
|
||||
public @Nullable String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("heading", heading).append("signalQuality", signalQuality)
|
||||
.append("type", type).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Safety {
|
||||
|
||||
private @Nullable ZonedDateTime createdAt;
|
||||
private @Nullable String beltWarning;
|
||||
private @Nullable String eCallTriggeringRequest;
|
||||
|
||||
public @Nullable ZonedDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public @Nullable String getBeltWarning() {
|
||||
return beltWarning;
|
||||
}
|
||||
|
||||
public @Nullable String getECallTriggeringRequest() {
|
||||
return eCallTriggeringRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("createdAt", createdAt).append("beltWarning", beltWarning)
|
||||
.append("eCallTriggeringRequest", eCallTriggeringRequest).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Service {
|
||||
|
||||
private @Nullable String type;
|
||||
private @Nullable ZonedDateTime updatedAt;
|
||||
|
||||
public @Nullable String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public @Nullable ZonedDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("type", type).append("updatedAt", updatedAt).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class ToStringBuilder implements Appendable, CharSequence {
|
||||
protected StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
ToStringBuilder(Object obj) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return stringBuilder.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
return stringBuilder.charAt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
return stringBuilder.subSequence(start, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToStringBuilder append(@Nullable CharSequence csq) throws IOException {
|
||||
if (stringBuilder.length() != 0) {
|
||||
stringBuilder.append(", ");
|
||||
}
|
||||
stringBuilder.append(csq);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToStringBuilder append(@Nullable CharSequence csq, int start, int end) throws IOException {
|
||||
if (stringBuilder.length() != 0) {
|
||||
stringBuilder.append(", ");
|
||||
}
|
||||
stringBuilder.append(csq, start, end);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToStringBuilder append(char c) throws IOException {
|
||||
if (stringBuilder.length() != 0) {
|
||||
stringBuilder.append(", ");
|
||||
}
|
||||
stringBuilder.append(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ToStringBuilder append(Object key, @Nullable Object value) {
|
||||
if (stringBuilder.length() != 0) {
|
||||
stringBuilder.append(", ");
|
||||
}
|
||||
stringBuilder.append(key.toString() + ": " + ((value == null) ? "(null)" : value.toString()));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{ " + stringBuilder.toString() + " }";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class User {
|
||||
private @Nullable String email;
|
||||
private @Nullable String firstName;
|
||||
private @Nullable String lastName;
|
||||
@SerializedName("_embedded")
|
||||
private @Nullable Embedded embedded;
|
||||
private @Nullable ZonedDateTime createdAt;
|
||||
private @Nullable ZonedDateTime updatedAt;
|
||||
|
||||
private static class Embedded {
|
||||
private @Nullable List<Vehicle> vehicles;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("vehicles", vehicles).toString();
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public @Nullable String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public @Nullable String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public @Nullable List<Vehicle> getVehicles() {
|
||||
final Embedded resEmbedded = embedded;
|
||||
if (resEmbedded != null) {
|
||||
return resEmbedded.vehicles;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable ZonedDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public @Nullable ZonedDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("createdAt", createdAt).append("updatedAt", createdAt)
|
||||
.append("email", email).append("firstName", firstName).append("lastName", lastName)
|
||||
.append("vehicles", embedded != null ? embedded : null).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Vehicle {
|
||||
private @Nullable String id;
|
||||
private @Nullable String vin;
|
||||
private @Nullable String brand;
|
||||
private @Nullable String label;
|
||||
@SerializedName("engine")
|
||||
private @Nullable List<Engine> engines;
|
||||
private @Nullable ZonedDateTime createdAt;
|
||||
private @Nullable ZonedDateTime updatedAt;
|
||||
|
||||
public @Nullable String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public @Nullable String getVin() {
|
||||
return vin;
|
||||
}
|
||||
|
||||
public @Nullable String getBrand() {
|
||||
return brand;
|
||||
}
|
||||
|
||||
public @Nullable String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public @Nullable List<Engine> getEngines() {
|
||||
return engines;
|
||||
}
|
||||
|
||||
public @Nullable ZonedDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public @Nullable ZonedDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("createdAt", createdAt).append("updatedAt", createdAt).append("id", id)
|
||||
.append("vin", vin).append("brand", brand).append("label", label).append("engines", engines).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.api.dto;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VehicleStatus {
|
||||
|
||||
private @Nullable ZonedDateTime updatedAt;
|
||||
@SerializedName("_embedded")
|
||||
private @Nullable Embedded embedded;
|
||||
private @Nullable Battery battery;
|
||||
private @Nullable DoorsState doorsState;
|
||||
private @Nullable List<Energy> energy = null;
|
||||
private @Nullable Environment environment;
|
||||
private @Nullable Ignition ignition;
|
||||
private @Nullable Kinetic kinetic;
|
||||
@SerializedName("timed.odometer")
|
||||
private @Nullable Odometer odometer;
|
||||
private @Nullable Position lastPosition;
|
||||
private @Nullable Preconditionning preconditionning;
|
||||
private @Nullable Privacy privacy;
|
||||
private @Nullable Safety safety;
|
||||
private @Nullable Service service;
|
||||
|
||||
private static class Embedded {
|
||||
private @Nullable Extension extension;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("extension", extension).toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static class Extension {
|
||||
private @Nullable Kinetic kinetic;
|
||||
private @Nullable Odometer odometer;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("kinetic", kinetic).append("odometer", odometer).toString();
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable Kinetic getKinetic() {
|
||||
if (kinetic != null) {
|
||||
return kinetic;
|
||||
} else {
|
||||
final Embedded finalEmbedded = embedded;
|
||||
if (finalEmbedded != null) {
|
||||
final Extension finalExtension = finalEmbedded.extension;
|
||||
if (finalExtension != null) {
|
||||
return finalExtension.kinetic;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable Odometer getOdometer() {
|
||||
if (odometer != null) {
|
||||
return odometer;
|
||||
} else {
|
||||
Embedded finalEmbedded = embedded;
|
||||
if (finalEmbedded != null) {
|
||||
final Extension finalExtension = finalEmbedded.extension;
|
||||
if (finalExtension != null) {
|
||||
return finalExtension.odometer;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable ZonedDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public @Nullable Battery getBattery() {
|
||||
return battery;
|
||||
}
|
||||
|
||||
public @Nullable DoorsState getDoorsState() {
|
||||
return doorsState;
|
||||
}
|
||||
|
||||
public @Nullable List<Energy> getEnergy() {
|
||||
return energy;
|
||||
}
|
||||
|
||||
public @Nullable Environment getEnvironment() {
|
||||
return environment;
|
||||
}
|
||||
|
||||
public @Nullable Ignition getIgnition() {
|
||||
return ignition;
|
||||
}
|
||||
|
||||
public @Nullable Position getLastPosition() {
|
||||
return lastPosition;
|
||||
}
|
||||
|
||||
public @Nullable Preconditionning getPreconditionning() {
|
||||
return preconditionning;
|
||||
}
|
||||
|
||||
public @Nullable Privacy getPrivacy() {
|
||||
return privacy;
|
||||
}
|
||||
|
||||
public @Nullable Safety getSafety() {
|
||||
return safety;
|
||||
}
|
||||
|
||||
public @Nullable Service getService() {
|
||||
return service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("updatedAt", updatedAt).append("_embedded", embedded)
|
||||
.append("battery", battery).append("doorsState", doorsState).append("energy", energy)
|
||||
.append("environment", environment).append("ignition", ignition).append("kinetic", kinetic)
|
||||
.append("odometer", odometer).append("lastPosition", lastPosition)
|
||||
.append("preconditionning", preconditionning).append("privacy", privacy).append("safety", safety)
|
||||
.append("service", service).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.exceptions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An exception that occurred while communicating with an groupepsa or an groupepsa bridge
|
||||
*
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GroupePSACommunicationException extends IOException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private int statusCode = -1;
|
||||
|
||||
public GroupePSACommunicationException(Exception e) {
|
||||
super(e);
|
||||
}
|
||||
|
||||
public GroupePSACommunicationException(int statusCode, Exception e) {
|
||||
super(e);
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
public GroupePSACommunicationException(int statusCode) {
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
public GroupePSACommunicationException(int statusCode, String message) {
|
||||
super(message);
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
public GroupePSACommunicationException(String message, Exception e) {
|
||||
super(message, e);
|
||||
}
|
||||
|
||||
public GroupePSACommunicationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public int getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getMessage() {
|
||||
String message = super.getMessage();
|
||||
return message == null ? null : "Rest call failed: statusCode=" + statusCode + ", message=" + message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + ": statusCode=" + statusCode + ", message=" + super.getMessage()
|
||||
+ ", cause: " + getCause();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.exceptions;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class UnauthorizedException extends GroupePSACommunicationException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UnauthorizedException(int statusCode, Exception e) {
|
||||
super(statusCode, e);
|
||||
}
|
||||
|
||||
public UnauthorizedException(int statusCode) {
|
||||
super(statusCode);
|
||||
}
|
||||
|
||||
public UnauthorizedException(int statusCode, String message) {
|
||||
super(statusCode, message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.rest.exceptions;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class UnavailableException extends GroupePSACommunicationException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UnavailableException(int statusCode, Exception e) {
|
||||
super(statusCode, e);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.things;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link GroupePSAConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GroupePSAConfiguration {
|
||||
|
||||
private @Nullable String id;
|
||||
private @Nullable Integer pollingInterval;
|
||||
private @Nullable Integer onlineInterval;
|
||||
|
||||
@Nullable
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public @Nullable Integer getPollingInterval() {
|
||||
return pollingInterval;
|
||||
}
|
||||
|
||||
public void setPollingInterval(Integer pollingInterval) {
|
||||
this.pollingInterval = pollingInterval;
|
||||
}
|
||||
|
||||
public @Nullable Integer getOnlineInterval() {
|
||||
return onlineInterval;
|
||||
}
|
||||
|
||||
public void setOnlineInterval(Integer onlineInterval) {
|
||||
this.onlineInterval = onlineInterval;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,479 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.things;
|
||||
|
||||
import static org.openhab.binding.groupepsa.internal.GroupePSABindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.measure.Quantity;
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.groupepsa.internal.bridge.GroupePSABridgeHandler;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Air;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.AirConditioning;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Battery;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.BatteryStatus;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Charging;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.DoorsState;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Energy;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Environment;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Health;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Ignition;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Kinetic;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Luminosity;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Odometer;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Opening;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Position;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Preconditionning;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Privacy;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Properties;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Safety;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.Service;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.dto.VehicleStatus;
|
||||
import org.openhab.binding.groupepsa.internal.rest.exceptions.GroupePSACommunicationException;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OpenClosedType;
|
||||
import org.openhab.core.library.types.PointType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.MetricPrefix;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerCallback;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.filosganga.geogson.model.Geometry;
|
||||
import com.github.filosganga.geogson.model.positions.SinglePosition;
|
||||
|
||||
/**
|
||||
* The {@link GroupePSAHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GroupePSAHandler extends BaseThingHandler {
|
||||
private static final long DEFAULT_POLLING_INTERVAL_M = TimeUnit.MINUTES.toMinutes(1);
|
||||
private static final long DEFAULT_ONLINE_INTERVAL_M = TimeUnit.MINUTES.toMinutes(60);
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(GroupePSAHandler.class);
|
||||
|
||||
private @Nullable String id = null;
|
||||
private long lastQueryTimeNs = 0L;
|
||||
|
||||
private @Nullable ScheduledFuture<?> groupepsaPollingJob;
|
||||
private long maxQueryFrequencyNanos = TimeUnit.MINUTES.toNanos(1);
|
||||
private long onlineIntervalM;
|
||||
|
||||
public GroupePSAHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Bridge getBridge() {
|
||||
return super.getBridge();
|
||||
}
|
||||
|
||||
private void pollStatus() {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge != null && bridge.getStatus() == ThingStatus.ONLINE) {
|
||||
updateGroupePSAState();
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
refreshChannels(channelUID);
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshChannels(ChannelUID channelUID) {
|
||||
updateGroupePSAState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (getBridgeHandler() != null) {
|
||||
GroupePSAConfiguration currentConfig = getConfigAs(GroupePSAConfiguration.class);
|
||||
final String id = currentConfig.getId();
|
||||
final Integer pollingIntervalM = currentConfig.getPollingInterval();
|
||||
final Integer onlineIntervalM = currentConfig.getOnlineInterval();
|
||||
|
||||
if (id == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/conf-error-no-vehicle-id");
|
||||
} else if (pollingIntervalM != null && pollingIntervalM < 1) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/conf-error-invalid-polling-interval");
|
||||
} else if (onlineIntervalM != null && onlineIntervalM < 1) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/conf-error-invalid-online-interval");
|
||||
} else {
|
||||
this.id = id;
|
||||
this.onlineIntervalM = onlineIntervalM != null ? onlineIntervalM : DEFAULT_ONLINE_INTERVAL_M;
|
||||
startGroupePSAPolling(pollingIntervalM);
|
||||
}
|
||||
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public GroupePSABridgeHandler getBridgeHandler() {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge != null) {
|
||||
ThingHandler handler = bridge.getHandler();
|
||||
if (handler instanceof GroupePSABridgeHandler) {
|
||||
return (GroupePSABridgeHandler) handler;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
stopGroupePSAPolling();
|
||||
id = null;
|
||||
}
|
||||
|
||||
private void startGroupePSAPolling(@Nullable Integer pollingIntervalM) {
|
||||
if (groupepsaPollingJob == null) {
|
||||
final long pollingIntervalToUse = pollingIntervalM == null ? DEFAULT_POLLING_INTERVAL_M : pollingIntervalM;
|
||||
groupepsaPollingJob = scheduler.scheduleWithFixedDelay(() -> pollStatus(), 1, pollingIntervalToUse * 60,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void stopGroupePSAPolling() {
|
||||
ScheduledFuture<?> job = groupepsaPollingJob;
|
||||
if (job != null) {
|
||||
job.cancel(true);
|
||||
groupepsaPollingJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidResult(VehicleStatus vehicle) {
|
||||
return vehicle.getUpdatedAt() != null;
|
||||
}
|
||||
|
||||
private boolean isConnected(VehicleStatus vehicle) {
|
||||
ZonedDateTime updatedAt = vehicle.getUpdatedAt();
|
||||
if (updatedAt == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return updatedAt.isAfter(ZonedDateTime.now().minusMinutes(onlineIntervalM));
|
||||
}
|
||||
|
||||
private synchronized void updateGroupePSAState() {
|
||||
if (System.nanoTime() - lastQueryTimeNs <= maxQueryFrequencyNanos) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastQueryTimeNs = System.nanoTime();
|
||||
|
||||
String id = this.id;
|
||||
if (id == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "@text/conf-error-no-vehicle-id");
|
||||
return;
|
||||
}
|
||||
|
||||
GroupePSABridgeHandler groupepsaBridge = getBridgeHandler();
|
||||
if (groupepsaBridge == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "@text/conf-error-no-bridge");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
VehicleStatus vehicle = groupepsaBridge.getVehicleStatus(id);
|
||||
|
||||
if (vehicle != null && isValidResult(vehicle)) {
|
||||
logger.trace("Vehicle: {}", vehicle.toString());
|
||||
|
||||
logger.debug("Update vehicle state now: {}, lastupdate: {}", ZonedDateTime.now(),
|
||||
vehicle.getUpdatedAt());
|
||||
|
||||
updateChannelState(vehicle);
|
||||
|
||||
if (isConnected(vehicle)) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
|
||||
"@text/comm-error-vehicle-not-connected-to-cloud");
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"@text/comm-error-query-vehicle-failed");
|
||||
}
|
||||
} catch (GroupePSACommunicationException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
MessageFormat.format("@text/comm-error-query-vehicle-failed", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateChannelState(VehicleStatus vehicle) {
|
||||
final DoorsState doorsState = vehicle.getDoorsState();
|
||||
if (doorsState != null) {
|
||||
buildDoorChannels(doorsState);
|
||||
|
||||
List<Opening> openings = doorsState.getOpening();
|
||||
if (openings != null) {
|
||||
for (Opening opening : openings) {
|
||||
String id = opening.getIdentifier();
|
||||
if (id != null) {
|
||||
ChannelUID channelUID = new ChannelUID(getThing().getUID(), CHANNEL_GROUP_DOORS,
|
||||
id.toLowerCase());
|
||||
updateState(channelUID, "open".equalsIgnoreCase(opening.getState()) ? OpenClosedType.OPEN
|
||||
: OpenClosedType.CLOSED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> lockedState = doorsState.getLockedState();
|
||||
updateState(CHANNEL_DOORS_LOCK, lockedState, x -> x.get(0));
|
||||
} else {
|
||||
updateState(CHANNEL_DOORS_LOCK, UnDefType.UNDEF);
|
||||
}
|
||||
|
||||
updateState(CHANNEL_BATTERY_CURRENT, vehicle.getBattery(), Battery::getCurrent, Units.AMPERE);
|
||||
updateState(CHANNEL_BATTERY_VOLTAGE, vehicle.getBattery(), Battery::getVoltage, Units.VOLT);
|
||||
|
||||
updateState(CHANNEL_ENVIRONMENT_TEMPERATURE, vehicle.getEnvironment(), Environment::getAir, Air::getTemp,
|
||||
SIUnits.CELSIUS);
|
||||
updateStateBoolean(CHANNEL_ENVIRONMENT_DAYTIME, vehicle.getEnvironment(), Environment::getLuminosity,
|
||||
Luminosity::isDay);
|
||||
|
||||
updateState(CHANNEL_MOTION_IGNITION, vehicle.getIgnition(), Ignition::getType);
|
||||
|
||||
updateStateBoolean(CHANNEL_MOTION_MOVING, vehicle.getKinetic(), Kinetic::isMoving);
|
||||
updateState(CHANNEL_MOTION_ACCELERATION, vehicle.getKinetic(), Kinetic::getAcceleration,
|
||||
Units.METRE_PER_SQUARE_SECOND);
|
||||
updateState(CHANNEL_MOTION_SPEED, vehicle.getKinetic(), Kinetic::getSpeed, SIUnits.KILOMETRE_PER_HOUR);
|
||||
|
||||
updateState(CHANNEL_MOTION_MILEAGE, vehicle.getOdometer(), Odometer::getMileage,
|
||||
MetricPrefix.KILO(SIUnits.METRE));
|
||||
|
||||
Position lastPosition = vehicle.getLastPosition();
|
||||
if (lastPosition != null) {
|
||||
Geometry<SinglePosition> geometry = lastPosition.getGeometry();
|
||||
if (geometry != null) {
|
||||
SinglePosition position = (SinglePosition) geometry.positions();
|
||||
if (Double.isFinite(position.alt())) {
|
||||
updateState(CHANNEL_POSITION_POSITION, new PointType(new DecimalType(position.lat()),
|
||||
new DecimalType(position.lon()), new DecimalType(position.alt())));
|
||||
} else {
|
||||
updateState(CHANNEL_POSITION_POSITION,
|
||||
new PointType(new DecimalType(position.lat()), new DecimalType(position.lon())));
|
||||
}
|
||||
} else {
|
||||
updateState(CHANNEL_POSITION_POSITION, UnDefType.UNDEF);
|
||||
}
|
||||
updateState(CHANNEL_POSITION_HEADING, lastPosition.getProperties(), Properties::getHeading,
|
||||
Units.DEGREE_ANGLE);
|
||||
updateState(CHANNEL_POSITION_TYPE, lastPosition.getProperties(), Properties::getType);
|
||||
updateState(CHANNEL_POSITION_SIGNALSTRENGTH, lastPosition.getProperties(), Properties::getSignalQuality,
|
||||
Units.PERCENT);
|
||||
}
|
||||
|
||||
updateState(CHANNEL_VARIOUS_LAST_UPDATED, vehicle.getUpdatedAt());
|
||||
updateState(CHANNEL_VARIOUS_PRIVACY, vehicle.getPrivacy(), Privacy::getState);
|
||||
updateState(CHANNEL_VARIOUS_BELT, vehicle.getSafety(), Safety::getBeltWarning);
|
||||
updateState(CHANNEL_VARIOUS_EMERGENCY, vehicle.getSafety(), Safety::getECallTriggeringRequest);
|
||||
updateState(CHANNEL_VARIOUS_SERVICE, vehicle.getService(), Service::getType);
|
||||
updateState(CHANNEL_VARIOUS_PRECONDITINING, vehicle.getPreconditionning(), Preconditionning::getAirConditioning,
|
||||
AirConditioning::getStatus);
|
||||
updateState(CHANNEL_VARIOUS_PRECONDITINING_FAILURE, vehicle.getPreconditionning(),
|
||||
Preconditionning::getAirConditioning, AirConditioning::getFailureCause);
|
||||
|
||||
List<Energy> energies = vehicle.getEnergy();
|
||||
if (energies != null) {
|
||||
for (Energy energy : energies) {
|
||||
if ("Fuel".equalsIgnoreCase(energy.getType())) {
|
||||
updateState(CHANNEL_FUEL_AUTONOMY, energy, Energy::getAutonomy, MetricPrefix.KILO(SIUnits.METRE));
|
||||
updateState(CHANNEL_FUEL_CONSUMPTION, energy, Energy::getConsumption,
|
||||
Units.LITRE.divide(MetricPrefix.KILO(SIUnits.METRE)));
|
||||
updateState(CHANNEL_FUEL_LEVEL, energy, Energy::getLevel, Units.PERCENT);
|
||||
} else if ("Electric".equalsIgnoreCase(energy.getType())) {
|
||||
updateState(CHANNEL_ELECTRIC_AUTONOMY, energy, Energy::getAutonomy,
|
||||
MetricPrefix.KILO(SIUnits.METRE));
|
||||
updateState(CHANNEL_ELECTRIC_RESIDUAL, energy, Energy::getResidual, Units.KILOWATT_HOUR);
|
||||
updateState(CHANNEL_ELECTRIC_LEVEL, energy, Energy::getLevel, Units.PERCENT);
|
||||
|
||||
updateState(CHANNEL_ELECTRIC_BATTERY_CAPACITY, energy, Energy::getBattery,
|
||||
BatteryStatus::getCapacity, Units.KILOWATT_HOUR);
|
||||
updateState(CHANNEL_ELECTRIC_BATTERY_HEALTH_CAPACITY, energy, Energy::getBattery,
|
||||
BatteryStatus::getHealth, Health::getCapacity, Units.PERCENT);
|
||||
updateState(CHANNEL_ELECTRIC_BATTERY_HEALTH_RESISTANCE, energy, Energy::getBattery,
|
||||
BatteryStatus::getHealth, Health::getResistance, Units.PERCENT);
|
||||
|
||||
updateState(CHANNEL_ELECTRIC_CHARGING_STATUS, energy, Energy::getCharging, Charging::getStatus);
|
||||
updateState(CHANNEL_ELECTRIC_CHARGING_MODE, energy, Energy::getCharging, Charging::getChargingMode);
|
||||
updateStateBoolean(CHANNEL_ELECTRIC_CHARGING_PLUGGED, energy, Energy::getCharging,
|
||||
Charging::isPlugged);
|
||||
updateState(CHANNEL_ELECTRIC_CHARGING_RATE, energy, Energy::getCharging, Charging::getChargingRate,
|
||||
SIUnits.KILOMETRE_PER_HOUR);
|
||||
|
||||
updateState(CHANNEL_ELECTRIC_CHARGING_REMAININGTIME, energy, Energy::getCharging,
|
||||
Charging::getRemainingTime, x -> new BigDecimal(x.getSeconds()), Units.SECOND);
|
||||
updateState(CHANNEL_ELECTRIC_CHARGING_NEXTDELAYEDTIME, energy, Energy::getCharging,
|
||||
Charging::getNextDelayedTime, x -> new BigDecimal(x.getSeconds()), Units.SECOND);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void buildDoorChannels(final DoorsState doorsState) {
|
||||
ThingHandlerCallback callback = getCallback();
|
||||
if (callback == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ThingBuilder thingBuilder = editThing();
|
||||
List<Channel> channels = getThing().getChannelsOfGroup(CHANNEL_GROUP_DOORS);
|
||||
thingBuilder.withoutChannels(channels);
|
||||
|
||||
ChannelUID channelUID = new ChannelUID(getThing().getUID(), CHANNEL_DOORS_LOCK);
|
||||
ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, CHANNEL_TYPE_DOORLOCK);
|
||||
thingBuilder.withChannel(callback.createChannelBuilder(channelUID, channelTypeUID).build());
|
||||
|
||||
List<Opening> openings = doorsState.getOpening();
|
||||
if (openings != null) {
|
||||
for (Opening opening : openings) {
|
||||
String id = opening.getIdentifier();
|
||||
if (id != null) {
|
||||
channelUID = new ChannelUID(getThing().getUID(), CHANNEL_GROUP_DOORS, id.toLowerCase());
|
||||
channelTypeUID = new ChannelTypeUID(BINDING_ID, CHANNEL_TYPE_DOOROPEN);
|
||||
thingBuilder.withChannel(callback.createChannelBuilder(channelUID, channelTypeUID).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateThing(thingBuilder.build());
|
||||
}
|
||||
|
||||
// Various update helper functions
|
||||
|
||||
protected <T extends Quantity<T>> void updateState(String channelID, @Nullable BigDecimal number, Unit<T> unit) {
|
||||
if (number != null) {
|
||||
updateState(channelID, new QuantityType<T>(number, unit));
|
||||
} else {
|
||||
updateState(channelID, UnDefType.UNDEF);
|
||||
}
|
||||
}
|
||||
|
||||
protected <T1, T2 extends Quantity<T2>> void updateState(String channelID, final @Nullable T1 object,
|
||||
Function<? super T1, @Nullable BigDecimal> mapper, Unit<T2> unit) {
|
||||
updateState(channelID, object != null ? mapper.apply(object) : null, unit);
|
||||
}
|
||||
|
||||
protected <T1, T2, T3 extends Quantity<T3>> void updateState(String channelID, final @Nullable T1 object1,
|
||||
Function<? super T1, @Nullable T2> mapper1, Function<? super T2, @Nullable BigDecimal> mapper2,
|
||||
Unit<T3> unit) {
|
||||
final @Nullable T2 object2 = object1 != null ? mapper1.apply(object1) : null;
|
||||
updateState(channelID, object2 != null ? mapper2.apply(object2) : null, unit);
|
||||
}
|
||||
|
||||
protected <T1, T2, T3, T4 extends Quantity<T4>> void updateState(String channelID, final @Nullable T1 object1,
|
||||
Function<? super T1, @Nullable T2> mapper1, Function<? super T2, @Nullable T3> mapper2,
|
||||
Function<? super T3, @Nullable BigDecimal> mapper3, Unit<T4> unit) {
|
||||
final @Nullable T2 object2 = object1 != null ? mapper1.apply(object1) : null;
|
||||
final @Nullable T3 object3 = object2 != null ? mapper2.apply(object2) : null;
|
||||
updateState(channelID, object3 != null ? mapper3.apply(object3) : null, unit);
|
||||
}
|
||||
|
||||
protected void updateState(String channelID, @Nullable ZonedDateTime date) {
|
||||
if (date != null) {
|
||||
updateState(channelID, new DateTimeType(date));
|
||||
} else {
|
||||
updateState(channelID, UnDefType.UNDEF);
|
||||
}
|
||||
}
|
||||
|
||||
protected <T1> void updateStateDate(String channelID, @Nullable T1 object,
|
||||
Function<? super T1, @Nullable ZonedDateTime> mapper) {
|
||||
updateState(channelID, object != null ? mapper.apply(object) : null);
|
||||
}
|
||||
|
||||
protected <T1, T2> void updateStateDate(String channelID, @Nullable T1 object1,
|
||||
Function<? super T1, @Nullable T2> mapper1, Function<? super T2, @Nullable ZonedDateTime> mapper2) {
|
||||
final @Nullable T2 object2 = object1 != null ? mapper1.apply(object1) : null;
|
||||
updateState(channelID, object2 != null ? mapper2.apply(object2) : null);
|
||||
}
|
||||
|
||||
protected void updateState(String channelID, @Nullable String text) {
|
||||
if (text != null) {
|
||||
updateState(channelID, new StringType(text));
|
||||
} else {
|
||||
updateState(channelID, UnDefType.UNDEF);
|
||||
}
|
||||
}
|
||||
|
||||
protected <T1> void updateState(String channelID, @Nullable T1 object,
|
||||
Function<? super T1, @Nullable String> mapper) {
|
||||
updateState(channelID, object != null ? mapper.apply(object) : null);
|
||||
}
|
||||
|
||||
protected <T1, T2> void updateState(String channelID, @Nullable T1 object1,
|
||||
Function<? super T1, @Nullable T2> mapper1, Function<? super T2, @Nullable String> mapper2) {
|
||||
final @Nullable T2 object2 = object1 != null ? mapper1.apply(object1) : null;
|
||||
updateState(channelID, object2 != null ? mapper2.apply(object2) : null);
|
||||
}
|
||||
|
||||
protected void updateState(String channelID, @Nullable Boolean value) {
|
||||
if (value != null) {
|
||||
updateState(channelID, value ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
|
||||
} else {
|
||||
updateState(channelID, UnDefType.UNDEF);
|
||||
}
|
||||
}
|
||||
|
||||
protected <T1> void updateStateBoolean(String channelID, @Nullable T1 object,
|
||||
Function<? super T1, @Nullable Boolean> mapper) {
|
||||
updateState(channelID, object != null ? mapper.apply(object) : null);
|
||||
}
|
||||
|
||||
protected <T1, T2> void updateStateBoolean(String channelID, final @Nullable T1 object1,
|
||||
Function<? super T1, @Nullable T2> mapper1, Function<? super T2, @Nullable Boolean> mapper2) {
|
||||
final @Nullable T2 object2 = object1 != null ? mapper1.apply(object1) : null;
|
||||
updateState(channelID, object2 != null ? mapper2.apply(object2) : null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="groupepsa" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>Groupe PSA Binding</name>
|
||||
<description>Provides information and (limited) control of cars from the Groupe PSA (Peugeot, Citroen, Opel, etc.).</description>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,21 @@
|
||||
# binding
|
||||
binding.groupepsa.name = Groupe PSA Binding
|
||||
binding.groupepsa.description = Provides information and (limited) control of cars from the Groupe PSA (Peugeot, Citroen, Opel, etc.).
|
||||
|
||||
#configuration errors
|
||||
conf-error-no-vendor = Cannot connect to Groupe PSA bridge as no vendor is available in the configuration
|
||||
conf-error-unknown-vendor = Cannot connect to Groupe PSA bridge as the vendor is not valid
|
||||
conf-error-no-username = Cannot connect to Groupe PSA bridge as no username is available in the configuration
|
||||
conf-error-no-password = Cannot connect to Groupe PSA bridge as no password is available in the configuration
|
||||
conf-error-no-clientid = Cannot connect to Groupe PSA bridge as no client ID is available in the configuration
|
||||
conf-error-no-clientsecret = Cannot connect to Groupe PSA bridge as no client secret is available in the configuration
|
||||
conf-error-invalid-polling-interval = Invalid polling interval specified. The interval has to be >= 1
|
||||
conf-error-invalid-online-interval = Invalid online check interval specified. The interval has to be >= 1
|
||||
|
||||
conf-error-no-vehicle-id = No VIN specified. Unable to communicate with the vehicle without an ID
|
||||
conf-error-no-bridge = No valid bridge for the vehicle is available
|
||||
|
||||
#communication errors
|
||||
comm-error-vehicle-not-connected-to-cloud = Vehicle not connected to the cloud
|
||||
comm-error-query-vehicle-failed = Unable to query the vehicle status ({0})
|
||||
comm-error-query-vehicles-failed = Unable to get a list of vehicles ({0})
|
||||
@@ -0,0 +1,535 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="groupepsa"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
|
||||
<bridge-type id="bridge">
|
||||
<label>Groupe PSA Bridge</label>
|
||||
<description>The bridge to communicate with the PSA (Peugeot, Citroen, Vauxhall, Opel, DS) Web API for End-Users</description>
|
||||
<category>WebService</category>
|
||||
|
||||
<representation-property>vendor</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="vendor" type="text" required="true">
|
||||
<label>Brand</label>
|
||||
<description>The brand of the car</description>
|
||||
<options>
|
||||
<option value="PEUGEOT">Peugeot</option>
|
||||
<option value="CITROEN">Citroen</option>
|
||||
<option value="DS">DS</option>
|
||||
<option value="OPEL">Opel</option>
|
||||
<option value="VAUXHALL">Vauxhall</option>
|
||||
</options>
|
||||
</parameter>
|
||||
<parameter name="userName" type="text" required="true">
|
||||
<label>User Name</label>
|
||||
<description>The user name for the mypeugot/mycitroen/myds/myopel/myvauxhall website or app</description>
|
||||
</parameter>
|
||||
<parameter name="password" type="text" required="true">
|
||||
<context>password</context>
|
||||
<description>The password for the given user</description>
|
||||
</parameter>
|
||||
<parameter name="pollingInterval" type="integer" required="false" unit="min">
|
||||
<label>Polling Interval</label>
|
||||
<default>60</default>
|
||||
<description>How often the available vehicles should be queried in minutes</description>
|
||||
</parameter>
|
||||
<parameter name="clientId" type="text" required="true">
|
||||
<advanced>true</advanced>
|
||||
<default>07364655-93cb-4194-8158-6b035ac2c24c</default>
|
||||
<label>Client ID</label>
|
||||
<description>The client ID for API access: can normally left at the default value. (see:
|
||||
https://developer.groupe-psa.io/webapi/b2c/quickstart/connect/#article)</description>
|
||||
</parameter>
|
||||
<parameter name="clientSecret" type="text" required="true">
|
||||
<advanced>true</advanced>
|
||||
<default>F2kK7lC5kF5qN7tM0wT8kE3cW1dP0wC5pI6vC0sQ5iP5cN8cJ8</default>
|
||||
<label>Client Secret</label>
|
||||
<description>The client secret for API access: can normally left at the default value. (see:
|
||||
https://developer.groupe-psa.io/webapi/b2c/quickstart/connect/#article)</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</bridge-type>
|
||||
|
||||
<thing-type id="vehicle">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Groupe PSA Car</label>
|
||||
<description>Car connected via Groupe PSA (Peugeot, Citroen, Vauxhall, Opel, DS) Bridge</description>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="battery" typeId="battery"/>
|
||||
<channel-group id="doors" typeId="doors"/>
|
||||
<channel-group id="environment" typeId="environment"/>
|
||||
<channel-group id="motion" typeId="motion"/>
|
||||
<channel-group id="position" typeId="position"/>
|
||||
<channel-group id="various" typeId="various"/>
|
||||
<channel-group id="fuel" typeId="fuel"/>
|
||||
<channel-group id="electric" typeId="electric"/>
|
||||
</channel-groups>
|
||||
|
||||
<properties>
|
||||
<property name="vendor">N/A</property>
|
||||
<property name="model">N/A</property>
|
||||
<property name="vin">N/A</property>
|
||||
</properties>
|
||||
|
||||
<representation-property>id</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="id" type="text" required="true">
|
||||
<label>ID</label>
|
||||
<description>Vehicle API ID (obtained automatically during discovery, not equal to the VIN)</description>
|
||||
</parameter>
|
||||
<parameter name="pollingInterval" type="integer" required="false" unit="min">
|
||||
<label>Polling Interval</label>
|
||||
<default>5</default>
|
||||
<description>How often this vehicle should be polled for updated information</description>
|
||||
</parameter>
|
||||
<parameter name="onlineInterval" type="integer" required="false" unit="min">
|
||||
<label>Online Timeout</label>
|
||||
<default>15</default>
|
||||
<description>Timeout when the vehicle is considered offline</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</thing-type>
|
||||
|
||||
<channel-group-type id="battery">
|
||||
<label>Battery</label>
|
||||
<description>Main battery</description>
|
||||
<category>Energy</category>
|
||||
<channels>
|
||||
<channel id="current" typeId="current"/>
|
||||
<channel id="voltage" typeId="level">
|
||||
<label>Battery Level</label>
|
||||
<description>Battery level</description>
|
||||
</channel>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="doors">
|
||||
<label>Doors</label>
|
||||
<description>State of the doors</description>
|
||||
<category>Door</category>
|
||||
<channels>
|
||||
<channel id="locked" typeId="doorLock"/>
|
||||
<channel id="driver" typeId="doorOpen">
|
||||
<label>Driver Door</label>
|
||||
<description>Driver door open state</description>
|
||||
</channel>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="environment">
|
||||
<label>Environment</label>
|
||||
<description>Environmental conditions</description>
|
||||
<channels>
|
||||
<channel id="temperature" typeId="temperature">
|
||||
<label>Outside Temperature</label>
|
||||
<description>Outside Temperature</description>
|
||||
</channel>
|
||||
<channel id="daytime" typeId="daytime"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="motion">
|
||||
<label>Motion</label>
|
||||
<description>Motion information</description>
|
||||
<channels>
|
||||
<channel id="ignition" typeId="ignition"/>
|
||||
<channel id="acceleration" typeId="acceleration"/>
|
||||
<channel id="moving" typeId="moving"/>
|
||||
<channel id="speed" typeId="speed"/>
|
||||
<channel id="mileage" typeId="mileage"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="position">
|
||||
<label>Position</label>
|
||||
<description>Location information</description>
|
||||
<channels>
|
||||
<channel id="position" typeId="position"/>
|
||||
<channel id="heading" typeId="heading"/>
|
||||
<channel id="type" typeId="type"/>
|
||||
<channel id="signal" typeId="system.signal-strength"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="various">
|
||||
<label>Various</label>
|
||||
<description>Miscellaneous information</description>
|
||||
<channels>
|
||||
<channel id="lastUpdated" typeId="lastUpdated"/>
|
||||
<channel id="privacy" typeId="privacy"/>
|
||||
<channel id="belt" typeId="belt"/>
|
||||
<channel id="emergency" typeId="emergency"/>
|
||||
<channel id="service" typeId="service"/>
|
||||
<channel id="preconditioning" typeId="preconditioning"/>
|
||||
<channel id="preconditioningFailure" typeId="preconditioningFailure"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-type id="current">
|
||||
<item-type>Number:ElectricCurrent</item-type>
|
||||
<label>Current</label>
|
||||
<description>Electrical current</description>
|
||||
<category>Energy</category>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="voltage">
|
||||
<item-type>Number:ElectricPotential</item-type>
|
||||
<label>Voltage</label>
|
||||
<description>Voltage</description>
|
||||
<category>Energy</category>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature</label>
|
||||
<description>Temperature</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="daytime">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Daytime</label>
|
||||
<description>Enabled if it is daytime</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="doorLock">
|
||||
<item-type>String</item-type>
|
||||
<label>Door Lock</label>
|
||||
<description>Door lock state</description>
|
||||
<category>Door</category>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="Unlocked">Unlocked</option>
|
||||
<option value="Locked">Locked</option>
|
||||
<option value="SuperLocked">Super Locked</option>
|
||||
<option value="DriverDoorUnlocked">Driver Door Unlocked</option>
|
||||
<option value="CabinDoorsUnlocked">Cabin Doors Unlocked</option>
|
||||
<option value="CargoDoorsLocked">Cargo Doors Locked</option>
|
||||
<option value="CargoDoorsUnlocked">Cargo Doors Unlocked</option>
|
||||
<option value="RearDoorsLocked">Rear Doors Locked</option>
|
||||
<option value="RearDoorsUnlocked">Rear Doors Unlocked</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="doorOpen">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Door Open</label>
|
||||
<description>Door is open</description>
|
||||
<category>Door</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ignition">
|
||||
<item-type>String</item-type>
|
||||
<label>Ignition</label>
|
||||
<description>Ignition state</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="Stop">Stop</option>
|
||||
<option value="StartUp">Start up</option>
|
||||
<option value="Start">Start</option>
|
||||
<option value="Free">Free</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="moving">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Moving</label>
|
||||
<description>Vehicle is moving</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="acceleration">
|
||||
<item-type>Number:Acceleration</item-type>
|
||||
<label>Acceleration</label>
|
||||
<description>Current acceleration</description>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="speed">
|
||||
<item-type>Number:Speed</item-type>
|
||||
<label>Speed</label>
|
||||
<description>Current speed</description>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="mileage">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>Mileage</label>
|
||||
<description>Total travelled distance</description>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="position">
|
||||
<item-type>Location</item-type>
|
||||
<label>Position</label>
|
||||
<description>Last known position</description>
|
||||
<state pattern="%2$s°N %3$s°E %1$sm"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="heading">
|
||||
<item-type>Number:Angle</item-type>
|
||||
<label>Heading</label>
|
||||
<description>Direction of travel</description>
|
||||
<state pattern="%.0f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="type">
|
||||
<item-type>String</item-type>
|
||||
<label>Position Type</label>
|
||||
<description>Position acquisition type</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="Estimate">Estimate</option>
|
||||
<option value="Acquire">Acquire</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="lastUpdated">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Time of Last Update</label>
|
||||
<description>Last time the results were updated on the server</description>
|
||||
<category>Time</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="privacy">
|
||||
<item-type>String</item-type>
|
||||
<label>Privacy Status</label>
|
||||
<description>Privacy status</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="None">None</option>
|
||||
<option value="Geolocation">Location</option>
|
||||
<option value="Full">Full</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="belt">
|
||||
<item-type>String</item-type>
|
||||
<label>Belt Status</label>
|
||||
<description>Seat belt status</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="Normal">Belts on</option>
|
||||
<option value="Omission">Belt open</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="emergency">
|
||||
<item-type>String</item-type>
|
||||
<label>Emergency Call</label>
|
||||
<description>Emergency call status</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="NoRequest">None</option>
|
||||
<option value="AirbagUnabled">Airbag Deployed</option>
|
||||
<option value="Requested">Emergency Call Requested</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="service">
|
||||
<item-type>String</item-type>
|
||||
<label>Service</label>
|
||||
<description>Service Type</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="Electric">Electric</option>
|
||||
<option value="Hybrid">Hybrid</option>
|
||||
<option value="Unknown">Unknown</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="preconditioning">
|
||||
<item-type>String</item-type>
|
||||
<label>Air Conditioning</label>
|
||||
<description>Air conditioning status</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="Enabled">Enabled</option>
|
||||
<option value="Disabled">Disabled</option>
|
||||
<option value="Finished">Finished</option>
|
||||
<option value="Failure">Failure</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="preconditioningFailure">
|
||||
<item-type>String</item-type>
|
||||
<label>Air Conditioning Failure</label>
|
||||
<description>Air conditioning failure cause</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="Defect">Defect</option>
|
||||
<option value="DoorOpened">Door Opened</option>
|
||||
<option value="LowBattery">Low Battery</option>
|
||||
<option value="LowFuelLevel">Low Fuel Level</option>
|
||||
<option value="TooManyUnusedProg">Too many times unused</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-group-type id="fuel">
|
||||
<label>Fuel</label>
|
||||
<description>Thermic Motor Fuel Status</description>
|
||||
<category>Energy</category>
|
||||
<channels>
|
||||
<channel id="autonomy" typeId="autonomy"/>
|
||||
<channel id="consumption" typeId="consumption"/>
|
||||
<channel id="level" typeId="level"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="electric">
|
||||
<label>Electric Energy</label>
|
||||
<description>Electric motor energy status</description>
|
||||
<channels>
|
||||
<channel id="autonomy" typeId="autonomy">
|
||||
<label>Electric Autonomy</label>
|
||||
<description>Remaining distance</description>
|
||||
</channel>
|
||||
<channel id="level" typeId="level">
|
||||
<label>Electricity Level</label>
|
||||
<description>Electricity level</description>
|
||||
</channel>
|
||||
<channel id="residual" typeId="residual"/>
|
||||
<channel id="batteryCapacity" typeId="capacity"/>
|
||||
<channel id="batteryHealthCapacity" typeId="healthCapacity"/>
|
||||
<channel id="batteryHealthResistance" typeId="healthResistance"/>
|
||||
<channel id="chargingStatus" typeId="chargingStatus"/>
|
||||
<channel id="chargingMode" typeId="chargingMode"/>
|
||||
<channel id="chargingPlugged" typeId="chargingPlugged"/>
|
||||
<channel id="chargingRate" typeId="chargingRate"/>
|
||||
<channel id="chargingRemainingTime" typeId="chargingRemainingTime"/>
|
||||
<channel id="chargingNextDelayedTime" typeId="chargingNextDelayedTime"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-type id="level">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Fuel Level</label>
|
||||
<description>Fuel level</description>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="autonomy">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>Fuel Autonomy</label>
|
||||
<description>Remaining distance</description>
|
||||
<state pattern="%.0f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="consumption">
|
||||
<item-type>Number:VolumetricFlowRate</item-type>
|
||||
<label>Fuel Consumption</label>
|
||||
<description>Fuel consumption</description>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="residual">
|
||||
<item-type>Number:Energy</item-type>
|
||||
<label>Remaining Charge</label>
|
||||
<description>Remaining battery charge</description>
|
||||
<category>BatteryLevel</category>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="capacity">
|
||||
<item-type>Number:Energy</item-type>
|
||||
<label>Battery Capacity</label>
|
||||
<description>Battery capacity</description>
|
||||
<category>BatteryLevel</category>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="healthCapacity">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Battery Health - Capacity</label>
|
||||
<description>Health of the battery capacity</description>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="healthResistance">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Battery Health - Resistance</label>
|
||||
<description>Health of the battery resistance</description>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="chargingStatus">
|
||||
<item-type>String</item-type>
|
||||
<label>Charging Status</label>
|
||||
<description>Battery charging status</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="Disconnected">Disconnected</option>
|
||||
<option value="InProgess">In Progress</option>
|
||||
<option value="Failure">Failure</option>
|
||||
<option value="Stopped">Stopped</option>
|
||||
<option value="Finished">Finished</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="chargingMode">
|
||||
<item-type>String</item-type>
|
||||
<label>Charging Mode</label>
|
||||
<description>Battery charging mode</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="No">No</option>
|
||||
<option value="Slow">Slow</option>
|
||||
<option value="Quick">Fast</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="chargingPlugged">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Plugged In</label>
|
||||
<description>Vehicle plugged in to charger</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="chargingRate">
|
||||
<item-type>Number:Speed</item-type>
|
||||
<label>Charging Rate</label>
|
||||
<description>Battery Charging Rate</description>
|
||||
<category>BatteryLevel</category>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="chargingRemainingTime">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Charging Time Remaining</label>
|
||||
<description>Time remaining till charged</description>
|
||||
<category>Time</category>
|
||||
<state pattern="%tT"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="chargingNextDelayedTime">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Time Till Next Charging</label>
|
||||
<description>Time till the next charging starts</description>
|
||||
<category>Time</category>
|
||||
<state pattern="%tT"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.groupepsa.internal.things;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpContentResponse;
|
||||
import org.eclipse.jetty.client.HttpResponse;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.openhab.binding.groupepsa.internal.bridge.GroupePSABridgeHandler;
|
||||
import org.openhab.binding.groupepsa.internal.rest.api.GroupePSAConnectApi;
|
||||
import org.openhab.binding.groupepsa.internal.rest.exceptions.GroupePSACommunicationException;
|
||||
import org.openhab.core.auth.client.oauth2.OAuthFactory;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.ThingHandlerCallback;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The {@link GroupePSAHandlerTest} is responsible for testing the binding
|
||||
*
|
||||
* @author Arjan Mels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GroupePSAHandlerTest {
|
||||
private @NonNullByDefault({}) AutoCloseable closeable;
|
||||
|
||||
private @NonNullByDefault({}) GroupePSAConnectApi api;
|
||||
private @NonNullByDefault({}) GroupePSABridgeHandler bridgeHandler;
|
||||
private @NonNullByDefault({}) GroupePSAHandler thingHandler;
|
||||
|
||||
private @NonNullByDefault({}) @Mock ThingHandlerCallback thingCallback;
|
||||
private @NonNullByDefault({}) @Mock ThingHandlerCallback bridgeCallback;
|
||||
private @NonNullByDefault({}) @Mock Thing thing;
|
||||
private @NonNullByDefault({}) @Mock Bridge bridge;
|
||||
|
||||
private @NonNullByDefault({}) @Mock OAuthFactory oAuthFactory;
|
||||
private @NonNullByDefault({}) @Mock HttpClient httpClient;
|
||||
|
||||
static String getResourceFileAsString(String fileName) throws GroupePSACommunicationException {
|
||||
try (InputStream is = GroupePSAConnectApi.class.getResourceAsStream(fileName)) {
|
||||
try (InputStreamReader isr = new InputStreamReader(is); BufferedReader reader = new BufferedReader(isr)) {
|
||||
return reader.lines().collect(Collectors.joining(System.lineSeparator()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new GroupePSACommunicationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static HttpContentResponse createHttpResponse(String file) throws GroupePSACommunicationException {
|
||||
return new HttpContentResponse(new HttpResponse(null, null).status(200),
|
||||
getResourceFileAsString("/" + file).getBytes(), "json", "UTF-8");
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@SuppressWarnings("null")
|
||||
public void setUp() throws GroupePSACommunicationException {
|
||||
closeable = MockitoAnnotations.openMocks(this);
|
||||
|
||||
// Create real objects
|
||||
bridgeHandler = spy(new GroupePSABridgeHandler(bridge, oAuthFactory, httpClient));
|
||||
thingHandler = spy(new GroupePSAHandler(thing));
|
||||
api = spy(new GroupePSAConnectApi(httpClient, bridgeHandler, "clientId", "realm"));
|
||||
|
||||
// Setup API mock
|
||||
doReturn(createHttpResponse("dummy_user.json")).when(api).executeRequest(contains("user"), anyString());
|
||||
doReturn(createHttpResponse("dummy_vehiclestatus3.json")).when(api).executeRequest(contains("status"),
|
||||
anyString());
|
||||
|
||||
// Setup bridge handler mock
|
||||
bridgeHandler.setCallback(bridgeCallback);
|
||||
doReturn(api).when(bridgeHandler).getAPI();
|
||||
|
||||
// Setup bridge mock
|
||||
Configuration bridgeConfig = new Configuration();
|
||||
bridgeConfig.put("vendor", "OPEL");
|
||||
bridgeConfig.put("userName", "user");
|
||||
bridgeConfig.put("password", "pwd");
|
||||
bridgeConfig.put("clientId", "clientIdValue");
|
||||
bridgeConfig.put("clientSecret", "clientSecretValue");
|
||||
doReturn(bridgeConfig).when(bridge).getConfiguration();
|
||||
doReturn(ThingStatus.ONLINE).when(bridge).getStatus();
|
||||
doReturn(bridgeHandler).when(bridge).getHandler();
|
||||
doReturn(new ThingUID("a:b:c")).when(bridge).getUID();
|
||||
|
||||
// Setup thing mock
|
||||
Configuration thingConfig = new Configuration();
|
||||
thingConfig.put("id", "mock_id");
|
||||
doReturn(thingConfig).when(thing).getConfiguration();
|
||||
doReturn(new ThingUID("a:b:c")).when(thing).getUID();
|
||||
|
||||
// Setup thing handler mock
|
||||
thingHandler.setCallback(thingCallback);
|
||||
doReturn(bridge).when(thingHandler).getBridge();
|
||||
doNothing().when(thingHandler).buildDoorChannels(any());
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() throws Exception {
|
||||
// Free any resources, like open database connections, files etc.
|
||||
thingHandler.dispose();
|
||||
bridgeHandler.dispose();
|
||||
closeable.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void intializeAndCheckChannels() throws InterruptedException {
|
||||
// Initialize the bridge
|
||||
bridgeHandler.initialize();
|
||||
|
||||
// check that the bridge is online
|
||||
verify(bridgeCallback, timeout(2000)).statusUpdated(eq(bridge),
|
||||
argThat(arg -> arg.getStatus().equals(ThingStatus.ONLINE)));
|
||||
|
||||
// Initialize the thing
|
||||
thingHandler.initialize();
|
||||
|
||||
// check that the thing is offline without detail (last update time is not
|
||||
// within 15 minutes)
|
||||
verify(thingCallback, timeout(2000)).statusUpdated(eq(thing),
|
||||
argThat(arg -> arg.getStatus().equals(ThingStatus.OFFLINE)
|
||||
&& arg.getStatusDetail().equals(ThingStatusDetail.NONE)));
|
||||
|
||||
// check that the channels are updated
|
||||
verify(thingCallback, atLeast(30)).stateUpdated(any(ChannelUID.class), any(State.class));
|
||||
verify(thingCallback).stateUpdated(eq(new ChannelUID("a:b:c:electric#chargingStatus")),
|
||||
eq(new StringType("Disconnected")));
|
||||
verify(thingCallback).stateUpdated(eq(new ChannelUID("a:b:c:various#lastUpdated")), any(DateTimeType.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "ivuvawoj"
|
||||
},
|
||||
"trips": {
|
||||
"href": "ugihub"
|
||||
},
|
||||
"lastTrip": {
|
||||
"href": "culugakin"
|
||||
},
|
||||
"lastEcodriving": {
|
||||
"href": "bagnu"
|
||||
}
|
||||
},
|
||||
"id": "7000650216898560",
|
||||
"email": "iwni@georure.kr",
|
||||
"firstName": "Floyd",
|
||||
"lastName": "Gilbert",
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"updatedAt": "2019-08-24T14:15:22Z",
|
||||
"_embedded": {
|
||||
"vehicles": [
|
||||
{
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "ovoha"
|
||||
},
|
||||
"lastTrip": {
|
||||
"href": "lotudwe"
|
||||
},
|
||||
"lastPosition": {
|
||||
"href": "bobediirewelojbu"
|
||||
},
|
||||
"trips": {
|
||||
"href": "vacofgutv"
|
||||
},
|
||||
"collisions": {
|
||||
"href": "koafeu"
|
||||
},
|
||||
"telemetry": {
|
||||
"href": "ewahzonug"
|
||||
},
|
||||
"maintenance": {
|
||||
"href": "dovuzibwudmicel"
|
||||
},
|
||||
"alerts": {
|
||||
"href": "izbisbiwpejunun"
|
||||
},
|
||||
"events": {
|
||||
"href": "tece"
|
||||
}
|
||||
},
|
||||
"id": "4336155157856256",
|
||||
"vin": "mycar_vin1",
|
||||
"brand": "opel",
|
||||
"engine": [
|
||||
{
|
||||
"class": "Thermic",
|
||||
"energy": "GPL"
|
||||
},
|
||||
{
|
||||
"class": "Electric"
|
||||
}
|
||||
],
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"updatedAt": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"lastPosition": {
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
2.2221432,
|
||||
48.772476,
|
||||
172
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"updatedAt": "2019-08-24T14:15:22Z",
|
||||
"type": "Aquire",
|
||||
"signalQuality": 6
|
||||
}
|
||||
},
|
||||
"preconditionning": {
|
||||
"airConditioning": {
|
||||
"updatedAt": "2019-08-24T14:15:22Z",
|
||||
"status": "Disabled",
|
||||
"programs": [
|
||||
{
|
||||
"enabled": false,
|
||||
"recurrence": "Daily",
|
||||
"start": "PT0S"
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"recurrence": "Daily",
|
||||
"start": "PT0S"
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"recurrence": "Daily",
|
||||
"start": "PT0S"
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"recurrence": "Daily",
|
||||
"start": "PT0S"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"energy": [
|
||||
{
|
||||
"type": "Electric",
|
||||
"level": 0,
|
||||
"autonomy": 0,
|
||||
"residual": 0
|
||||
},
|
||||
{
|
||||
"type": "Fuel",
|
||||
"level": 0,
|
||||
"residual": 0
|
||||
}
|
||||
],
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"autonomy": 2000,
|
||||
"ignition": {
|
||||
"createdAt": "2019-08-24T14:15:22Z"
|
||||
},
|
||||
"vin": "VF3A12BCDEF3456",
|
||||
"privacy": {
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"state": "None"
|
||||
},
|
||||
"battery": {
|
||||
"voltage": 0.55,
|
||||
"current": 0.55,
|
||||
"createdAt": "2019-08-24T14:15:22Z"
|
||||
},
|
||||
"kinetic": {
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"acceleration": 0.55,
|
||||
"speed": 0.55,
|
||||
"pace": 0.55,
|
||||
"moving": false
|
||||
},
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "https://api.groupe-psa.com/connectedcar/v4/user/vehicles/{id}/status"
|
||||
},
|
||||
"vehicles": {
|
||||
"href": "https://api.groupe-psa.com/connectedcar/v4/user/vehicles/{id}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
{
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"_embedded": {
|
||||
"extension": {
|
||||
"kinetic": {
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"acceleration": 0,
|
||||
"moving": true,
|
||||
"pace": 0,
|
||||
"speed": 0
|
||||
},
|
||||
"odometer": {
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"mileage": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"_links": {
|
||||
"self": {
|
||||
"deprecation": "string",
|
||||
"href": "string",
|
||||
"hreflang": "string",
|
||||
"name": "string",
|
||||
"profile": "string",
|
||||
"templated": true,
|
||||
"title": "string",
|
||||
"type": "string"
|
||||
},
|
||||
"vehicle": {
|
||||
"deprecation": "string",
|
||||
"href": "string",
|
||||
"hreflang": "string",
|
||||
"name": "string",
|
||||
"profile": "string",
|
||||
"templated": true,
|
||||
"title": "string",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"battery": {
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"current": 0,
|
||||
"voltage": 0
|
||||
},
|
||||
"doorsState": {
|
||||
"lockedState": [
|
||||
"Unlocked"
|
||||
],
|
||||
"opening": [
|
||||
{
|
||||
"identifier": "Driver",
|
||||
"state": "Open"
|
||||
}
|
||||
],
|
||||
"updatedAt": "2019-08-24T14:15:22Z"
|
||||
},
|
||||
"energy": [
|
||||
{
|
||||
"updatedAt": "2019-08-24T14:15:22Z",
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"autonomy": 1,
|
||||
"battery": {
|
||||
"capacity": 0,
|
||||
"health": {
|
||||
"capacity": 0,
|
||||
"resistance": 0
|
||||
}
|
||||
},
|
||||
"charging": {
|
||||
"chargingMode": "No",
|
||||
"chargingRate": 0,
|
||||
"nextDelayedTime": "PT15M",
|
||||
"plugged": true,
|
||||
"remainingTime": "PT15M",
|
||||
"status": "Disconnected"
|
||||
},
|
||||
"consumption": 0,
|
||||
"level": 0,
|
||||
"residual": 0,
|
||||
"type": "Fuel"
|
||||
},
|
||||
{
|
||||
"updatedAt": "2019-08-24T14:15:22Z",
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"autonomy": 2,
|
||||
"battery": {
|
||||
"capacity": 0,
|
||||
"health": {
|
||||
"capacity": 0,
|
||||
"resistance": 0
|
||||
}
|
||||
},
|
||||
"charging": {
|
||||
"chargingMode": "No",
|
||||
"chargingRate": 0,
|
||||
"nextDelayedTime": "PT15M",
|
||||
"plugged": true,
|
||||
"remainingTime": "PT15M",
|
||||
"status": "Disconnected"
|
||||
},
|
||||
"consumption": 0,
|
||||
"level": 0,
|
||||
"residual": 0,
|
||||
"type": "Electric"
|
||||
}
|
||||
],
|
||||
"environment": {
|
||||
"updatedAt": "2019-08-24T14:15:22Z",
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"air": {
|
||||
"temp": 0
|
||||
},
|
||||
"luminosity": {
|
||||
"day": true
|
||||
}
|
||||
},
|
||||
"ignition": {
|
||||
"updatedAt": "2019-08-24T14:15:22Z",
|
||||
"type": "Stop"
|
||||
},
|
||||
"kinetic": {
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"acceleration": 0,
|
||||
"moving": true,
|
||||
"pace": 0,
|
||||
"speed": 0
|
||||
},
|
||||
"lastPosition": {
|
||||
"updatedAt": "2019-08-24T14:15:22Z",
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
0, 0, 0
|
||||
],
|
||||
"type": "Point"
|
||||
},
|
||||
"properties": {
|
||||
"heading": 0,
|
||||
"signalQuality": 0,
|
||||
"type": "Estimate"
|
||||
},
|
||||
"type": "Feature"
|
||||
},
|
||||
"preconditionning": {
|
||||
"airConditioning": {
|
||||
"failureCause": "Defect",
|
||||
"programs": [
|
||||
{
|
||||
"occurence": {
|
||||
"day": [
|
||||
"Mon"
|
||||
],
|
||||
"week": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"recurrence": "Daily",
|
||||
"start": "string",
|
||||
"enabled": true,
|
||||
"slot": 0
|
||||
}
|
||||
],
|
||||
"status": "Enabled",
|
||||
"updatedAt": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
},
|
||||
"privacy": {
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"state": "None"
|
||||
},
|
||||
"safety": {
|
||||
"createdAt": "2019-08-24T14:15:22Z",
|
||||
"beltWarning": "Normal",
|
||||
"eCallTriggeringRequest": "AirbagUnabled"
|
||||
},
|
||||
"service": {
|
||||
"type": "Electric",
|
||||
"updatedAt": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"lastPosition": {
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
22.1111111,
|
||||
11.2222222
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"updatedAt": "2020-12-25T15:16:48Z",
|
||||
"heading": 331,
|
||||
"type": "Estimated"
|
||||
}
|
||||
},
|
||||
"preconditionning": {
|
||||
"airConditioning": {
|
||||
"updatedAt": "2020-12-23T16:54:14Z",
|
||||
"status": "Disabled",
|
||||
"programs": [
|
||||
{
|
||||
"enabled": false,
|
||||
"slot": 1,
|
||||
"recurrence": "Daily",
|
||||
"start": "PT6H15M",
|
||||
"occurence": {
|
||||
"day": [
|
||||
"Mon",
|
||||
"Tue",
|
||||
"Wed",
|
||||
"Thu",
|
||||
"Fri"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"slot": 2,
|
||||
"recurrence": "Daily",
|
||||
"start": "PT8H",
|
||||
"occurence": {
|
||||
"day": [
|
||||
"Mon",
|
||||
"Tue",
|
||||
"Wed",
|
||||
"Thu",
|
||||
"Fri"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"energy": [
|
||||
{
|
||||
"updatedAt": "2020-12-23T16:54:13Z",
|
||||
"type": "Electric",
|
||||
"level": 77,
|
||||
"autonomy": 200,
|
||||
"charging": {
|
||||
"plugged": false,
|
||||
"status": "Disconnected",
|
||||
"remainingTime": "PT0S",
|
||||
"chargingRate": 0,
|
||||
"chargingMode": "No",
|
||||
"nextDelayedTime": "PT5H"
|
||||
}
|
||||
}
|
||||
],
|
||||
"createdAt": "2020-12-25T15:16:48Z",
|
||||
"battery": {
|
||||
"voltage": 87,
|
||||
"current": 0,
|
||||
"createdAt": "2020-12-23T16:54:13Z"
|
||||
},
|
||||
"kinetic": {
|
||||
"createdAt": "2020-12-25T15:16:48Z",
|
||||
"moving": false
|
||||
},
|
||||
"privacy": {
|
||||
"createdAt": "2020-12-25T15:16:43Z",
|
||||
"state": "None"
|
||||
},
|
||||
"service": {
|
||||
"type": "Electric",
|
||||
"updatedAt": "2020-11-06T19:56:10Z"
|
||||
},
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "dummy_link/status"
|
||||
},
|
||||
"vehicles": {
|
||||
"href": "dummy_link/vehicles"
|
||||
}
|
||||
},
|
||||
"timed.odometer": {
|
||||
"createdAt": null,
|
||||
"mileage": 1539
|
||||
},
|
||||
"updatedAt": "2020-12-25T15:16:48Z"
|
||||
}
|
||||
Reference in New Issue
Block a user