public enum TraitUnit

  1. Object
  2. Enum<TraitUnit>
  3. TraitUnit

ImplementsComparable<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 constants

NONENo unit: an ordinal, a count, a plain number.
PERCENTPercent, 0 to 100.
CELSIUSDegrees Celsius.
FAHRENHEITDegrees Fahrenheit.
ARC_DEGREEDegrees of arc, 0 to 360.
MIREDMireds – micro reciprocal degrees, the reciprocal of colour temperature in Kelvin scaled by a million.
LUXLux.
PPMParts per million.
PPBParts per billion.
MICROGRAM_PER_CUBIC_METERMicrograms per cubic metre.

Methods

public static TraitUnit[] values()
public static TraitUnit valueOf(String name)
public int getWireId()The stable identifier this unit crosses the native boundary as.
public TraitUnitDimension getDimension()What this unit measures.
public boolean isCompatibleWith(TraitUnit other)Whether a value in this unit can be converted into the supplied one.
public static double convert(double value, TraitUnit from, TraitUnit to)Converts a value between two units of the same dimension.
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.
public static double miredToKelvin(double mireds)Converts mireds to Kelvin.
public static double kelvinToMired(double kelvin)Converts Kelvin to mireds.

Inherited methods

Enum constant details

NONE

NONE
No unit: an ordinal, a count, a plain number. The canonical unit of TraitUnitDimension.DIMENSIONLESS.

PERCENT

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

CELSIUS
Degrees Celsius. The canonical unit of TraitUnitDimension.TEMPERATURE.

FAHRENHEIT

FAHRENHEIT
Degrees Fahrenheit.

ARC_DEGREE

ARC_DEGREE
Degrees of arc, 0 to 360. The canonical unit of TraitUnitDimension.ANGLE, used for colour hue.

MIRED

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

LUX
Lux. The canonical unit of TraitUnitDimension.ILLUMINANCE.

PPM

PPM
Parts per million. The canonical unit of TraitUnitDimension.CONCENTRATION_PARTS.

PPB

PPB
Parts per billion.

MICROGRAM_PER_CUBIC_METER

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()

valueOf

public static TraitUnit valueOf(String name)

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 TraitUnit
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 double
the quantity to convert
from TraitUnit
the unit value is expressed in
to TraitUnit
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 int
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 double
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 double
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