[RE-RELEASE] EcoWitt and Wittboy Weather Stations And Sensors (Local)

The port is one that the HE hub is setup to listen on, that is what dictates the setting we need to use on the EcoWitt setup. From what @bertabcd1234 explained, the HE platform looks at the data coming in on that port, reads the Mac/IP and forwards that on to a device with either of those details as the devices Device Network Identifier (DNI), calling a parse() method in the devices driver.

3 Likes

hard to believe but there doesnt seem to be a function in hubitat to resolve an ip address from a hostname, and it throws an error trying to import java.net.InetAddress

Maybe @thebearmay might have some thoughts on this.....?

1 Like

Threw this together a while back:

https://raw.githubusercontent.com/thebearmay/hubitat/main/nslookup.groovy

Command is nslookup(String lookupName, Optional String dnsServer)

There are at least 3 variations of returns and parameters depending on the DNS server you choose so I went with Google’s variation. dnsServer will default to 8.8.8.8 if you don’t override, but if you’re running a local DNS it gives you an option.

3 Likes

thanks integrated and written into the fx ... now testing the changes but think it is done will post later if passes muster.

2 Likes

ok working.. code changes:

1. new attribute

attribute "status", "string"; // Display current driver status
attribute "lastUpdate", "string";
attribute "dynamicIPResult","STRING"
}

2. new include

// Preferences ----------------------------------------------------------------------------------------------------------------

import groovy.json.JsonSlurper;

