Accessing Davis weatherstation with Serial binding in openHAB3

Hi,

as there is no port of the Davis binding to OpenHAB 3, i made an alternative solution using the serial binding and rules. It is so far able to extract data from the two main messages sent by Davis Vantgae Pro2, but it should not be to hard to extend or adapt to other versions of Davis weatherstations. This solution uses the text file configuration approach, see below.
Have fun!

davis.things

Bridge serial:serialBridge:davis [serialPort = "/dev/ttyUSB.davis", baudRate = 19200, charset = "ISO-8859-1"]

davis.items

Group gDavis

String Davis_rawString {channel="serial:serialBridge:davis:string"}
String Davis_rawBinary {channel="serial:serialBridge:davis:binary"}
String Davis_rawDataTrigger {channel="serial:serialBridge:davis:data"}

//LOOP msg
Number Davis_Barometer                          "Barometer [%.0f hPa]"                      <pressure>      (gDavis)
Number Davis_InsideTemp                         "Dachboden Wetterstation [%.1f °C]"         <temperature>   (gDavis)     
Number Davis_InsideHum                          "Dachboden Wetterstation [%.0f %% ]"        <humidity>      (gDavis)     
Number Davis_OutsideTemp                        "Outside Temp [%.1f °C]"                    <temperature>   (gDavis,TemperatureOutside)   
Number Davis_WindSpeed                          "Wind Speed [%.1f km/h]"                    <wind>          (gDavis)     
Number Davis_WindSpeed10minAvg                  "Wind Speed 10min Avg [%.1f km/h]"          <wind>          (gDavis)  
Number Davis_WindDirection                      "Wind Richtung [%.0f °]"                    <wind>          (gDavis)  
Number Davis_OutsideHum                         "Outside Hum [%.0f %% ]"                    <humidity>      (gDavis)  
Number Davis_RainRate                           "Rain Rate [%.1f mm/h ]"                    <rain>          (gDavis)     
Number Davis_UVIndex                            "UV Index [%.1f ]"                          <sun>           (gDavis)  
Number Davis_Solar                              "Solar Radiation [%.0f W/m²]"               <sun>           (gDavis)  
Number Davis_TransmitterBattery                 "Transmitter Battery [%.1f]"                <energy>        (gDavis)     
Number Davis_ConsoleBatteryVoltage              "Console Battery [%.2f V]"                  <energy>        (gDavis)     

//LOOP2 msg
//some are already included in LOOP
Number Davis_WindSpeed10minHiRes                "Wind Speed 10min Avg HiRes [%.2f km/h]"    <wind>          (gDavis) 
Number Davis_WindSpeed2minHiRes                 "Wind Speed 2min Avg HiRes [%.2f km/h]"     <wind>          (gDavis) 
Number Davis_WindSpeed10minGustHiRes    		"Wind Speed 10min BöeHiRes [%.2f km/h]"     <wind>          (gDavis) 
Number Davis_WindDirectionGust                  "Wind Richtung Böen [%.0f °]"               <wind>          (gDavis) 
Number Davis_DewPoint                           "Dew Point [%.1f °C]"                       <temperature>   (gDavis)     
Number Davis_Rain15min                          "Rain Rate 15min [%.1f mm/h ]"              <rain>          (gDavis)    
Number Davis_Rainlast1h                         "Rain Rate 1h [%.1f mm/h ]"                 <rain>          (gDavis)     
Number Davis_Rainlast24h                        "Rain Rate 24h [%.1f mm/h ]"                <rain>          (gDavis)     

davis.rules

import java.nio.ByteBuffer
import java.nio.ByteOrder

var String packetFormat = ""
var String responseType
var String responseLimiterType
var int responseLen 
var String crcType
var int loopType = 1

val publishValue = [
	NumberItem trgtItem,Number newVal,Number minVal,Number maxVal |
        if (newVal >= minVal && newVal <= maxVal) {
            trgtItem.postUpdate(newVal)
        }
		true
]

rule "Send Davis Cmd"
when
	Time cron "5/10 * * * * ? *"
then
    if (packetFormat == "") {
        sendCommand(Davis_rawString,"LPS "+loopType+" 1\n")
        packetFormat = "LOOP"    
        responseType = "ACK"
        responseLimiterType = "FIXED_SIZE"
        responseLen = 99
        crcType = "VAR1"
        if (loopType==2) {
            loopType = 1
        } else {
            loopType = 2
        }
    } else {
        logWarn("Davis", "skipping sending LOOP2 command due to late response")
        packetFormat = ""
    }
end

rule "Davis bin data received"
when
	Item Davis_rawBinary received update 
then
    //logInfo("Davis", "binary data received!! " + Davis_rawBinary)

    var byte[] byteArray = RawType.valueOf(Davis_rawBinary.state.toString()).getBytes()         
    var ByteBuffer data = ByteBuffer.wrap(byteArray).order(ByteOrder.LITTLE_ENDIAN)
    var offset = 0

    if (packetFormat == "") {
        logWarn("Davis", "recevied without prior sending command") 
        return;
    }

    switch responseType {
        case "ACK": {
            offset = 1
        }
        case "OK": {
            offset = 6
        }
    }

    switch responseLimiterType {
        case "FIXED_SIZE": {
            if (byteArray.length - offset == responseLen) {
                //logInfo("Davis", "response length as expected") 
            } else {
                logWarn("Davis", "wrong response length: "+byteArray.length) 
                packetFormat = ""              
            }
        }
        case "CRLF": {
            if (data.get(byteArray.length-2) == '\n' && data.get(byteArray.length-1) == '\r') {
                //logInfo("Davis", "response end as expected")
            } else {
                logWarn("Davis", "wrong response end (no CRLF), length: "+byteArray.length)
                packetFormat = ""                 
            }
        }
    }

