Proteus sum pump level monitor - json

Hi everyone, I have a proteus sensor to monitor my sum pump level.

It is publishing a JSON on a local address. It there a way to integrate those data into Hubitat ?

image

Thanks.

That should absolutely be possible! How is it "publishing" the JSON? Do you have to poll it from the device or can it POST or otherwise "send" it to a URL of your choosing? That will affect how you get the data.emphasized text

Thanks for your quick answer. The JSON is available on a local address :

There are also giving a home-assistant integration :

https://proteussensor.com/blog/proteus-wifi-sensor-integration-with-home-assistant.html

1 Like

As a general rule, I don't like WiFi sensors, but this device might be an exception. Just ordered one to use in my Primary Sump. Thanks for posting about this device.

S.

Sorry for the delay! I was hoping this would be an easy driver to write, just fetching and parsing local JSON, but I'm not aware of any "generic" JSON-parsing driver that exists. I took a look at the Home Assistant integration you mentioned, and it looks like the only value of interest in the JSON is the fld value, where 1 is dry (normal?) and 0 is wet. I threw together a quick driver that should do this:

/**
 * ================  Proteus Sump Pump Montitor ===============
 * Driver
 * Platform: Hubitat
 *
 * =======================================================================================
 *
 *  Last modified: 2021-04-04
 */

 import groovy.transform.Field

@Field static final String protocol = "http"
@Field static final String resourcePath = "/status.json"

metadata {
   definition (name: "Proteus Sump Pump Monitor", namespace: "RMoRobert", author: "Robert Morris") {
      capability "Sensor"
      capability "Initialize"
      capability "WaterSensor"
      capability "Refresh"
   }
   
   preferences() {
      input name: "ipAddress", type: "string", title: "Proteus IP address", description: "Example: 192.168.1.2"
      input name: "refreshInterval", type: "enum", title: "Refresh every...",
         options: ["1 minute", "5 minutes", "10 minutes", "15 minutes", "30 minutes", "1 hour", "3 hours"],
         defaultValue: "1 minute"
      input name: "enableDebug", type: "bool", title: "Enable debug logging", defaultValue: true
      input name: "enableDesc", type: "bool", title: "Enable descriptionText logging", defaultValue: true
   }   
}

void debugOff() {
   log.warn "Disabling debug logging"
   device.updateSetting("enableDebug", [value:"false", type:"bool"])
}

void installed() {
   log.debug "Installed..."
   initialize()
}

void updated() {
   log.debug "Updated..."
   initialize()
}

void initialize() {
   log.debug "Initializing"
   unschedule()
   if (enableDebug) {
      Integer disableTime = 1800
      log.debug "Debug logging will be automatically disabled in ${disableTime} seconds"
      runIn(disableTime, debugOff)
   }
   if (enableDebug) log.debug "Configuring polling every ${settings['runEvery'] ?: '1 minute'}..."
   switch (settings["runEvery"] ?: "1 minute") {
      case "1 minute":
         runEvery1Minute("refresh"); break
      case "5 minutes":
         runEvery5Minutes("refresh"); break
      case "10 minutes":
         runEvery10Minutes("refresh"); break
      case "15 minutes":
         runEvery15Minutes("refresh"); break
      case "30 minutes":
         runEvery30Minutes("refresh"); break
      case "1 hour":
         runEvery1Hour("refresh"); break
      case "3 hours":
         runEvery3Hours("refresh"); break
      default:
         runEvery30Minutes("refresh")
   }
   if (now() - (device.currentValue("lastUpdated") ?: 0) > 600000) {
      if (enableDebug) log.debug "Refreshing since has been longer than 10 minutes..."
      runIn(2, "refresh")
   }
}

void parse(String description) {
   log.warn "Unexpected parse(): $description"
}

void refresh() {
   if (enableDebug) log.debug "refresh()"
   String uri = "${protocol}://${settings['ipAddress']}${resourcePath}"
   if (enableDebug) log.debug "uri = $uri"
   Map params = [
      uri: uri,
      contentType: "application/json",
      timeout: 20
   ]
   try {
      asynchttpGet("parseRefreshResponse", params)
   }
   catch (Exception ex) {
      log.error "Error in refresh(): $ex"
   }
}

