Water Flow Meters and "scaledMeterValue" vs "meterValue"

I'm trying to configure my Fortrezz Water Flow Meter and I'm seeing an odd behavior that I'm struggling to understand.

First I tried to use the community driver mentioned here, very kindly provided by @tsuthar

And I found that it was not reporting the correct GPM. The driver was reporting a GPM of 6.6gpm while the actual flow rate was 11.25GPM. (I calculated the 11.25 by taking a video of the dials with my phone and using the video to calculate the exact number of seconds it took to deliver a specific number of gallons and did the math)

I also know that my well pump, based on it's performance curves, has an expected GPM rate at it's specific depth and my water pressure (400 ft deep and 50 PSI) of 11.4 GPM.

So I'm quite sure the 6.6gpm being reported by the driver here is wrong. It's off by a factor of almost (But not quite) 2 (or roughly half).

So I switched to using the official Fortrezz Driver and just ported it myself. Now the "official" driver gives me a result of 1.1 GPM. .. Why would the community driver report 6.6, and the official driver report 1.1? The community driver is exactly 6x higher than the official driver. Let's look at the code:

The official driver uses this calculation to determine GPM:

def delta = cmd.scaledMeterValue - cmd.scaledPreviousMeterValue

while the community driver does this:

def delta = Math.round((((cmd.scaledMeterValue - cmd.scaledPreviousMeterValue) / (reportThreshhold*10)) * 60)*100)/100 //rounds to 2 decimal positions

So the community driver has this added variable (reportThreshhold) involved which comes from an input parameter on the driver configuration:

		//Nothing changes this value on the device yet.  Set to 1
       input "reportThreshhold", "decimal", title: "Reporting Rate Threshhold", description: "The time interval between meter reports while water is flowing. 6 = 60 seconds, 1 = 10 seconds. Options are 1, 2, 3, 4, 5, or 6.", defaultValue: 1, required: false, displayDuringSetup: true

A couple things I thought were strange here: The comment above the input line suggests that changing this value doesn't change anything on the device. If that's the case I'm not sure why this parameter is here? Do some Flow Meters report on different intervals by default?

The comment also suggests that you should leave this set to "1". But I also noticed that my flow meter actually issues reports every 60 seconds. So it seems like the "correct" value for my flow meter would be "6".

When I set it to 6 I now get the same 1.1 GPM that the official driver gives me. So at least now both drivers agree (Even though both are still wrong.)

However: Now both drivers are wrong by a factor of almost exactly 10. They are reporting 1.1 GPM when the actual flow is 11 GPM. And now it's starting to make sense: Fortrezz offers flow meters in different sizes. This particular flow meter is the 1.5 inch version. (Most people are proably using the 3/4 or 1 inch versions). I'm using the 1.5 inch version because this is attached directly to my well head and the piping from my water well is 1.5 inches to support the flow rates needed to run irrigation, my house, a barn, etc. (I live on 5 acres)

The smaller Flow Meters send a pulse for every 0.1gal, but the larger flow meter only sends a pulse for every full 1gal. So somehow the scaling needs to be set correctly for the larger meter.

So I added this debug logging where it does the calculation:

    log.debug(cmd)
    def delta = cmd.scaledMeterValue - cmd.scaledPreviousMeterValue
    log.debug "delta(${delta}) = cmd.scaledMeterValue(${cmd.scaledMeterValue}) - cmd.scaledPreviousMeterValue(${cmd.scaledPreviousMeterValue})"

Which results in log output that looks like:

delta(1.1) = cmd.scaledMeterValue(48.3) - cmd.scaledPreviousMeterValue(47.2)
MeterReport(scale: 2, rateType: 1, scale2: 0, deltaTime: 60, previousMeterValue: [0, 0, 1, 216], meterType: 3, precision: 1, size: 4, meterValue: [0, 0, 1, 227])

So here it gets more interesting:

Remember the code is doing it's calculation like so:

def delta = cmd.scaledMeterValue - cmd.scaledPreviousMeterValue

Notice it uses cmd.scaledMeterValue and cmd.scaledPreviousMeterValue

But in the log output: There is no cmd.scaledMeterValue or cmd.scaledPreviousMeterValue. There is only: previousMeterValue and meterValue: IE: Without scaled being prepended.

I notice that if you use the non-scaled values: previousMeterValue is 216, and meterValue is 227. The difference between those is 11, which is the correct GPM. So somehow the scaled values are 1/10th.

So all of this was basically provided to give context around these questions:

  1. So where does this scaled value come from?
  2. How do I change the scale?
  3. Why don't the scaled values show up when I do log.debug(cmd) ?

I realize I could just modify the driver code to multiply delta by 10, but I wanted to understand the why/how of this before making changes to the driver.

Thanks in advance.
-Jeremy

That cmd variable is a special class, not just a regular map or string, when you convert it to a string to log it, it has a preformatted output.
I have found some of those outputs do not have the scaled values as you have found on this one. I ran into the same thing with power metering.

The regular "meterValue" is an 8 byte array in your example, which needs to be converted to an integer. So the value is not just 216, is it [0,0,1,216] which I think would equal 472 (0+0+256+216). The scaledMeterValue does that conversion for you and also sometimes applies other useful conversions depending on the command class.