/*
    if (crcType == "VAR1") {
        //TODO migrate CRC16 to rule using lamba expressions, check if possible
        if (CRC16.check(responseBlock, offset, responseBlock.length - offset)) {
            //CRC ok
        } else {
            //CRC faulty
        }
    } 
*/

    if (packetFormat=="LOOP") {
        if ((data.get(offset+0) == 0x4C) && (data.get(offset+1) == 0x4F) && (data.get(offset+2) == 0x4F)) {
            if (data.get(offset+4) == 0x00) {
                publishValue.apply(Davis_Barometer,(data.getShort(offset+7) * 0.0338638),700,1300)
                publishValue.apply(Davis_InsideTemp,((data.getShort(offset+9) * 0.1 - 32) * 5 / 9.0),0,40)
                publishValue.apply(Davis_InsideHum,(data.get(offset+11) * 1.0),0,100)
                publishValue.apply(Davis_OutsideTemp,((data.getShort(offset+12) * 0.1 - 32) * 5 / 9.0),-40,85)
                publishValue.apply(Davis_WindSpeed,(data.get(offset+14) * 1.609344),0,200)
                publishValue.apply(Davis_WindSpeed10minAvg,(data.get(offset+15) * 1.609344),0,200)
                publishValue.apply(Davis_WindDirection,(data.getShort(offset+16) * 0.1),0,360)
                publishValue.apply(Davis_OutsideHum,(data.get(offset+33) * 1.0),0,100)
                publishValue.apply(Davis_RainRate,(data.getShort(offset+41) * 0.2),0,1000)
                publishValue.apply(Davis_UVIndex,(data.get(offset+43) * 0.1),0,10)
                publishValue.apply(Davis_Solar,(data.getShort(offset+44) * 1.0),0,1500)
                publishValue.apply(Davis_TransmitterBattery,(data.get(offset+86) * 1.0),0,1)
                publishValue.apply(Davis_ConsoleBatteryVoltage,(data.getShort(offset+87) * 0.00585937),0,10)
                logInfo("Davis", "LOOP decoded!!")
            } else if (data.get(offset+4) == 0x01) {       
                publishValue.apply(Davis_Barometer,(data.getShort(offset+7) * 0.0338638),700,1300)        
                publishValue.apply(Davis_InsideTemp,((data.getShort(offset+9) * 0.1 - 32) * 5 / 9.0),0,40)
                publishValue.apply(Davis_InsideHum,(data.get(offset+11) * 1.0),0,100)
                publishValue.apply(Davis_OutsideTemp,((data.getShort(offset+12) * 0.1 - 32) * 5 / 9.0),-40,85)
                publishValue.apply(Davis_WindSpeed,(data.get(offset+14) * 1.609344),0,200)
                publishValue.apply(Davis_WindDirection,(data.getShort(offset+16) * 0.1),0,360)
                publishValue.apply(Davis_WindSpeed10minHiRes,(data.getShort(offset+18) * 0.1609344),0,200)
                publishValue.apply(Davis_WindSpeed2minHiRes,(data.getShort(offset+20) * 0.1609344),0,200)
                publishValue.apply(Davis_WindSpeed10minGustHiRes,(data.getShort(offset+22) * 0.1609344),0,200)
                publishValue.apply(Davis_WindDirectionGust,(data.getShort(offset+24) * 0.1),0,360)
                publishValue.apply(Davis_DewPoint,((data.getShort(offset+30) - 32) * 5 / 9.0),-40,85)
                publishValue.apply(Davis_OutsideHum,(data.get(offset+33) * 1.0),0,100)
                publishValue.apply(Davis_RainRate,(data.getShort(offset+41) * 0.2),0,1000)
                publishValue.apply(Davis_Rain15min,(data.getShort(offset+52) * 0.2),0,1000)
                publishValue.apply(Davis_Rainlast1h,(data.getShort(offset+54) * 0.2),0,1000)
                publishValue.apply(Davis_Rainlast24h,(data.getShort(offset+58) * 0.2),0,1000)
                logInfo("Davis", "LOOP2 decoded!!") 
            } else {
                logWarn("Davis", "Invalid LOOP packet("+Integer::toHexString(data.get(offset+4))+")!")
            }
        } else {
            logWarn("Davis", "Unexpected packet(0x"+Integer::toHexString(data.get(offset+0))+" 0x"+Integer::toHexString(data.get(offset+1))+" 0x"+Integer::toHexString(data.get(offset+2))+"), LOOP expected!")
        }       
    } else {
        logWarn("Davis", "Unexpected packet!")
    }
    packetFormat = ""
end
1 Like

Welcome to the openHAB community!

Thanks for contributing a solution. I’d suggest changing your title to be something like “Accessing Davis weatherstation with Serial binding in openHAB 3”, so that it’s a little closer to what you describe.

You might also want to provide a little more guidance on the items and what your rules are doing. It’s tricky right now since we’re kind of between folks using text configuration (which I’m also still doing) and folks who only know UI configuration. I’m not saying you have to duplicate everything in the UI, though. We can only do so much as volunteers.

Cheers!

Hi, changed the title according to your proposal und added info about the text configuration.

1 Like