Connect LPG gas tank level meter GOK IAF70 as item

Monitoring the filling level of LPG gas tanks is essential when using this energy for home heating. The idea was to connect the remote level meter IAF70 (built by GOK) to OpenHAB and display it on HABPanel.
The sensor pickup of the IAF70 communicates with the display unit via serial interface. (TTL level, 1200Baud). The data telegram being sent starts with a sync byte (55h) followed by sensor address and level reading. Address and level bytes are sent twice to allow detection of transmission problems. The reading range is 1 to 99 percent. Due to operating in EX environment, the circuitry has to be intrinsically safe.

Glue logic:
Adapt the IAF signal, shape it and feed it to the RxD input of Raspberry Pi

Thing definition:

/Heating system

String GasTank "Fuellstand [%s]" { serial="/dev/ttyAMA0@1200,CHARSET(ISO-8859-1),BASE64"}
Number LPG_fill "Gastank [%d %%]" <batterylevel> (gHeating) 

Rule to convert reading:

rule "adjust Gastank reading"
    Item GasTank received update //changed 
    var boolean logging = false // enable / disable logging
    if (logging) {logInfo("rule adjust Gastank reading", "fired")}
    var List<String> FA70 = new ArrayList(5)

    // convert BASE64 reading to a usable string of hex values
    val char[] hexArray = "0123456789ABCDEF".toCharArray()
    val byte[] bytes = DatatypeConverter::parseBase64Binary(GasTank.state.toString())
    val char[] hexChars = newCharArrayOfSize(bytes.length() * 2)
    for ( var j = 0; j < bytes.length(); j++ ) {
        var int v = bytes.get(j).bitwiseAnd(0xFF)
        hexChars.set(j * 2,  hexArray.get(v >>> 4))
        hexChars.set(j * 2 + 1,  hexArray.get(v.bitwiseAnd(0x0F)))
    val outString = new String(hexChars)
    if (logging) {logInfo("rule adjust Gastank reading", "FA70 serial string: " + outString)}

    //split outstring to get array of hex bytes
    for (String readings : outString.split("(?<=\\G..)")) {
        FA70.add (readings)
    if (logging) {logInfo("rule adjust Gastank reading", "FA70 size: " + FA70.size() + "bytes,  FA70 values: " + FA70 )}

    // perform plausibility check
    if( (FA70.size() == 5)                      // we expect 5 bytes
            && (FA70.get(0) == "55")            // start byte
            && (FA70.get(1) == FA70.get(2))     // address sent twice
            &&  (FA70.get(3) == FA70.get(4)))   // reading sent twice 
            // yes, we did it
            if (logging) {logInfo("rule adjust Gastank reading", "FA70 valid reading, shows " + FA70.get(4) +"%")}
            LPG_fill.sendCommand(new PercentType(Integer.parseInt(FA70.get(4))))
        } else {
           // oops
           logInfo("rule adjust Gastank reading", "FA70 reading: plausibility check failed")

Saving the readings:
The local NAS is hosting a MariaDB instance accessible by jdbc

    // persist gas tank reading on change
    LPG_fill : strategy = everyChange

Works for me :slight_smile:

Since this uses the 1.x Serial binding this example won’t run in OH 3 which is worth mentioning. This should be implementable using the new Serial Binding potentially with a simpler Rule.

Beyond that I’ve moved it to the tutorials and solutions section where it can be more easily found.

Thanks for posting!