Enum TraitUnit

java.lang.Object
java.lang.Enum<TraitUnit>
com.codename1.home.TraitUnit
All Implemented Interfaces:
Comparable<TraitUnit>

public enum TraitUnit extends Enum<TraitUnit>

A unit of measure for a Trait value.

Conversion is affine, with one honest exception

canonical = value * scale + offset, the same model com.codename1.health.HealthUnit uses, because temperature needs the offset. Converting between units of different TraitUnitDimensions throws IllegalArgumentException: that is a bug in the calling code, not a condition to report through an AsyncResource.

Mireds and Kelvin are reciprocal, not affine, so Kelvin is deliberately not a constant here -- it cannot be expressed in the table, and forcing it in would produce a colour temperature that is silently wrong rather than obviously wrong. Use miredToKelvin(double) and kelvinToMired(double), or TraitValue.getColorTemperatureKelvin(), which are named so that stepping outside the conversion table is a visible act.

And the trap that catches everyone once: a higher mired value is a warmer light, because mireds are the reciprocal of Kelvin. 153 mireds is a cold blue-white; 400 is candlelight.

Why this is an enum where HealthUnit is a class

HealthUnit is an interned final class because its symbol is the wire format Apple's HKUnit(from:) parses, and because the set grows with the data types. Neither is true here: the set is small, closed and defined by what the two backends can actually express, and nothing about a home accessory will need a unit that is not already on this list. An enum gets switch and exhaustive reasoning for free.

The one thing an enum does not get for free is a stable wire form -- ordinal() shifts the moment a constant is inserted in the middle -- so each carries an explicit getWireId() and forWireId(int) resolves it.

  • Enum Constant Details

    • NONE

      public static final TraitUnit NONE
      No unit: an ordinal, a count, a plain number. The canonical unit of TraitUnitDimension.DIMENSIONLESS.
    • PERCENT

      public static final TraitUnit PERCENT

      Percent, 0 to 100. The canonical unit of TraitUnitDimension.RATIO, and the unit of every proportion in this API -- brightness, saturation, covering position, fan speed, battery level, humidity.

      Both backends carry these as scaled integers with different scales (Matter's level control is 0 to 254, its covering position is 0 to 10000, its battery percentage is in halves) and every one of those conversions happens inside the port. Application code sees percent.

    • CELSIUS

      public static final TraitUnit CELSIUS
      Degrees Celsius. The canonical unit of TraitUnitDimension.TEMPERATURE.
    • FAHRENHEIT

      public static final TraitUnit FAHRENHEIT
      Degrees Fahrenheit.
    • ARC_DEGREE

      public static final TraitUnit ARC_DEGREE
      Degrees of arc, 0 to 360. The canonical unit of TraitUnitDimension.ANGLE, used for colour hue.
    • MIRED

      public static final TraitUnit MIRED

      Mireds -- micro reciprocal degrees, the reciprocal of colour temperature in Kelvin scaled by a million. The canonical unit of TraitUnitDimension.COLOR_TEMPERATURE.

      Chosen over Kelvin because it is what both platforms use natively: HomeKit's HMCharacteristicTypeColorTemperature is in mireds and Matter's ColorTemperatureMireds is in mireds. Making Kelvin canonical would mean a reciprocal on every read and every write, in both ports, for no gain.

    • LUX

      public static final TraitUnit LUX
      Lux. The canonical unit of TraitUnitDimension.ILLUMINANCE.
    • PPM

      public static final TraitUnit PPM
      Parts per million. The canonical unit of TraitUnitDimension.CONCENTRATION_PARTS.
    • PPB

      public static final TraitUnit PPB
      Parts per billion.
    • MICROGRAM_PER_CUBIC_METER

      public static final TraitUnit MICROGRAM_PER_CUBIC_METER
      Micrograms per cubic metre. The canonical unit of TraitUnitDimension.CONCENTRATION_MASS, used for particulate matter.
  • Method Details

    • values

      public static TraitUnit[] values()
      Returns an array containing the constants of this enum type, in the order they are declared.
      Returns:
      an array containing the constants of this enum type, in the order they are declared
    • valueOf

      public static TraitUnit valueOf(String name)
      Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
      Parameters:
      name - the name of the enum constant to be returned.
      Returns:
      the enum constant with the specified name
      Throws:
      IllegalArgumentException - if this enum type has no constant with the specified name
      NullPointerException - if the argument is null
    • getWireId

      public int getWireId()

      The stable identifier this unit crosses the native boundary as.

      Fixed per constant and never reused, so inserting a unit into the middle of this list cannot silently re-label values a port already sends.

      Returns

      the wire identifier

    • getDimension

      public TraitUnitDimension getDimension()

      What this unit measures.

      Returns

      the dimension, never null

    • isCompatibleWith

      public boolean isCompatibleWith(TraitUnit other)

      Whether a value in this unit can be converted into the supplied one.

      Parameters
      • other: the target unit, or null
      Returns

      true when both measure the same dimension

    • convert

      public static double convert(double value, TraitUnit from, TraitUnit to)

      Converts a value between two units of the same dimension.

      Parameters
      • value: the quantity to convert

      • from: the unit value is expressed in

      • to: the unit to express it in

      Returns

      the converted quantity

      Throws
      • IllegalArgumentException: when either unit is null or they measure different dimensions
    • forWireId

      public static TraitUnit forWireId(int wireId)

      Resolves a unit by its wire identifier, total: an unrecognized id answers null rather than throwing, so a value from a newer port degrades to "no value" instead of taking down the decode.

      Parameters
      • wireId: an identifier previously returned by getWireId()
      Returns

      the matching unit, or null

    • miredToKelvin

      public static double miredToKelvin(double mireds)

      Converts mireds to Kelvin.

      Outside the convert(double, TraitUnit, TraitUnit) table on purpose: the relationship is reciprocal, and an affine table that pretended otherwise would return a plausible number that is wrong everywhere except at one point.

      Parameters
      • mireds: a colour temperature in mireds; must be greater than zero
      Returns

      the same colour temperature in Kelvin

      Throws
      • IllegalArgumentException: when mireds is zero, negative or not a number
    • kelvinToMired

      public static double kelvinToMired(double kelvin)

      Converts Kelvin to mireds. See miredToKelvin(double) for why this is a named method rather than a table entry.

      Parameters
      • kelvin: a colour temperature in Kelvin; must be greater than zero
      Returns

      the same colour temperature in mireds

      Throws
      • IllegalArgumentException: when kelvin is zero, negative or not a number