I would like to connect several PMS5003 units to OpenHAB via serial. The devices measures PM1.0, PM2.5 and PM10 dust concentration in the air. The data is spit out of the serial port at 9600 baud with 32 byte frame that starts with 0X42 0C4d. The data I care about is broken up in high eight bits and low eight bits. So as an example:
Start Character 1 0x42(fixed bit)
Start Character 2 0x4d(fixed bit)
Frame Length 16-byte Frame Length = 2*9+2 (data+check bit)
Data 1, 16-byte concentration of PM1.0, ug/m3
Data 2, 16-byte concentration of PM2.5, ug/m3
Data 3, 16-byte concentration of PM10.0, ug/m3
Data 4, 16-byte Internal test data
Data 5, 16-byte Internal test data
Data 6, 16-byte Internal test data
Data 7, 16-byte the number of particulate of diameter above 0.3um in 0.1 liters of air
Data 8, 16-byte the number of particulate of diameter above 0.5um in 0.1 liters of air
Data 9, 16-byte the number of particulate of diameter above 1.0um in 0.1 liters of air
Data 10, 16-byte the number of particulate of diameter above 2.5um in 0.1 liters of air
Data 11, 16-byte the number of particulate of diameter above 5.0um in 0.1 liters of air
Data 12, 16-byte the number of particulate of diameter above 10.0um in 0.1 liters of air
Data 13, 16-byte Internal test data
Check Bit for Data Sum, 16-byte
Is it possible with OpenHAB to make an item for Data 1, Data 2, and Data 3, each made up of a the two 8 bits from the serial stream such as:
I personally havenât done much with Serial devices on OH, but maybe these links would help. My thought would be to use a regex in the serial binding config to extract the values you are afterâŚ
The serial binding receives the data as a String. And given this is a pretty specific binary encoded message I think your best bet will be to create one Item to receive the messages from your devices and a rule to pick out the values and apply them to your Items.
2016-04-05 08:19:16.335 [INFO ] [runtime.busevents ] - Air_Quality state updated to Qk0AHAABAAEAAwABAAEAAwR6AO+/vQAQAAIAAgAAcQACSA==
2016-04-05 08:19:16.336 [INFO ] [g.openhab.model.script.Testing] - Air Quality: [B@2a4a201
I also tried:
var String air = new DatatypeConverter::parseBase64Binary(Air_Quality.state.toString)
loginfo("testing", "Air Quality: " + air)
And got:
2016-04-05 08:30:35.294 [INFO ] [runtime.busevents ] - Air_Quality state updated to Qk0AHAABAAEAAQABAAEAAQTvv70AfAALAAAAAAAAcQACPA==
2016-04-05 08:30:35.405 [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule 'Testing': The name 'parseBase64Binary(<XMemberFeatureCallImplCustom>)' cannot be resolved to an item or type.
getBytes returns an array of byte primitives so what you are seeing when you print it is the memory address of the start of that array. You probably want something along the lines of:
val StringBuilder bts = new StringBuilder
bts.append("Air Quality:")
Air_Quality.state.toString.getBytes.forEach[b | bts.append(Integer.toHexString(b)]
logInfo("Testing", bts.toString)
Neither Java nor the Rules DSL makes dealing with raw binary data obvious nor easy.
Usual disclaimer, I just typed in the above, there may be typos.
2016-04-05 10:16:01.631 [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule âTestingâ: The name âIntegerâ cannot be resolved to an item or type.
Actually, this may be what I want, how do I access that array and pull two 1 byte values and then combine them in a 16 bit number? As an example if byte 1 is 42 and byte 2 is 4d I have valid data. I then need to update item1 with 5th and 6th bytes and item 2 with 7th and 8th bytes and so on. The first byte is the high eight bits and the 2nd byte is the low eight bits.
val ByteBuffer bb = ByteBuffer::wrap(Air_Quality.state.toString.getBytes)
bb.order(ByteOrder.LITTLE_ENDIAN)
val short first = bb.getShort
logInfo("Testing", "1st Bytes: " + first)
val short second = bb.getShort
logInfo("Testing", "2nd Bytes: " + second)
It does not like the ByteOrder:
2016-04-05 13:04:58.726 [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule 'Testing': The name 'ByteOrder' cannot be resolved to an item or type.
If I take that out I get my two vars, but they donât look right (I am not 100% tho). I also want to run DatatypeConverter::parseBase64Binary on it. How can I do that as part of this code?
But unless you know that the incoming data is indeed Base-64 encoded (from your description and example I would say the answer is ânoâ) it is not going to do much for you. âďż˝u qďż˝â is not a Base-64 encoded string. There are no special characters in Base-64, only "0-1, a-z, A-Z, and â+â and â/â are valid characters in a Base-64 encoded string.
Ya, I figured that part out, I have import java.nio.*, but its still giving me:
2016-04-05 14:14:53.534 [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule 'Testing': The name 'ByteOrder' cannot be resolved to an item or type.
Code so far:
DatatypeConverter::parseBase64Binary(Air_Quality.state.toString)
val ByteBuffer bb = ByteBuffer::wrap(Air_Quality.state.toString.getBytes)
bb.order(ByteOrder.LITTLE_ENDIAN)
val short first = bb.getShort
logInfo("Testing", "1st Bytes: " + first)
val short second = bb.getShort
logInfo("Testing", "2nd Bytes: " + second)
val short third = bb.getShort
logInfo("Testing", "3rd Bytes: " + third)
val short forth = bb.getShort
logInfo("Testing", "4th Bytes: " + forth)
val short fith = bb.getShort
P.S. Your right on Base64, I am changing the item tho to BASE64 so I donât get junk in my log.
Try ByteOrder::LITTLE_ENDIAN or java.nio.ByteOrder::LITTLE_ENDIAN. Reference to something that is static needs to use â::â instead of â.â.
Though I looked it up and âfirst byte is the high eight bits and second byte the low eight bitsâ is big endian which is the default so you probably donât need it anyway.
2016-04-05 16:57:44.861 [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule 'Testing': The name 'potUpdate(<XFeatureCallImplCustom>,<XMemberFeatureCallImplCustom>)' cannot be resolved to an item or type.
Then tried to just use pm1 var:
val short pm1 = bb.getShort
logInfo("Testing", "PM 1.0 : " + pm1)
potUpdate(Outside_PM1, pm1)