Skip to content

Commit

Permalink
[mybmw] Improve data refresh handling (openhab#16418)
Browse files Browse the repository at this point in the history
* [mybmw] add functionality for updating
disable updating by setting the refresh-interval to 0
enable force update by adding some switches

Signed-off-by: Martin Grassl <[email protected]>
  • Loading branch information
martingrassl authored Feb 25, 2024
1 parent 3d9ac22 commit d56c9e5
Show file tree
Hide file tree
Showing 23 changed files with 491 additions and 144 deletions.
248 changes: 134 additions & 114 deletions bundles/org.openhab.binding.mybmw/README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public interface MyBMWConstants {

static final int DEFAULT_IMAGE_SIZE_PX = 1024;

static final int DEFAULT_REFRESH_INTERVAL_MINUTES = 5;
static final int DEFAULT_REFRESH_INTERVAL_MINUTES = 60;

// See constants from bimmer-connected
// https://github.com/bimmerconnected/bimmer_connected/blob/master/bimmer_connected/vehicle.py
Expand Down Expand Up @@ -107,6 +107,7 @@ enum ChargingPreference {
THING_TYPE_PHEV, THING_TYPE_BEV_REX, THING_TYPE_BEV);

// Thing Group definitions
static final String CHANNEL_GROUP_UPDATE = "update";
static final String CHANNEL_GROUP_STATUS = "status";
static final String CHANNEL_GROUP_SERVICE = "service";
static final String CHANNEL_GROUP_CHECK_CONTROL = "check";
Expand All @@ -120,6 +121,11 @@ enum ChargingPreference {
static final String CHANNEL_GROUP_TIRES = "tires";
static final String CHANNEL_GROUP_VEHICLE_IMAGE = "image";

// types of updates
static final String STATE_UPDATE = "state-update";
static final String CHARGING_UPDATE = "charging-update";
static final String IMAGE_UPDATE = "image-update";

// Charge Statistics & Sessions
static final String SESSIONS = "sessions";
static final String ENERGY = "energy";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ private void getState() {
ExecutionState.TIMEOUT.name().toLowerCase());
reset();
// immediately refresh data
handler.getData();
handler.updateData();
} else {
counter++;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import static org.openhab.binding.mybmw.internal.MyBMWConstants.CHANNEL_GROUP_SERVICE;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.CHANNEL_GROUP_STATUS;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.CHANNEL_GROUP_TIRES;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.CHANNEL_GROUP_UPDATE;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.CHANNEL_GROUP_VEHICLE_IMAGE;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.CHARGE_ENABLED;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.CHARGE_PROFILE_CLIMATE;
Expand All @@ -34,6 +35,7 @@
import static org.openhab.binding.mybmw.internal.MyBMWConstants.CHARGE_PROFILE_TARGET;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.CHARGE_REMAINING;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.CHARGE_STATUS;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.CHARGING_UPDATE;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.CHECK_CONTROL;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.DATE;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.DETAILS;
Expand All @@ -54,6 +56,7 @@
import static org.openhab.binding.mybmw.internal.MyBMWConstants.HOME_DISTANCE;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.HOOD;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.IMAGE_FORMAT;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.IMAGE_UPDATE;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.IMAGE_VIEWPORT;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.ISSUE;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.LAST_FETCHED;
Expand Down Expand Up @@ -81,6 +84,7 @@
import static org.openhab.binding.mybmw.internal.MyBMWConstants.SESSIONS;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.SEVERITY;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.SOC;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.STATE_UPDATE;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.STATUS;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.SUBTITLE;
import static org.openhab.binding.mybmw.internal.MyBMWConstants.SUNROOF;
Expand Down Expand Up @@ -207,6 +211,8 @@ public class VehicleHandler extends BaseThingHandler {

private ImageProperties imageProperties = new ImageProperties();

private ThingStatus currentStatus = ThingStatus.UNKNOWN;

public VehicleHandler(Thing thing, MyBMWCommandOptionProvider commandOptionProvider,
LocationProvider locationProvider, TimeZoneProvider timeZoneProvider, String driveTrain) {
super(thing);
Expand Down Expand Up @@ -237,7 +243,8 @@ private void setOptions(final String group, final String id, List<CommandOption>
@Override
public void initialize() {
logger.trace("VehicleHandler.initialize");
updateStatus(ThingStatus.UNKNOWN);
currentStatus = ThingStatus.UNKNOWN;
updateStatus(currentStatus);
vehicleConfiguration = Optional.of(getConfigAs(MyBMWVehicleConfiguration.class));

Bridge bridge = getBridge();
Expand All @@ -257,20 +264,26 @@ public void initialize() {
updateChannel(CHANNEL_GROUP_VEHICLE_IMAGE, IMAGE_VIEWPORT, Converter.toTitleCase(imageProperties.viewport),
null);

// start update schedule
startSchedule(vehicleConfiguration.get().getRefreshInterval());
}

private void startSchedule(int interval) {
logger.trace("VehicleHandler.startSchedule");
refreshJob.ifPresentOrElse(job -> {
if (job.isCancelled()) {
// start update schedule only if the refreshInterval is not 0
if (interval > 0) {
logger.info("VehicleHandler.startSchedule with interval {}min", interval);
refreshJob.ifPresentOrElse(job -> {
if (job.isCancelled()) {
refreshJob = Optional
.of(scheduler.scheduleWithFixedDelay(this::updateData, 0, interval, TimeUnit.MINUTES));
} // else - scheduler is already running!
}, () -> {
refreshJob = Optional
.of(scheduler.scheduleWithFixedDelay(this::getData, 0, interval, TimeUnit.MINUTES));
} // else - scheduler is already running!
}, () -> {
refreshJob = Optional.of(scheduler.scheduleWithFixedDelay(this::getData, 0, interval, TimeUnit.MINUTES));
});
.of(scheduler.scheduleWithFixedDelay(this::updateData, 0, interval, TimeUnit.MINUTES));
});
} else {
logger.info("VehicleHandler initialize: don't start schedule as interval is 0");
updateData();
}
}

@Override
Expand All @@ -281,25 +294,44 @@ public void dispose() {
remote.ifPresent(RemoteServiceExecutor::cancel);
}

public void getData() {
logger.trace("VehicleHandler.getData");
/**
* update all data
*/
void updateData() {
logger.trace("VehicleHandler.updateData");
updateVehicleStatus();
if (isElectric) {
updateCharging();
}
updateImage();
}

private void updateVehicleStatus() {
proxy.ifPresentOrElse(prox -> {
vehicleConfiguration.ifPresentOrElse(config -> {

boolean stateError = false;
try {
VehicleStateContainer vehicleState = prox.requestVehicleState(config.getVin(),
config.getVehicleBrand());
triggerVehicleStatusUpdate(vehicleState, null);
stateError = false;
currentStatus = ThingStatus.ONLINE;
updateStatus(currentStatus);
} catch (NetworkException e) {
logger.debug("{}", e.toString());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Vehicle State Update failed");
stateError = true;
currentStatus = ThingStatus.OFFLINE;
updateStatus(currentStatus, ThingStatusDetail.COMMUNICATION_ERROR, "Vehicle State Update failed");
}
}, () -> {
logger.warn("MyBMW Vehicle Configuration isn't present");
});
}, () -> {
logger.warn("MyBMWProxy isn't present");
});
}

if (!stateError && isElectric) {
private void updateCharging() {
proxy.ifPresentOrElse(prox -> {
vehicleConfiguration.ifPresentOrElse(config -> {
if (isElectric && ThingStatus.ONLINE.equals(currentStatus)) {
try {
updateChargingStatistics(
prox.requestChargeStatistics(config.getVin(), config.getVehicleBrand()), null);
Expand All @@ -309,7 +341,19 @@ public void getData() {
logger.debug("{}", e.toString());
}
}
if (!stateError && !imageCache.isPresent() && !imageProperties.failLimitReached()) {
}, () -> {
logger.warn("MyBMW Vehicle Configuration isn't present");
});
}, () -> {
logger.warn("MyBMWProxy isn't present");
});
}

private void updateImage() {
proxy.ifPresentOrElse(prox -> {
vehicleConfiguration.ifPresentOrElse(config -> {
if (!imageCache.isPresent() && !imageProperties.failLimitReached()
&& ThingStatus.ONLINE.equals(currentStatus)) {
try {
updateImage(prox.requestImage(config.getVin(), config.getVehicleBrand(), imageProperties));
} catch (NetworkException e) {
Expand All @@ -334,8 +378,6 @@ private void triggerVehicleStatusUpdate(VehicleStateContainer vehicleState, @Nul
if (isElectric) {
updateChargingProfile(vehicleState.getState().getChargingProfile(), channelToBeUpdated);
}

updateStatus(ThingStatus.ONLINE);
} else {
logger.debug("configuration not present");
}
Expand Down Expand Up @@ -951,6 +993,23 @@ public void handleCommand(ChannelUID channelUID, Command command) {
logger.debug("Cannot handle command {}, channel {} in group {} not a command channel",
command.toFullString(), channelUID.getAsString(), group);
}
} else if (command instanceof OnOffType) {
if (CHANNEL_GROUP_UPDATE.equals(group) && OnOffType.ON.equals(command)) {
// triggering the update of the respective channel
switch (channelUID.getIdWithoutGroup()) {
case STATE_UPDATE:
updateVehicleStatus();
break;
case CHARGING_UPDATE:
updateCharging();
break;
case IMAGE_UPDATE:
updateImage();
break;
default:
break;
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<label>Vehicle Identification Number (VIN)</label>
<description>Unique VIN given by BMW</description>
</parameter>
<parameter name="refreshInterval" type="integer" min="1" unit="min" required="true">
<parameter name="refreshInterval" type="integer" min="0" unit="min" required="true">
<label>Refresh Interval</label>
<description>Data refresh rate for your vehicle data</description>
<default>5</default>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ thing-type.config.mybmw.bridge.region.option.ROW = Rest of the World
thing-type.config.mybmw.bridge.userName.description = MyBMW Username
thing-type.config.mybmw.bridge.userName.label = Username

thing-type.config.mybmw.vehicle.refreshInterval.description = Data refresh rate for your vehicle data
thing-type.config.mybmw.vehicle.refreshInterval.description = Data refresh rate for your vehicle data. If set to 0 no refresh will be triggered automatically.
thing-type.config.mybmw.vehicle.refreshInterval.label = Refresh Interval
thing-type.config.mybmw.vehicle.vehicleBrand.description = Vehicle brand like BMW or Mini
thing-type.config.mybmw.vehicle.vehicleBrand.label = Brand of the Vehicle
Expand Down Expand Up @@ -46,6 +46,8 @@ channel-group-type.mybmw.ev-range-values.description = Provides Mileage, remaini
channel-group-type.mybmw.ev-range-values.label = Range and Charge Data
channel-group-type.mybmw.ev-vehicle-status.description = Overall vehicle status
channel-group-type.mybmw.ev-vehicle-status.label = Vehicle Status
channel-group-type.mybmw.ev-vehicle-update.description = Force the update of the vehicle data
channel-group-type.mybmw.ev-vehicle-update.label = Force Vehicle Update
channel-group-type.mybmw.hybrid-range-values.description = Provides mileage, remaining fuel and range data for hybrid vehicles
channel-group-type.mybmw.hybrid-range-values.label = Range, Charge / Fuel Data
channel-group-type.mybmw.image-values.description = Provides an image of your vehicle
Expand All @@ -65,12 +67,16 @@ channel-group-type.mybmw.tire-pressures.description = Current and wanted pressur
channel-group-type.mybmw.tire-pressures.label = Tire Pressure
channel-group-type.mybmw.vehicle-status.description = Overall vehicle status
channel-group-type.mybmw.vehicle-status.label = Vehicle Status
channel-group-type.mybmw.vehicle-update.description = Force the update of the vehicle data
channel-group-type.mybmw.vehicle-update.label = Force Vehicle Update


# channel types
channel-type.mybmw.address-channel.label = Address
channel-type.mybmw.charging-info-channel.label = Charging Information
channel-type.mybmw.charging-remaining-channel.label = Remaining Charging Time
channel-type.mybmw.charging-status-channel.label = Charging Status
channel-type.mybmw.charging-update-channel.label = Force update of the charging data
channel-type.mybmw.check-control-channel.label = Check Control
channel-type.mybmw.checkcontrol-details-channel.label = CheckControl Details
channel-type.mybmw.checkcontrol-name-channel.label = CheckControl Description
Expand All @@ -91,6 +97,7 @@ channel-type.mybmw.home-distance-channel.description = Computed distance between
channel-type.mybmw.home-distance-channel.label = Distance From Home
channel-type.mybmw.hood-channel.label = Hood

channel-type.mybmw.image-update-channel.label = Force update of the image
channel-type.mybmw.image-view-channel.command.option.FrontLeft = Left Side View
channel-type.mybmw.image-view-channel.command.option.FrontRight = Right Side View
channel-type.mybmw.image-view-channel.command.option.FrontView = Front View
Expand Down Expand Up @@ -161,6 +168,7 @@ channel-type.mybmw.session-subtitle-channel.label = Session Details
channel-type.mybmw.session-title-channel.label = Session Title
channel-type.mybmw.soc-channel.label = Battery Charge Level

channel-type.mybmw.state-update-channel.label = Force update of the vehicle state data
channel-type.mybmw.statistic-energy-channel.description = Total energy charged in current month
channel-type.mybmw.statistic-energy-channel.label = Energy Charged
channel-type.mybmw.statistic-sessions-channel.description = Number of charging sessions this month
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="mybmw"
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">
<channel-group-type id="ev-vehicle-update">
<label>Vehicle Update</label>
<description>Triggering the vehicle update</description>
<channels>
<channel id="state-update" typeId="state-update-channel"/>
<channel id="charging-update" typeId="charging-update-channel"/>
<channel id="image-update" typeId="image-update-channel"/>
</channels>
</channel-group-type>
</thing:thing-descriptions>
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<description>Battery Electric Vehicle (BEV)</description>

<channel-groups>
<channel-group id="update" typeId="ev-vehicle-update"/>
<channel-group id="status" typeId="ev-vehicle-status"/>
<channel-group id="doors" typeId="door-values"/>
<channel-group id="range" typeId="ev-range-values"/>
Expand All @@ -28,7 +29,7 @@
</channel-groups>

<properties>
<property name="thingTypeVersion">1</property>
<property name="thingTypeVersion">2</property>
</properties>

<representation-property>vin</representation-property>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<description>Battery Electric Vehicle with Range Extender (BEV_REX)</description>

<channel-groups>
<channel-group id="update" typeId="ev-vehicle-update"/>
<channel-group id="status" typeId="ev-vehicle-status"/>
<channel-group id="doors" typeId="door-values"/>
<channel-group id="range" typeId="hybrid-range-values"/>
Expand All @@ -28,7 +29,7 @@
</channel-groups>

<properties>
<property name="thingTypeVersion">1</property>
<property name="thingTypeVersion">2</property>
</properties>

<representation-property>vin</representation-property>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<description>Conventional Fuel Vehicle (CONV)</description>

<channel-groups>
<channel-group id="update" typeId="vehicle-update"/>
<channel-group id="status" typeId="vehicle-status"/>
<channel-group id="doors" typeId="door-values"/>
<channel-group id="range" typeId="conv-range-values"/>
Expand All @@ -25,7 +26,7 @@
</channel-groups>

<properties>
<property name="thingTypeVersion">1</property>
<property name="thingTypeVersion">2</property>
</properties>

<representation-property>vin</representation-property>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<description>Conventional Fuel Vehicle with supporting Electric Engine (PHEV)</description>

<channel-groups>
<channel-group id="update" typeId="ev-vehicle-update"/>
<channel-group id="status" typeId="ev-vehicle-status"/>
<channel-group id="doors" typeId="door-values"/>
<channel-group id="range" typeId="hybrid-range-values"/>
Expand All @@ -28,7 +29,7 @@
</channel-groups>

<properties>
<property name="thingTypeVersion">1</property>
<property name="thingTypeVersion">2</property>
</properties>

<representation-property>vin</representation-property>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="mybmw"
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">
<channel-type id="state-update-channel">
<item-type>Switch</item-type>
<label>trigger the update of the state</label>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
<channel-type id="charging-update-channel">
<item-type>Switch</item-type>
<label>trigger the update of the charging information</label>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
<channel-type id="image-update-channel">
<item-type>Switch</item-type>
<label>trigger the update of the image</label>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
</thing:thing-descriptions>
Loading

0 comments on commit d56c9e5

Please sign in to comment.