Add default units for all dimensions (#3143)

* Add default units for all dimensions

Signed-off-by: Jan N. Klug <github@klug.nrw>
This commit is contained in:
J-N-K 2022-11-19 23:10:38 +01:00 committed by GitHub
parent 4f35d474fc
commit d00d14d9fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 125 additions and 35 deletions

View File

@ -25,12 +25,39 @@ import java.util.ResourceBundle;
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;
@ -40,7 +67,13 @@ import org.openhab.core.i18n.LocationProvider;
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;
@ -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<>();
@ -122,7 +155,7 @@ public class I18nProviderImpl
}
@Deactivate
protected void deactivate(ComponentContext componentContext) {
protected void deactivate() {
this.resourceBundleTracker.close();
}
@ -319,8 +352,8 @@ public class I18nProviderImpl
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) {
@ -344,39 +377,53 @@ public class I18nProviderImpl
}
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);
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);
}
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);
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));
}
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);
private <T extends Quantity<T>> void addDefaultUnit(Class<T> dimension, Unit<T> unit) {
dimensionMap.put(dimension, Map.of(SIUnits.getInstance(), unit, ImperialUnits.getInstance(), unit));
}
}

View File

@ -17,6 +17,7 @@ import java.math.BigInteger;
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;
@ -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))));

View File

@ -14,23 +14,37 @@ package org.openhab.core.internal.i18n;
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;
@ -158,6 +172,23 @@ public class I18nProviderImplTest {
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);

View File

@ -23,6 +23,7 @@ import javax.measure.Quantity;
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;
@ -54,6 +55,14 @@ public class UnitsTest {
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);