Type Conversions

@rlkoshak as promised here some edits and rewrites.
In addition to general comments, here some specific comments to discuss:

  • I deleted the Contact and Switch; did not find the example of conversion too helpful and Player item description is really helpful here.
  • Added references to the eclipse descriptions of items, I had the impression that it may be the primary source (maybe I sprinkled them too generously throughout the document, but it appeared to me to be a pretty important reference that may have been underutilized so far)
  • Analogous to the Contact, I deleted the Player item; after checking eclipse docu, it appears that it only accepts the binary enum types PlayPauseType (PLAY, PAUSE), RewindFastforwardType (REWIND, FASTFORWARD), NextPreviousType (NEXT, PREVIOUS)
  • changed some of the formatting (level of indent, etc) to try to match the doc style in the rules document

Happy to post over your original article, but as stated above, was not fully comfortable doing so without hearing from you first

It appears that I am lacking the privileges to make this a wiki (would have made for easier editing)…


Interacting with Items in rules

A frequent operation in rules is to calculate other values from Item states or compare Item states against other values or perform other operations that are either responses to changes in item states or intended to change the item state.

In openHAB, every item carries a state that is reflective of the status the item is in (for switch the state can be ON or OFF, for an RGB LED the state could be hue, saturation and brightness, HSB, for dimmer it could a value such as 68%). The state of an item is an object itself and can be accessed with MyItem.state.

Just to recap some nomenclature, type refers here to the kind of data structure with which the item status reported by the Item. For example, some of the simplest data structures are of the type integers (whole numbers) or boolean (0 or 1) and other so-called primitives. But more often they are of more complex structure such as the HSB type mentioned above and those more complex structures are referred to generally as Objects. The conversion of one datatype into another is called type casting, or just casting.

To use the state of an item in rules for comparisons and other operations it is necessary to know what type of state the item is carrying and how to convert it into types that can be used in such operations.

Conversely, to use the result of a calculation in a rule that intends to change the state of an item will require the data type used for calculation and how to cast it into a type the item can accept as a modification of its state.

For a complete and up-to-date list of what item types are currently allowed in OpenHAB and the command types each item can accept see the Eclipse documentation for items.

Items and their types: retrieving, commanding and updating

