Help with Parsing Json

Looking for a little guidance here.

I am building a device type for an energy monitor, and have managed to get as far as receiving a response back from a LAN Http request executed by a hubaction. However, I am at a loss as to how to extract the pieces of data that I need from the response.

This is the data I am getting back:

{“report”:“Instantaneous values:
voltage=246.5 Vrms
FFTComponents:
Phase 1:
\tcurrent=2.243 A, activePower=484.742 W, reactivePower=266.086 var, apparentPower=552.971 VA, cosfi=87, quadrant=0, phaseshift=0.0, phaseDiff=0.0
\tFFTComponents:
Phase 2:
\tcurrent=0.117 A, activePower=-3.926 W, reactivePower=28.746 var, apparentPower=29.013 VA, cosfi=10, quadrant=0, phaseshift=0.0, phaseDiff=0.0
\tFFTComponents:
Phase 3:
\tcurrent=2.199 A, activePower=480.816 W, reactivePower=250.56 var, apparentPower=542.185 VA, cosfi=88, quadrant=0, phaseshift=0.0, phaseDiff=0.0
\tFFTComponents:

Load[280114] state[1] power: 65.5 on Sat Oct 24 22:23:25 GMT 2015
Load[275162] state[1] power: 134.4 on Sat Oct 24 22:15:02 GMT 2015

Phase 3, peak active power 8808.649 W at 27/06/2015 19:20:35
”}

The data I need to get back is the figure after “activePower” for each of Phase 1, Phase 2, and Phase 3.

Where do I start ?

That’s not a well formatted JSON response. From a JSON perspective, you basically have:

{ "report": "block_of_text_data" }

So you’ll either need to see if there is a better way of getting an actual fully formatted JSON response from the device, or you would need to manually parse through the response - perhaps using a regular expression.

2 Likes

Thanks Joshua.

I don’t think there is any way to get a different form of output, as the device is a commercial one with almost no configuration options. It is a Smappee energy monitor. I used “Content-Type” : “application/json” in the header for the Http GET command that retrieved the data.

I’m not sure how to go about this in groovy code. Basically what I want to achieve in natural language is the following:

look through the text until you find ‘activePower=’, then take the next characters up until ’ W’ as the power value. Call this number Phase1. Continue to look through the text until you again find ‘activePower=’, then take the next characters up until ’ W’ as the power value. Call this number Phase2. Continue to look through the text until you find ‘activePower=’, then take the next characters up until ’ W’ as the power value. Call this number Phase3.

I will continue researching in the meantime to see if I can find some similar code somewhere, no suitable hits in the forum search yet.

[quote=“djtucker, post:3, topic:27084”]
I’m not sure how to go about this in groovy code
[/quote]You could look into using regular expression parsing in groovy

http://naleid.com/blog/2009/04/07/groovy-161-released-with-new-find-and-findall-regexp-methods-on-string/

Regex is really not that bad. Use some online tester to get your expression right, like this one

http://www.regexplanet.com/advanced/java/index.html

2 Likes

I have worked out that the string I need to find in the response is this
" activePower=[0-9]*.[0-9] *.W"

Using http://myregexp.com/, I have proved that this will find the correct three instances of the phrase, together with the value contained within.

So the next stage is, how do I write the code that will search the for this string in the response, and then how do I take each found string and extract the value that I need (i.e. 1,059) from something like this " activePower=1059.111 W"

An update…

Using https://regex101.com/#javascript

" activePower=([0-9]*.[0-9] *).W"

returns a single captured group which just contains the number I am looking for, so I think I am gradually understanding this. Now trying to work out how to get all three instances of the text I am looking for to be returned, and then how to get my Smartthings DeviceType to do what is being done in the online tester.

@djtucker This worked

def testString = " A, activePower=484.742 W, reactivePower=266.086 var, , activePower=-3.926 W, reactiveP, activePower=480.816 W, reactivePower=250.56 var, apparentPower=542.185 VA, cosfi=88, quadrant=0, phaseshift=0.0, phaseDiff=0.0"

def regex = " activePower=([-]?[0-9]*.[0-9]*) W"

def matches = testString.findAll( / activePower=([-]?[0-9]*.[0-9]*) W/  ) { match, power -> power }

log.debug matches

(logged [484.742, -3.926, 480.816])

Your data is in the json field data.report, so you should use that instead of testString above. You’ll get an array of values back.

I now think I have a possible easier solution. Having go nowhere with working out how to use regular expressions within the groovy code, I have managed to extract a different JSON response from the original device…an unpublished response which I found buried within the device html code.

Here is now the JSON response that I get back:

[{“value”:“673193”,“key”:“phase0ActivePower”},{“value”:“93”,“key”:“phase0Cosfi”},{“value”:“0”,“key”:“phase0Quadrant”},{“value”:"-4005",“key”:“phase1ActivePower”},{“value”:“13”,“key”:“phase1Cosfi”},{“value”:“0”,“key”:“phase1Quadrant”},{“value”:“669188”,“key”:“phase2ActivePower”},{“value”:“93”,“key”:“phase2Cosfi”},{“value”:“0”,“key”:“phase2Quadrant”},{“value”:“0”,“key”:“autoCommissioningRunning”},{“value”:“0”,“key”:“voltageReversed”}]

I have the following code in my device type:

if (tstat.containsKey("phase0ActivePower")) {
    //Float temp = tstat.temp.toFloat()
    def ev = [
        name:   "grid",
        value:  tsat.phase0ActivePower.value,
        //unit:   getTemperatureScale(),
    ]

    events << createEvent(ev)
}

but I get an error appearing in the log

groovy.lang.MissingMethodException: No signature of method: script14458104756451404145205.parseTstatData() is applicable for argument types: (java.util.ArrayList) values: [[[value:593118, key:phase0ActivePower], …]] @ line 241

Is there something obviously wrong here?

That’s an array of json records

You’d need to iterate over them and see if each one contains the desired key.

tstat.foreach { it.containsKey() } or something like that

Well I couldn’t get anything to work using foreach or containskey() and just came up against error messages that I cannot understand, but I did manage to access the data using code similar to this:

log.debug tstat.key [0]
log.debug tstat.value [0]

So whilst this is probably far from robust, and I don’t really know why it works, it does give me the data I need, and I now have a device with tiles that display my home power load, solar production, and net grid import/export :grinning:

2 Likes