You can manually add the values to your log output which is what I am doing in my drivers so I can see all the info:
"${cmd} (meterValue: ${cmd.scaledMeterValue}, previousMeter: ${cmd.scaledPreviousMeterValue})"

Hope that helps you figure out the problem with the values.

Also, you can see all of the names and types of the supplied values for each report type in the docs: Z-Wave Classes | Hubitat Documentation (very slow to load simetimes). I use this as reference quite a bit when making drivers.

Oh this is very helpful insight and this helps explain why the [0,0,1,216] maps to a scaled value of 47.2: It's just the 472 (value that you calculated) divided by 10.

I also took a look at those Zwave class docs and noticed for this specific class:

I do see a "scale" value, and I see it being logged as well. The scale value is set to 2... So I'm not sure how 2 causes it to scale it to 1/10th the value, or how to figure out what the correct scale should be, nor how to set it.

I know the easy fix is to just add a * 10 to the end of the calculation but I'm just wanting to understand the correct way to fix this if I can. Especially in case there's any other conversions being handled by the scaling that could cause other unintended consequences.

I believe what you are looking for is the precision, which is 1 in your example, meaning 1 decimal place. So the scaledValue converts the whole integer to have one decimal (dividing by 10).

The actual "scale" value along with the meterType actually just tells you what type of meter value you are getting. For example electrical metering is type 1, and then within that you have a "scale" for power, energy, amps, and volts. Not sure why they use the key word scale for this, it is confusing. There is a chart in the zwave specs that shows what all the different values mean.

Ahh, that makes sense.

Any idea how to change the precision value? I'm assuming this is a value stored inside the physical Zwave device since I don't see anywhere where this precision is set within the driver code.

I'm guessing I can set it similarly to how they set the flow alarm threshold here:

def setThreshhold(rate)
{
	log.debug "Setting Threshhold to ${rate}"
    
    def event = createEvent(name: "lastThreshhold", value: rate, displayed: false)
    def cmds = []
    cmds << zwave.configurationV2.configurationSet(configurationValue: [(int)Math.round(rate*10)], parameterNumber: 5, size: 1).format()
    sendEvent(event)
    return response(cmds) // return a list containing the event and the result of response()
}

I probably just need to figure out what the proper configurationValue needs to be? Looks like I'd need to know the parameterNumber for that configuration value for that device.

The precision comes from the device itself, that is what it is telling the hub to do in the report it is sending. If the scaledMeter is off by a factor of 10 maybe the device is reporting the wrong precision (bug in device firmware maybe??).

If you have some docs for the device it should list all all the settings, or you could try using my scanner tool to see if you can scan the device for its settings

Well don't forget that the most common versions of this flow meter, the 3/4 inch and 1 inch models, report 10 pulses per gallon. So a precision of 1 would be correct for those meters.

This 1.5 inch meter, due to it's larger size, only sends 1 pulse per gallon. The actual Zwave device just plugs into this wire from the flow meter and counts the pulses and sends Zwave events back to the hub based on how many pulses it counts.

So I suspect when they sent me the 1.5 inch version, someone forgot to reconfigure the pulse counter for 1 pulse per gallon vs 10 pulses per gallon. The 3/4, 1 inch, and 1.5 inch meters all come with the same little black box that counts the pulses and converts that count into Zwave events.

I've emailed Fortrezz to see if there's a way to configure this. Only issue is they got bought out a couple years ago and they aren't making these flow meters any more so I'm not sure if they can still offer support.

I'll give your scanner a shot as well.

And if all else fails I'll just add * 10 to the end of the calculation line. :joy:

Ok that makes sense then as to why it would be off. If you can find a manual for the pulse counter device, it may have some of the parameters listed in there.

I found the PDF docs for the flow meter online here:

It lists the parameters, but I don't see anything for setting precision or the pulses per gallon value.

I also tried your scan tool driver. But I'm not sure if I'm doing something wrong or if it just doesn't work with this device. It just hangs and doesn't return anything.

Thanks for your help. I'll let you know if Fortrezz / Ezlo ever comes back with a solution. Until then I'll just multiply by 10 and be done with it. :slight_smile:

The device probably does not support the required command classes and is ignoring the request that the driver sends it. I have not added any logic yet to check if the device actually supports it, it just blasts out the requests.

Hello,
@ jeremy.akers Would it be possible for you to provide a link to the driver that is working for you ? I have had the Fortrezz flow meter for a while.. and it used to work in hubitat via ST (funnily that was the only thing left in ST till last year) , and when they moved over to edge drivers, I just turned off ST hub , but couldn't setup this flow meter in hubitat.. if you could provide the driver in hubitat that would be very helpful..
I tried using the driver listed in
https://raw.githubusercontent.com/tman785/Fortrezz/master/devicetypes/jsconstantelos/my-fortrezz-flow-meter-interface.src/my-fortrezz-flow-meter-interface.groovy
but it only updates the alarmState, temperature and water as dry.. everything else is just zeroes.

Thanks