There are two parts that will be considered separately, how to update or send commands to items and how to retrieve item states. For a more detailed discussion about updating and commanding, please see here (LINK TO TEXT ONCE #PR469 HAS MERGED)

Types for commanding and updating

The section on items in the Eclipse documentation and openHAB documentation gives a full overview on the datatypes that each item can accept. This section differentiates between command type and state type. For ease of reading, it is possible to simply add “type” to the end of a command type thereby obtaining the state type. For example the “Switch” can accept the “Command Type” labeled “OnOff”. Thus the state type is referred to as “OnOffType” in the second part of the introduction to items linked above.

And to present a more complex example, a Color Item can receive an OnOffType, IncreaseDecreaseType, PercentType, or HSBType. Therefore the following are all valid commands one can send to a Color Item:

  • MyColorItem.sendCommand(ON)
  • MyColorItem.sendCommand(INCREASE)
  • MyColorItem.sendCommand(new PercentType(50))
  • MyColorItem.sendCommand(new HSBType(new DecimalType(123), new PercentType(45), new PercentType(67)))

An alternative way to command or update the state of an item is through the use of specially formatted strings. The section in the item documentation on formatting details the requirements for the formatting.

Methods used to update or command items can use as their argument either the appropriate object or an appropriately formatted string. In addition, as shown in the example above for the Color item, the two types “PercentType” and “DecimalType” can also accept numerical value is also permissible.

Types for Retrieving

Even though many Items accept commands and updates of various different types, each stores its state internally using only one type. For example, even though a Color Item will accept OnOffType, IncreaseDecreaseType, PercentType, and HSBType, when you call MyColorItem.state it will only return an HSBType. For a complete and up-to-date list of what item types are currently allowed in OpenHAB and the command types each item can accept see the Eclipse documentation for items.

Groups can be declared with any Item type so it’s internal state will match that type. For example, Group:Switch will return an OnOffType for its state.

Each State Type provides a number of convenience methods that will greatly aid in conversion and calculations. Unfortunately, the best way to discover these methods are to either:

  • Use the Eclipse SmartHome Designer and the <ctrl><space> key combo to list all the available methods
  • Look at the JavaDocs for the given type (e.g. the JavaDoc for HSBType shows getRed, getBlue, and getGreen methods which would be called without the “get” part in name as in (MyColorItem.state as HSBType).red), which retrieves the state of MyColorItem and then casts it as HSBType to be able to use the methods associated with the HSBType.

Conversion Examples for retrieving and working with item states

Reminder: For a complete and up-to-date list of what item types are currently allowed in openHAB and the command types each item can accept refer to the Eclispe documentation.

Below a non-exhaustive list of some more common conversions

Color Item

A Color Item stores an HSBType.
The HSB stands for Hue, Saturation, and Brightness. Often one has the desired color as an RGB values (Red, Green, Blue). The following code can be used to send an RGB value to a Color Item.

import java.awt.Color

...

// in rule body
val newColor = new Color(red, blue, green) // where red, blue, and green are ints between 0 and 255
MyColorItem.sendCommand(new HSBType(newColor))

When individual color values from a HSBType as a PercentType are retrieved, it will be necessary to multiply that PercentType by 255 to obtain a standard 8-bit per color channel RGB. Correspondingly, the for 16 or 32 bit representation, the percent type needs to be multiplied the percent type by 16^2 or 32^2, respectively.

... 
//Example for conversion to 8-bit representation
// In rule body
val red = (MyColorItem.state as HSBType).red * 255
val green = (MyColorItem.state as HSBType).green * 255
val blue = (MyColorItem.state as HSBType).blue * 255

DateTime Item

A DateTime Item carries a DateTimeType.
DateTimeType presents the biggest challenge when converting and performing calculations. The problems stem from the fact that by default the Rules use a Joda DateTime class to represent time, most notably now. However, DateTimeType is not a Joda DateTime and in fact the two are incompatible, requiring some conversion in order to use the two together.

The lowest common denominator when working with time is to get at the epoch value. Epoch is the number of milliseconds that has passed since 1 January 1970 GMT and stored in a long. With epoc, one can compare two dates together, convert a Joda DateTime to a DateTimeType and visa versa.

// Get epoc from DateTimeType
val Number epoc = (MyDateTimeItem.state as DateTimeType).calendar.timeInMillis

// Get epoc from Joda DateTime
val Number nowEpoc = now.millis

// Convert DateTimeType to Joda DateTime
val joda = new DateTime((MyDateTimeItem.state as DateTimeType).calendar.timeInMillis)

// Convert Joda DateTime to DateTimeType
val calendar = java.util.Calendar::getInstance
calendar.timeInMillis = now.millis
val dtt = new DateTimeType(calendar)

There are always more than one way. In certain cases it is needed to convert an epoch timestamp to a human readable and/or store it in a DateTimeType and a DateTime Item. Here’s another option to do so utilizing SimpleDateFormat:

import java.text.SimpleDateFormat
import java.util.Date

// Convert epoch to a human readable
val SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
val String timestampString = sdf.format(new Date(timestampEpoch))

// Convert human readable time stamp to DateTimeType
val DateTimeType timestamp = DateTimeType.valueOf(timestampString)

Both Joda DateTime as well as DateTimeType (primarily through the calendar data member) provide a number of useful methods for comparing date times together and/or extracting parts of the date. For some examples (these examples are not comprehensive):

// See if DateTimeType is before Joda DateTime
if(now.isBefore((MyDateTimeItem.state as DateTimeType).calendar.timeInMillis)) ...

// See if DateTimeType is after Joda DateTime
if(now.isAfter((MyDateTimeItem.state as DateTimeType).calendar.timeInMillis))...

// Get the hour in the day from a DateTimeType
val hours = (MyDateTimeItem.state as DateTimeType).calendar.get(Calendar::HOUR_OF_DAY)
// See the Calendar javadocs for the full set of parameters available

Dimmer Item

A Dimmer Item carries a PercentType.
PercentType can be cast to and treated like a java.lang.Number. Number represents any type of numerical value. The Rules language supports doing comparisons with Numbers and doing math with Numbers and the Number supports methods for getting primitive versions of that number if needed.

val dimVal = MyDimmerItem.state as Number

if(dimVal > 50)...

val newDimVal = dimVal + 10

val int dimAsInt = dimVal.intValue

val float dimAsFloat = dimVal.floatValue

Location Item

A Location Items carries a PointType.
A PointType consist of two or three DecimalType numbers representing latitude and longitude in degrees, and an optional altitude in meters. Here are a few examples:

// Creation
val location = new PointType(new DecimalType(50.12345), new DecimalType(10.12345))

// Saving to an Item
Device_Coordinates.postUpdate(location)

// Loading from an Item
val PointType location = Device_Coordinates.state as PointType

Comment: This does not give any indication on how to extract a single value out of this tuple(?). Is there a method getLongitude?

Number Item

A Number Items carries a DecimalType. A DecimalType is also a java.lang.Number so all the conversions listed above apply.

One warning comes with DecimalType. The full exmplanation is beyond the scope of this introduction. To avoid an error mentioning an “Ambiguous Method Call” always cast the state of a DecimalType to a Number, not DecimalType.

PointType

See Location item

Rollershutter Item

See Dimmer
In addition to the command types of the item type Dimmer, the Rollershutter item accepts the StopMoveType with the commands STOP and MOVE

String Item

To convert from a StringType just call toString.

val stateAsString = MyStringItem.state.toString
1 Like