Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
12 changes: 6 additions & 6 deletions bundles/org.openhab.binding.ondilo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,19 +99,19 @@ Example using default interval:

```Java
Bridge ondilo:account:ondiloAccount [ url="http://localhost:8080", refreshInterval=900 ] {
Thing ondilo 12345 [ id=12345 ] { // 12345 is an example of the id received via discovery
}
Thing ondilo 12345 [ id=12345 ] // 12345 is an example of the id received via discovery
}
```

### Item Configuration

```java
Number:Temperature Ondilo_Temperature "Pool Temperature [%.1f %unit%]" { channel="ondilo:ondilo:ondiloAccount:12345:measure#temperature" }
Number Ondilo_pH "Pool pH [%d]" { channel="ondilo:ondilo:ondiloAccount:12345:measure#ph" }
Number:ElectricPotential Ondilo_ORP "Pool ORP [%.1f %unit%]" { channel="ondilo:ondilo:ondiloAccount:12345:measure#orp" }
Number Ondilo_pH "Pool pH [%.2f]" { channel="ondilo:ondilo:ondiloAccount:12345:measure#ph" }
Number:ElectricPotential Ondilo_ORP "Pool ORP [%.0f %unit%]" { channel="ondilo:ondilo:ondiloAccount:12345:measure#orp" }
Number:Density Ondilo_Salt "Pool Salt [%.0f %unit%]" { channel="ondilo:ondilo:ondiloAccount:12345:measure#salt" }
Number:Dimensionless Ondilo_Battery "Pool Battery [%d %]" { channel="ondilo:ondilo:ondiloAccount:12345:measure#battery" }
Number:Dimensionless Ondilo_RSSI "Pool RSSI [%.0f]" { channel="ondilo:ondilo:ondiloAccount:12345:measure#rssi" }
Number:Dimensionless Ondilo_Battery "Pool Battery [%d %%]" { channel="ondilo:ondilo:ondiloAccount:12345:measure#battery" }
Number:Dimensionless Ondilo_RSSI "Pool RSSI [%d]" { channel="ondilo:ondilo:ondiloAccount:12345:measure#rssi" }

String Ondilo_RecTitle "Recommendation Title [%s]" { channel="ondilo:ondilo:ondiloAccount:12345:recommendation#title" }
String Ondilo_RecMessage "Recommendation Message [%s]" { channel="ondilo:ondilo:ondiloAccount:12345:recommendation#message" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,9 @@ private void adaptPollingToValueTime(Instant lastValueTime, int refreshInterval)
logger.warn("No lastMeasures available for Ondilo ICO with ID: {}", id);
ondiloHandler.clearLastMeasuresChannels();
} else {
for (LastMeasure lastMeasure : lastMeasures) {
logger.trace("LastMeasure: type={}, value={}", lastMeasure.dataType, lastMeasure.value);
Instant valueTime = ondiloHandler.updateLastMeasuresChannels(lastMeasure);
if (lastValueTime == null || valueTime.isBefore(lastValueTime)) {
lastValueTime = valueTime;
}
Instant valueTime = ondiloHandler.updateLastMeasuresChannels(lastMeasures);
if (lastValueTime == null || valueTime.isBefore(lastValueTime)) {
lastValueTime = valueTime;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,13 @@ public class OndiloHandler extends BaseThingHandler {
private final LocaleProvider localeProvider;
private final int configPoolId;

private int recommendationId; // Used to track the last recommendation ID processed
private AtomicReference<String> ondiloId = new AtomicReference<>(NO_ID);

private @Nullable ScheduledFuture<?> bridgeRecoveryJob;

private @Nullable LastMeasure lastMeasures[] = new LastMeasure[0];
private @Nullable Recommendation lastRecommendation = null;

// Store last value and valueTime for trend calculation
private OndiloMeasureState lastTemperatureState = new OndiloMeasureState(Double.NaN, null);
private OndiloMeasureState lastPhState = new OndiloMeasureState(Double.NaN, null);
Expand All @@ -88,17 +90,35 @@ public OndiloHandler(Thing thing, LocaleProvider localeProvider) {
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (RefreshType.REFRESH == command) {
// not implemented as it would causes >10 channel updates in a row during setup (exceeds given API quota)
// If you want to update the values, use the poll channel instead
String groupId = channelUID.getGroupId();
if (groupId == null) {
logger.warn("Received refresh command for unknown channel: {}", channelUID.getId());
} else if (GROUP_MEASURES.startsWith(groupId)) {
if (lastMeasures == null || lastMeasures.length == 0) {
clearLastMeasuresChannels();
} else {
updateLastMeasuresChannels(lastMeasures);
}
} else if (GROUP_RECOMMENDATIONS.startsWith(groupId)) {
Recommendation lastRecommendation = this.lastRecommendation;
if (lastRecommendation == null) {
clearRecommendationChannels();
} else {
updateRecommendationChannels(lastRecommendation);
}
} else {
logger.warn("Received refresh command for unknown channel: {}", channelUID.getId());
}
return;
} else if (CHANNEL_RECOMMENDATION_STATUS.equals(channelUID.getId())) {
if (command instanceof StringType cmd) {
try {
Recommendation.Status status = Recommendation.Status.valueOf(cmd.toString());
if (status == Recommendation.Status.ok) {
OndiloBridge ondiloBridge = getOndiloBridge();
if (ondiloBridge != null && this.recommendationId != 0) {
ondiloBridge.validateRecommendation(configPoolId, recommendationId);
if (ondiloBridge != null && this.lastRecommendation != null
&& this.lastRecommendation.id != 0) {
ondiloBridge.validateRecommendation(configPoolId, this.lastRecommendation.id);
} else {
logger.warn(
"Cannot validate recommendation, as the bridge is not initialized or no recommendation ID is set");
Expand All @@ -120,8 +140,9 @@ public void handleCommand(ChannelUID channelUID, Command command) {
public void initialize() {
OndiloBridge ondiloBridge = getOndiloBridge();
if (ondiloBridge != null) {
// Initialize to 0, as no recommendation has been processed yet
recommendationId = 0;
// Initialize to empty array, as no measure / recommendation has been processed yet
this.lastMeasures = new LastMeasure[0];
this.lastRecommendation = null;

if (configPoolId == 0) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, I18N_ID_INVALID);
Expand Down Expand Up @@ -163,7 +184,10 @@ public void dispose() {
if (!ondiloId.get().equals(NO_ID)) {
ondiloId.set(NO_ID);
}
recommendationId = 0; // Reset last processed recommendation ID

// Initialize to empty array, as no measure / recommendation has been processed yet
this.lastMeasures = new LastMeasure[0];
this.lastRecommendation = null;
}

public void clearLastMeasuresChannels() {
Expand All @@ -175,6 +199,7 @@ public void clearLastMeasuresChannels() {
updateState(CHANNEL_TDS, UnDefType.UNDEF);
updateState(CHANNEL_BATTERY, UnDefType.UNDEF);
updateState(CHANNEL_RSSI, UnDefType.UNDEF);
this.lastMeasures = new LastMeasure[0];
}

public void clearRecommendationChannels() {
Expand All @@ -186,7 +211,7 @@ public void clearRecommendationChannels() {
updateState(CHANNEL_RECOMMENDATION_UPDATED_AT, UnDefType.NULL);
updateState(CHANNEL_RECOMMENDATION_STATUS, UnDefType.NULL);
updateState(CHANNEL_RECOMMENDATION_DEADLINE, UnDefType.NULL);
this.recommendationId = 0; // Reset last processed recommendation ID
this.lastRecommendation = null;
}

private void updateTrendChannel(String channel, String trendChannel, double value, Instant valueTime,
Expand Down Expand Up @@ -219,40 +244,49 @@ private void updateTrendChannel(String channel, String trendChannel, double valu
lastMeasureState.time = valueTime;
}

public Instant updateLastMeasuresChannels(LastMeasure measure) {
Instant valueTime = parseUtcTimeToInstant(measure.valueTime);
switch (measure.dataType) {
case "temperature":
updateTrendChannel(CHANNEL_TEMPERATURE, CHANNEL_TEMPERATURE_TREND, measure.value, valueTime,
lastTemperatureState, SIUnits.CELSIUS);
break;
case "ph":
updateTrendChannel(CHANNEL_PH, CHANNEL_PH_TREND, measure.value, valueTime, lastPhState,
DecimalType.class);
break;
case "orp":
updateTrendChannel(CHANNEL_ORP, CHANNEL_ORP_TREND, measure.value / 1000.0, valueTime, lastOrpState,
Units.VOLT); // Convert mV to V
break;
case "salt":
updateTrendChannel(CHANNEL_SALT, CHANNEL_SALT_TREND, measure.value * 0.001, valueTime, lastSaltState,
Units.KILOGRAM_PER_CUBICMETRE); // Convert mg/l to kg/m³
break;
case "tds":
updateTrendChannel(CHANNEL_TDS, CHANNEL_TDS_TREND, measure.value, valueTime, lastTdsState,
Units.PARTS_PER_MILLION);
break;
case "battery":
updateState(CHANNEL_BATTERY, new QuantityType<>(measure.value, Units.PERCENT));
break;
case "rssi":
updateState(CHANNEL_RSSI, new DecimalType(measure.value));
break;
default:
logger.warn("Unknown data type: {}", measure.dataType);
public @Nullable Instant updateLastMeasuresChannels(LastMeasure measures[]) {
Instant valueTime = null;
for (LastMeasure measure : measures) {
logger.trace("LastMeasure: type={}, value={}", measure.dataType, measure.value);
valueTime = parseUtcTimeToInstant(measure.valueTime);
switch (measure.dataType) {
case "temperature":
updateTrendChannel(CHANNEL_TEMPERATURE, CHANNEL_TEMPERATURE_TREND, measure.value, valueTime,
lastTemperatureState, SIUnits.CELSIUS);
break;
case "ph":
updateTrendChannel(CHANNEL_PH, CHANNEL_PH_TREND, measure.value, valueTime, lastPhState,
DecimalType.class);
break;
case "orp":
updateTrendChannel(CHANNEL_ORP, CHANNEL_ORP_TREND, measure.value / 1000.0, valueTime, lastOrpState,
Units.VOLT); // Convert mV to V
break;
case "salt":
updateTrendChannel(CHANNEL_SALT, CHANNEL_SALT_TREND, measure.value * 0.001, valueTime,
lastSaltState, Units.KILOGRAM_PER_CUBICMETRE); // Convert mg/l to kg/m³
break;
case "tds":
updateTrendChannel(CHANNEL_TDS, CHANNEL_TDS_TREND, measure.value, valueTime, lastTdsState,
Units.PARTS_PER_MILLION);
break;
case "battery":
updateState(CHANNEL_BATTERY, new QuantityType<>(measure.value, Units.PERCENT));
break;
case "rssi":
updateState(CHANNEL_RSSI, new DecimalType(measure.value));
break;
default:
logger.warn("Unknown data type: {}", measure.dataType);
}
}
// Update value time channel (expect that it is the same for all measures)
updateState(CHANNEL_VALUE_TIME, new DateTimeType(valueTime));

if (valueTime != null) {
// Update value time channel (expect that it is the same for all measures)
updateState(CHANNEL_VALUE_TIME, new DateTimeType(valueTime));
}

this.lastMeasures = measures;
return valueTime;
}

Expand All @@ -264,7 +298,7 @@ public void updateRecommendationChannels(Recommendation recommendation) {
updateState(CHANNEL_RECOMMENDATION_UPDATED_AT, new DateTimeType(recommendation.updatedAt));
updateState(CHANNEL_RECOMMENDATION_STATUS, new StringType(recommendation.status.name()));
updateState(CHANNEL_RECOMMENDATION_DEADLINE, new DateTimeType(recommendation.deadline));
this.recommendationId = recommendation.id; // Update last processed recommendation ID
this.lastRecommendation = recommendation;
}

public void updatePool(Pool pool) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@
<tags>
<tag>Measurement</tag>
</tags>
<state readOnly="true" pattern="%.1f %unit%"/>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="orp-trend" advanced="true">
<item-type unitHint="mV">Number:ElectricPotential</item-type>
Expand All @@ -198,7 +198,7 @@
<tags>
<tag>Measurement</tag>
</tags>
<state readOnly="true" pattern="Δ %+.1f %unit%"/>
<state readOnly="true" pattern="Δ %+.0f %unit%"/>
</channel-type>
<channel-type id="salt">
<item-type unitHint="mg/l">Number:Density</item-type>
Expand Down