[SOLVED] Rs485 to MQTT gateway?

One possibility is to use new tranformation service available in 2.5 called Binary To JSON Transformation Service. This service can be used to transform binary data to json format. Then you can use e.g json path tranformation to extract different information to items.

The output of getBytes() is some kind of java array we don’t often use in rules.
I think maybe you get a member with
bytesarray.get(7)

EDIT - this should do the un-signing part. It looks like you don’t expect byte values above 127 and so not risking misinterpreting as negative values, but it might be smart to avoid surprises.
bytesarray.get(5).bitwiseAnd(255).
On the other hand … what happen with a negative temperature? Maybe you do need to take account of negatives. You need a sample of how they get encoded really.

When you get a byte that way, it might be a primitive integer and not have a .toString method. You may have to parse it into something more amenable.

Maybe a java programmer can suggest a neat method here.

Okay have made a bit more progress on this…

Logging output…
2019-07-01_122623

Saving a few values to Items and then showing them in Grafana…

1 Like

Argh!!! SD Card Corruption… Just what I need…
Last SD card image was a month ago :frowning:

1 Like

Okay got my config files off the corrupt card so have everything up and running again at least!

I just can’t get the USB Serial convertor to update my item anymore :frowning:

I’ve rebooted several time etc but just nothing seems to be coming in on the serial port…

Most likely something to do with port enumeration or permissions, after a rebuild

Okay, so I have taken a different approach and am using an ESP8266 running Tasmota which is picking up the data being put out by the fan and sending it as an MQTT topic. The payload looks like this…

2019-11-07_224711

I am using a rule strip off the extra stuff that Tasmota is adding and then running it though the rule I had.
It so almost works!!!

It appears that if one of the values is a 0 then I’m losing data when it converts to Decimal Bytes.
You can see it here when the temperature hits a whole number moving from 24.9 to 25.0

2019-11-07_224919

This dropping off of the zero breaks my rule now because I’m trying to grab the wrong segments as some have been dropped off.

Does anyone have any initial ideas on how to stop it dropping off the zeros?
Here is my rule for reminder.

rule "Ventillation Fan Serial"
when
   Item VentillationSerial changed
then
   val ReplaceTest = triggeringItem.state.toString().replace(',"SSerialReceived":"', '').replace('"}', '')
   VentillationSerial1.postUpdate(ReplaceTest)
   
   var bytesarray = VentillationSerial1.state.toString.getBytes()
   val StringBuilder decdisplay = new StringBuilder
   bytesarray.forEach[b |
      var int x = b.intValue.bitwiseAnd(255) // this converts -128 to 127 to 0 to 255
      decdisplay.append(Integer::toString(x) + " ")
      ]
   logInfo("Serial test", "decimal bytes " + decdisplay)
   logInfo("Serial test", "Fan Speed " + bytesarray.get(1).toString + "%")
   logInfo("Serial test", "Fan Phase " + bytesarray.get(3).toString + " : 1=STARTUP, 2=ADJUST, 3=SLOWDOWN")
   logInfo("Serial test", "Fan Temp " + bytesarray.get(5).toString + "." + bytesarray.get(6).toString)
   logInfo("Serial test", "Fan Humidity " + bytesarray.get(8).toString + "%")
   logInfo("Serial test", "Fan Mode " + bytesarray.get(10).toString + " : 0=OFF, 1=LOW, 2=MED, 3=HIGH, 4=LL and 5=TEST")
   logInfo("Serial test", "Fan Summer Mode " + bytesarray.get(12).toString + " : 0=OFF, 1=ON")
   logInfo("Serial test", "-------------------------------------------------------------------------------------------------------------------")

   VentillationSpeed.postUpdate(bytesarray.get(1).toString)
   VentillationTemp.postUpdate(bytesarray.get(5).toString + "." + bytesarray.get(6).toString)
   VentillationHumid.postUpdate(bytesarray.get(8).toString)
   VentillationMode.postUpdate(bytesarray.get(10).toString)
end

You need to determine your source data. I’m guessing the root of this issue is the bonkers serial encoding system.

Can you reinstate whatever you did to get raw bytes?

