public final class TraitValue

  1. Object
  2. TraitValue

One value of one Trait: immutable, typed, and carrying its unit.

TraitValue on = TraitValue.of(true);
TraitValue dim = TraitValue.of(40, TraitUnit.PERCENT);
TraitValue warm = TraitValue.of(370, TraitUnit.MIRED);

A tagged union, not forty subclasses

Home values are genuinely heterogeneous – a switch is a boolean, a dimmer is a percentage, a lock is one of a fixed set – and both native layers hand them over as raw numbers. Something has to give them types back.

A class per trait would mean a cast at every read site, and this codebase has a hard rule against a cast whose failure you expect to handle: ParparVM does not check CHECKCAST, so on iOS a wrong cast does not throw, it hands the wrong object to the next instruction and reads the target type’s fields out of it. One class with kind-checked getters turns the same mistake into an IllegalStateException naming both kinds, on every platform.

There is no zero-argument getDouble

getDouble(TraitUnit) makes you name the unit you expect and converts, or throws if the dimensions disagree. That is inherited straight from com.codename1.health.HealthQuantity, and the reason is the same: a bare getDouble() is how a Celsius setpoint gets rendered as Fahrenheit and how a colour temperature in mireds gets treated as Kelvin. Neither mistake raises anything at the time.

getRawDouble() is the escape hatch, named to be awkward enough that it is not reached for by habit.

The raw platform value

Some mappings in this API are judgment calls – HomeKit has six air-quality levels and Matter has seven, and Matter has five thermostat modes HomeKit cannot express. Where the canonical answer is lossy, getRawPlatformValue() carries the platform’s own ordinal alongside it. Without it every lossy mapping decision would be a permanent lie; with it, an app that must be exact can be.

Methods

public static TraitValue of(boolean value)A boolean value – a switch, a motion flag, a mute.
public static TraitValue of(int value)A unitless whole number.
public static TraitValue of(double value, TraitUnit unit)A measured quantity.
public static TraitValue of(String value)Free text.
public static TraitValue ofEnum(Enum<?> value)One of a fixed set, from one of this package’s domain enums.
public static TraitValue ofEnumOrdinal(int ordinal)Builds an enum value straight from an ordinal, for the codec.
public TraitValue withRawPlatformValue(int raw)This value with the platform’s own ordinal attached.
public TraitValueKind getKind()What sort of value this is, and therefore which getter works.
public TraitUnit getUnit()The unit a TraitValueKind.DOUBLE value is expressed in.
public boolean getBoolean()The boolean.
public int getInt()The whole number.
public String getString()The text.
public int getEnumOrdinal()The ordinal of an enum value, for the codec and for LockState.of(TraitValue) and its siblings.
public String getEnumName()The name of the enum constant this value was built from.
public double getDouble(TraitUnit in)The quantity, converted into the unit you name.
public double getRawDouble()The quantity in whatever unit it happens to be in, with no conversion and no check.
public double getColorTemperatureKelvin()A colour temperature in Kelvin.
public boolean hasRawPlatformValue()Whether the backend’s own numeric value is available alongside the canonical one.
public int getRawPlatformValue()The backend’s own numeric value, where the canonical mapping was lossy.
public boolean equals(Object o)Indicates whether some other object is “equal to” this one.
public int hashCode()Returns a hash code value for the object.
public String toString()Returns a string representation of the object.

Inherited methods

Method details

of

public static TraitValue of(boolean value)
A boolean value – a switch, a motion flag, a mute.

Parameters

value boolean
the boolean

Returns

a value of kind TraitValueKind.BOOLEAN

of

public static TraitValue of(int value)
A unitless whole number.

Parameters

value int
the number

Returns

a value of kind TraitValueKind.INT

of

public static TraitValue of(double value, TraitUnit unit)
A measured quantity.

Parameters

value double
the quantity
unit TraitUnit
the unit it is expressed in

Returns

a value of kind TraitValueKind.DOUBLE

Throws

IllegalArgumentException
when unit is null. A quantity with no unit is the bug this class exists to prevent, so it is refused at construction rather than defaulted to something plausible.
IllegalArgumentException
when value is NaN or an infinity. Nothing downstream can carry one: the wire encodes a number as text and its decoder refuses these as INVALID_DATA, so a write that got this far was accepted, stored by the local backend, and then read back as a failure – and on a device it would be a number no accessory could act on.

of

public static TraitValue of(String value)
Free text.

Parameters

value String
the text; null becomes the empty string

Returns

a value of kind TraitValueKind.STRING

ofEnum

public static TraitValue ofEnum(Enum<?> value)
One of a fixed set, from one of this package’s domain enums.

Parameters

value Enum<?>
the constant

Returns

a value of kind TraitValueKind.ENUM

Throws

IllegalArgumentException
when value is null

ofEnumOrdinal

public static TraitValue ofEnumOrdinal(int ordinal)

