这是indexloc提供的服务,不要输入任何密码
Skip to content
This repository was archived by the owner on May 17, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.prefs.Preferences;

import org.apache.commons.beanutils.ConvertUtils;
Expand Down Expand Up @@ -76,10 +77,15 @@ public class EcobeeBinding extends AbstractActiveBinding<EcobeeBindingProvider>
EcobeeActionProvider {

private static final String DEFAULT_USER_ID = "DEFAULT_USER";
private static final long DEFAULT_GRANULARITY = 5000;
private static final long DEFAULT_REFRESH = 180000;
private static final long DEFAULT_QUICKPOLL = 6000;

private static final Logger logger = LoggerFactory.getLogger(EcobeeBinding.class);

protected static final String CONFIG_GRANULARITY = "granularity";
protected static final String CONFIG_REFRESH = "refresh";
protected static final String CONFIG_QUICKPOLL = "quickpoll";
protected static final String CONFIG_TIMEOUT = "timeout";
protected static final String CONFIG_APP_KEY = "appkey";
protected static final String CONFIG_SCOPE = "scope";
Expand Down Expand Up @@ -158,9 +164,20 @@ public Object convert(Class type, Object value) {
}

/**
* the refresh interval which is used to poll values from the Ecobee server (optional, defaults to 180000ms)
* the interval which is used to call the execute() method
*/
private long refreshInterval = 180000;
private long granularity = DEFAULT_GRANULARITY;

/**
* the normal refresh interval which is used to poll values from the Ecobee server
*/
private long refreshInterval = DEFAULT_REFRESH;

/**
* the quick refresh interval which is used to poll values from the Ecobee server after a command was sent, a state
* was updated or an action was called
*/
private long quickPollInterval = DEFAULT_QUICKPOLL;

/**
* A map of userids from the openhab.cfg file to OAuth credentials used to communicate with each app instance.
Expand Down Expand Up @@ -222,7 +239,7 @@ public void deactivate() {
*/
@Override
protected long getRefreshInterval() {
return refreshInterval;
return granularity;
}

/**
Expand All @@ -238,27 +255,32 @@ protected String getName() {
*/
@Override
protected void execute() {
logger.trace("Querying Ecobee API");

try {
for (String userid : credentialsCache.keySet()) {
OAuthCredentials oauthCredentials = getOAuthCredentials(userid);

Selection selection = createSelection(oauthCredentials);
if (selection == null) {
logger.debug("Nothing to retrieve for '{}'; skipping thermostat retrieval.",
oauthCredentials.userid);
continue;
}
if (oauthCredentials.pollTimeExpired()) {
// schedule the next poll at the standard refresh interval
oauthCredentials.schedulePoll(this.refreshInterval);

if (oauthCredentials.noAccessToken()) {
if (!oauthCredentials.refreshTokens()) {
logger.warn("Periodic poll skipped for '{}'.", oauthCredentials.userid);
logger.trace("Querying Ecobee API for instance {}", oauthCredentials.userid);

Selection selection = createSelection(oauthCredentials);
if (selection == null) {
logger.debug("Nothing to retrieve for '{}'; skipping thermostat retrieval.",
oauthCredentials.userid);
continue;
}
}

readEcobee(oauthCredentials, selection);
if (oauthCredentials.noAccessToken()) {
if (!oauthCredentials.refreshTokens()) {
logger.warn("Periodic poll skipped for '{}'.", oauthCredentials.userid);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it might be helpful to the reason why polling is skipped (due to a missing token)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rely on the refreshTokens() method to log the specific error and then return false, so the caller only has to report how it affects control flow.

continue;
}
}

readEcobee(oauthCredentials, selection);
}
}
} catch (Exception e) {
if (logger.isDebugEnabled()) {
Expand Down Expand Up @@ -533,7 +555,7 @@ private void updateEcobee(final String itemName, final State newState) {
}

if (!provider.isOutBound(itemName)) {
logger.warn("attempt to update non-outbound item skipped [itemName={}, newState={}]", itemName, newState);
logger.debug("attempt to update non-outbound item skipped [itemName={}, newState={}]", itemName, newState);
return;
}

Expand Down Expand Up @@ -578,6 +600,9 @@ private void updateEcobee(final String itemName, final State newState) {
} else {
logger.error("Error updating thermostat(s): {}", response);
}
} else {
// schedule the next poll to happen quickly
oauthCredentials.schedulePoll(this.quickPollInterval);
}
} catch (Exception e) {
logger.error("Unable to update thermostat(s)", e);
Expand Down Expand Up @@ -642,8 +667,11 @@ public boolean callEcobee(final String itemName, final AbstractFunction function
logger.error("Error calling function: {}", response);
}
return false;
} else {
// schedule the next poll to happen quickly
oauthCredentials.schedulePoll(this.quickPollInterval);
return true;
}
return true;
} catch (Exception e) {
logger.error("Unable to call function", e);
return false;
Expand Down Expand Up @@ -705,12 +733,23 @@ private OAuthCredentials getOAuthCredentials(String userid) {
public void updated(Dictionary<String, ?> config) throws ConfigurationException {
if (config != null) {

// to override the default granularity one has to add a
// parameter to openhab.cfg like ecobee:granularity=2000
String granularityString = (String) config.get(CONFIG_GRANULARITY);
granularity = isNotBlank(granularityString) ? Long.parseLong(granularityString) : DEFAULT_GRANULARITY;

// to override the default refresh interval one has to add a
// parameter to openhab.cfg like ecobee:refresh=240000
String refreshIntervalString = (String) config.get(CONFIG_REFRESH);
if (isNotBlank(refreshIntervalString)) {
refreshInterval = Long.parseLong(refreshIntervalString);
}
refreshInterval = isNotBlank(refreshIntervalString) ? Long.parseLong(refreshIntervalString)
: DEFAULT_REFRESH;

// to override the default quickPoll interval one has to add a
// parameter to openhab.cfg like ecobee:quickpoll=4000
String quickPollIntervalString = (String) config.get(CONFIG_QUICKPOLL);
quickPollInterval = isNotBlank(quickPollIntervalString) ? Long.parseLong(quickPollIntervalString)
: DEFAULT_QUICKPOLL;

// to override the default HTTP timeout one has to add a
// parameter to openhab.cfg like ecobee:timeout=20000
String timeoutString = (String) config.get(CONFIG_TIMEOUT);
Expand All @@ -735,7 +774,8 @@ public void updated(Dictionary<String, ?> config) throws ConfigurationException

// the config-key enumeration contains additional keys that we
// don't want to process here ...
if (CONFIG_REFRESH.equals(configKey) || CONFIG_TIMEOUT.equals(configKey)
if (CONFIG_GRANULARITY.equals(configKey) || CONFIG_REFRESH.equals(configKey)
|| CONFIG_QUICKPOLL.equals(configKey) || CONFIG_TIMEOUT.equals(configKey)
|| CONFIG_TEMP_SCALE.equals(configKey) || "service.pid".equals(configKey)) {
continue;
}
Expand Down Expand Up @@ -995,6 +1035,11 @@ static class OAuthCredentials {
*/
private String accessToken;

/**
* The next time to poll this instance. Initially 0 so pollTimeExpired() initially returns true.
*/
private final AtomicLong pollTime = new AtomicLong(0);

/**
* The most recently received list of revisions, or an empty Map if none have been retrieved yet.
*/
Expand Down Expand Up @@ -1131,5 +1176,24 @@ public boolean refreshTokens() {
}
}
}

/**
* Return true if this instance is at or past the time to poll.
*
* @return if this instance is at or past the time to poll.
*/
private boolean pollTimeExpired() {
return System.currentTimeMillis() >= this.pollTime.get();
}

/**
* Record the earliest time in the future at which we are allowed to poll this instance.
*
* @param future
* the number of milliseconds in the future
*/
private void schedulePoll(long future) {
this.pollTime.set(System.currentTimeMillis() + future);
}
}
}
23 changes: 16 additions & 7 deletions distribution/openhabhome/configurations/openhab_default.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -2050,20 +2050,29 @@ tcp:refreshinterval=250

################################ Ecobee Binding #######################################
#
# the private API key issued be Ecobee to use the API (required, replace with your own)
# ecobee:appkey=9T4huoUXlT5b5qNpEJvM5sqTMgaNCFoV

# the application scope used when authorizing the binding
# choices are smartWrite,smartRead, or ems, or multiple (required, comma-separated, no spaces)
# ecobee:scope=smartWrite

# Rate at which to check if poll is to run, in ms (optional, defaults to 5000)
# ecobee:granularity=5000

# Data refresh interval in ms (optional, defaults to 180000)
# ecobee:refresh=180000

# Time in ms to wait after successful update, command or action before refresh (optional, defaults to 6000)
# ecobee:quickpoll=6000

# Time in ms to allow an API request to complete (optional, defaults to 20000)
# ecobee:timeout=20000

# the temperature scale to use when sending or receiving temperatures
# optional, defaults to Fahrenheit (F)
# ecobee:tempscale=C

# the private API key issued be Ecobee to use the API (replace with your own)
# ecobee:appkey=9T4huoUXlT5b5qNpEJvM5sqTMgaNCFoV

# the application scope used when authorizing the binding
# choices are smartWrite,smartRead, or ems, or multiple (comma-separated, no spaces)
# ecobee:scope=smartWrite

################################ Panasonic TV Binding #######################################
#
# IP address of a Panasonic TV instance
Expand Down