SimpleBinary Binding - jfederico/openhab GitHub Wiki

Introduction

SimpleBinary is openHAB binding that lest you easily connect small devices like Arduino via serial port. Binding uses own binary protocol which is easy to implement. The protocol is described below. Implementation example for Arduino is part of my repository: https://github.com/docbender/openHAB-SimpleBinary. Latest release can be found also there in release section: https://github.com/docbender/openHAB-SimpleBinary/releases.

It is possible to configure several ports not only one. At one line it is possible to connect several devices (ready for RS422/RS485).

Each port has separated configuration (speed, mode). Communication can operate in 2 data read modes - OnScan and OnChange.

Operating modes

Communication can operate it 2 modes reading data from connected devices - OnScan and OnChange. In OnScan mode all data are reading cyclically. In OnChange mode only new data are sent to openHAB. Each device is polled whether has new data and then sends new data to openHAB.

Supported data types

Binding support openHAB data types listed in the table. Individual item type are converted to simple data types such as byte, word, double word, float, array, rgb. For same types may be converted type defined, others has it strictly defined. Supported data types

Item type Supported data type Notes
Number byte, word, dword, float Numbers are represent in signed form. Their maximum value depends on the used type.
Floating point number is represented by float type. Float is stored in 4 bytes formatted according to IEEE 754.
Color hsb, rgb, rgbw All color parts are transferred in one double word. Each color component corresponds to one byte. Assignment of bytes depending on the chosen data type is following:

HSB - byte 0 - Hue, 1 - Saturation , 2 - Brightness, 3 - Not used
RGB - byte 0 - Red, 1 - Green, 2 - Blue, 3 - Not used
RGBW - byte 0 - Red, 1 - Green, 2 - Blue, 3 - White
String array Array of bytes. Length of array is specified in square brackets behind type definition (e.g. array[32] defines byte array with length 32 bytes)
Contact byte 0 - off, 1 - on
Switch byte 0 - off, 1 - on
Dimmer byte
Rollershutter word Lower byte for position, upper byte for StopMove/UpDown command - 1-Stop,2-Move,4-Up,8-Down

Binding configuration

In openhab.cfg is binding configured this way:

################################### SimpleBinary Binding ######################################
#
# Select port (ex.: COM1:115000;onscan;forceRTSInv or /dev/ttyUSB1:9600). It is possible defined 
# more ports ex. port1, port2,port145,... Behind semicolon you can specify data pool control (optional).    
# Options for reach slave data are onchange(ask configured devices for new data - default) 
# or onscan(read all data every scan). Option forceRTS or forceRTSInv are for trigger RTS signal
# during data send (useful for RS485 converter). 
# 
simplebinary:port=COM4:9600;onchange
#refresh - check for new data interval - default 10000ms 
simplebinary:refresh=2000

Item configuration

Binding specify item configuration is located as usual in the brackets at the end of the configuration line. It consists of three compulsory and two optional parameters.

Configuration format:

simplebinary="port name:device address:item address:[used data type]:[direction]"
Configuration parameter Description
port name Port name that is specified in binding configuration in openhab.cfg. For simplebinary:port= port name is port. For simplebinary:port1= port name is port1.
device address The device address is number that device is indicated on the bus (for RS485)
item address It is the address under which the data is stored in the target device.
used data type Optional. Allow define data type. See table Supported data types
direction Optional. Can be I - input, O - output or IO - both (default). It is used only for request data from connected devices. So if all device items are outputs only, there would be no requesting for data from device.

Example of binding configuration:

Dimmer    Item01    "Value[%d]"    { simplebinary="port:1:1" }
Number    Item02    "Value[%d]"    { simplebinary="port:1:3:dword:IO" }
Number    Item03    "Value[%f]"    { simplebinary="port:1:4:float:O" }
Number    Item04    "Value[%f]"    { simplebinary="port:1:14:float:I" }
String    Item05    "Value[%s]"    { simplebinary="port:2:1:array[32]:O" }
Color     TestColor01              { simplebinary="port:2:2:rgb:O" }

