mirror of
https://github.com/danieldemus/openhab-addons
synced 2026-07-29 12:34:21 +02:00
[tado] Add rate limit info channels (#19766)
* First commit Adds rate limit info channels Signed-off-by: Erik De Boeck <deboeck.erik@gmail.com>
This commit is contained in:
@@ -15,7 +15,7 @@ It must be authenticated before it will actually go online.
|
||||
Authenticatation is done online via the OAuth Device Code Grant Flow (RFC-8628) authentication process via the link provided at `http://[openhab-ip-address]:8080/tado`.
|
||||
|
||||
| Parameter | Optional | Description | Default |
|
||||
|---------------|----------|-------------------------------------------------------------------------------|------------------------------|
|
||||
| ------------- | -------- | ----------------------------------------------------------------------------- | ---------------------------- |
|
||||
| `rfcWithUser` | yes | Determines if the user name is included in the oAuth RFC-8628 authentication. | |
|
||||
| `tadoApiUrl` | no | Selects the URL to be used for API calls (it's possible to use a proxy) | `https://my.tado.com/api/v2` |
|
||||
| `username` | yes | Selects the tado° account to be used if there is more than one account. | |
|
||||
@@ -42,10 +42,14 @@ Once the `home` thing is online, the binding will discover all its respective zo
|
||||
|
||||
### Channels
|
||||
|
||||
| Name | Type | Description | Read/Write |
|
||||
|---------------------|--------|---------------------------------------------------------------------|------------|
|
||||
| `homePresence` | Switch | Current presence value of the tado home; `ON` = HOME / `OFF` = AWAY | RW |
|
||||
| `geofencingEnabled` | Switch | Selects if automatic geofencing is enabled or disabled | RW |
|
||||
| Name | Type | Description | Read/Write |
|
||||
| ------------------- | ----------- | -------------------------------------------------------------------------- | ---------- |
|
||||
| `homePresence` | Switch | Current presence value of the tado home; `ON` = HOME / `OFF` = AWAY | RW |
|
||||
| `geofencingEnabled` | Switch | Selects if automatic geofencing is enabled or disabled | RW |
|
||||
| `apiRateRemaining` | Number | Number of API calls remaining before the maximum is reached | R |
|
||||
| `apiRateLimit` | Number | Maximum API calls allowed per specified duration | R |
|
||||
| `apiRateDuration` | Number:Time | Duration in which the API count rises until maximum | R |
|
||||
| `apiRateReset` | Number:Time | Duration before the API count resets (only when the API limit is breached) | R |
|
||||
|
||||
## `zone` Thing
|
||||
|
||||
@@ -54,7 +58,7 @@ You have defined them during installation.
|
||||
One zone relates to one page in the tado° mobile- or webapp.
|
||||
|
||||
| Parameter | Required | Description | Default |
|
||||
|----------------------|----------|---------------------------------------------------------------|---------|
|
||||
| -------------------- | -------- | ------------------------------------------------------------- | ------- |
|
||||
| `id` | yes | Zone Id | - |
|
||||
| `refreshInterval` | no | Refresh interval of state updates in seconds | 30 |
|
||||
| `hvacChangeDebounce` | no | Duration in seconds to combine multiple HVAC changes into one | 5 |
|
||||
@@ -79,26 +83,26 @@ A zone is either of type `HEATING`, `AC` or `DHW` (domestic hot water).
|
||||
The availability of items as well as their allowed values depend on type and capabilities of the HVAC setup.
|
||||
If you are unsure, have a look at the tado° app and see if the functionality is available and what values are supported.
|
||||
|
||||
| Name | Type | Description | Read/Write | Zone type |
|
||||
|--------------------------------|----------------------|-------------------------------------------------------------------------------------------------------------------|------------|------------------------|
|
||||
| `currentTemperature` | Number:Temperature | Current inside temperature | R | `HEATING`, `AC` |
|
||||
| `humidity` | Number:Dimensionless | Current relative inside humidity in percent | R | `HEATING`, `AC` |
|
||||
| `hvacMode` | String | Active mode, one of `OFF`, `HEAT`, `COOL`, `DRY`, `FAN`, `AUTO` | RW | `HEATING` and `DHW` support `OFF` and `HEAT`, `AC` can support more |
|
||||
| `targetTemperature` | Number:Temperature | Set point | RW | `HEATING`, `AC`, `DHW` |
|
||||
| `operationMode` | String | Operation mode the zone is currently in. One of `SCHEDULE` (follow smart schedule), `MANUAL` (override until ended manually), `TIMER` (override for a given time), `UNTIL_CHANGE` (active until next smart schedule block or until AWAY mode becomes active) | RW | `HEATING`, `AC`, `DHW` |
|
||||
| `overlayExpiry` | DateTime | End date and time of a timer | R | `HEATING`, `AC`, `DHW` |
|
||||
| `timerDuration` | Number | Timer duration in minutes | RW | `HEATING`, `AC`, `DHW` |
|
||||
| `heatingPower` | Number:Dimensionless | Amount of heating power currently present | R | `HEATING` |
|
||||
| `acPower` | Switch | Indicates if the Air-Conditioning is Off or On | R | `AC` |
|
||||
| `fanspeed`<sup>1)</sup> | String | Fan speed, one of `AUTO`, `LOW`, `MIDDLE`, `HIGH` | RW | `AC` |
|
||||
| `fanLevel`<sup>1)</sup> | String | Fan speed, one of <sup>3)</sup> `AUTO`, `SILENT`, `LEVEL1`, `LEVEL2`, `LEVEL3`, `LEVEL4`, `LEVEL5` | RW | `AC` |
|
||||
| `swing`<sup>2)</sup> | Switch | Swing on/off | RW | `AC` |
|
||||
| `verticalSwing`<sup>2)</sup> | String | Vertical swing state, one of <sup>3)</sup> `OFF`, `ON`, `UP`, `MID_UP`, `MID`, `MID_DOWN`, `DOWN`, `AUTO` | RW | `AC` |
|
||||
| `horizontalSwing`<sup>2)</sup> | String | Horizontal swing state, one of <sup>3)</sup> `OFF`, `ON`, `LEFT`, `MID_LEFT`, `MID`, `MID_RIGHT`, `RIGHT`, `AUTO` | RW | `AC` |
|
||||
| `batteryLowAlarm` | Switch | A control device in the Zone has a low battery | R | Any Zone |
|
||||
| `openWindowDetected` | Switch | An open window has been detected in the Zone | R | `HEATING`, `AC` |
|
||||
| `openWindowRemainingTime` | Number:Time | The remaining Open Window heating/cooling Override time in the Zone | R | `HEATING`, `AC` |
|
||||
| `light` | Switch | State (`ON`, `OFF`) of the control panel light | RW | `AC` |
|
||||
| Name | Type | Description | Read/Write | Zone type |
|
||||
| ------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- | ------------------------------------------------------------------- |
|
||||
| `currentTemperature` | Number:Temperature | Current inside temperature | R | `HEATING`, `AC` |
|
||||
| `humidity` | Number:Dimensionless | Current relative inside humidity in percent | R | `HEATING`, `AC` |
|
||||
| `hvacMode` | String | Active mode, one of `OFF`, `HEAT`, `COOL`, `DRY`, `FAN`, `AUTO` | RW | `HEATING` and `DHW` support `OFF` and `HEAT`, `AC` can support more |
|
||||
| `targetTemperature` | Number:Temperature | Set point | RW | `HEATING`, `AC`, `DHW` |
|
||||
| `operationMode` | String | Operation mode the zone is currently in. One of `SCHEDULE` (follow smart schedule), `MANUAL` (override until ended manually), `TIMER` (override for a given time), `UNTIL_CHANGE` (active until next smart schedule block or until AWAY mode becomes active) | RW | `HEATING`, `AC`, `DHW` |
|
||||
| `overlayExpiry` | DateTime | End date and time of a timer | R | `HEATING`, `AC`, `DHW` |
|
||||
| `timerDuration` | Number | Timer duration in minutes | RW | `HEATING`, `AC`, `DHW` |
|
||||
| `heatingPower` | Number:Dimensionless | Amount of heating power currently present | R | `HEATING` |
|
||||
| `acPower` | Switch | Indicates if the Air-Conditioning is Off or On | R | `AC` |
|
||||
| `fanspeed`<sup>1)</sup> | String | Fan speed, one of `AUTO`, `LOW`, `MIDDLE`, `HIGH` | RW | `AC` |
|
||||
| `fanLevel`<sup>1)</sup> | String | Fan speed, one of <sup>3)</sup> `AUTO`, `SILENT`, `LEVEL1`, `LEVEL2`, `LEVEL3`, `LEVEL4`, `LEVEL5` | RW | `AC` |
|
||||
| `swing`<sup>2)</sup> | Switch | Swing on/off | RW | `AC` |
|
||||
| `verticalSwing`<sup>2)</sup> | String | Vertical swing state, one of <sup>3)</sup> `OFF`, `ON`, `UP`, `MID_UP`, `MID`, `MID_DOWN`, `DOWN`, `AUTO` | RW | `AC` |
|
||||
| `horizontalSwing`<sup>2)</sup> | String | Horizontal swing state, one of <sup>3)</sup> `OFF`, `ON`, `LEFT`, `MID_LEFT`, `MID`, `MID_RIGHT`, `RIGHT`, `AUTO` | RW | `AC` |
|
||||
| `batteryLowAlarm` | Switch | A control device in the Zone has a low battery | R | Any Zone |
|
||||
| `openWindowDetected` | Switch | An open window has been detected in the Zone | R | `HEATING`, `AC` |
|
||||
| `openWindowRemainingTime` | Number:Time | The remaining Open Window heating/cooling Override time in the Zone | R | `HEATING`, `AC` |
|
||||
| `light` | Switch | State (`ON`, `OFF`) of the control panel light | RW | `AC` |
|
||||
|
||||
You will see some of the above mentioned Channels only if your tado° device supports the respective function.
|
||||
|
||||
@@ -147,7 +151,7 @@ In case the zone is currently in smart-schedule mode and thus doesn't have a ter
|
||||
The `mobiledevice` thing represents a smart phone that is configured for tado°. It provides access to the geotracking functionality.
|
||||
|
||||
| Parameter | Required | Description | Default |
|
||||
|-------------------|----------|----------------------------------------------|---------|
|
||||
| ----------------- | -------- | -------------------------------------------- | ------- |
|
||||
| `id` | yes | Mobile Device Id | - |
|
||||
| `refreshInterval` | no | Refresh interval of state updates in seconds | 60 |
|
||||
|
||||
@@ -162,10 +166,10 @@ Bridge tado:home:demo [ username="mail@example.com", password="secret" ] {
|
||||
}
|
||||
```
|
||||
|
||||
### Items
|
||||
### Channels
|
||||
|
||||
| Name | Type | Description | Read/Write |
|
||||
|----------|--------|--------------------------------------------------|------------|
|
||||
| -------- | ------ | ------------------------------------------------ | ---------- |
|
||||
| `atHome` | Switch | ON if mobile device is in HOME mode, OFF if AWAY | R |
|
||||
|
||||
Group `OR` can be used to define an item for _'is any device at home'_.
|
||||
|
||||
+5
@@ -44,6 +44,11 @@ public class TadoBindingConstants {
|
||||
public static final String CHANNEL_HOME_PRESENCE_MODE = "homePresence";
|
||||
public static final String CHANNEL_HOME_GEOFENCING_ENABLED = "geofencingEnabled";
|
||||
|
||||
public static final String CHANNEL_API_RATE_LIMIT = "apiRateLimit";
|
||||
public static final String CHANNEL_API_RATE_DURATION = "apiRateDuration";
|
||||
public static final String CHANNEL_API_RATE_REMAINING = "apiRateRemaining";
|
||||
public static final String CHANNEL_API_RATE_RESET = "apiRateReset";
|
||||
|
||||
public static final String CHANNEL_ZONE_CURRENT_TEMPERATURE = "currentTemperature";
|
||||
public static final String CHANNEL_ZONE_HUMIDITY = "humidity";
|
||||
|
||||
|
||||
+3
-2
@@ -13,6 +13,7 @@
|
||||
package org.openhab.binding.tado.internal.api;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.tado.internal.handler.TadoHomeHandler;
|
||||
import org.openhab.binding.tado.swagger.codegen.api.GsonBuilderFactory;
|
||||
import org.openhab.binding.tado.swagger.codegen.api.client.HomeApi;
|
||||
import org.openhab.binding.tado.swagger.codegen.api.client.OAuthorizerV2;
|
||||
@@ -29,9 +30,9 @@ import com.google.gson.Gson;
|
||||
@NonNullByDefault
|
||||
public class HomeApiFactory {
|
||||
|
||||
public HomeApi create(OAuthClientService oAuthClientService, String baseUrl) {
|
||||
public HomeApi create(OAuthClientService oAuthClientService, String baseUrl, TadoHomeHandler homeHandler) {
|
||||
Gson gson = GsonBuilderFactory.defaultGsonBuilder().create();
|
||||
OAuthorizerV2 authorizer = new OAuthorizerV2(oAuthClientService);
|
||||
return new HomeApi(gson, authorizer, baseUrl);
|
||||
return new HomeApi(gson, authorizer, baseUrl, homeHandler);
|
||||
}
|
||||
}
|
||||
|
||||
+28
-1
@@ -20,8 +20,11 @@ import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.tado.internal.TadoBindingConstants;
|
||||
import org.openhab.binding.tado.internal.TadoBindingConstants.TemperatureUnit;
|
||||
import org.openhab.binding.tado.internal.api.HomeApiFactory;
|
||||
import org.openhab.binding.tado.internal.config.TadoHomeConfig;
|
||||
@@ -37,7 +40,10 @@ import org.openhab.binding.tado.swagger.codegen.api.model.UserHomes;
|
||||
import org.openhab.core.auth.client.oauth2.AccessTokenRefreshListener;
|
||||
import org.openhab.core.auth.client.oauth2.AccessTokenResponse;
|
||||
import org.openhab.core.auth.client.oauth2.OAuthClientService;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
@@ -47,6 +53,7 @@ import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
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;
|
||||
|
||||
@@ -101,7 +108,7 @@ public class TadoHomeHandler extends BaseBridgeHandler implements AccessTokenRef
|
||||
|
||||
OAuthClientService oAuthClientService = tadoHandlerFactory.subscribeOAuthClientService(this, user);
|
||||
oAuthClientService.addAccessTokenRefreshListener(this);
|
||||
this.api = new HomeApiFactory().create(oAuthClientService, configuration.tadoApiUrl);
|
||||
this.api = new HomeApiFactory().create(oAuthClientService, configuration.tadoApiUrl, this);
|
||||
this.oAuthClientService = oAuthClientService;
|
||||
logger.trace("initialize() api v2 created");
|
||||
confPendingText = CONF_PENDING_OAUTH_CREDS.formatted(TadoAuthenticationServlet.PATH,
|
||||
@@ -287,4 +294,24 @@ public class TadoHomeHandler extends BaseBridgeHandler implements AccessTokenRef
|
||||
public void onAccessTokenResponse(AccessTokenResponse atr) {
|
||||
initializeBridgeStatusAndPropertiesIfOffline();
|
||||
}
|
||||
|
||||
public void updateRateLimitInfo(int apiRateLimit, int apiRateDuration, int apiRateRemaining, int apiRateReset) {
|
||||
updateAPIChannels(apiRateLimit, TadoBindingConstants.CHANNEL_API_RATE_LIMIT, Units.ONE);
|
||||
updateAPIChannels(apiRateDuration, TadoBindingConstants.CHANNEL_API_RATE_DURATION, Units.SECOND);
|
||||
updateAPIChannels(apiRateRemaining, TadoBindingConstants.CHANNEL_API_RATE_REMAINING, Units.ONE);
|
||||
updateAPIChannels(apiRateReset, TadoBindingConstants.CHANNEL_API_RATE_RESET, Units.SECOND);
|
||||
}
|
||||
|
||||
private void updateAPIChannels(int value, String channelName, Unit unit) {
|
||||
if (value > -1) {
|
||||
if (TadoBindingConstants.CHANNEL_API_RATE_LIMIT.equals(channelName)
|
||||
|| TadoBindingConstants.CHANNEL_API_RATE_REMAINING.equals(channelName)) {
|
||||
updateState(channelName, new DecimalType(value));
|
||||
} else {
|
||||
updateState(channelName, new QuantityType<>(value, unit));
|
||||
}
|
||||
} else {
|
||||
updateState(channelName, UnDefType.UNDEF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+60
-1
@@ -22,10 +22,12 @@ import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.openhab.binding.tado.internal.handler.TadoHomeHandler;
|
||||
import org.openhab.binding.tado.swagger.codegen.api.ApiException;
|
||||
import org.openhab.binding.tado.swagger.codegen.api.model.GenericZoneCapabilities;
|
||||
import org.openhab.binding.tado.swagger.codegen.api.model.HomeInfo;
|
||||
@@ -54,11 +56,55 @@ public class HomeApi {
|
||||
|
||||
private Gson gson;
|
||||
private OAuthorizerV2 authorizer;
|
||||
private final TadoHomeHandler homeHandler;
|
||||
|
||||
public HomeApi(Gson gson, OAuthorizerV2 authorizer, String baseUrl) {
|
||||
private void extractRateLimitInfo(ContentResponse response) {
|
||||
int apiRateLimit = -1;
|
||||
int apiRateDuration = -1;
|
||||
int apiRateRemaining = -1;
|
||||
int apiRateReset = -1;
|
||||
|
||||
HttpFields headersfields = response.getHeaders();
|
||||
|
||||
String rateLimitPolicyValueString = headersfields.get("RateLimit-Policy");
|
||||
if (rateLimitPolicyValueString != null) {
|
||||
String[] rateLimitPolicyValues = rateLimitPolicyValueString.split(";");
|
||||
for (String value : rateLimitPolicyValues) {
|
||||
if (value.startsWith("q=")) {
|
||||
apiRateLimit = safeParseInt(value.substring(2));
|
||||
} else if (value.startsWith("w=")) {
|
||||
apiRateDuration = safeParseInt(value.substring(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String rateLimitValueString = headersfields.get("RateLimit");
|
||||
if (rateLimitValueString != null) {
|
||||
String[] rateLimitValues = rateLimitValueString.split(";");
|
||||
for (String value : rateLimitValues) {
|
||||
if (value.startsWith("r=")) {
|
||||
apiRateRemaining = safeParseInt(value.substring(2));
|
||||
} else if (value.startsWith("w=")) { // some providers use 'w' as window/reset seconds
|
||||
apiRateReset = safeParseInt(value.substring(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
homeHandler.updateRateLimitInfo(apiRateLimit, apiRateDuration, apiRateRemaining, apiRateReset);
|
||||
}
|
||||
|
||||
private static int safeParseInt(String s) {
|
||||
try {
|
||||
return Integer.parseInt(s.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public HomeApi(Gson gson, OAuthorizerV2 authorizer, String baseUrl, TadoHomeHandler homeHandler) {
|
||||
this.gson = gson;
|
||||
this.authorizer = authorizer;
|
||||
this.baseUrl = baseUrl;
|
||||
this.homeHandler = homeHandler;
|
||||
}
|
||||
|
||||
public void deleteZoneOverlay(Long homeId, Long zoneId) throws IOException, ApiException {
|
||||
@@ -97,6 +143,7 @@ public class HomeApi {
|
||||
}
|
||||
|
||||
int statusCode = response.getStatus();
|
||||
extractRateLimitInfo(response);
|
||||
if (statusCode >= HttpStatus.BAD_REQUEST_400) {
|
||||
throw new ApiException(response, "Operation deleteZoneOverlay failed with error " + statusCode);
|
||||
}
|
||||
@@ -137,6 +184,7 @@ public class HomeApi {
|
||||
|
||||
Type returnType = new TypeToken<HomeState>() {
|
||||
}.getType();
|
||||
extractRateLimitInfo(response);
|
||||
return gson.fromJson(response.getContentAsString(), returnType);
|
||||
}
|
||||
|
||||
@@ -175,6 +223,7 @@ public class HomeApi {
|
||||
|
||||
Type returnType = new TypeToken<List<MobileDevice>>() {
|
||||
}.getType();
|
||||
extractRateLimitInfo(response);
|
||||
return gson.fromJson(response.getContentAsString(), returnType);
|
||||
}
|
||||
|
||||
@@ -213,6 +262,7 @@ public class HomeApi {
|
||||
|
||||
Type returnType = new TypeToken<List<Zone>>() {
|
||||
}.getType();
|
||||
extractRateLimitInfo(response);
|
||||
return gson.fromJson(response.getContentAsString(), returnType);
|
||||
}
|
||||
|
||||
@@ -251,6 +301,7 @@ public class HomeApi {
|
||||
|
||||
Type returnType = new TypeToken<HomeInfo>() {
|
||||
}.getType();
|
||||
extractRateLimitInfo(response);
|
||||
return gson.fromJson(response.getContentAsString(), returnType);
|
||||
}
|
||||
|
||||
@@ -284,6 +335,7 @@ public class HomeApi {
|
||||
|
||||
Type returnType = new TypeToken<User>() {
|
||||
}.getType();
|
||||
extractRateLimitInfo(response);
|
||||
return gson.fromJson(response.getContentAsString(), returnType);
|
||||
}
|
||||
|
||||
@@ -329,6 +381,7 @@ public class HomeApi {
|
||||
|
||||
Type returnType = new TypeToken<GenericZoneCapabilities>() {
|
||||
}.getType();
|
||||
extractRateLimitInfo(response);
|
||||
return gson.fromJson(response.getContentAsString(), returnType);
|
||||
}
|
||||
|
||||
@@ -374,6 +427,7 @@ public class HomeApi {
|
||||
|
||||
Type returnType = new TypeToken<OverlayTemplate>() {
|
||||
}.getType();
|
||||
extractRateLimitInfo(response);
|
||||
return gson.fromJson(response.getContentAsString(), returnType);
|
||||
}
|
||||
|
||||
@@ -419,6 +473,7 @@ public class HomeApi {
|
||||
|
||||
Type returnType = new TypeToken<Zone>() {
|
||||
}.getType();
|
||||
extractRateLimitInfo(response);
|
||||
return gson.fromJson(response.getContentAsString(), returnType);
|
||||
}
|
||||
|
||||
@@ -464,6 +519,7 @@ public class HomeApi {
|
||||
|
||||
Type returnType = new TypeToken<Overlay>() {
|
||||
}.getType();
|
||||
extractRateLimitInfo(response);
|
||||
return gson.fromJson(response.getContentAsString(), returnType);
|
||||
}
|
||||
|
||||
@@ -508,6 +564,7 @@ public class HomeApi {
|
||||
|
||||
Type returnType = new TypeToken<ZoneState>() {
|
||||
}.getType();
|
||||
extractRateLimitInfo(response);
|
||||
return gson.fromJson(response.getContentAsString(), returnType);
|
||||
}
|
||||
|
||||
@@ -548,6 +605,7 @@ public class HomeApi {
|
||||
}
|
||||
|
||||
int statusCode = response.getStatus();
|
||||
extractRateLimitInfo(response);
|
||||
if (statusCode >= HttpStatus.BAD_REQUEST_400) {
|
||||
throw new ApiException(response, "Operation updatePresenceLock failed with error " + statusCode);
|
||||
}
|
||||
@@ -603,6 +661,7 @@ public class HomeApi {
|
||||
|
||||
Type returnType = new TypeToken<Overlay>() {
|
||||
}.getType();
|
||||
extractRateLimitInfo(response);
|
||||
return gson.fromJson(response.getContentAsString(), returnType);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,14 @@ thing-type.config.tado.zone.refreshInterval.description = Refresh interval of ho
|
||||
|
||||
channel-type.tado.acPower.label = Air-conditioning Power
|
||||
channel-type.tado.acPower.description = Current power state of the air-conditioning
|
||||
channel-type.tado.apiRateDuration.label = API Max Duration
|
||||
channel-type.tado.apiRateDuration.description = Duration in which the API count rises until maximum
|
||||
channel-type.tado.apiRateLimit.label = API Max
|
||||
channel-type.tado.apiRateLimit.description = Maximum API calls allowed per specified duration
|
||||
channel-type.tado.apiRateRemaining.label = API Calls remaining
|
||||
channel-type.tado.apiRateRemaining.description = Number of API calls remaining before the maximum is reached
|
||||
channel-type.tado.apiRateReset.label = Time until API count resets
|
||||
channel-type.tado.apiRateReset.description = Time until the API count resets
|
||||
channel-type.tado.atHome.label = At Home
|
||||
channel-type.tado.atHome.description = ON if at home, OFF if away
|
||||
channel-type.tado.currentTemperature.label = Temperature
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
<channels>
|
||||
<channel typeId="homePresence" id="homePresence"/>
|
||||
<channel typeId="geofencingEnabled" id="geofencingEnabled"/>
|
||||
<channel typeId="apiRateLimit" id="apiRateLimit"/>
|
||||
<channel typeId="apiRateDuration" id="apiRateDuration"/>
|
||||
<channel typeId="apiRateRemaining" id="apiRateRemaining"/>
|
||||
<channel typeId="apiRateReset" id="apiRateReset"/>
|
||||
</channels>
|
||||
|
||||
<properties>
|
||||
@@ -28,7 +32,7 @@
|
||||
|
||||
<parameter name="tadoApiUrl" type="text" required="true">
|
||||
<label>API Base URL</label>
|
||||
<description>he base URL used for all API requests. Can be changed to use a proxy.</description>
|
||||
<description>The base URL used for all API requests. Can be changed to use a proxy.</description>
|
||||
<default>https://my.tado.com/api/v2</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
@@ -416,4 +420,48 @@
|
||||
<state readOnly="true" pattern="%.0f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="apiRateDuration" advanced="true">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>API Max Duration</label>
|
||||
<description>Duration in which the API count rises until maximum</description>
|
||||
<category>Time</category>
|
||||
<tags>
|
||||
<tag>Status</tag>
|
||||
<tag>Duration</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="apiRateRemaining" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>API Calls remaining</label>
|
||||
<description>Number of API calls remaining before the maximum is reached</description>
|
||||
<tags>
|
||||
<tag>Status</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%d"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="apiRateLimit" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>API Max</label>
|
||||
<description>Maximum API calls allowed per specified duration</description>
|
||||
<tags>
|
||||
<tag>Status</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%d"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="apiRateReset" advanced="true">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Time until API count resets</label>
|
||||
<description>Time until the API count resets</description>
|
||||
<category>Time</category>
|
||||
<tags>
|
||||
<tag>Status</tag>
|
||||
<tag>Duration</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
|
||||
Reference in New Issue
Block a user