private String gatewayMacAddress() {
//

3. new parameters

preferences {
input(name: "macAddress", type: "string", title: "MAC / IP Address", description: "Wi-Fi gateway MAC or IP address", defaultValue: "", required: true);
input(name: "DDNSName", type: "text", title: "Dynamic DNS Name to use to resolve a changing ip address. Leave Blank if not used.", description: "Enter DDNS Name", required: false)
input(name: "DDNSRefreshTime", type: "number", title: "How often (in Hours) to check/resolve the DDNS Name to discover an IP address change on a remote weather station? (Range 1 - 720, Default 24)?", range: "1..720", defaultValue: 3, required: false)
input(name: "bundleSensors", type: "bool", title: "Compound Outdoor Sensors", description: "Combine sensors in a virtual PWS array", defaultValue: true);
input(name: "unitSystem", type: "enum", title: "System of Measurement", description: "Unit system all values are converted to", options: [0:"Imperial", 1:"Metric"], multiple: false, defaultValue: 0, required: true);
input(name: "logLevel", type: "enum", title: "Log Verbosity", description: "Default: 'Debug' for 30 min and 'Info' thereafter", options: [0:"Error", 1:"Warning", 2:"Info", 3:"Debug", 4:"Trace"], multiple: false, defaultValue: 3, required: true);
}

4. function changes

def nsCallback(resp, data)
{
logDebug("in callback")

// test change

def jSlurp = new JsonSlurper()
Map ipData = (Map)jSlurp.parseText((String)resp.data)
def String newIP = ipData.Answer.data[0]
sendEvent(name:"dynamicIPResult", value:ipData.Answer.data[0])

// now compare ip to our own and if different reset and log
if ((newIP != null) && (newIP != ""))
{
    def String currentIP = settings.macAddress
    logInfo("Comparing resolved IP: $newIP to $currentIP")
    
    if (currentIP != newIP)
    {
        logInfo("IP address has Changed !!! Resetting DNI !")
         Map dni = dniIsValid(newIP);
         // Update Device Network ID
        logDebug("got back dni = $dni")
        if (dni) 
        { 
        device.updateSetting("macAddress", [type: "string", value: dni.canonical]);
        dniUpdate();
        resyncSensors();
        }
    }
       
}

}

void DNSCheckCallback()
{
logInfo("Dns Update Check Callback Startup")
updated()
}

void updated() {
//
// Called everytime the user saves the driver preferences
//
try {
logDebug("updated()");

// Clear previous states
state.clear();

// Unschedule possible previous runIn() calls
unschedule();

 // lgk if ddns name resolve this first and do ip check before dniupdatE.. ALSO schedule the re-check.
 def String ddnsname = settings.DDNSName
 def Number ddnsupdatetime = settings.DDNSRefreshTime
                                      
 logDebug("DDNS Name = $ddnsname")
 logDebug("DDNS Refresh Time = $ddnsupdatetime")
                                      
 if ((ddnsname != null) && (ddnsname != ""))
   {
       logDebug("Got ddns name $ddnsname")
       // now resolve

 Map params = [
    uri: "https://8.8.8.8/resolve?name=$ddnsname&type=A",
    contentType: "text/plain",
    timeout: 20
]

logDebug("calling dns Update url = $params")
asynchttpGet("nsCallback", params)

}
// now schedule next run of update
if ((ddnsupdatetime != null) && (ddnsupdatetime != 00))
{
def thesecs = ddnsupdatetime * 3600
logInfo("Rescheduling IP Address Check to run again in $thesecs seconds.")
runIn(thesecs, "DNSCheckCallback");
}

// Update Device Network ID
String error = dniUpdate();
if (error == null) {
  // The gateway dni hasn't changed: we set OK only if a resync sensors is not pending
  if (device.getDataValue("sensorResync")) ztatus("Sensor sync pending", "blue");
  else ztatus("OK", "green");
}
else if (error != "") ztatus(error, "red");
else resyncSensors();

// Update driver version now and every Sunday @ 2am

// versionUpdate();
// schedule("0 0 2 ? * 1 *", versionUpdate);

// Turn off debug log in 30 minutes
if (logGetLevel() > 2) runIn(1800, logDebugOff);
    
// lgk get rid of now unused time attribute
 device.deleteCurrentState("time")   

}
catch (Exception e) {
logError("Exception in updated(): ${e}");
}
}

my version in its entirety

https://raw.githubusercontent.com/lgkahn/hubitat/master/ecowittgateway.groovy


3 Likes

Am I correct in thinking the port definition of 39501 on the Ecowitt is for the Ecowitt and NOT for the Hubitat, yes? Hubitat is monitoring the IP/MAC and doesn't care what the port is.

If that's not the case where is 39501 being defined in Hubitat?

No, Hubitat is only listening for unsolicited inbound traffic on port 39501 (at least at the "automatic" level; an app can define an OAuth endpoint on the regular HTTP or HTTPS ports to listen for whatever it wants as well, but this is a way to handle traffic on a device/driver directly without an app in between--which I guess is the other way you could handle something like this).

Thanks for the quick response! So it seems like me finding 39501 somewhere in some driver code isn't going to happen, is that correct (or am I just missing it) ?

Right, the port is handled at the Hubitat platform level. You could use an app instead of a driver, but then you're stuck with a similar port isssue (just different ports), so I'm not sure there's much benefit.

1 Like

lastUpdate change has been made, replacing the time attribute. Thanks again for your help with this @kahn-hubitat. I did choose a slightly different date format of yyyy-MM-dd.

2 Likes

Released another update today incorporating the Dynamic DNS lookup @kahn-hubitat tested, utilising code from @thebearmay.

I can't really test this change myself, but am comfortable with the code and the fact it has been tested successfully in a modified version of the driver.

3 Likes

Should we call that the down-under format? :wink:

Thanks for the updates (to you, @sburke781, and to @kahn-hubitat, and @thebearmay).

My station is working/reporting great through Ecowitt. The Google Home integration is lacking, unfortunately. I can't get it to give me a simple current weather report or forecast, Seems I can only get a full report of all sensors when I'd just like a summary ("x temperature, partly cloudy" or similar).

1 Like

Can someone remind me - I remember there was a limit to the number of certain types of sensors I can add to the gateway.

Can I add multiple WH32 sensors? I have one currently, would like to add a couple more. Would they go in this section?

Additional/optional sensors:
• *One WH32 outdoor temperature and humidity sensor
• One WH40 self-emptying rain gauge sensor
• One WS68 wireless anemometer
• Up to 8 WH31 multi-channel temperature and humidity sensors or 8 WN30 multichannel temp sensors
• Up to 8 WH51 soil moisture sensors
• Up to 4 WH41/WH43 PM2.5 air quality sensors
• One WH45 PM2.5/PM10/CO2/temperature and humidity all-in-1 sensor
• Up to 4 WH55 Water leak sensors
• One WH57 Lightning sensor
• Up to 8 WN34 Temp Sensors
• Up to 8 WN35 leaf wetness sensors

Manual

*GW1000 and WH32 combo. Minimum PWS needed for Weather Underground API

3 Likes

Excellent!

ANdt

And thanks for the references. :slight_smile:

2 Likes

Thanks, except the answer to your question is No.

Only one WH32 per gateway. :slightly_frowning_face:

Yup - but I can have a bunch of Wh31's so I'm good. :slight_smile: So it was a good "no." :slight_smile:

2 Likes

It's nice to have taken over a driver with such a knowledgeable and proactive user-base... :slight_smile: Thanks @Ranchitat.

(and thanks again to @kahn-hubitat for his recent efforts in enhancing the networking options for the drivers). @vitaliy_kh - I did start work on per-reading settings for the units (imperial vs metric), I just need to iron out a few more kinks in the code...

1 Like

Thank you very much.

1 Like