Diagnostic item configuration

Binding itself offers some diagnostic states. There are available statuses for communication port itself and also statuses for connected devices. These statuses can be provided into openHAB if they are properly configured (by use configuration parameter info behind port name or device address).

Port diagnostic info configuration format:

simplebinary="port name:info:port status"

Port statuses:

Status Description Returned values
state Return current port status. 0 - Unknown
1 - Listening (opened and ready)
2 - Closed
3 - Not exist
4 - Not available (probably used)
previous_state Return previous port status Same as state
state_change_time Return time when status was changed DateTime value

Device diagnostic info configuration format:

simplebinary="port name:device address:info:device status"

Device statuses:

Status Description Returned values
state Return current device status. 0 - Unknown
1 - Connected and answering
2 - Not responding
3 - Response error (device still wants repeat query - received message had bad CRC)
4 - Data error (device report unknown item address, unknown data, unsupported message or error while saving delivered data)
previous_state Return previous device status Same as state
state_change_time Return time when status was changed DateTime value
packet_lost Return percentage of packet lost (not delivered, bad CRC, ...) within last 5 minutes 0-100%

Example of diagnostic item configuration:

Number    PortState            "Port state [%s]"                 { simplebinary="port:info:state" }
Number    PortPreviouState     "Port previous state [%s]"        { simplebinary="port:info:previous_state" }
DateTime  PortStateChangeTime  "Port changed [%1$tA, %1$td.%1$tm.%1$tY %1$tT]"    { simplebinary="port:info:state_change_time" }

Number    Dev01State           "Device 1 state [%s]"             { simplebinary="port:1:info:state" }
Number    Dev01PreviouState    "Device 1 previous state [%s]"    { simplebinary="port:1:info:previous_state" }
DateTime  Dev01StateChangeTime "Device 1 changed [%1$tA, %1$td.%1$tm.%1$tY %1$tT]" { simplebinary="port:1:info:state_change_time" }
Number    Dev01PacketLost      "Device 1 packet lost rate [%s]"  { simplebinary="port:1:info:packet_lost" }

Number    Dev02State           "Device 2 state [%s]"             { simplebinary="port:2:info:state" }
Number    Dev02PreviouState    "Device 2 previous state [%s]"    { simplebinary="port:2:info:previous_state" }
DateTime  Dev02StateChangeTime "Device 2 changed [%1$tA, %1$td.%1$tm.%1$tY %1$tT]" { simplebinary="port:2:info:state_change_time" }
Number    Dev02PacketLost      "Device 2 packet lost rate [%s]"  { simplebinary="port:2:info:packet_lost" }

UART setting

Binding sets the serial port speed according to user configuration. Other parameters are set as follows: 8 data bits, 1 stop bit, without parity and without flow control.

Flow control (especially for RS-485 converters) can be provided through RTS pin. This can be turned on by adding forceRTS parameter in binding port configuration. If it is required inverted function of RTS pin, forceRTSInv parameter should be added in configuration instead forceRTS.

Protocol

Binding implements master/slave communication model. OpenHAB binding is master and connected devices are slaves. Master sends command and waits for response from slave. Answer should arrived in order tens of milliseconds. However bindings has 2000ms timeout to receive answer.

Communication protocol itself depends on requested operating mode of the device (OnScan / OnChange). Of course device can support both operating modes.

Every packet start with slave address and is followed by message type. Minimum packet length is 4 bytes. Packets are secured with CRC8 which should be enough for short packets.

###Master query for new data - OnChange mode On this packet master expecting as answer "data" packet or "no data" packet (message type 0xE2).

Byte Value Description
0 0xXX Device slave address
1 0xD0 Message type
2 0xXX Control byte. Supported values:
0 - standard (data check only)
1 - force all data request
3 CRC8
Control byte of this packet can says type of new data retrieve: * _Standard_ (value 0) - only really new data are requested. * _Force all data_ (value 1) - that device should mark all his data as new and send it to master. This message master send when there was connection lost between devices. That because meantime data could be changed, openHAB or device restarted, ....

