mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[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:
parent
7adfc482da
commit
8e7c78cef5
@ -546,6 +546,11 @@
|
|||||||
<artifactId>org.openhab.binding.groheondus</artifactId>
|
<artifactId>org.openhab.binding.groheondus</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openhab.addons.bundles</groupId>
|
||||||
|
<artifactId>org.openhab.binding.groupepsa</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openhab.addons.bundles</groupId>
|
<groupId>org.openhab.addons.bundles</groupId>
|
||||||
<artifactId>org.openhab.binding.guntamatic</artifactId>
|
<artifactId>org.openhab.binding.guntamatic</artifactId>
|
||||||
|
20
bundles/org.openhab.binding.groupepsa/NOTICE
Normal file
20
bundles/org.openhab.binding.groupepsa/NOTICE
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
This content is produced and maintained by the openHAB project.
|
||||||
|
|
||||||
|
* Project home: https://www.openhab.org
|
||||||
|
|
||||||
|
== Declared Project Licenses
|
||||||
|
|
||||||
|
This program and the accompanying materials are made available under the terms
|
||||||
|
of the Eclipse Public License 2.0 which is available at
|
||||||
|
https://www.eclipse.org/legal/epl-2.0/.
|
||||||
|
|
||||||
|
== Source Code
|
||||||
|
|
||||||
|
https://github.com/openhab/openhab-addons
|
||||||
|
|
||||||
|
== Third-party Content
|
||||||
|
|
||||||
|
GeoJSON support for Gson
|
||||||
|
* License: Apache License 2.0
|
||||||
|
* Project: https://github.com/filosganga/geogson
|
||||||
|
* Source: https://github.com/filosganga/geogson
|
151
bundles/org.openhab.binding.groupepsa/README.md
Normal file
151
bundles/org.openhab.binding.groupepsa/README.md
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
# Groupe PSA Binding
|
||||||
|
|
||||||
|
Binding to retrieve information via the Groupe PSA Web API for cars from Opel, Peugeot, Citroen, DS and Vauxhall.
|
||||||
|
|
||||||
|
## Supported Things
|
||||||
|
|
||||||
|
bridge - Groupe PSA Web Api Bridge: The Thing to auto discover your cars
|
||||||
|
|
||||||
|
vehicle - Groupe PSA Car: The actual car thing.
|
||||||
|
|
||||||
|
## Discovery
|
||||||
|
|
||||||
|
Use the "Groupe PSA Web Api bridge" to auto discover your cars. You need to select the brand for the bridge binding and only cars for the brand will be auto discovered. If you need to add for multiple brands or multiple different users, add multiple bridges.
|
||||||
|
|
||||||
|
## Bridge Configuration
|
||||||
|
|
||||||
|
You need to select a brand and enter the User Name and Password.
|
||||||
|
The Polling interval (in minutes) determines how often the API will polled for new cars.
|
||||||
|
The Client ID and Client Secret should not need to be updated. (However you can register your own app via https://developer.groupe-psa.com/inc/ and use this client information if you wish.)
|
||||||
|
|
||||||
|
### parameters
|
||||||
|
|
||||||
|
| Property | Default | Required | Description |
|
||||||
|
| --------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| vendor | None | Yes | The brand of the car (PEUGEOT, CITROEN, DS, OPEL or VAUXHALL) |
|
||||||
|
| userName | None | Yes | The user name for the mypeugot/mycitroen/myds/myopel/myvauxhall website or app |
|
||||||
|
| password | None | Yes | The password for the given user |
|
||||||
|
| pollingInterval | 60 | No | The Polling interval (in minutes) determines how often the available vehicles are queried |
|
||||||
|
| clientId | | Yes | The client ID for API access: can normally left at the default value. (see: https://developer.groupe-psa.io/webapi/b2c/quickstart/connect/#article) |
|
||||||
|
| clientSecret | | Yes | The client secret for API access: can normally left at the default value. (see: https://developer.groupe-psa.io/webapi/b2c/quickstart/connect/#article) |
|
||||||
|
|
||||||
|
## Vehicle Configuration
|
||||||
|
|
||||||
|
Normally the vehicles will be autodiscovered. The Polling Interval and Online Timeout can be adjusted.
|
||||||
|
|
||||||
|
### parameters
|
||||||
|
|
||||||
|
| Property | Default | Required | Description |
|
||||||
|
| --------------- | ------- | -------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
|
||||||
|
| id | None | Yes | Vehicle API ID | The ID is the vehicle API ID (not equal to the VIN), which is autodiscoverd by the bridge. |
|
||||||
|
| pollingInterval | 5 | No | The Polling interval (in minutes) determines how often the car is polled for updated information |
|
||||||
|
| onlineInterval | 15 | No | The Online Timeout (in minutes) determines when the car is deemed to be offline. |
|
||||||
|
|
||||||
|
## Channels
|
||||||
|
|
||||||
|
| Channel Type ID | Item Type | Description |
|
||||||
|
| ----------------------- | ------------------------- | ------------------------------------------------ |
|
||||||
|
| current | Number:ElectricCurrent | Electrical current |
|
||||||
|
| voltage | Number:ElectricPotential | Voltage |
|
||||||
|
| temperature | Number:Temperature | Temperature |
|
||||||
|
| daytime | Contact | Enabled if it is daytime |
|
||||||
|
| doorLock | String | Door lock state |
|
||||||
|
| doorOpen | Contact | Door is open |
|
||||||
|
| ignition | String | Ignition state |
|
||||||
|
| moving | Contact | Vehicle is moving |
|
||||||
|
| acceleration | Number:Acceleration | Current acceleration |
|
||||||
|
| speed | Number:Speed | Current speed |
|
||||||
|
| mileage | Number:Length | Total travelled distance |
|
||||||
|
| position | Location | Last known position |
|
||||||
|
| heading | Number:Angle | Direction of travel |
|
||||||
|
| type | String | Position acquisition type |
|
||||||
|
| signal | Number:Dimensionless | Strength of the position localization signal |
|
||||||
|
| lastUpdated | DateTime | Last time the results were updated on the server |
|
||||||
|
| privacy | String | Privacy status |
|
||||||
|
| belt | String | Seat belt status |
|
||||||
|
| emergency | String | Emergency call status |
|
||||||
|
| service | String | Service Type |
|
||||||
|
| preconditioning | String | Air conditioning status |
|
||||||
|
| preconditioningFailure | String | Airr conditioning failure cause |
|
||||||
|
| level | Number:Dimensionless | Fuel level |
|
||||||
|
| autonomy | Number:Length | Remaining distance |
|
||||||
|
| consumption | Number:VolumetricFlowRate | Fuel consumption |
|
||||||
|
| residual | Number:Energy | Remaining battery charge |
|
||||||
|
| capacity | Number:Energy | Battery capacity |
|
||||||
|
| healthCapacity | Number:Dimensionless | Health of the battery capacity |
|
||||||
|
| healthResistance | Number:Dimensionless | Health of the battery resistance |
|
||||||
|
| chargingStatus | String | Battery charging status |
|
||||||
|
| chargingMode | String | Battery charging mode |
|
||||||
|
| chargingPlugged | Contact | Vehicle plugged in to charger |
|
||||||
|
| chargingRate | Number:Speed | Battery Charging Rate |
|
||||||
|
| chargingRemainingTime | Number:Time | Time remaining till charged |
|
||||||
|
| chargingNextDelayedTime | Number:Time | Time till the next charging starts |
|
||||||
|
|
||||||
|
Further documentation can be found at: https://developer.groupe-psa.io/webapi/b2c/api-reference/specification/#article
|
||||||
|
|
||||||
|
## Full Example
|
||||||
|
|
||||||
|
### Things file
|
||||||
|
|
||||||
|
```
|
||||||
|
Bridge groupepsa:bridge:opel "Auto Interface" [
|
||||||
|
pollingInterval=60,
|
||||||
|
userName="anonymous@anonymous.email",
|
||||||
|
password="password",
|
||||||
|
vendor="OPEL"
|
||||||
|
] {
|
||||||
|
Things:
|
||||||
|
vehicle zafira "Auto" @ "Outdoors"
|
||||||
|
[
|
||||||
|
id="<web api id here>",
|
||||||
|
pollingInterval=5,
|
||||||
|
onlineInterval=1440
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Items file
|
||||||
|
|
||||||
|
```
|
||||||
|
Group Auto
|
||||||
|
|
||||||
|
Number:ElectricCurrent Auto_Aux_Current "Auxillliary Battery Current [%.1f %unit%]" (Auto) ["Measurement","Current"] {channel="groupepsa:vehicle:opel:zafira:battery#current"}
|
||||||
|
Number Auto_Aux_Level "Auxillliary Battery Level [%.1f %unit%]" (Auto) ["Measurement","Level"] {channel="groupepsa:vehicle:opel:zafira:battery#voltage"}
|
||||||
|
|
||||||
|
Number:Temperature Auto_Outside_Temperature "Outside Temperature [%.1f %unit%]" (Auto) ["Measurement","Temperature"] {channel="groupepsa:vehicle:opel:zafira:environment#temperature"}
|
||||||
|
|
||||||
|
Number:Length Auto_Mileage "Mileage [%.1f %unit%]" (Auto) ["Measurement"] {channel="groupepsa:vehicle:opel:zafira:motion#mileage"}
|
||||||
|
Number:Speed Auto_Speed "Speed [%.1f %unit%]" (Auto) ["Measurement"] {channel="groupepsa:vehicle:opel:zafira:motion#speed"}
|
||||||
|
Number:Acceleration Auto_Acceleration "Acceleration [%.1f %unit%]" (Auto) ["Measurement"] {channel="groupepsa:vehicle:opel:zafira:motion#acceleration"}
|
||||||
|
|
||||||
|
Location Auto_Location "Locatie" (Auto) ["Point"] {channel="groupepsa:vehicle:opel:zafira:position#position"}
|
||||||
|
|
||||||
|
Number:Angle Auto_Heading "Richting" (Auto) ["Measurement"] {channel="groupepsa:vehicle:opel:zafira:position#heading"}
|
||||||
|
String Auto_Location_Type "Locatie Type" (Auto) ["Measurement"] {channel="groupepsa:vehicle:opel:zafira:position#type"}
|
||||||
|
Number Auto_Signal_Strength "Signaal Sterkte [%.1f %unit%]" (Auto) ["Measurement"] {channel="groupepsa:vehicle:opel:zafira:position#signal"}
|
||||||
|
|
||||||
|
DateTime Auto_Last_Update "Laatst bijgewerkt [%1$tA, %1$te %1$tb %1$tY %1$tR]" (Auto) ["Measurement", "Timestamp"] {channel="groupepsa:vehicle:opel:zafira:various#lastUpdated"}
|
||||||
|
String Auto_Privacy_Status "Privacy Status" (Auto) ["Status"] {channel="groupepsa:vehicle:opel:zafira:various#privacyStatus"}
|
||||||
|
String Auto_Belt_Status "Belt Status" (Auto) ["Status"] {channel="groupepsa:vehicle:opel:zafira:various#beltStatus"}
|
||||||
|
String Auto_Emergency_Call "Emergency Call" (Auto) ["Status"] {channel="groupepsa:vehicle:opel:zafira:various#emergencyCall"}
|
||||||
|
String Auto_Service "Service" (Auto) ["Status"] {channel="groupepsa:vehicle:opel:zafira:various#service"}
|
||||||
|
String Auto_Air_Conditioning "Air Conditioning" (Auto) ["Status"] {channel="groupepsa:vehicle:opel:zafira:various#preconditioning"}
|
||||||
|
String Auto_Air_Conditioning_Failure "Air Conditioning Failure" (Auto) ["Status"] {channel="groupepsa:vehicle:opel:zafira:various#preconditioningFailure"}
|
||||||
|
|
||||||
|
Number:Length Auto_Autonomy "Autonomy [%.1f %unit%]" (Auto) ["Measurement"] {channel="groupepsa:vehicle:opel:zafira:electric#autonomy"}
|
||||||
|
Number Auto_Level "Battery Level [%.1f %unit%]" (Auto) ["Measurement", "Level"] {channel="groupepsa:vehicle:opel:zafira:electric#level"}
|
||||||
|
Number:Energy Auto_Residual "Battery Residual [%.1f %unit%]" (Auto) ["Measurement", "Level"] {channel="groupepsa:vehicle:opel:zafira:electric#residual"}
|
||||||
|
|
||||||
|
Number:Energy Auto_Capacity "Battery Capacity [%.1f %unit%]" (Auto) ["Measurement"] {channel="groupepsa:vehicle:opel:zafira:electric#capacity"}
|
||||||
|
Number Auto_Health_Capacity "Battery Health Capacity [%.1f %unit%]" (Auto) ["Measurement"] {channel="groupepsa:vehicle:opel:zafira:electric#batteryHealthCapacity"}
|
||||||
|
Number Auto_Health_Resistance "Battery Health Resistance [%.1f %unit%]" (Auto) ["Measurement"] {channel="groupepsa:vehicle:opel:zafira:electric#batteryHealthResistance"}
|
||||||
|
|
||||||
|
String Auto_Charging_Status "Charging Status" (Auto) ["Status"] {channel="groupepsa:vehicle:opel:zafira:electric#chargingStatus"}
|
||||||
|
String Auto_Charging_Mode "Charging Mode" (Auto) ["Status"] {channel="groupepsa:vehicle:opel:zafira:electric#chargingMode"}
|
||||||
|
Contact Auto_Plugged_In "Plugged In" (Auto) ["Status"] {channel="groupepsa:vehicle:opel:zafira:electric#chargingPlugged"}
|
||||||
|
Number:Speed Auto_Charging_Rate "Charging Rate [%.1f %unit%]" (Auto) ["Measurement"] {channel="groupepsa:vehicle:opel:zafira:electric#chargingRate"}
|
||||||
|
|
||||||
|
Number:Time Auto_Charging_Time_Remaining "Charging Time Remaining [%.1f %unit%]" (Auto) ["Measurement", "Duration"] {channel="groupepsa:vehicle:opel:zafira:electric#chargingRemainingTime"}
|
||||||
|
Number:Time Auto_Charging_Time_Till_Next "Charging Time Till Next Charging [%.1f %unit%]" (Auto) ["Measurement", "Duration"] {channel="groupepsa:vehicle:opel:zafira:electric#chargingNextDelayedTime"}
|
||||||
|
```
|
25
bundles/org.openhab.binding.groupepsa/pom.xml
Normal file
25
bundles/org.openhab.binding.groupepsa/pom.xml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.openhab.addons.bundles</groupId>
|
||||||
|
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||||
|
<version>3.3.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>org.openhab.binding.groupepsa</artifactId>
|
||||||
|
|
||||||
|
<name>openHAB Add-ons :: Bundles :: Groupe PSA Binding</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.filosganga</groupId>
|
||||||
|
<artifactId>geogson-core</artifactId>
|
||||||
|
<version>1.4.31</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
@ -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"
|
||||||
|
}
|
@ -142,6 +142,7 @@
|
|||||||
<module>org.openhab.binding.globalcache</module>
|
<module>org.openhab.binding.globalcache</module>
|
||||||
<module>org.openhab.binding.gpstracker</module>
|
<module>org.openhab.binding.gpstracker</module>
|
||||||
<module>org.openhab.binding.gree</module>
|
<module>org.openhab.binding.gree</module>
|
||||||
|
<module>org.openhab.binding.groupepsa</module>
|
||||||
<module>org.openhab.binding.groheondus</module>
|
<module>org.openhab.binding.groheondus</module>
|
||||||
<module>org.openhab.binding.guntamatic</module>
|
<module>org.openhab.binding.guntamatic</module>
|
||||||
<module>org.openhab.binding.haassohnpelletstove</module>
|
<module>org.openhab.binding.haassohnpelletstove</module>
|
||||||
|
Loading…
Reference in New Issue
Block a user