add QuantityType.toUnitRelative (#3177)

this is a useful helper that can eliminate some complicated code elsewhere.
starting in SystemOffsetProfile. then I also want to use it in the homekit
addon.

Signed-off-by: Cody Cutrer <cody@cutrer.us>
This commit is contained in:
Cody Cutrer 2022-11-27 02:09:52 -07:00 committed by GitHub
parent 0cceb5b156
commit af3738487c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 17 deletions

View File

@ -21,8 +21,6 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.ImperialUnits;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.profiles.ProfileCallback;
import org.openhab.core.thing.profiles.ProfileContext;
@ -44,10 +42,6 @@ import org.slf4j.LoggerFactory;
@NonNullByDefault
public class SystemOffsetProfile implements StateProfile {
private static final @Nullable QuantityType<Temperature> ZERO_CELSIUS_IN_KELVIN = new QuantityType<>(0,
SIUnits.CELSIUS).toUnit(Units.KELVIN);
private static final @Nullable QuantityType<Temperature> ZERO_FAHRENHEIT_IN_KELVIN = new QuantityType<>(0,
ImperialUnits.FAHRENHEIT).toUnit(Units.KELVIN);
static final String OFFSET_PARAM = "offset";
private final Logger logger = LoggerFactory.getLogger(SystemOffsetProfile.class);
@ -152,20 +146,11 @@ public class SystemOffsetProfile implements StateProfile {
QuantityType<Temperature> offset) {
// do the math in Kelvin and afterwards convert it back to the unit of the state
final QuantityType<Temperature> kelvinState = qtState.toUnit(Units.KELVIN);
final QuantityType<Temperature> kelvinOffset = offset.toUnit(Units.KELVIN);
final QuantityType<Temperature> kelvinOffset = offset.toUnitRelative(Units.KELVIN);
if (kelvinState == null || kelvinOffset == null) {
return null;
}
final QuantityType<Temperature> finalOffset;
if (SIUnits.CELSIUS.equals(offset.getUnit())) {
finalOffset = kelvinOffset.add(ZERO_CELSIUS_IN_KELVIN.negate());
} else if (ImperialUnits.FAHRENHEIT.equals(offset.getUnit())) {
finalOffset = kelvinOffset.add(ZERO_FAHRENHEIT_IN_KELVIN.negate());
} else {
// offset is already in Kelvin
finalOffset = offset;
}
return kelvinState.add(finalOffset).toUnit(qtState.getUnit());
return kelvinState.add(kelvinOffset).toUnit(qtState.getUnit());
}
}

View File

@ -314,6 +314,31 @@ public class QuantityType<T extends Quantity<T>> extends Number
return null;
}
/**
* Convert this QuantityType to a new {@link QuantityType} using the given target unit.
*
* Similar to {@link toUnit}, except that it treats the values as relative instead of absolute.
* This means that any offsets in the conversion of absolute values are ignored.
* This is useful when your quantity represents a delta, and not necessarily a measured
* value itself. For example, 32 °F, when converted with toUnit to Celsius, it will become 0 °C.
* But when converted with toUnitRelative, it will become 17.8 °C.
*
* @param targetUnit the unit to which this {@link QuantityType} will be converted to.
* @return the new {@link QuantityType} in the given {@link Unit} or {@code null} in case of an error.
*/
@SuppressWarnings("unchecked")
public @Nullable QuantityType<T> toUnitRelative(Unit<T> targetUnit) {
if (targetUnit.equals(getUnit())) {
return this;
}
if (!quantity.getUnit().isCompatible(targetUnit)) {
return null;
}
Quantity<?> result = quantity.to(targetUnit);
return new QuantityType<T>(result.getValue(), (Unit<T>) targetUnit);
}
public BigDecimal toBigDecimal() {
return new BigDecimal(quantity.getValue().toString());
}

View File

@ -40,6 +40,7 @@ import org.openhab.core.library.dimension.DataTransferRate;
import org.openhab.core.library.dimension.Density;
import org.openhab.core.library.dimension.Intensity;
import org.openhab.core.library.unit.BinaryPrefix;
import org.openhab.core.library.unit.ImperialUnits;
import org.openhab.core.library.unit.MetricPrefix;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.Units;
@ -483,4 +484,11 @@ public class QuantityTypeTest {
QuantityType<?> andBack = mireds.toInvertibleUnit(Units.KELVIN);
assertEquals(2700, andBack.intValue());
}
@Test
public void testRelativeConversion() {
QuantityType<Temperature> c = new QuantityType("1 °C");
QuantityType<Temperature> f = c.toUnitRelative(ImperialUnits.FAHRENHEIT);
assertEquals(1.8, f.doubleValue());
}
}