###Master query for data with specified address - OnScan mode On this packet master expecting as answer "data" packet or "invalid address" packet (message type 0xE4).

Byte Value Description
0 0xXX Device slave address
1 0xD1 Message type
2 0xXX Data address - low byte
3 0xXX Data address - high byte
4 CRC8

###Data packet for data type byte This "data" packet could be send by master to write data into slave or by slave as answer for data request. Answer from slave should "done" when everything was right.

Byte Value Description
0 0xXX Device slave address
1 0xDA Message type
2 0xXX Data address - low byte
3 0xXX Data address - high byte
4 0xXX Data
5 CRC8

###Data packet for data type word This "data" packet could be send by master to write data into slave or by slave as answer for data request. Answer from slave should "done" when everything was right.

Byte Value Description
0 0xXX Device slave address
1 0xDB Message type
2 0xXX Data address - low byte
3 0xXX Data address - high byte
4 0xXX Data - low byte
5 0xXX Data - high byte
6 CRC8

###Data packet for data type dword This "data" packet could be send by master to write data into slave or by slave as answer for data request. Answer from slave should "done" when everything was right.

Byte Value Description
0 0xXX Device slave address
1 0xDC Message type
2 0xXX Data address - low byte
3 0xXX Data address - high byte
4 0xXX Data - 1. byte (lowest)
5 0xXX Data - 2. byte
6 0xXX Data - 3. byte
7 0xXX Data - 4. byte (highest)
8 CRC8

###Data packet for type HSB, RGB, RGBW This "data" packet could be send by master to write data into slave or by slave as answer for data request. Answer from slave should "done" when everything was right.

Byte Value Description
0 0xXX Device slave address
1 0xDD Message type
2 0xXX Data address - low byte
3 0xXX Data address - high byte
4 0xXX Data - 1. byte (lowest)
5 0xXX Data - 2. byte
6 0xXX Data - 3. byte
7 0xXX Data - 4. byte (highest)
8 CRC8

###Data packet for type array This "data" packet could be send by master to write data into slave or by slave as answer for data request. Answer from slave should "done" when everything was right.

Byte Value Description
0 0xXX Device slave address
1 0xDE Message type
2 0xXX Data address - low byte
3 0xXX Data address - high byte
4 0xXX Data length - low byte
5 0xXX Data length - high byte
6 0xXX Data
... 0xXX Data
n-1 CRC8

###Acknowledge packet - Done Answer from slave that data write from master was accepted.

Byte Value Description
0 0xXX Device slave address
1 0xE0 Message type
2 0x00
3 CRC8

###Error packet - Repeat Answer that received packet had wrong CRC. On this packet master react by sending last packet again (max. 3 time).

Byte Value Description
0 0xXX Device slave address
1 0xE1 Message type
2 0xXX Here is expected CRC8 calculated by slave (master logged it for comparison).
3 CRC8

###Acknowledge packet - No new data Slave react with this packet on query for new data in OnChange mode in case that there's no data to send.

Byte Value Description
0 0xXX Device slave address
1 0xE2 Message type
2 0x00
3 CRC8

###Error packet - Unknown data Slave react with this packet if received message had unknown/unsupported type.

Byte Value Description
0 0xXX Device slave address
1 0xE3 Message type
2 0x00
3 CRC8

###Error packet - Unknown address Slave react with this packet if received message had unknown data item address.

Byte Value Description
0 0xXX Device slave address
1 0xE4 Message type
2 0x00
3 CRC8

###Error packet - Error while saving data Slave send this packet when he could not save received data from master.

Byte Value Description
0 0xXX Device slave address
1 0xE5 Message type
2 0x00
3 CRC8

##Implementation The extent of implementation depends on the required features and data types (see chapter Protocol).

At first device should check if message is correctly received (CRC check). Secondly device should check if message is for him by compare message address and his own assigned address. If the address is different device must not respond! Otherwise device must response in corresponding way (see chapter Protocol).