void parseRefreshResponse(response, data) {
   if (enableDebug) log.debug "parseRefreshResponse()"
   if (response.hasError()) {
      log.warn(response.getErrorMessage())
   }
   else if (response?.status == 200 && response?.json) {
      if (enableDebug) "response.json = ${response.json}"
      if ((response.json.fld as Integer) == 0) {
         doSendEvent("water", "wet")
      }
      else if ((response.json.fld as Integer) == 1) {
         doSendEvent("water", "dry")
      }
      else {
         if (enableDebug) log.warn "Unexpected fld value: ${response.json.fld}"
      }
   }
   else {
      log.warn "Unexpeted response: HTTP ${response.status}, body = ${response.body}"
   }   
}

private void doSendEvent(String eventName, eventValue, String eventUnit=null) {
   //if (enableDebug) log.debug "doSendEvent(eventName: $eventName, eventValue: $eventValue, eventUnit: $eventUnit)..."
   String descriptionText = "${device.displayName} ${eventName} is ${eventValue}${eventUnit != null ? ' ' + eventUnit : ''}"
   if (enableDesc && ("${device.currentValue(eventName)}" != "$eventValue")) log.info descriptionText
   if (eventUnit != null) sendEvent(name: eventName, value: eventValue, eventUnit: eventUnit, descriptionText: descriptionText)
   else sendEvent(name: eventName, value: eventValue, descriptionText: descriptionText)
}

I don't have one of these devices, so obviously I'm not really able to test it. :slight_smile: If something doesn't work right, hopefully the logs will show why. To use, just create a virtual device on Hubitat, assign it this driver, and fill out at least the IP address in the device preferences, then save. Keep an eye on the logs for any oddities, and if all looks well, consider testing it to make sure both "wet" and "dry" events get reported.

Thanks a lot for the driver ! It is much more than what I was expecting.

I am trying to make It work. Here are the logs :

Any idea about what should be modified ? Do you need more details ? Let me know. Thanks again.

Hmm, I made a typo that prevents the errors from showing me anything useful. If you change line 118 (which should be the same as this, minus the $ signs) to this, it should help me figure it out:

log.warn "Unexpeted response: HTTP ${response.status}, body = ${response.body}"

I'd probably also re-enable debug logging, since it will get disabled by default after 30 minutes and might have more information.

Thanks!

Thanks, here are my results :

First attempt :

Line 118 :

Logs :

Second attempt :

Line 118 :

Logs :

Not sure It gives you more hints ...

It works !

I changed for line 118:

image

if(response.hasError()) {
    log.warn(response.getErrorMessage())
}

From here, I found the log code : 408 Response From Async HTTP Actions Doesn't Bring Data Map?

Then I got this log :

image

It was only a small typo :

String uri = "${protocol}://${settings['ipAddress']}${resoucePath}"

r in resourcePath was missing.

Now, It gives me the status :slightly_smiling_face:

Thanks a lot for your help. I will try tomorrow If I change the state If It works (from dry to wet).

Thanks for playing around with it to find something that worked! I've edited my post above to fix the typo you found and another omission I made that would have made it easier to see what went wrong in the first place (line 89 was supposed to have a log.debug in it).

Hopefully it works as expected when you test it!

Hi,

I realised that the status is not updating :

When the device is created It Is sending a status but It is not updating after :

The log is not really helpful this time. I am using your last version. Any idea ?

Hi Robert, can you me with that ? Thanks.

This is hard without seeing what is coming into the driver. If you enable debug logging, my original code should show the JSON that parseRefreshResponse() extracts, which would probably be the most helpful.

The other thing to note is that you won't get an event every time data comes in, or really every time you call sendEvent(). By default, this will only actually create an even when the value changes, so you won't get an event every time data is parsed from the sensor.

I understand now.

When the value change It is showing into Hubitat :

Thanks again !