mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 23:22:02 +01:00
[hdpowerview] Add Hub configuration option hardRefreshBatteryLevel (#11260)
* Add Hub configuration option hardRefreshBatteryLevel for refreshing battery status more frequently. * Explicitly update battery channels to Undefined when data is missing or invalid. Fixes #11259 Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
This commit is contained in:
parent
84ba4fc333
commit
805d56dc08
@ -44,6 +44,7 @@ If in the future, you add additional shades or scenes to your system, the bindin
|
||||
| host | The host name or IP address of the hub on your network. |
|
||||
| refresh | The number of milli-seconds between fetches of the PowerView hub's shade state (default 60'000 one minute). |
|
||||
| hardRefresh | The number of minutes between hard refreshes of the PowerView hub's shade state (default 180 three hours). See [Refreshing the PowerView Hub Cache](#Refreshing-the-PowerView-Hub-Cache). |
|
||||
| hardRefreshBatteryLevel | The number of hours between hard refreshes of battery levels from the PowerView Hub (or 0 to disable, defaulting to weekly). See [Refreshing the PowerView Hub Cache](#Refreshing-the-PowerView-Hub-Cache). |
|
||||
|
||||
### Thing Configuration for PowerView Shades
|
||||
|
||||
@ -135,6 +136,10 @@ The hub periodically does a _**"hard refresh"**_ in order to overcome this issue
|
||||
The time interval between hard refreshes is set in the `hardRefresh` configuration parameter.
|
||||
To disable periodic hard refreshes, set `hardRefresh` to zero.
|
||||
|
||||
Similarly, the battery level is transient and is only updated automatically by the hub once a week.
|
||||
To change this interval, set `hardRefreshBatteryLevel` to number of hours between refreshes.
|
||||
To use default hub behavior (weekly updates), set `hardRefreshBatteryLevel` to zero.
|
||||
|
||||
Note: You can also force the hub to refresh itself by sending a `REFRESH` command in a rule to an item that is connected to a channel in the hub as follows:
|
||||
|
||||
```
|
||||
|
@ -234,8 +234,8 @@ public class HDPowerViewWebTargets {
|
||||
|
||||
/**
|
||||
* Instructs the hub to do a hard refresh (discovery on the hubs RF network) on
|
||||
* a specific shade; fetches a JSON package that describes that shade, and wraps
|
||||
* it in a Shade class instance
|
||||
* a specific shade's position; fetches a JSON package that describes that shade,
|
||||
* and wraps it in a Shade class instance
|
||||
*
|
||||
* @param shadeId id of the shade to be refreshed
|
||||
* @return Shade class instance
|
||||
@ -243,13 +243,31 @@ public class HDPowerViewWebTargets {
|
||||
* @throws HubProcessingException if there is any processing error
|
||||
* @throws HubMaintenanceException if the hub is down for maintenance
|
||||
*/
|
||||
public @Nullable Shade refreshShade(int shadeId)
|
||||
public @Nullable Shade refreshShadePosition(int shadeId)
|
||||
throws JsonParseException, HubProcessingException, HubMaintenanceException {
|
||||
String json = invoke(HttpMethod.GET, shades + Integer.toString(shadeId),
|
||||
Query.of("refresh", Boolean.toString(true)), null);
|
||||
return gson.fromJson(json, Shade.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the hub to do a hard refresh (discovery on the hubs RF network) on
|
||||
* a specific shade's battery level; fetches a JSON package that describes that shade,
|
||||
* and wraps it in a Shade class instance
|
||||
*
|
||||
* @param shadeId id of the shade to be refreshed
|
||||
* @return Shade class instance
|
||||
* @throws JsonParseException if there is a JSON parsing error
|
||||
* @throws HubProcessingException if there is any processing error
|
||||
* @throws HubMaintenanceException if the hub is down for maintenance
|
||||
*/
|
||||
public @Nullable Shade refreshShadeBatteryLevel(int shadeId)
|
||||
throws JsonParseException, HubProcessingException, HubMaintenanceException {
|
||||
String json = invoke(HttpMethod.GET, shades + Integer.toString(shadeId),
|
||||
Query.of("updateBatteryLevel", Boolean.toString(true)), null);
|
||||
return gson.fromJson(json, Shade.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the hub to stop movement of a specific shade
|
||||
*
|
||||
|
@ -29,4 +29,5 @@ public class HDPowerViewHubConfiguration {
|
||||
|
||||
public long refresh;
|
||||
public long hardRefresh;
|
||||
public long hardRefreshBatteryLevel;
|
||||
}
|
||||
|
@ -67,11 +67,13 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
|
||||
private final HttpClient httpClient;
|
||||
|
||||
private long refreshInterval;
|
||||
private long hardRefreshInterval;
|
||||
private long hardRefreshPositionInterval;
|
||||
private long hardRefreshBatteryLevelInterval;
|
||||
|
||||
private @Nullable HDPowerViewWebTargets webTargets;
|
||||
private @Nullable ScheduledFuture<?> pollFuture;
|
||||
private @Nullable ScheduledFuture<?> hardRefreshFuture;
|
||||
private @Nullable ScheduledFuture<?> hardRefreshPositionFuture;
|
||||
private @Nullable ScheduledFuture<?> hardRefreshBatteryLevelFuture;
|
||||
|
||||
private final ChannelTypeUID sceneChannelTypeUID = new ChannelTypeUID(HDPowerViewBindingConstants.BINDING_ID,
|
||||
HDPowerViewBindingConstants.CHANNELTYPE_SCENE_ACTIVATE);
|
||||
@ -84,7 +86,7 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (RefreshType.REFRESH.equals(command)) {
|
||||
requestRefreshShades();
|
||||
requestRefreshShadePositions();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -119,7 +121,8 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
|
||||
|
||||
webTargets = new HDPowerViewWebTargets(httpClient, host);
|
||||
refreshInterval = config.refresh;
|
||||
hardRefreshInterval = config.hardRefresh;
|
||||
hardRefreshPositionInterval = config.hardRefresh;
|
||||
hardRefreshBatteryLevelInterval = config.hardRefreshBatteryLevel;
|
||||
schedulePoll();
|
||||
}
|
||||
|
||||
@ -147,14 +150,24 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
|
||||
logger.debug("Scheduling poll for 5000ms out, then every {}ms", refreshInterval);
|
||||
this.pollFuture = scheduler.scheduleWithFixedDelay(this::poll, 5000, refreshInterval, TimeUnit.MILLISECONDS);
|
||||
|
||||
future = this.hardRefreshFuture;
|
||||
future = this.hardRefreshPositionFuture;
|
||||
if (future != null) {
|
||||
future.cancel(false);
|
||||
}
|
||||
if (hardRefreshInterval > 0) {
|
||||
logger.debug("Scheduling hard refresh every {}minutes", hardRefreshInterval);
|
||||
this.hardRefreshFuture = scheduler.scheduleWithFixedDelay(this::requestRefreshShades, 1,
|
||||
hardRefreshInterval, TimeUnit.MINUTES);
|
||||
if (hardRefreshPositionInterval > 0) {
|
||||
logger.debug("Scheduling hard position refresh every {} minutes", hardRefreshPositionInterval);
|
||||
this.hardRefreshPositionFuture = scheduler.scheduleWithFixedDelay(this::requestRefreshShadePositions, 1,
|
||||
hardRefreshPositionInterval, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
future = this.hardRefreshBatteryLevelFuture;
|
||||
if (future != null) {
|
||||
future.cancel(false);
|
||||
}
|
||||
if (hardRefreshBatteryLevelInterval > 0) {
|
||||
logger.debug("Scheduling hard battery level refresh every {} hours", hardRefreshBatteryLevelInterval);
|
||||
this.hardRefreshBatteryLevelFuture = scheduler.scheduleWithFixedDelay(
|
||||
this::requestRefreshShadeBatteryLevels, 1, hardRefreshBatteryLevelInterval, TimeUnit.HOURS);
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,11 +178,17 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
|
||||
}
|
||||
this.pollFuture = null;
|
||||
|
||||
future = this.hardRefreshFuture;
|
||||
future = this.hardRefreshPositionFuture;
|
||||
if (future != null) {
|
||||
future.cancel(true);
|
||||
}
|
||||
this.hardRefreshFuture = null;
|
||||
this.hardRefreshPositionFuture = null;
|
||||
|
||||
future = this.hardRefreshBatteryLevelFuture;
|
||||
if (future != null) {
|
||||
future.cancel(true);
|
||||
}
|
||||
this.hardRefreshBatteryLevelFuture = null;
|
||||
}
|
||||
|
||||
private synchronized void poll() {
|
||||
@ -304,13 +323,27 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void requestRefreshShades() {
|
||||
private void requestRefreshShadePositions() {
|
||||
Map<Thing, String> thingIdMap = getThingIdMap();
|
||||
for (Entry<Thing, String> item : thingIdMap.entrySet()) {
|
||||
Thing thing = item.getKey();
|
||||
ThingHandler handler = thing.getHandler();
|
||||
if (handler instanceof HDPowerViewShadeHandler) {
|
||||
((HDPowerViewShadeHandler) handler).requestRefreshShade();
|
||||
((HDPowerViewShadeHandler) handler).requestRefreshShadePosition();
|
||||
} else {
|
||||
String shadeId = item.getValue();
|
||||
logger.debug("Shade '{}' handler not initialized", shadeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void requestRefreshShadeBatteryLevels() {
|
||||
Map<Thing, String> thingIdMap = getThingIdMap();
|
||||
for (Entry<Thing, String> item : thingIdMap.entrySet()) {
|
||||
Thing thing = item.getKey();
|
||||
ThingHandler handler = thing.getHandler();
|
||||
if (handler instanceof HDPowerViewShadeHandler) {
|
||||
((HDPowerViewShadeHandler) handler).requestRefreshShadeBatteryLevel();
|
||||
} else {
|
||||
String shadeId = item.getValue();
|
||||
logger.debug("Shade '{}' handler not initialized", shadeId);
|
||||
|
@ -19,6 +19,8 @@ import static org.openhab.binding.hdpowerview.internal.api.CoordinateSystem.*;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.ws.rs.NotSupportedException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.hdpowerview.internal.HDPowerViewWebTargets;
|
||||
@ -57,10 +59,16 @@ import org.slf4j.LoggerFactory;
|
||||
@NonNullByDefault
|
||||
public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
|
||||
|
||||
private enum RefreshKind {
|
||||
POSITION,
|
||||
BATTERY_LEVEL
|
||||
}
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(HDPowerViewShadeHandler.class);
|
||||
|
||||
private static final int REFRESH_DELAY_SEC = 10;
|
||||
private @Nullable ScheduledFuture<?> refreshFuture = null;
|
||||
private @Nullable ScheduledFuture<?> refreshPositionFuture = null;
|
||||
private @Nullable ScheduledFuture<?> refreshBatteryLevelFuture = null;
|
||||
|
||||
public HDPowerViewShadeHandler(Thing thing) {
|
||||
super(thing);
|
||||
@ -85,7 +93,7 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (RefreshType.REFRESH.equals(command)) {
|
||||
requestRefreshShade();
|
||||
requestRefreshShadePosition();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -138,7 +146,9 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
updateBindingStates(shadeData.positions);
|
||||
updateBatteryLevel(shadeData.batteryStatus);
|
||||
updateState(CHANNEL_SHADE_BATTERY_VOLTAGE, new QuantityType<>(shadeData.batteryStrength / 10, Units.VOLT));
|
||||
updateState(CHANNEL_SHADE_BATTERY_VOLTAGE,
|
||||
shadeData.batteryStrength > 0 ? new QuantityType<>(shadeData.batteryStrength / 10, Units.VOLT)
|
||||
: UnDefType.UNDEF);
|
||||
updateState(CHANNEL_SHADE_SIGNAL_STRENGTH, new DecimalType(shadeData.signalStrength));
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||
@ -171,6 +181,8 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
|
||||
mappedValue = 100;
|
||||
break;
|
||||
default: // No status available (0) or invalid
|
||||
updateState(CHANNEL_SHADE_LOW_BATTERY, UnDefType.UNDEF);
|
||||
updateState(CHANNEL_SHADE_BATTERY_LEVEL, UnDefType.UNDEF);
|
||||
return;
|
||||
}
|
||||
updateState(CHANNEL_SHADE_LOW_BATTERY, batteryStatus == 1 ? OnOffType.ON : OnOffType.OFF);
|
||||
@ -243,7 +255,7 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
|
||||
}
|
||||
int shadeId = getShadeId();
|
||||
webTargets.stopShade(shadeId);
|
||||
requestRefreshShade();
|
||||
requestRefreshShadePosition();
|
||||
} catch (HubProcessingException | NumberFormatException e) {
|
||||
logger.warn("Unexpected error: {}", e.getMessage());
|
||||
return;
|
||||
@ -254,15 +266,36 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that the shade shall undergo a 'hard' refresh
|
||||
* Request that the shade shall undergo a 'hard' refresh for querying its current position
|
||||
*/
|
||||
protected synchronized void requestRefreshShade() {
|
||||
if (refreshFuture == null) {
|
||||
refreshFuture = scheduler.schedule(this::doRefreshShade, REFRESH_DELAY_SEC, TimeUnit.SECONDS);
|
||||
protected synchronized void requestRefreshShadePosition() {
|
||||
if (refreshPositionFuture == null) {
|
||||
refreshPositionFuture = scheduler.schedule(this::doRefreshShadePosition, REFRESH_DELAY_SEC,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void doRefreshShade() {
|
||||
/**
|
||||
* Request that the shade shall undergo a 'hard' refresh for querying its battery level state
|
||||
*/
|
||||
protected synchronized void requestRefreshShadeBatteryLevel() {
|
||||
if (refreshBatteryLevelFuture == null) {
|
||||
refreshBatteryLevelFuture = scheduler.schedule(this::doRefreshShadeBatteryLevel, REFRESH_DELAY_SEC,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void doRefreshShadePosition() {
|
||||
this.doRefreshShade(RefreshKind.POSITION);
|
||||
refreshPositionFuture = null;
|
||||
}
|
||||
|
||||
private void doRefreshShadeBatteryLevel() {
|
||||
this.doRefreshShade(RefreshKind.BATTERY_LEVEL);
|
||||
refreshBatteryLevelFuture = null;
|
||||
}
|
||||
|
||||
private void doRefreshShade(RefreshKind kind) {
|
||||
try {
|
||||
HDPowerViewHubHandler bridge;
|
||||
if ((bridge = getBridgeHandler()) == null) {
|
||||
@ -273,7 +306,17 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
|
||||
throw new HubProcessingException("Web targets not initialized");
|
||||
}
|
||||
int shadeId = getShadeId();
|
||||
Shade shade = webTargets.refreshShade(shadeId);
|
||||
Shade shade;
|
||||
switch (kind) {
|
||||
case POSITION:
|
||||
shade = webTargets.refreshShadePosition(shadeId);
|
||||
break;
|
||||
case BATTERY_LEVEL:
|
||||
shade = webTargets.refreshShadeBatteryLevel(shadeId);
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("Unsupported refresh kind " + kind.toString());
|
||||
}
|
||||
if (shade != null) {
|
||||
ShadeData shadeData = shade.shade;
|
||||
if (shadeData != null) {
|
||||
@ -287,6 +330,5 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
|
||||
} catch (HubMaintenanceException e) {
|
||||
// exceptions are logged in HDPowerViewWebTargets
|
||||
}
|
||||
refreshFuture = null;
|
||||
}
|
||||
}
|
||||
|
@ -26,10 +26,17 @@
|
||||
<default>60000</default>
|
||||
</parameter>
|
||||
<parameter name="hardRefresh" type="integer" required="false">
|
||||
<label>Hard Refresh Interval</label>
|
||||
<description>The number of minutes between hard refreshes of the PowerView Hub (or 0 to disable)</description>
|
||||
<label>Hard Position Refresh Interval</label>
|
||||
<description>The number of minutes between hard refreshes of positions from the PowerView Hub (or 0 to disable)</description>
|
||||
<default>180</default>
|
||||
</parameter>
|
||||
<parameter name="hardRefreshBatteryLevel" type="integer" required="false">
|
||||
<label>Hard Battery Level Refresh Interval</label>
|
||||
<description>The number of hours between hard refreshes of battery levels from the PowerView Hub (or 0 to disable,
|
||||
default is weekly)</description>
|
||||
<advanced>true</advanced>
|
||||
<default>0</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
|
||||
|
@ -218,7 +218,7 @@ public class HDPowerViewJUnitTests {
|
||||
Shade shade = null;
|
||||
try {
|
||||
assertNotEquals(0, shadeId);
|
||||
shade = webTargets.refreshShade(shadeId);
|
||||
shade = webTargets.refreshShadePosition(shadeId);
|
||||
assertNotNull(shade);
|
||||
} catch (HubProcessingException | HubMaintenanceException e) {
|
||||
fail(e.getMessage());
|
||||
|
Loading…
Reference in New Issue
Block a user