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"
when
Item GasTank received update //changed
then
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")
}
end
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