##Implementation example Implementation example for Arduino can be found in repo folder arduino/SimpleBinaryExample.

It consists of two main classes. Class simpleBinary which contains protocol implementation itself and class itemData which provides item data storage and handling with item.


Class simpleBinary - public methods
simpleBinary(int uartAddress, int size)
Constructor.
Parameters: uartAddress - device address at communication line, size - number of exchanged items
void initItem(int idx, int address, itemType type, void (*pFce)(itemData*))
Initilize item.
Parameters: idx - item index in array, address - item address used during communication, type - item data type, last parameter is pointer to function that is executed on data receive(NULL for no action).
void processSerial()
Process data received by UART.
bool checkAddress(int address)
Check if address exist in items array.
Parameters: address - item address used during communication
void readData(int address)
Read data on given address and send it to master.
Parameters: address - item address used during communication
bool saveByte(int address, char* data)
Save byte from given data pointer to addresed item. Return false if target is not expected data type.
Parameters: address - item address used during communication, data - pointer to data to save.
bool saveWord(int address, char* data)
Save word from given data pointer to addresed item. Return false if target is not expected data type.
Parameters: address - item address used during communication, data - pointer to data to save.
bool saveDword(int address, char* data)
Save double word from given data pointer to addresed item. Return false if target is not expected data type.
Parameters: address - item address used during communication, data - pointer to data to save.
bool saveArray(int address, char *pData, int len)
Save byte array from given data pointer to addresed item. Return false if target is not expected data type.
Parameters: address - item address used during communication, pData - pointer to data to save, len - array length (byte count)
int size()
Return items count.
void enableRTS(int pinNumber)
Enable RTS handling. RTS pin is passed as parameter.
void setSendDelay(unsigned int delayms)
Sets delay between receive and transmit message (in ms). Good for communication line stabilization.

Class itemData - public methods
itemData()
Constructor.
itemData(int address, itemType type, void (*pFce)(itemData*) )
Constructor with item initialization .
Parameters: address - item address used during communication, type - item data type, last parameter is pointer to function that is executed on data receive(NULL for no action).
itemData(int address, itemType type, int size, void (*pFce)(itemData*) )
Constructor with item initialization for arrays.
Parameters: address - item address used during communication, type - item data type, size - data size in bytes, last parameter is pointer to function that is executed on data receive(NULL for no action).
void init(int address, itemType type, void (*pFce)(itemData*))
Item initialization .
Parameters: address - item address used during communication, type - item data type, last parameter is pointer to function that is executed on data receive(NULL for no action).
bool saveByte(char* data)
Save byte from given data pointer. Return false if target is not expected data type.
Parameters: data - pointer to data to save.
bool saveWord(char* data)
Save word from given data pointer. Return false if target is not expected data type.
Parameters: data - pointer to data to save.
bool saveDword(char* data)
Save double word from given data pointer. Return false if target is not expected data type.
Parameters: data - pointer to data to save/td>
bool saveArray(char *pData, int len)
Save array from given data pointer. Return false if target is not expected data type.
Parameters: data - pointer to data to save, len - array length (byte count)
void save(int value)
Save int value.
Parameters: value - value to save
void save(float value)
Save float value.
Parameters: value - value to save
int getAddress()
Return item address.
void setNewData()
Set item "new data" flag.
bool hasNewData()
Check if item has "new data" flag set.
char* getData()
Return item data.
char* readNewData()
Return item data and reset "new data" flag.
itemType getType()
Return item data type.
int getDataLength()
Return length of data.
void executeAction()
Execute action connected at item initialization.

###CRC8 calculation implementation

char CRC8::evalCRC(char *data, int length)
{
   int crc = 0;
   int i, j;

   for(j=0; j < length; j++)
   {
      crc ^= (data[j] << 8);
	
      for(i=0;i<8;i++)
      {
         if((crc & 0x8000) != 0)
            crc ^= (0x1070 << 3);
	
         crc <<= 1;
      }
   }	
   return (char)(crc >> 8);
}
⚠️ **GitHub.com Fallback** ⚠️