# 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 `TraitUnitDimension`s 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 Summary

  Enum Constants
  Enum Constant
  Description
  `ARC_DEGREE`
  Degrees of arc, 0 to 360.
  `CELSIUS`
  Degrees Celsius.
  `FAHRENHEIT`
  Degrees Fahrenheit.
  `LUX`
  Lux.
  `MICROGRAM_PER_CUBIC_METER`
  Micrograms per cubic metre.
  `MIRED`
  Mireds -- micro reciprocal degrees, the reciprocal of colour temperature in Kelvin scaled by a million.
  `NONE`
  No unit: an ordinal, a count, a plain number.
  `PERCENT`
  Percent, 0 to 100.
  `PPB`
  Parts per billion.
  `PPM`
  Parts per million.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `static double`
  `convert(double value, TraitUnit from, TraitUnit to)`
  Converts a value between two units of the same dimension.
  `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.
  `TraitUnitDimension`
  `getDimension()`
  What this unit measures.
  `int`
  `getWireId()`
  The stable identifier this unit crosses the native boundary as.
  `boolean`
  `isCompatibleWith(TraitUnit other)`
  Whether a value in this unit can be converted into the supplied one.
  `static double`
  `kelvinToMired(double kelvin)`
  Converts Kelvin to mireds.
  `static double`
  `miredToKelvin(double mireds)`
  Converts mireds to Kelvin.
  `static TraitUnit`
  `valueOf(String name)`
  Returns the enum constant of this type with the specified name.
  `static TraitUnit[]`
  `values()`
  Returns an array containing the constants of this enum type, in the order they are declared.

  ### Methods inherited from class Enum

  `clone, compareTo, equals, getDeclaringClass, getEnumValues, hashCode, name, ordinal, setEnumValues, toString, valueOf`

  ### Methods inherited from class Object

  `getClass, notify, notifyAll, wait, wait, wait`

- ## 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