Skip to content
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 @@ -49,6 +49,6 @@ public class FlumeBindingConstants {
// Properties
public static final String PROPERTY_ID = "id";

public static final int DEFAULT_POLLING_INTERVAL_INSTANTANEOUS = 1;
public static final int DEFAULT_POLLING_INTERVAL_CUMULATIVE = 5;
public static final int DEFAULT_POLLING_INTERVAL_INSTANTANEOUS_MIN = 1;
public static final int DEFAULT_POLLING_INTERVAL_CUMULATIVE_MIN = 5;
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ public class FlumeBridgeConfig {
public String username = "";
public String password = "";

public int refreshIntervalInstantaneous = DEFAULT_POLLING_INTERVAL_INSTANTANEOUS;
public int refreshIntervalCumulative = DEFAULT_POLLING_INTERVAL_CUMULATIVE;
public int refreshIntervalInstantaneous = DEFAULT_POLLING_INTERVAL_INSTANTANEOUS_MIN;
public int refreshIntervalCumulative = DEFAULT_POLLING_INTERVAL_CUMULATIVE_MIN;
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.openhab.core.i18n.TranslationProvider;
import org.openhab.core.i18n.UnitProvider;
import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.storage.StorageService;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
Expand All @@ -50,15 +51,18 @@ public class FlumeHandlerFactory extends BaseThingHandlerFactory {
private final HttpClientFactory httpClientFactory;
private final TranslationProvider i18nProvider;
private final LocaleProvider localeProvider;
private final StorageService storageService;
public final SystemOfUnits systemOfUnits;

@Activate
public FlumeHandlerFactory(@Reference UnitProvider unitProvider, @Reference HttpClientFactory httpClientFactory,
final @Reference TranslationProvider i18nProvider, final @Reference LocaleProvider localeProvider) {
final @Reference TranslationProvider i18nProvider, final @Reference LocaleProvider localeProvider,
final @Reference StorageService storageService) {
this.systemOfUnits = unitProvider.getMeasurementSystem();
this.httpClientFactory = httpClientFactory;
this.i18nProvider = i18nProvider;
this.localeProvider = localeProvider;
this.storageService = storageService;
}

@Override
Expand All @@ -74,7 +78,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return new FlumeBridgeHandler((Bridge) thing, systemOfUnits, this.httpClientFactory.getCommonHttpClient(),
i18nProvider, localeProvider);
} else if (THING_TYPE_METER.equals(thingTypeUID)) {
return new FlumeDeviceHandler(thing);
return new FlumeDeviceHandler(thing, systemOfUnits, storageService);
}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@ public void setThingHandler(@Nullable ThingHandler handler) {
@ActionInput(name = "operation", label = "Operation", required = true, description = "The aggregate/accumulate operation to perform (SUM, AVG, MIN, MAX, CNT).") @Nullable String operation) {
logger.info("queryWaterUsage called");

FlumeApiQueryWaterUsage query = new FlumeApiQueryWaterUsage();

FlumeDeviceHandler localDeviceHandler = deviceHandler;
if (localDeviceHandler == null) {
logger.debug("querying device usage, but device is undefined.");
Expand All @@ -90,31 +88,26 @@ public void setThingHandler(@Nullable ThingHandler handler) {
logger.warn("queryWaterUsage called with null inputs");
return null;
}

if (!untilDateTime.isAfter(sinceDateTime)) {
logger.warn("sinceDateTime must be earlier than untilDateTime");
return null;
}
if (!FlumeApi.OperationType.contains(operation)) {
logger.warn("Invalid aggregation operation in call to queryWaterUsage");
return null;
} else {
query.operation = FlumeApi.OperationType.valueOf(operation);
}

if (!FlumeApi.BucketType.contains(bucket)) {
logger.warn("Invalid bucket type in call to queryWaterUsage");
return null;
} else {
query.bucket = FlumeApi.BucketType.valueOf(bucket);
}

if (untilDateTime.isBefore(sinceDateTime)) {
logger.warn("sinceDateTime must be earlier than untilDateTime");
return null;
}

query.requestId = QUERYID;
query.sinceDateTime = sinceDateTime;
query.untilDateTime = untilDateTime;
query.bucket = FlumeApi.BucketType.valueOf(bucket);
query.units = imperialUnits ? FlumeApi.UnitType.GALLONS : FlumeApi.UnitType.LITERS;
FlumeApiQueryWaterUsage query = new FlumeApiQueryWaterUsage(QUERYID, //
Copy link

Copilot AI Jun 12, 2025

Choose a reason for hiding this comment

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

[nitpick] Consider replacing the hard-coded group multiplier (currently set to 100) with a named constant to improve clarity and ease future changes.

Copilot uses AI. Check for mistakes.

sinceDateTime, //
untilDateTime, //
FlumeApi.BucketType.valueOf(bucket), //
100, //
FlumeApi.OperationType.valueOf(operation), //
imperialUnits ? FlumeApi.UnitType.GALLONS : FlumeApi.UnitType.LITERS, FlumeApi.SortDirectionType.ASC);

Float usage;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,7 @@ public List<FlumeApiDevice> getDeviceList()
}

Map<String, List<FlumeApiQueryBucket>> queryBuckets = queryData.get(0);

List<FlumeApiQueryBucket> queryBucket = queryBuckets.get(query.requestId);
List<FlumeApiQueryBucket> queryBucket = queryBuckets.get(query.requestId());

return (queryBucket == null || queryBucket.isEmpty()) ? null : queryBucket.get(0).value;
}
Expand Down Expand Up @@ -404,8 +403,8 @@ private JsonObject sendAndValidate(Request request, boolean verifyToken)
case 200:
break;
case 400:
// Flume API sense response code 400 (vs. normal 401) on invalid user credentials
throw new FlumeApiException("@text/api.invalid-user-credentials [\"" + response.getReason() + "\"]",
logger.warn("@text/api-request: {}", response);
throw new FlumeApiException("@text/api.bad-request [\"" + response.getReason() + "\"]",
response.getStatus(), true);
case 401:
throw new FlumeApiException("@text/api.invalid-user-credentials [\"" + response.getReason() + "\"]",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,13 @@
*
* @author Jeff James - Initial contribution
*/
public class FlumeApiQueryWaterUsage {
@SerializedName("request_id")
public String requestId;
@SerializedName("since_datetime")
public LocalDateTime sinceDateTime;
@SerializedName("until_datetime")
public LocalDateTime untilDateTime;
@SerializedName("tz")
public String timeZone;
public FlumeApi.BucketType bucket;
@SerializedName("device_id")
public String[] deviceId;
@SerializedName("group_multiplier")
public Integer groupMultiplier;
public FlumeApi.OperationType operation;
public FlumeApi.UnitType units;
@SerializedName("sort_direction")
public FlumeApi.SortDirectionType sortDirection;
public record FlumeApiQueryWaterUsage( //
@SerializedName("request_id") String requestId, //
@SerializedName("since_datetime") LocalDateTime sinceDateTime, //
@SerializedName("until_datetime") LocalDateTime untilDateTime, //
FlumeApi.BucketType bucket, //
@SerializedName("group_multiplier") Integer groupMultiplier, //
FlumeApi.OperationType operation, //
FlumeApi.UnitType units, //
@SerializedName("sort_direction") FlumeApi.SortDirectionType sortDirection) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public void initialize() {
scheduler.execute(this::goOnline);
}

public void goOnline() {
public synchronized void goOnline() {
try {
api.initialize(config.clientId, config.clientSecret, config.username, config.password,
this.getThing().getUID());
Expand Down Expand Up @@ -218,15 +218,13 @@ public boolean refreshDevices(boolean forcedUpdate) {
*/
@Nullable
public FlumeDeviceHandler getFlumeDeviceHandler(String id) {
//@formatter:off
return getThing().getThings().stream()
.filter(t -> t.getThingTypeUID().equals(THING_TYPE_METER))
.map(t -> (FlumeDeviceHandler)t.getHandler())
.filter(Objects::nonNull)
.filter(h -> h.getId().equals(id))
.findFirst()
.orElse(null);
//@formatter:on
return getThing().getThings().stream() //
.filter(t -> t.getThingTypeUID().equals(THING_TYPE_METER)) //
.map(t -> (FlumeDeviceHandler) t.getHandler()) //
.filter(Objects::nonNull) //
.filter(h -> h.getId().equals(id)) //
.findFirst() //
.orElse(null);
}

public void handleApiException(Exception e) {
Expand Down Expand Up @@ -277,10 +275,11 @@ private void pollDevices() {
refreshDevices(true);
}

//@formatter:off
getThing().getThings().stream()
.forEach(t -> { if(t.getHandler() instanceof FlumeDeviceHandler handler) { handler.queryUsage(); } });
//@formatter:on
getThing().getThings().stream() //
.map(t -> t.getHandler()) //
.filter(FlumeDeviceHandler.class::isInstance) //
.map(FlumeDeviceHandler.class::cast) //
.forEach(FlumeDeviceHandler::queryUsage);
}

public @Nullable String getLocaleString(String key) {
Expand Down
Loading