Let us first make sure that your problem revolves around getting a character x00 rather than your fan not sending it.
Sending x00 is a bit fraught because in ASCII it is a NUL character and likely to get lost in string handling. That also makes it difficult to report in logs etc.

How is your VentillationSerial Item populated? I fear you are hiding a script here

I’m using pretty much the same rule as before except the serial data is being posted to a MQTT topic by an ESP8266 using the Tasmota firmware.

The VentillationSerial string item is just being updated by an MQTT topic.

String VentillationSerial "Fan Serial"	{mqtt="<[openhabianpi:tele/FanController/RESULT:state:default]"}

So hopefully I’m not losing the x00 somewhere in the MQTT side of things?

This is what I see in MQTT Explorer…

2019-11-08_181308

Okay, that is a pretty important detail.

You’re posting raw serial data via MQTT, which can include x00 bytes - that is to say, nul ASCII characters?
I’m not surprised it gets lost. MQTT isn’t set up as a binary data transport, which is what you’d want.

You should check the value is not arriving at your OH Item - so far as I can see, it doesn’t, but you understand the parts better than I.

You might need to look into Tasmota, see if it offers any data encoding options for binary data. Example, ASCII encoding would send each byte as two string characters x21 x00 -> "2" "1" "0" "0"

Okay thanks… I think Tasmota has some type of rules concept so I’ll investigate from that perspective…

I’ll follow this. This is getting very interesting.
What kind of fan is it?

There is a small company here in New Zealand that does home ventillation systems that have some software on their main board to try and regulate the speed and flow…

I got chatting to the owner and they put in a custom firmware for me so that it spits out all the metrics like speed, temp, humidity etc…

They did me a favour so I didn’t want to hassle them about the format of the output :slight_smile:

Cool, thanks

Okay a small change in Tasmota and now the serial data is coming through as this…

“SSerialReceived”:“531D5002541900483A56014D00”

The whole concept of Hex and Binary still confuses me but this looks a little different to what I was previously getting but might be usable?

Some trial and error leads me to these are the conversions I need to make…

53 = S (Hex to ASCII)
1D = 29 (Hex to Decimal)
50 = P (Hex to ASCII)
02 = 2 (Hex to Decimal)
54 = T (Hex to ASCII)
19 = 25 (Hex to Decimal)
00 = 0 (Hex to Decimal)
48 = H (Hex to ASCII)
3A = 58 (Hex to Decimal)
56 = V (Hex to ASCII)
01 = 1 (Hex to Decimal)
4D = M (Hex to ASCII)
00 = 0 (Hex to Decimal)

So the second HEX value in the string being 1D is actually the fan speed in percent…

Aarghhh…
Nice little coding challenge and I am stuck at a dinner party I do not want to be at.
@TommySharp, have fun!

Alright slow progress… I have broken up the received string into separate pieces so for starters I have the fan speed in a string variable like this…

var HEXSpeedPercent = ReplaceString.substring(2,4)

The value is actuall “1D” which I need to convert from HEX to Decimal which would give me the number 29…

Any clues while I keep digging through forums :slight_smile:

Try this:

var HEXSpeedPercent = ReplaceString.substring(2,4)
var Number SpeedPercent = Integer::parseInt(HEXSpeedPercent, 16)

NICE!!! I get this in my log output so I think I can see the light at the end of the tunnel!!!

Speed HEX 1D converts to 29
1 Like

Alright, happy the x00 values are now getting smuggled through the communications chain.

Yes. You’ve got e.g. byte hex 29 coming as a two-character encoded string now “2” + “9” etc.
There might be some nifty way to reconstitute the whole string back into binary bytes, but you needn’t bother. The fixed string format needs you only need to pick out your two-character pairs by position and parse (the magic word) as hex into numeric.

I think this would do
val Number myNumeric = Integer::parseInt( your2charSubstring , 16 )
The 16 should tell parser to expect hex.chars like "1D"

You’ll have to build your decimal temperature from getting two integers as above, then something like
val Number mytemp = tempfirst + (tempsecond / 10).floatValue
I think you need to do something with float like that when dividing integers.