Skip to content

Commit

Permalink
Add default units for all dimensions (openhab#3143)
Browse files Browse the repository at this point in the history
* Add default units for all dimensions

Signed-off-by: Jan N. Klug <github@klug.nrw>
  • Loading branch information
J-N-K authored Nov 19, 2022
1 parent 4f35d47 commit d00d14d
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,39 @@

import javax.measure.Quantity;
import javax.measure.Unit;
import javax.measure.quantity.Acceleration;
import javax.measure.quantity.AmountOfSubstance;
import javax.measure.quantity.Angle;
import javax.measure.quantity.Area;
import javax.measure.quantity.CatalyticActivity;
import javax.measure.quantity.Dimensionless;
import javax.measure.quantity.ElectricCapacitance;
import javax.measure.quantity.ElectricCharge;
import javax.measure.quantity.ElectricConductance;
import javax.measure.quantity.ElectricCurrent;
import javax.measure.quantity.ElectricInductance;
import javax.measure.quantity.ElectricPotential;
import javax.measure.quantity.ElectricResistance;
import javax.measure.quantity.Energy;
import javax.measure.quantity.Force;
import javax.measure.quantity.Frequency;
import javax.measure.quantity.Illuminance;
import javax.measure.quantity.Length;
import javax.measure.quantity.LuminousFlux;
import javax.measure.quantity.LuminousIntensity;
import javax.measure.quantity.MagneticFlux;
import javax.measure.quantity.MagneticFluxDensity;
import javax.measure.quantity.Mass;
import javax.measure.quantity.Power;
import javax.measure.quantity.Pressure;
import javax.measure.quantity.RadiationDoseAbsorbed;
import javax.measure.quantity.RadiationDoseEffective;
import javax.measure.quantity.Radioactivity;
import javax.measure.quantity.SolidAngle;
import javax.measure.quantity.Speed;
import javax.measure.quantity.Temperature;
import javax.measure.quantity.Time;
import javax.measure.quantity.Volume;
import javax.measure.spi.SystemOfUnits;

import org.eclipse.jdt.annotation.NonNullByDefault;
Expand All @@ -40,7 +67,13 @@
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.i18n.TranslationProvider;
import org.openhab.core.i18n.UnitProvider;
import org.openhab.core.library.dimension.ArealDensity;
import org.openhab.core.library.dimension.DataAmount;
import org.openhab.core.library.dimension.DataTransferRate;
import org.openhab.core.library.dimension.Density;
import org.openhab.core.library.dimension.ElectricConductivity;
import org.openhab.core.library.dimension.Intensity;
import org.openhab.core.library.dimension.VolumetricFlowRate;
import org.openhab.core.library.types.PointType;
import org.openhab.core.library.unit.ImperialUnits;
import org.openhab.core.library.unit.SIUnits;
Expand Down Expand Up @@ -107,7 +140,7 @@ public class I18nProviderImpl
private @Nullable ZoneId timeZone;

// UnitProvider
private static final String MEASUREMENT_SYSTEM = "measurementSystem";
static final String MEASUREMENT_SYSTEM = "measurementSystem";
private @Nullable SystemOfUnits measurementSystem;
private final Map<Class<? extends Quantity<?>>, Map<SystemOfUnits, Unit<? extends Quantity<?>>>> dimensionMap = new HashMap<>();

Expand All @@ -122,7 +155,7 @@ public I18nProviderImpl(ComponentContext componentContext) {
}

@Deactivate
protected void deactivate(ComponentContext componentContext) {
protected void deactivate() {
this.resourceBundleTracker.close();
}

Expand Down Expand Up @@ -319,8 +352,8 @@ public Locale getLocale() {
return text;
}

@SuppressWarnings("unchecked")
@Override
@SuppressWarnings("unchecked")
public <T extends Quantity<T>> @Nullable Unit<T> getUnit(@Nullable Class<T> dimension) {
Map<SystemOfUnits, Unit<? extends Quantity<?>>> map = dimensionMap.get(dimension);
if (map == null) {
Expand All @@ -344,39 +377,53 @@ public SystemOfUnits getMeasurementSystem() {
}

private void initDimensionMap() {
Map<SystemOfUnits, Unit<? extends Quantity<?>>> temperatureMap = new HashMap<>();
temperatureMap.put(SIUnits.getInstance(), SIUnits.CELSIUS);
temperatureMap.put(ImperialUnits.getInstance(), ImperialUnits.FAHRENHEIT);
dimensionMap.put(Temperature.class, temperatureMap);

Map<SystemOfUnits, Unit<? extends Quantity<?>>> pressureMap = new HashMap<>();
pressureMap.put(SIUnits.getInstance(), HECTO(SIUnits.PASCAL));
pressureMap.put(ImperialUnits.getInstance(), ImperialUnits.INCH_OF_MERCURY);
dimensionMap.put(Pressure.class, pressureMap);

Map<SystemOfUnits, Unit<? extends Quantity<?>>> speedMap = new HashMap<>();
speedMap.put(SIUnits.getInstance(), SIUnits.KILOMETRE_PER_HOUR);
speedMap.put(ImperialUnits.getInstance(), ImperialUnits.MILES_PER_HOUR);
dimensionMap.put(Speed.class, speedMap);

Map<SystemOfUnits, Unit<? extends Quantity<?>>> lengthMap = new HashMap<>();
lengthMap.put(SIUnits.getInstance(), SIUnits.METRE);
lengthMap.put(ImperialUnits.getInstance(), ImperialUnits.INCH);
dimensionMap.put(Length.class, lengthMap);

Map<SystemOfUnits, Unit<? extends Quantity<?>>> intensityMap = new HashMap<>();
intensityMap.put(SIUnits.getInstance(), Units.IRRADIANCE);
intensityMap.put(ImperialUnits.getInstance(), Units.IRRADIANCE);
dimensionMap.put(Intensity.class, intensityMap);

Map<SystemOfUnits, Unit<? extends Quantity<?>>> percentMap = new HashMap<>();
percentMap.put(SIUnits.getInstance(), Units.ONE);
percentMap.put(ImperialUnits.getInstance(), Units.ONE);
dimensionMap.put(Dimensionless.class, percentMap);

Map<SystemOfUnits, Unit<? extends Quantity<?>>> angleMap = new HashMap<>();
angleMap.put(SIUnits.getInstance(), Units.DEGREE_ANGLE);
angleMap.put(ImperialUnits.getInstance(), Units.DEGREE_ANGLE);
dimensionMap.put(Angle.class, angleMap);
addDefaultUnit(Acceleration.class, Units.METRE_PER_SQUARE_SECOND);
addDefaultUnit(AmountOfSubstance.class, Units.MOLE);
addDefaultUnit(Angle.class, Units.DEGREE_ANGLE, Units.DEGREE_ANGLE);
addDefaultUnit(Area.class, SIUnits.SQUARE_METRE, ImperialUnits.SQUARE_FOOT);
addDefaultUnit(ArealDensity.class, Units.DOBSON_UNIT);
addDefaultUnit(CatalyticActivity.class, Units.KATAL);
addDefaultUnit(DataAmount.class, Units.BYTE);
addDefaultUnit(DataTransferRate.class, Units.MEGABIT_PER_SECOND);
addDefaultUnit(Density.class, Units.KILOGRAM_PER_CUBICMETRE);
addDefaultUnit(Dimensionless.class, Units.ONE);
addDefaultUnit(ElectricCapacitance.class, Units.FARAD);
addDefaultUnit(ElectricCharge.class, Units.COULOMB);
addDefaultUnit(ElectricConductance.class, Units.SIEMENS);
addDefaultUnit(ElectricConductivity.class, Units.SIEMENS_PER_METRE);
addDefaultUnit(ElectricCurrent.class, Units.AMPERE);
addDefaultUnit(ElectricInductance.class, Units.HENRY);
addDefaultUnit(ElectricPotential.class, Units.VOLT);
addDefaultUnit(ElectricResistance.class, Units.OHM);
addDefaultUnit(Energy.class, Units.JOULE);
addDefaultUnit(Force.class, Units.NEWTON);
addDefaultUnit(Frequency.class, Units.HERTZ);
addDefaultUnit(Illuminance.class, Units.LUX);
addDefaultUnit(Intensity.class, Units.IRRADIANCE);
addDefaultUnit(Length.class, SIUnits.METRE, ImperialUnits.FOOT);
addDefaultUnit(LuminousFlux.class, Units.LUMEN);
addDefaultUnit(LuminousIntensity.class, Units.CANDELA);
addDefaultUnit(MagneticFlux.class, Units.WEBER);
addDefaultUnit(MagneticFluxDensity.class, Units.TESLA);
addDefaultUnit(Mass.class, SIUnits.KILOGRAM, ImperialUnits.POUND);
addDefaultUnit(Power.class, Units.WATT);
addDefaultUnit(Pressure.class, HECTO(SIUnits.PASCAL), ImperialUnits.INCH_OF_MERCURY);
addDefaultUnit(RadiationDoseAbsorbed.class, Units.GRAY);
addDefaultUnit(RadiationDoseEffective.class, Units.SIEVERT);
addDefaultUnit(Radioactivity.class, Units.BECQUEREL);
addDefaultUnit(SolidAngle.class, Units.STERADIAN);
addDefaultUnit(Speed.class, SIUnits.KILOMETRE_PER_HOUR, ImperialUnits.MILES_PER_HOUR);
addDefaultUnit(Temperature.class, SIUnits.CELSIUS, ImperialUnits.FAHRENHEIT);
addDefaultUnit(Time.class, Units.SECOND);
addDefaultUnit(Volume.class, SIUnits.CUBIC_METRE, ImperialUnits.GALLON_LIQUID_US);
addDefaultUnit(VolumetricFlowRate.class, Units.LITRE_PER_MINUTE, ImperialUnits.GALLON_PER_MINUTE);
}

private <T extends Quantity<T>> void addDefaultUnit(Class<T> dimension, Unit<T> siUnit, Unit<T> imperialUnit) {
dimensionMap.put(dimension, Map.of(SIUnits.getInstance(), siUnit, ImperialUnits.getInstance(), imperialUnit));
}

private <T extends Quantity<T>> void addDefaultUnit(Class<T> dimension, Unit<T> unit) {
dimensionMap.put(dimension, Map.of(SIUnits.getInstance(), unit, ImperialUnits.getInstance(), unit));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import javax.measure.Unit;
import javax.measure.quantity.Area;
import javax.measure.quantity.Length;
import javax.measure.quantity.Mass;
import javax.measure.quantity.Pressure;
import javax.measure.quantity.Speed;
import javax.measure.quantity.Temperature;
Expand Down Expand Up @@ -45,6 +46,8 @@ public final class ImperialUnits extends CustomUnits {

private static final ImperialUnits INSTANCE = new ImperialUnits();

public static final Unit<Mass> POUND = addUnit(new TransformedUnit<>("lb", Units.GRAM,
MultiplyConverter.ofRational(BigInteger.valueOf(45359237), BigInteger.valueOf(100000))));
/** Additionally defined units to be used in openHAB **/
public static final Unit<Pressure> INCH_OF_MERCURY = addUnit(new TransformedUnit<>("inHg", Units.PASCAL,
MultiplyConverter.ofRational(BigInteger.valueOf(3386388), BigInteger.valueOf(1000))));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,37 @@

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.Mockito.when;
import static org.openhab.core.internal.i18n.I18nProviderImpl.*;

import java.time.ZoneId;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;

import javax.measure.Quantity;
import javax.measure.Unit;
import javax.measure.spi.SystemOfUnits;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.openhab.core.library.types.PointType;
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.types.util.UnitUtils;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.ComponentContext;
Expand Down Expand Up @@ -158,6 +172,23 @@ public void assertThatConfigurationChangeWorks() {
assertThat(setLocale.getVariant(), is(VARIANT_RU));
}

@ParameterizedTest
@MethodSource("getAllDimensions")
@SuppressWarnings("unchecked")
public <T extends Quantity<T>> void assertThatUnitProviderIsComplete(String dimensionName) {
Class<? extends Quantity<?>> dimension = UnitUtils.parseDimension(dimensionName);
assertThat(dimension, is(notNullValue()));

Unit<?> defaultUnit = i18nProviderImpl.getUnit((Class<T>) dimension);
assertThat(dimensionName + " has no default unit", defaultUnit, notNullValue());
}

private static Stream<String> getAllDimensions() {
return Stream.of(SIUnits.getInstance(), Units.getInstance(), ImperialUnits.getInstance())
.map(SystemOfUnits::getUnits).flatMap(Collection::stream) //
.map(UnitUtils::getDimensionName).filter(Objects::nonNull).map(Objects::requireNonNull).distinct();
}

private Dictionary<String, Object> buildInitialConfig() {
Dictionary<String, Object> conf = new Hashtable<>();
conf.put(LOCATION, LOCATION_ZERO);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import javax.measure.quantity.Dimensionless;
import javax.measure.quantity.Energy;
import javax.measure.quantity.Length;
import javax.measure.quantity.Mass;
import javax.measure.quantity.Power;
import javax.measure.quantity.Pressure;
import javax.measure.quantity.Speed;
Expand Down Expand Up @@ -54,6 +55,14 @@ private static <Q extends Quantity<?>> Matcher<? super Q> isQuantityEquals(Q qua
return new QuantityEquals(quantity);
}

@Test
public void pound2KilogramConversion() {
Quantity<Mass> lb = Quantities.getQuantity(BigDecimal.ONE, ImperialUnits.POUND);

assertThat(lb.to(SIUnits.GRAM),
isQuantityEquals(Quantities.getQuantity(new BigDecimal("453.59237"), SIUnits.GRAM)));
}

@Test
public void testInHg2PascalConversion() {
Quantity<Pressure> inHg = Quantities.getQuantity(BigDecimal.ONE, ImperialUnits.INCH_OF_MERCURY);
Expand Down

0 comments on commit d00d14d

Please sign in to comment.