Builds an enum value straight from an ordinal, for the codec.

Application code should use ofEnum(java.lang.Enum); this exists because the wire carries an ordinal and the decoder has no constant to hand.

Parameters

ordinal int
the ordinal of a constant in this package’s domain enum for the trait in question

Returns

a value of kind TraitValueKind.ENUM

withRawPlatformValue

public TraitValue withRawPlatformValue(int raw)

This value with the platform’s own ordinal attached.

Used by the ports where the canonical mapping is lossy, so an app can see what the accessory actually said. See getRawPlatformValue().

Parameters

raw int
the backend’s own numeric value

Returns

a copy carrying the raw value; this instance is unchanged

getKind

public TraitValueKind getKind()
What sort of value this is, and therefore which getter works.

Returns

the kind, never null

getUnit

public TraitUnit getUnit()
The unit a TraitValueKind.DOUBLE value is expressed in. TraitUnit.NONE for every other kind.

Returns

the unit, never null

getBoolean

public boolean getBoolean()
The boolean.

Returns

the value

getInt

public int getInt()
The whole number.

Returns

the value

Throws

IllegalStateException
when this is not an TraitValueKind.INT

getString

public String getString()
The text.

Returns

the value, never null

getEnumOrdinal

public int getEnumOrdinal()

The ordinal of an enum value, for the codec and for LockState.of(TraitValue) and its siblings.

Application code should go through those lookups rather than reading the ordinal: they are total, they name the constant, and they document which ones a given backend can never produce.

Returns

the ordinal

getEnumName

public String getEnumName()

The name of the enum constant this value was built from.

null only for a value built straight from an ordinal with ofEnumOrdinal(int) and never resolved against a trait. Present for every value an application builds and for every reading the codec decodes – the trait names the ordinal there – which is what lets Trait.acceptsEnumValue(TraitValue) tell one domain enum from another – ParparVM’s Enum.getDeclaringClass() returns null, so the type itself is not available to check.

Returns

the constant’s name, or null

getDouble

public double getDouble(TraitUnit in)
The quantity, converted into the unit you name.

Parameters

in TraitUnit
the unit you want the answer in

Returns

the quantity expressed in in

Throws

IllegalStateException
when this is not a TraitValueKind.DOUBLE
IllegalArgumentException
when in measures a different dimension than this value

getRawDouble

public double getRawDouble()

The quantity in whatever unit it happens to be in, with no conversion and no check.

Deliberately awkward. Reach for getDouble(TraitUnit) unless you have already read getUnit() and are doing something with both.

Returns

the raw numeric component

getColorTemperatureKelvin

public double getColorTemperatureKelvin()

A colour temperature in Kelvin.

Separate from getDouble(TraitUnit) because mireds and Kelvin are reciprocal rather than affine and so cannot be a TraitUnit pair; see TraitUnit.miredToKelvin(double).

Returns

the colour temperature in Kelvin

Throws

IllegalStateException
when this is not a TraitValueKind.DOUBLE
IllegalArgumentException
when this value is not a colour temperature, or is not positive

hasRawPlatformValue

public boolean hasRawPlatformValue()
Whether the backend’s own numeric value is available alongside the canonical one.

Returns

true when getRawPlatformValue() is meaningful

getRawPlatformValue

public int getRawPlatformValue()

The backend’s own numeric value, where the canonical mapping was lossy.

Meaningful only when hasRawPlatformValue() answers true, and meaningful only in terms of the backend that produced it – read SmartHome.getBackend() before interpreting it. Zero otherwise.

Deliberately outside equals(java.lang.Object): it is metadata about where a value came from, not part of the value. Two readings that are equal can carry different raw ordinals, which is exactly the lossiness this exists to expose – compare these explicitly when that matters.

Returns

the platform’s own ordinal, or zero

equals

public boolean equals(Object o)
Indicates whether some other object is “equal to” this one. The equals method implements an equivalence relation: It is reflexive: for any reference value x, x.equals(x) should return true. It is symmetric: for any reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true. It is transitive: for any reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true. It is consistent: for any reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the object is modified. For any non-null reference value x, x.equals(null) should return false. The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any reference values x and y, this method returns true if and only if x and y refer to the same object (x==y has the value true).

hashCode

public int hashCode()
Returns a hash code value for the object. This method is supported for the benefit of hashtables such as those provided by java.util.Hashtable. The general contract of hashCode is: Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application. If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result. It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables. As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)

toString

public String toString()
Returns a string representation of the object. In general, the toString method returns a string that “textually represents” this object. The result should be a concise but informative representation that is easy for a person to read. It is recommended that all subclasses override this method. The toString method for class Object returns a string consisting of the name of the class of which the object is an instance, the at-sign character `@’, and the unsigned hexadecimal representation of the hash code of the object. In other words, this method returns a string equal to the value of: getClass().getName() + ‘@’ + Integer.toHexString(hashCode())