Examining the openhab_msgs
Before you start this chapter, look at the previous chapter Examining the openhab_static_examples.
This tutorial will guide you through the openhab_msgs investigation. It shows you which fields are used in each message type and how to work with them.
Motivation
Before we start thinking about what data can be transferred and how, let's look at the message types we can use for this.
Examining the openhab_msgs
In openHAB there are the item types Color, Contact, DateTime, Dimmer, Group, Image, Location, Number, Player, Rollershutter, String, Switch and the command types Decimal, HSB, IncreaseDecrease, NextPrevious, OnOff, OpenClosed, Percent, PlayPause, Point, RewindFastforward, StopMove, String, UpDown.
An Item Type allows at least one of these Command Types. However, depending on the item type, it is determined which command types are allowed. Conversely, there is also no item type that allows all command types. Finally, for each item type, a message type for states and a message type for commands were created. We will now go through all items and explain what can be received as a state and what can be sent to openHAB as a command.
What is the structure of an item?
Items are defined using the following syntax:
itemtype itemname "labeltext [stateformat]" <iconname> (group1, group2, ...) ["tag1", "tag2", ...] {bindingconfig}
- Fields must be entered in the order shown
- itemtype and itemname are mandatory
- All other fields are optional
- Fields may be separated by one or more spaces, or tabs
- An Item definition may span multiple lines
For example:
Switch Kitchen_Light "Kitchen Light" {channel="mqtt:topic:..." } String Bedroom_Sonos_CurrentTitle "Title [%s]" (gBedRoom) {channel="sonos:..."} Number Bathroom_WashingMachine_Power "Power [%.0f W]" <energy> (gPower) {channel="homematic:..."} Number Livingroom_Temperature "Temperature [%.1f °C]" <temperature> (gTemperature, gLivingroom) ["TargetTemperature"] {knx="1/0/15+0/0/15"}
Item type Number
Item name Livingroom_Temperature
Item label "Temperature"
Item state formatted to display temperature in Celsius to one-tenth of a degree - for example, "21.5 °C"
Item icon with the name temperature
Item belongs to groups gTemperature and gLivingroom (definition not shown in the example)
Item is tagged as a thermostat with the ability to set a target temperature ("TargetTemperature")
Item is bound to the openHAB Binding knx with binding specific settings ("1/0/15+0/0/15")
We are not interested in a lot of it. Primarily we are interested in the item type and the item name. In the event bus we are also interested in which state an item has and which command we have to send to this item!
Therefore, whether for a State Message Type or a Command Message Type, in each of the following Message Types we see:
Header header string item # the name of the item
The field item is of type std_msgs/String. We transfer not only states and commands, but to be ROS compliant also the name of the item. Much more we also need this name so that we can create topics generically. You will see this in the following tutorial. Another common feature is the use of std_msgs/Header. This is a standard metadata for higher-level stamped data types. This means it is generally used to communicate timestamped data in a particular coordinate frame.
Something that must not be lost is that an item in openHAB can also assume the states NULL and UNKNOWN. I cannot query UNKNOWN via the REST API of openHAB, but I can query NULL. Thus all message types still receive the following field:
bool isnull
This isnull field is of type std_msgs/Bool. If this field contains True, then either a state of an item is NULL or you want to send a NULL command to openHAB, which would mean for example <item>.sendCommand(NULL).
Why do we use this extra isnull/bool field? This is because you cannot use generics in ROS on the one hand. Generics would mean that a field can take different types. It wouldn't matter if I use a string, an int or a float, the field would be called the same and when assigning a value, the data type would first be assigned (generically). And on the other hand it is not possible in ROS to leave a field empty. Each field in a message type must be assigned a value!
What does this mean when I send a NULL? Generally speaking, this means that fields containing states or commands must also carry some value. But there I can use fake data. So in my programming I have to check each time if this isnull field is True or False!
Otherwise, I would continue to work with wrong values, which leads to errors. This is a quite practical workaround, which makes it possible that the nevertheless quite generic way of working in openHAB can also be transferred to ROS.
Why don't we just use strings for states and commands? The simple answer would be conformity! I'll expand on this idea a bit. Also in MQTT I can use a publisher-subscriber pattern. In MQTT, each message of a topic is parsed to a string. That means before publishing I have to parse to a string and when subscribing I have to parse back to my datatype accordingly. If you have enough experience with ROS, you will have noticed that we do not do this in ROS. With MQTT also no message type must be defined, since all are automatically string. In ROS, however, publisher and subscriber can only communicate if they have the same message type. One reason for these message types is that you don't have to parse the data anymore to avoid errors. So to be truly ROS compliant, we may also need to split data for the Message Types or use other Message Types that already exist. Therefore often in fields of a Message Type the std_msgs are used. In general, it is advisable to reuse existing message types, so that there is a uniform definition of different robots, for example.
There is also another rationale that explains this ROS compliance well: I can use rosnode to see which nodes are currently running and which publishers and subscribers are using those nodes. With rostopic I can also display a list of all topics or take a closer look at one of these topics. And finally I can use rosmsg to take a closer look at a message type. So if a ROS system (robot or here the openhab_bridge) is running, I have to have zero idea how the whole thing works. I just need a basic understanding of ROS. Work my way through and recognize on the basis of the message types, how I can query (subscribe) my data, can then also conclude how I process them and finally I know which data I can send back (publish) again.
Color
State
The Color Item Type contains a state that has color values in the HSB color system. It therefore describes the color information of an item. HSB stands for Hue, Saturation and Brightness. The openhab_msgs/ColorState looks like this:
# Color information (HSB) Header header string item # the name of the item uint32 hue # Color of the light uint32 saturation # Saturation of the light uint32 brightness # Brightness of the light bool isnull
As you can see, there is a separate field each for hue, saturation and brightness of type std_msgs/UInt32.
In ROS there is still the std_msgs/ColorRGBA. A conversion does not take place, because openHAB uses neither RGB nor RGBA. If you would need this for further processing, you have to convert the color system accordingly yourself.
Hue is specified with a number of degrees between 0 and 360. You can see this when you take a closer look at the color space of the color system. Saturation and Brightness, on the other hand, are two percentage values whose value lies between 0 and 100 accordingly.
The openhab_bridge uses this message type to publish the state information from openHAB. This can be seen in Examining the openhab_bridge with HABApp (Python), Examining the openhab_bridge without HABApp (Python) and Examining the openhab_bridge with C++ (C++). If you want to subscribe a color item, you must also use this message type. You can see this accordingly in Writing and examining a Simple Subscriber for the Color Item Type (Python) or Writing and examining a Simple Subscriber for the Color Item Type (C++).
Next, let's look at exemplary values for certain colors in the HSB and RGB color systems. RGB will be more familiar to most people. Both color systems are ultimately a three-dimensional array and are additive.
Color |
HSB |
RGB |
black |
0, 0, 0 |
0, 0, 0 |
blue |
0, 0, 255 |
240, 100, 100 |
green |
0, 255, 0 |
120, 100, 100 |
cyan |
0, 255, 255 |
180, 100, 100 |
red |
255, 0, 0 |
0, 100, 100 |
violet |
255, 0, 255 |
300, 100, 100 |
yellow |
255, 255, 0 |
60, 100, 100 |
white |
255, 255, 255 |
0, 0, 100 |
In my opinion cyan and turquoise is the same. Also violet and purple is the same. The absolute black is a synonym for OFF and the absolute white is a synonym for ON. In the end, however, every color that is not absoult black also means ON. At least when another item is ON for this. It would also be conceivable that a state is retained for a color item, but a switch item is OFF for this. If this switch is set to ON, no neutral color (such as white for lamps) is used, but the last known state is retained.
Commands
A color item allows the commands OnOff, IncreaseDeacrease, Percent and HSB. HSB is the same thing here and, in simple terms, means that you can also send back new color values directly. The openhab_msgs/ColorCommand looks like this:
# Color information (HSB) # Possible commands for Color string ON=ON string OFF=OFF string INCREASE=INCREASE string DECREASE=DECREASE string command # Color command enumerated above bool iscommand # False if you do not want to send a command enumerated above bool ispercentage # False if you do not want to send a percentage to your item int8 PERCENTAGE0=0 int8 PERCENTAGE1=1 ... int8 PERCENTAGE99=99 int8 PERCENTAGE100=100 int8 percentage bool ishsb # False if you do not want to send HSB values for changing the item uint32 hue # Color of the light uint32 saturation # Saturation of the light uint32 brightness # Brightness of the light Header header string item # the name of the item bool isnull
As you can see, this now looks a bit more complex. This is due to the fact that only mandatory attributes (fields) can be transferred to ROS. And as already mentioned, ROS does not allow generics. In the programming I need also appropriate case distinctions.
There are the std_msgs/Bool fields iscommand, ispercentage, ishsb and isnull.
If you want to send an command like ON, OFF, INCREASE or DECREASE you have to to set iscommand to True. And of course the command you want to execute in openHAB to the std_msgs/String field command. In openHAB there is the boolean command type OnOff for the commands ON or OFF. And in openHAB there is the boolean command type IncreaseDecrease for the commands INCREASE or DECREASE. We must now consider one thing. And that is that these commands are constants of the type string. So if we set a value for the command field, we have to set "ON", "OFF", "INCREASE" or "DECREASE". But the nice thing is that we can also use an enumeration for this type to make this easier. We also notice that we don't need to create an extra command type. This is because we have to perform a sendCommand with one of these values at the end and do not have to differentiate further. If we want to send one of these commands, ispercentage, ishsb and isnull must be set to False and the corresponding fields must be assigned fake values, because ROS only allows required fields.
If you want to send a Percentage you have to set ispercentage to True and iscommand, ishsb and isnull to False. Then you have to set a value between 0 and 100 to the std_msgs/Int8 field percentage. All other remaining fields now need some fake data again. Therefore, in the code shown above, you can also see the PERCENTAGE0...PERCENTAGE100 enumeration. You can also use these as constants in your code. It further restricts the value range of the message type. A certain restriction already exists through the type std_msgs/Int8. So extremely high integer values were not possible from the beginning.
If you want so send a HSB you have to set ishsb to True and the other std_msgs/Bool fields to False. As described at State Message Type therefore you have to use the std_msgs/UInt32 field hue, saturation and brightness for this. The other remaining fields receive fake values.
If you want to send a NULL you only have to set isnull to True and the other std_msgs/Bool fields to False. The other remaining fields receive fake values.
The openhab_bridge uses this message type to subscribe a command for an item and execute it in openHAB. This can be seen in Examining the openhab_bridge with HABApp (Python), Examining the openhab_bridge without HABApp (Python) and Examining the openhab_bridge with C++ (C++). If you want to publish a command for a color item, you must also use this message type. You can see this accordingly in Writing and examining a Simple Publisher for the Color Item Type (Python) or Writing and examining a Simple Publisher for the Color Item Type (C++).
Why don't we use Message Types for the Command Types? I hope this example explains relatively much at once. I can use this approach to restrict to which item I can execute which commands.
Why are multiple command types implemented in a single message type? Besides the restriction and assignment to an item type, this has the advantage that I can create publishers and subscribers based on an item type. This makes the application much less complex. Otherwise the openhab_bridge would have to provide a subscriber for each item type in combination with each command type. So in your programming you would also have to consider multiple publishers and ultimately make a case distinction as to which publisher you would want to use. So you only need a case distinction of the data you want to send.
In concrete terms, however, this also means that many more topics would have to be remembered. And on the other hand the topics are based on the events of openHAB. In openHAB a topic is called for example:
openhab/items/{itemName}/command
Here in ROS our topic is then either called the same or a leading / is added:
/openhab/items/{itemName}/command
If I wanted to use topics for individual commands, for example, I would have the following structure:
/openhab/items/{itemName}/command/OnOff /openhab/items/{itemName}/command/IncreaseDecrease /openhab/items/{itemName}/command/Percentage /openhab/items/{itemName}/command/HSB /openhab/items/{itemName}/command/NULL
Instead of the Command Message Types, which are based on the Item Types, I could have based the Command Message Types on the Command Types. Perhaps this approach will nevertheless turn out to be more clever in the future. But the disadvantage is obvious, you would have to know in advance which item type an item has, so that you will use a correct topic and therefore a correct command.
The same procedure applies to all other command message types explained below. The command types for the respective item types are included in their command message types.
As we have already seen, a color item can also be used to execute commands that you would expect from other item types. I will explain this example with a Philips Hue lamp, which is integrated in openHAB by the Philips Hue Binding. Exemplary the items look like this:
Switch Light1_Toggle { channel="hue:0210:1:bulb1:color" } Dimmer Light1_Dimmer { channel="hue:0210:1:bulb1:color" } Color Light1_Color { channel="hue:0210:1:bulb1:color" } Dimmer Light1_ColorTemp { channel="hue:0210:1:bulb1:color_temperature" } String Light1_Alert { channel="hue:0210:1:bulb1:alert" } Switch Light1_Effect { channel="hue:0210:1:bulb1:effect" }
The switch Light1_Toggle is used to switch a lamp ON or OFF. The dimmer Light1_Dimmer is used to dim this lamp. This means that the brightness is changed. Now comes our color item Light1_Color, which has an influence on the two attributes mentioned before. We can already see this because these three items use the same channel. This means that there is a dependency from the binding. Then there is the dimmer Light1_ColorTemp, which specifies the color temperature of the lamp. With the string Light_Alert an alarm of a lamp can be executed. Difficult to describe. A Hue lamp can shine continuously, but can also flash slowly or quickly. A flashing light is often used as a warning light. Last but not least there is the switch item Light1_Effect. This creates a so-called color effect. This color effect means that the color of the light changes several times in a row.
This is also a very nice example of how to work in openHAB. These items all refer to one and the same lamp. We can call this lamp Light1. In the channel we see with hue that the hue binding is used. The number 0210 represents a random ID for the Philips Hue Bridge, which is our gateway to the Philips Hue lamp. The number 1 stands for the ID of the lamp. Then comes the name of the lamp and the information we want to query about the lamp. All this is stored in a binding. So there is a Thing for the Philips Hue Bridge and a Thing for the Philips Hue Lamp. It is important that the Thing has multiple items.
You can also write subscribers for multiple items from one Thing or even corresponding publishers. See here:
Writing and examining a Simple Subscriber for multiple Items of a Thing (Python) or Writing and examining a Simple Subscriber for multiple Items of a Thing (C++) for writing your subscriber and Writing and examining a Simple Publisher for multiple Items of a Thing (Python) or Writing and examining a Simple Publisher for multiple Items of a Thing (C++) for writing your publisher.
As we have already learned, an Item communicates with a Thing via Channels. A Thing communicates with a physical device via a binding. In this case with the Philips Hue binding via the Philips Hue Bridge to a Philips Hue lamp. The important thing is that if I change one item, it can affect other items from the same Thing. In openHAB itself this only happens when I write a rule and specifically want to trigger something like this. But in this case there is a context because of the device itself. Means concretely, a command triggers only a single state change in openHAB. The lamp changes the state and the states of the dependent items also change via the binding. We can see the dependency as already explained by using the same channel for different items.
First, let's take a look at how a binding works. Similar to channels between Things and Items, the communication there is bidirectional. If I turn on my lamp in openHAB, it turns on. If I do not switch on my lamp with openHAB, but e.g. via a REST API, my smartphone app, a web application, etc., then this lamp also goes on and openHAB receives the state.
I send an ON command to Light1_Color, then I get a state from 5 items. If I send an ON command to Light1_Toggle, then I get a state from 5 items. The same is true for OFF. Or also another command to Light1_Color.
For example, if I send 100,100,100, which is an HSB command, the following happens:
Switch Light1_Toggle: ON Dimmer Light1_Dimmer: 100 Color Light1_Color: [100,100,100] Dimmer Light1_ColorTemp: 39 String Light1_Alert: "None" Switch Light1_Effect: OFF
The Light1_Effect is the only Item which will not receive an update by the binding. Not to be confused, color temperature and saturation are not the same thing. Any color that is not absolutely black means that the lamp should turn on. Means the Light1_Toggle will change to ON. HSB stands for Hue, Saturation and Brightness. The brightness is always specified directly individually once again at the dimmer Light1_Dimmer. If I change this, the brightness part of the color item Light1_Color would logically also change. If I dim a lamp to 0, it is logically also off. I cannot trigger the Alarm or Color Effect function via a Color Item. But the color temperature changes with every color change.
If I send e.g. 0,0,0, then the following happens:
Switch Light1_Toggle: OFF Dimmer Light1_Dimmer: 0 Color Light1_Color: [0,0,0] Dimmer Light1_ColorTemp: 0 String Light1_Alert: "None" Switch Light1_Effect: OFF
So the color value [0,0,0] is black and stands for OFF!
INCREASE or DECREASE dims the lamp. A multiple execution of DECREASE results in the following course:
[100,100,100] [100,100,89] [100,100,77] [100,100,65] [63,100,65] [63,100,53] [63,100,41] [63,100,30] [63,100,18] [63,100,6] [63,100,0]
With DECREASE you can switch a lamp OFF. And with INCREASE you can switch a lamp ON:
[63,100,0] [63,100,12] [63,100,24] [63,10036] [63,100,48] [63,100,60] [63,100,71] [63,100,83] [63,100,95] [63,100,100]
So both make about 11-steps and 12-steps, respectively. However, there are anomalies in these two examples: [100,100,65] changed to [63,100,65]. Also sometimes a step is 11 or 12 and sometimes a little bit higher or lower. This is because the lamps cannot reproduce 100% of all colors. This is referred to as color fidelity and color fastness. It can also happen that a command is sent out and the state changes minimally accordingly. Only the next convertible color value can be taken. So here a kind of interpolation takes place, which color is closest to the desired result. So not only the brightness is changed, but also Hue and sometimes also Saturation, if it is obvious.
The Philips Hue lamps can also not all colors. For example, [0,0,0] stands for OFF and not for black. In addition, [180,100,100], which should represent cyan/turquoise, the lamp is actually set to this value, but a white is output that hardly differs from [0,0,100]. However, the state can also differ only minimally. 180,100,100] becomes [180,99,100]. So it is nevertheless tried that one converts this cyan. So it is not interpolated to the next value, which should be much closer to white.
The last input I can make for Color would be the Percent type. This has a range between 0 and 100. A 0 again stands for OFF and a 100 for ON. In principle, every value that is not 0 stands for ON.
If you send 0 you will receive:
Switch Light1_Toggle: OFF Dimmer Light1_Dimmer: 0 Color Light1_Color: [63,100,0] Dimmer Light1_ColorTemp: 0 String Light1_Alert: "None" Switch Light1_Effect: OFF
If you send 100 you will receive:
Switch Light1_Toggle: ON Dimmer Light1_Dimmer: 100 Color Light1_Color: [63,100,100] Dimmer Light1_ColorTemp: 39 String Light1_Alert: "None" Switch Light1_Effect: OFF
It should be noted that the color temperature is a dimmer, so it is also between 0 and 100 percent. The difference is that the color temperature is calculated from Hue, Saturation and Brightness, while the dimmer for the Brightness changes 1:1 with the HSB value to be changed. HSB is an array [Hue,Saturation,Brightness].
Contact
State
A Contact item delievers the status of contacts, e.g. door/window contacts. It does not accept commands, only status updates in openHAB. The https://github.com/Michdo93/openhab_msgs/raw/noetic-devel/msg/ContactState.msg looks like this:
# Status of contacts e.g. door/window contacts. # Does not accept commands, only status updates. # Possbile states for Contact string OPEN=OPEN string CLOSED=CLOSED string state Header header string item # the name of the item bool isnull
There are only two states OPEN and CLOSED. So, for example, a door is either OPEN or CLOSED. Here we assume a pure sensor. For example, if I have a window that has the states OPEN, TILTED or CLOSED, then a string item is used for this. Note that the command type in openHAB is an enum consisting of string constants. Accordingly, "OPEN" or "CLOSED" must be used outside of openHAB, since the OpenClosed Type does not exist there. For the state field the message type std_msgs/String is used.
If you want to subscribe a Contact item, you must also use this message type. You can see this accordingly in Writing and examining a Simple Subscriber for the Contact Item Type (Python) or Writing and examining a Simple Subscriber for the Contact Item Type (C++).
Commands
The Message Type openhab_msgs/ContactCommand looks like this:
# Status of contacts e.g. door/window contacts. # Does not accept commands, only status updates. # Possbile commands for Contact string OPEN=OPEN string CLOSED=CLOSED string command # Contact commands enumerated above Header header string item # the name of the item bool isnull
Pretty much the same. For the command field the message type std_msgs/String is used. Why does this command type exist anyway? Simply said, so that one can also use this message type for the sake of completeness. However, one must note that a postUpdate and no sendCommand is performed. What does this mean concretely? A binding performs a postUpdate. So if I open a door, the item state changes to OPEN because of the binding. If I close the door, the state changes to CLOSED. As just mentioned, it is a pure sensor. The device has no actuator. A sendCommand would mean that one would send a command to the device. In this case a command OPEN could mean that a motor opens the door and the state changes from CLOSED to OPEN. And likewise in this case a command CLOSED could mean that the state changes from OPEN and CLOSED because the motor closes the door again.
If we now consider a scenario where a robot opens a door or a window, we still don't have to actively change anything here. Because the sensor still communicates with openHAB via its binding.
There are also windows that can be opened with motors. Therefore, the use of a command may make sense at some point in the future. Another far-fetched future scenario is that autonomous vehicles are robots. This is also referred to colloquially as robot cars or robotic cars. An open door, an open window, an open trunk or an open hood could then perhaps be covered by a contact item in the future. In this case, ROS would also function like a binding. In the openhab_bridge can be carried out namely also only one postUpdate!
DateTime
State
A DateTime item stores date and time. In ROS we will therefore use the openhab_msgs/DateTimeState. It looks like this:
# Stores date and time Header header string item # the name of the item time state # the datetime value of the item bool isnull
The state field uses the message type std_msgs/Time. You have to consider that openHAB is written in Java and uses a different date/time format than for example Python in ROS. Also C++ would use a different format. The std_msgs/Time is the default format for ROS. A conversion from openHAB to ROS and vice versa is therefore done in the openhab_bridge.
For example, a DateTime item is often used in addition to another item. An example would be a temperature sensor. You use a Number item for the temperature and at the same time you use a DateTime item, so that you also record when the last temperature change occurred.
If you want to subscribe a DateTime item, you must also use this message type. You can see this accordingly in Writing and examining a Simple Subscriber for the DateTime Item Type (Python) or Writing and examining a Simple Subscriber for the DateTime Item Type (C++).
Commands
The openhab_msgs/DateTimeCommand looks like this:
# Stores date and time Header header string item # the name of the item time command # the datetime value of the item bool isnull
Why is there a Command Type? Well, as already described, there are enough items, which are brought in a temporal dependence, with their value acquisition. If we want to change them, for example, we should also change the assigned time.
Another reason is ROS itself. In ROS we can publish different sensor and actuator information from different robots to openHAB. Depending on the use case, it makes additional sense that we also know the time of the value acquisition.
Dimmer
State
The Dimmer item stores a percentage value for dimmers. As we have already seen with the Color item, this usually refers to brightness. Another use case would be the volume of a TV or a sound system, for example. In ROS we will use the openhab_msgs/DimmerState for this. It looks like following:
# Percentage value for dimmers # Possible states for Dimmer int8 PERCENTAGE0=0 int8 PERCENTAGE1=1 ... int8 PERCENTAGE99=99 int8 PERCENTAGE100=100 int8 state # Dimmer state enumerated above Header header string item # the name of the item bool isnull
Because a percentage value is between '0' and '100' the state field uses the std_msgs/Int8 message type. It is only a small data type with a small range. More is not needed. Due to the enums between PERCENTAGE0 and PERCENTAGE100, this field has also been limited to between '0' and '100'. You can also use this to process the state.
If you want to subscribe a Dimmer item, you must also use this message type. You can see this accordingly in Writing and examining a Simple Subscriber for the Dimmer Item Type (Python) or Writing and examining a Simple Subscriber for the Dimmer Item Type (C++).
Commands
The openhab_msgs/DimmerCommand looks like this.
# Percentage value for dimmers # Possible commands for Dimmer string ON=ON string OFF=OFF string INCREASE=INCREASE string DECREASE=DECREASE string command # Dimmer command enumerated above bool iscommand # True if you want to send a command enumerated above bool ispercentage # True if you want to send a percentage enumerated above # Possible percentages for Dimmer int8 PERCENTAGE0=0 int8 PERCENTAGE1=1 ... int8 PERCENTAGE99=99 int8 PERCENTAGE100=100 int8 percentage Header header string item # the name of the item bool isnull
As we have already seen with the Color Item, there are the Command Types OnOff, IncreaseDecrease or Percent. Percent means simply that you also use a value between '0' and '100'. Therefore you have to set the std_msgs/Bool field ispercentage to True. The other std_msgs/Bool fields must be in this case False and the other fields should have fake values because ROS only supports required fields. The openhab_bridge will ignore it.
For running an OnOff command you have to set the std_msgs/String field command to "ON" or "OFF" or use the enums ON or OFF. Then the std_msgs/Bool field iscommand should be set to True and the other std_msgs/Bool fields to False. The remaining fields also receive fake values.
If you want to run a IncreaseDecrease command you have to use instead of "ON" or "OFF" the string values "INCREASE" or "DECREASE" or the enums INCREASE or DECREASE. The rest works the same.
If you want to send a NULL command you have to set the std_msgs/Bool field isnull to True.
As we see here again, a Dimmer Item may have dependencies on other Item Types. An example of color lamps, as with the Color Item, would therefore be superfluous for this consideration. We will therefore look at an example for Sonos speakers using the Sonos binding:
Group Sonos <player> Player Sonos_Controller "Controller" (Sonos) {channel="sonos:PLAY1:living:control"} Dimmer Sonos_Volume "Volume [%.1f %%]" <soundvolume> (Sonos) {channel="sonos:PLAY1:living:volume"} Switch Sonos_Mute "Mute" <soundvolume_mute> (Sonos) {channel="sonos:PLAY1:living:mute"} Switch Sonos_LED "LED" <switch> (Sonos) {channel="sonos:PLAY1:living:led"} String Sonos_CurrentTrack "Now playing [%s]" <text> (Sonos) {channel="sonos:PLAY1:living:currenttrack"} String Sonos_State "Status [%s]" <text> (Sonos) {channel="sonos:PLAY1:living:state"}
If you send an '0' or an 'OFF' command to the Dimmer item 'Sonos_Volume' the Switch 'Sonos_Mute' will be 'OFF'. If you send an command which is higher than '0' or an 'ON' command the Switch 'Sonos_Mute' will be 'ON'.
With INCREASE you will INCREASE the volume about 10 percent and with DECREASE you will DECREASE the volume about 10 percent. If you decrease the volume to '0' the Switch 'Sonos_Mute' will be 'OFF'. If you increase the volume from '0' to '10' then the Switch 'Sonos_Mute' will be 'ON'.
Group
State
A Group is used as an item to nest other items / collect them in groups. The openhab_msgs/GroupState looks like this:
# Item to nest other items / collect them in groups. Header header string item # the name of the group bool isnull
And this is where a problem arises with the Publish Subscribe Pattern. When I query a group item via the REST API, I get all the items that are in that group. Also accordingly if there are other Groups in this Group. This works because I get JSON objects via REST. There it is possible that an object owns or in this case subordinates further objects. In ROS and in MQTT I would have to iterate here per loop and publish each of the items individually. We do not do that because we mirror the event bus. In a group it is possible that only one item executes an ItemStateEvent. For the previously mentioned use case, you can follow the tutorial Writing and examining a Simple Subscriber for multiple Items of a Thing (Python) or Writing and examining a Simple Subscriber for multiple Items of a Thing (C++).
A Group also does not have a State. We only publish the name of a group if one should change here.
If you want to subscribe a Group item, you must also use this message type. You can see this accordingly in Writing and examining a Simple Subscriber for the Group Item Type (Python) or Writing and examining a Simple Subscriber for the Group Item Type (C++).
Commands
A Group item does not allow any Commands!
Image
State
The state of an Image item contains the binary data of an image. Specifically, this means that an image is base64 encoded and stored as a string. In openHAB, images are used in different ways. It can be actual frames from a surveillance camera, it can be snapshots, it can be album covers when music is playing or a cover from a movie and much more. The openhab_msgs/ImageState looks like this:
# Binary data of an image (openHAB) converted to sensor_msgs/Image of ROS Header header string item # the name of the item sensor_msgs/Image state # the real image data bool isnull
The state field is from sensor_msgs/Image type. This is the standard in ROS to transfer images. It is recommended to convert the images in ROS from OpenCV images to ROS images or vice versa. For this purpose there is the cv_bridge. I recommend the [[http://wiki.ros.org/cv_bridge/Tutorials/UsingCvBridgeToConvertBetweenROSImagesAndOpenCVImages|Converting between ROS images and OpenCV images (C++)] and the [[http://wiki.ros.org/cv_bridge/Tutorials/ConvertingBetweenROSImagesAndOpenCVImagesPython|]Converting between ROS images and OpenCV images (Python)] tutorial.
If you want to subscribe a Image item, you must also use this message type. You can see this accordingly in Writing and examining a Simple Subscriber for the Image Item Type (Python) or Writing and examining a Simple Subscriber for the Image Item Type (C++).
Commands
In openHAB you can only use an image by a binding doing a postUpdate. Since we work a lot with images in ROS (e.g. map information, camera streams), we also want to send an image (possibly a frame) to openHAB. For this there is the openhab_msgs/ImageCommand message type, which looks like this:
# Binary data of an image (openHAB) converted to sensor_msgs/Image of ROS Header header string item # the name of the item sensor_msgs/Image command # the real image data bool isnull
In fact, we end up performing a postUpdate with it. So ROS would behave the same here as a binding. This can be seen in Examining the openhab_bridge with HABApp (Python), Examining the openhab_bridge without HABApp (Python) and Examining the openhab_bridge with C++ (C++).
Location
State
How to specify a localization? Correct, with coordinates. Preferably even with GPS coordinates. Therefore you can use the openhab_msgs/LocationState message type, which looks like this:
# GPS coordinates Header header string item # the name of the item bool isnull # Latitude [degrees]. Positive is north of equator; negative is south. float64 latitude # Longitude [degrees]. Positive is east of prime meridian; negative is west. float64 longitude # Altitude [m]. Positive is above the WGS 84 ellipsoid # (quiet NaN if no altitude is available). float64 altitude
Longitude, latitude and altitude are all field of the std_msgs/Float64 message type. Longitude can be a value between -180 and 180 degrees. Latitude can be a value between -90 and 90 degrees. Altitude is in meters. There are locations that are below sea level and there are mountains that are quite a bit higher. A limit value is not known.
If you want to subscribe a Location item, you must also use this message type. You can see this accordingly in Writing and examining a Simple Subscriber for the Location Item Type (Python) or Writing and examining a Simple Subscriber for the Location Item Type (C++).
Commands
The openhab_msgs/LocationCommand looks like the same:
# GPS coordinates Header header string item # the name of the item bool isnull # Latitude [degrees]. Positive is north of equator; negative is south. float64 latitude # Longitude [degrees]. Positive is east of prime meridian; negative is west. float64 longitude # Altitude [m]. Positive is above the WGS 84 ellipsoid # (quiet NaN if no altitude is available). float64 altitude
GPS coordinates can not only show the current position, but as a command they can also be used for target coordinates.
Number
State
The Item Type Number is a fairly generic one for numbers in openHAB. It allows both integers and floating point numbers. This item type is used for a variety of different use cases. This is also due to the fact that it can be formatted in any way. Integers are often used for any numbered modes of a device. A simple example of a floating point number would be the current temperature measured by a temperature sensor. Here you usually format to one decimal place. If we think for example in currencies like Dollar or Euro, we can format to two decimal places, if we want to show the current exchange rate by an item. It is also common to specify the CPU load or how much RAM or hard disk space is used. As you can see, everything that has something to do with numbers can be assigned to the Number Type. The openhab_msgs/NumberState looks like this:
# Values in number format Header header string item # the name of the item float64 state # the number value of the item bool isnull
I used the std_msgs/Float64 message type for the state because an integer is a float without a significant value after the decimal point. With a float, however, I should never lose what would still be specified after the decimal point. So I can convert an integer to a float without losing any information. Conversely, I cut off possible important information.
If you want to subscribe a Number item, you must also use this message type. You can see this accordingly in Writing and examining a Simple Subscriber for the Number Item Type (Python) or Writing and examining a Simple Subscriber for the Number Item Type (C++).
Commands
The openhab_msgs/NumberCommand looks like this:
# Values in number format Header header string item # the name of the item float64 command # the number command for the item bool isnull
Who would have thought it? A number should continue to function as a number. One can exchange numerical values, but hardly process them in any other meaningful way. Surely one could imagine an INCREASE or DECREASE with which a numerical value is increased or decreased by 1. However, there is no such thing in openHAB.
However, you can very well use a number for a command. Just at this example that a device uses any number as modes. With a new number, one changes thus this mode.
Player
State
The Player item allows control of players (e.g. audio players). The openhab_msgs/PlayerState looks like this:
# Allows control of players (e.g. audio players) # Possible states for Player string PLAY=PLAY string PAUSE=PAUSE string NEXT=NEXT string PREVIOUS=PREVIOUS string REWIND=REWIND string FASTFORWARD=FASTFORWARD string state # Player state enumerated above Header header string item # the name of the item bool isnull
As you can see the state can be as examole "PLAY" or "PAUSE". These constants are specified in openHAB by means of a string. Accordingly, the field for state is of type [[http://docs.ros.org/en/noetic/api/std_msgs/html/msg/String.html|std_msgs/String].
If you want to subscribe a Player item, you must also use this message type. You can see this accordingly in Writing and examining a Simple Subscriber for the Player Item Type (Python) or Writing and examining a Simple Subscriber for the Player Item Type (C++).
Commands
The openhab_msgs/PlayerCommand looks like this:
# Allows control of players (e.g. audio players) # Possible commands for Player string PLAY=PLAY string PAUSE=PAUSE string NEXT=NEXT string PREVIOUS=PREVIOUS string REWIND=REWIND string FASTFORWARD=FASTFORWARD string command # Player command enumerated above Header header string item # the name of the item bool isnull
It actually does exactly what you would expect from a player. You can PLAY, PAUSE, NEXT, PREVIOUS, REWIND or FASTFORWARD.
Rollershutter
State
A Rollershutter Item is typically used for blinds or roller shutters. The openhab_msgs/RollershutterState looks like this:
# Roller shutter Item, typically used for blinds # Possible states for Rollershutter string UP=UP string DOWN=DOWN string STOP=STOP string MOVE=MOVE string state # Rollershutter state enumerated above bool isstate bool ispercentage int8 PERCENTAGE0=0 int8 PERCENTAGE1=1 ... int8 PERCENTAGE99=99 int8 PERCENTAGE100=100 int8 percentage Header header string item # the name of the item bool isnull
Again, a percentage value is used. The difference to the dimmer item is clearly the different commands. A percentage value is between '0' and '100' the state field uses the std_msgs/Int8 message type. It is only a small data type with a small range. More is not needed. Due to the enums between PERCENTAGE0 and PERCENTAGE100, this field has also been limited to between '0' and '100'. You can also use this to process the state.
If you want to subscribe a Rollershutter item, you must also use this message type. You can see this accordingly in Writing and examining a Simple Subscriber for the Rollershutter Item Type (Python) or Writing and examining a Simple Subscriber for the Rollershutter Item Type (C++).
Commands
The openhab_msgs/RollershutterCommand looks like this:
# Rollershutter Item, typically used for blinds # Possible commands for Rollershutter string UP=UP string DOWN=DOWN string STOP=STOP string MOVE=MOVE string command # Rollershutter command enumerated above bool iscommand bool ispercentage # Possible percentages for Rollershutter int8 PERCENTAGE0=0 int8 PERCENTAGE1=1 ... int8 PERCENTAGE99=99 int8 PERCENTAGE100=100 int8 percentage Header header string item # the name of the item bool isnull
You can raise or lower a shutter or blind. The UP or DOWN commands are used for this purpose. The process can be interrupted with STOP and continued again with MOVE. For these four commands there is an enum which can be used for the std_msgs/String command field. You must also set the std_msgs/Bool iscommand field to True.
If you want to drive the shutter or blind to a specific position you have to use the std_msgs/Bool ispercentage field to True. The same procedure is used for the percentage value as for the state.
If I would stop moving the shutter or the blind, the current state would also be between 0 and 100. It is important that as long as a shutter or a blind is moving, it still has the state of the command. Only when they stop, they take the percentage value. So with 0 I do the same as with DOWN and with 100 the same as with UP.
String
State
What do you expect with a string item? It stores a string. Nothing more and nothing less. The openhab_msgs/StringState looks like this:
# Stores texts Header header string item # the name of the item string state # string value of the item bool isnull
Surprise, surprise it uses the std_msgs/String for this.
Now we don't want to make the String item smaller and less important as it is. It is actually used very often. An example that I had already mentioned was that a contact item only knows OPEN and CLOSED, but window contacts partly also support the states OPEN, TILTED and CLOSED. A String Item can also be used for the current song title, the current TV station, a used radio or TV stream, the currently running game, any named modes of a device, the title or content of a news feed etc.
If you want to subscribe a String item, you must also use this message type. You can see this accordingly in Writing and examining a Simple Subscriber for the String Item Type (Python) or Writing and examining a Simple Subscriber for the String Item Type (C++).
Commands
The openhab_msgs/StringCommand looks like this:
# Stores texts Header header string item # the name of the item string command # string command for the item bool isnull
But here we have to be careful. Not every device or binding supports a string as a command. Let's take the news feed as an example, otherwise I would have to change the news with it.
Switch
State
The Switch Item is used for anything that needs to be switched ON and OFF. This can be a device, but it can also be an application on a computer or the activation of a mode on the device. In openHAB we use it very often for unbound items. An unbound item or a virtual item is not used by a binding. We often use this to write individual rules that we can then activate or deactivate. The openhab_msgs/SwitchState looks like this:
# Switch Item, used fo anything that needs to be switched ON and OFF # Possible states for Switch string ON=ON string OFF=OFF string state # Switch state enumerated above Header header string item # the name of the item bool isnull
We will use a std_msgs/String message type for the state field because a Switch has only the states ON and OFF which are string constants in openHAB.
If you want to subscribe a Switch item, you must also use this message type. You can see this accordingly in Writing and examining a Simple Subscriber for the Switch Item Type (Python) or Writing and examining a Simple Subscriber for the Switch Item Type (C++).
Commands
The openhab_msgs/SwitchCommand looks like this:
# Switch Item, used fo anything that needs to be switched ON and OFF # Possible commands for Switch string ON=ON string OFF=OFF string command # Switch command enumerated above Header header string item # the name of the item bool isnull
With an ON command I will change the state OFF to ON and with an OFF command I will change the state ON to OFF.
Using the openhab_msgs
Derived from this, the openhab_msgs were created, which can be summarized as follows:
Install the openhab_msgs
In the next step you have to install the openhab_msgs in your catkin workspace:
cd ~/catkin_ws/src git clone --branch <branchname> https://github.com/Michdo93/openhab_msgs cd ~/catkin_ws catkin_make
Please replace <branchname> with your branch, as example kinetic-devel, melodic-devel or noetic-devel.
Explanation
For subscribing from openHAB a State Message Type is used and for publishing to openHAB a Command Message Type is used. For an item type (openHAB), this means that two message types (ROS) are used in this event bus.
Type Name |
State Message Type |
Command Message Type |
Color |
||
Contact |
||
DateTime |
||
Dimmer |
||
Group |
n/a |
|
Image |
||
Location |
||
Number |
||
Player |
||
Rollershutter |
||
String |
||
Switch |
Item Types
To subscribe the items from openHAB or to publish an item including a command to openHAB you need the appropriate message types. These are based on the Item Types and Command Types of openHAB.
The Item type defines what kind of state can be stored in that Item and which commands the Item will accept. Item types are comparable to basic variable data types in programming languages. Each Item type has been optimized for a particular kind of component in your smart home. This optimization is reflected in the data and command types.
Available Item types are:
Item Type |
Description |
Command Types |
Color |
Color information (HSB) |
OnOff, IncreaseDecrease, Percent, HSB |
Contact |
Status of contacts, e.g. door/window contacts. Does not accept commands, only status updates. |
- |
DateTime |
Stores date and time |
- |
Dimmer |
Percentage value for dimmers |
OnOff, IncreaseDecrease, Percent |
Group |
Item to nest other items / collect them in groups |
- |
Image |
Binary data of an image. This means a base64 encoded string |
- |
Location |
GPS coordinates |
Point |
Number |
Values in number format |
Decimal |
Player |
Allows control of players (e.g. audio players) |
PlayPause, NextPrevious, RewindFastforward |
Rollershutter |
Rollershutter Item, typically used for blinds |
UpDown, StopMove, Percent |
String |
Stores texts |
String |
Switch |
Switch Item, used for anything that needs to be switched ON and OFF |
OnOff |
Command Types
In the last step we take a closer look at the Command Types and its Range of Values.
Command Type |
Range of Values |
Decimal |
<int> or <float> |
HSB |
"<hue>,<saturation>,<brightness>" |
IncreaseDecrease |
"INCREASE" or "DECREASE" |
NextPrevious |
"NEXT" or "PREVIOUS" |
OnOff |
"ON" or "OFF" |
OpenClosed |
"OPEN" or "CLOSED" |
!Percent |
0...100 |
PlayPause |
"PLAY" or "PAUSE" |
Point |
"<longitude>,<latitude>,<altitude>" |
RewindFastforward |
"REWIND" or "FASTFORWARD" |
StopMove |
"STOP" or "MOVE" |
String |
<String> |
UpDown |
"UP" or "DOWN" |
A command type like OnOff is ultimately an enum and contains the strings "ON" and "OFF" as constants (this is why they are written in UPPERCASE), so the other enum commands actually look the same. This means that there are only two constants per each enum type.
The Command Types are only used within openHAB. The openhab_msgs also have these enums in their field description, but you may have to work with a string in parts of your program!
The next chapter continues with Examining the openhab_bridge with HABApp (Python) or Examining the openhab_bridge without HABApp (Python) when you are using one of both Python bridges or with Examining the openhab_bridge with C++ (C++) when you are using the C++ bridge.