Efergy / Energyhive - JSON Transformation throws exception

Big step forward. Tested the JSON with https://jsonformatter.curiousconcept.com and realized that I misinterpreted the structure. Used https://jsonpath.curiousconcept.com to verify the query and realized I needed an extra dot, so now Plan A has the following http binding:

<[http://www.energyhive.com/mobile_proxy/getCurrentValuesSummary?token=XXXXX:60000:JSONPATH($..data.*)]

And the log looks like:
2015-10-13 05:33:39 - Energy_Instant_House state updated to [3277.96]

Feels like a big step forward!

1 Like

I’ve tried a thousand things, but can’t seem to turn “[3277.96X]” into “3277” - Anyone got a clue? Could this be achieved with a rule maybe?

Something like this maybe:

    $[?(@.cid == PWER)].data[0].*[0]

Here’s a rule version of it for testing various combinations:

import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*

rule "JSON Test"
  when
    Time cron "0/10 * * * * ?"
  then
    var String json = '[{"cid":"PWER","data":[{"1444632753000":1642.085}],"sid":"555610","units":"kWm","age":34}]'

    var String type = transform("JSONPATH", "$[?(@.cid == PWER)].data[0].*[0]", json)
    logInfo("json", type)
end

It doesn’t eliminate the decimal point, but the output is like:

19:33:40.004 DEBUG o.o.m.r.i.e.ExecuteRuleJob[:53]- Executing scheduled rule 'JSON Test'
19:33:40.011 INFO  org.openhab.model.script.json[:53]- 1642.085

The JSONPath Doc is here if you want to do something more complex:

Hi,
Any progress on this matter?
I’m also very interested to do so, but I use the other web which is
https://engage.efergy.com/

I do not konw how to get this specific numbers… could you help me to understand where to gather this info.

I only have my specific token code, but nothing else.

Thanks in advance, would be a nice Binding as item efergy engage hub is used for a lot of houseowners.

Regards,
Marc.

HUGE SUCCESS!

Thanks @guessed - your code did it… My http-binding now looks like:

<[http://www.energyhive.com/mobile_proxy/getCurrentValuesSummary?token=XXXX:60000:JSONPATH($[?(@.cid == PWER)].data[0].*[0])]

And it is logging -
2015-11-03 05:34:39 - Energy_Instant_House state updated to 1522.485

I haven’t used it yet, but at least it’s a number, so hopefully it will work out when I get some time… @mgalimany You should be able to use energyhive instead, they are the ones providing services for efergy. If I remember correctly the username/password from efergy works straight away on eneryghive - I think you can login and request an API token there. Replace XXXX above and you should be good to go!

1 Like

Great! Glad to hear you got it tuned up.

Hello Marc, I also use Efergy, were you able to get this to work?

For anyone struggling to get this working in openHAB 2 since the JSONPATH behaviour has changed, the JS transform still works if you define the item like

Number Energy_Instant_House “Current energy use [%d W]” (Power) { http="<[http://www.energyhive.com/mobile_proxy/getCurrentValuesSummary?token=XXXX:60000:JS(efergy.js)]"}

and stick this in /etc/openhab2/transform/efergy.js
JSON.parse(input)[0].data[0][Object.keys(JSON.parse(input)[0].data[0])[0]];

Thanks so much for this post guys.
I have a question though. I get this JSON string as a reply

[{"cid":"PWER","data":[{"1536592326000":331}],"sid":"xxx","units":"kWm","age":2},{"cid":"PWER","data":[{"1536592322000":20}],"sid":"yyy","units":"kWm","age":6}]

as I have more than one sensors in my household. How can I extract the info based on the SID ?

Regards

Hi, I too have efergy (energyhive) power monitor with 2 x Data Points (one for 3-Phase consumption and one for Controlled (off peak) load). The following is what I get back from the efergy API reply:
[{“cid”:“PWER”,“data”:[{“1595114390000”:3734}],“sid”:“816022”,“units”:“W”,“age”:5},{“cid”:“PWER”,“data”:[{“1595114376000”:0}],“sid”:“816590”,“units”:“W”,“age”:19}]

Any suggestions on how to extract the following values from the string (eg)?:
3Phase = 3734
OffPeak = 0

Thanks
Nathan

So this works. It should also work regardless of how many Efergy / Energyhive monitors you have (I have two). If you have one remove the second VAL and postUpdate lines. If you have more than two then add additional ones and increment the $.[n] value (starting at 0).

Items:

Number myHousePower "Power [%.0f W]" <energy>
Number myOffPeakPower "Power [%.0f W]" <energy>

Rules:

rule "House Power Consumption"
  when
    Time cron "0 0/1 * 1/1 * ? *" // Run every Minute
  then
    var String tempJson = sendHttpGetRequest("http://www.energyhive.com/mobile_proxy/getCurrentValuesSummary?token=xxxxxx")
    val tempMainPower = transform("JSONPATH", "$.[0].data[0].*", tempJson)  // This will pull the 1st Data Point
	val tempOffPeak = transform("JSONPATH", "$.[1].data[0].*", tempJson)  // This will pull the 2nd Data Point if you have a 2nd monitor 
	myHousePower.postUpdate(tempMainPower)
	myOffPeakPower.postUpdate(tempOffPeak)
end

It all updates values in the UI, and I can send alerts etc if myHousePower.state < 100 etc

Edit - Updated the code above with the comments below

postUpdate() can be funny about the type of object passed for the new state.

Passing a string usually overcomes snags, but the best way from a Number -
myOffPeakPower.postUpdate(tempOffPeak.toString)

1 Like

Thanks - this removed the warning and did not seem to break anything :slight_smile: I’ve updated my post above.

I was puzzling over why postUpdate(Number) seemed not to work, sure it usually does …

Thinking further on this … your variable won’t be a Number type at all.
Declaring types in rules is not strictly enforced. transform() of any kind always returns a string. (If you wanted it as number you would have to parse it.)
So you can just pass to postUpdate() as it is.
myOffPeakPower.postUpdate(tempOffPeak)
and the openHAB framework will parse the given string to something suitable.

unrelated - i would add a timeout to your sendHttpGetRequest() call, and perform a test for null results in case of failure of the HTTP fetch for whatever reason.

1 Like

Thanks - Tested with the following changes and they work :slight_smile: so I updated the code in my post above:

  • Removed “Number” declarations for tempMainPower / tempOffPeak
  • Removed “.toString” from the postUpdates

I’ve not yet looked at adding a specific HTTP timeout as I thought there was a Global Default of 5000ms anyway??? I “think” I’ll be fine on a failure to get a null result but I’d have to test to be sure.

So long as you are aware, people often overlook.

Well, the rule will throw an error trying to process tempJson as null input to the transform.
By testing if it is null first, you can avoid that and exit gracefully.
You might choose instead to update your Items to UNDEF to indicate unknown, depends what you want.

Thanks for all your help. I’ll drop my Internet Connection to test and report back (but I’ll need to find a time to do this when everyone is out).

So here is the latest with the addition of some error checking for both:

  • No Result / timeout of the http request (null)
  • Errors in the JSON result (such as Bad Token, or if the Web Site is up but the power monitors in the house are off line)

Rules

rule "House Power Consumption"
  when
    Time cron "0 0/1 * 1/1 * ? *" // Run every Minute
  then
    var String tempJson = sendHttpGetRequest("http://www.energyhive.com/mobile_proxy/getCurrentValuesSummary?token=b4sPDuDMwZinXhI_7GoHKAwcaeL2dSBq")
	if ( tempJson === null || tempJson.contains ("error") ) {  // Check to see if there is a response (and if it contains an error)
		logInfo("HousePower", "Unable to Update Energy Use: Reponse from EnergyHive / Efergy - {}", tempJson)
		myHousePower.postUpdate(UNDEF)
		myOffPeakPower.postUpdate(UNDEF)
	}
	else {
		val tempMainPower = transform("JSONPATH", "$.[0].data[0].*", tempJson)  // This will pull the 1st Data Point
		val tempOffPeak = transform("JSONPATH", "$.[1].data[0].*", tempJson)  // This will pull the 2nd Data Point if you have a 2nd monitor 
		myHousePower.postUpdate(tempMainPower)
		myOffPeakPower.postUpdate(tempOffPeak)
	}
end

After few years of just reading my power instant values from the Efergy system with Energyhive account (thanks to this community page!), I decided to go a bit deeper in my energy consumption overview.

Unfortunately, doing calculations from instant values inside Openhab, using daily rules, is not working as well as desired, so the simple way is to get the desired values directly from the Energyhive API (which I could not find before).

Here I found interesting info for the API, to get the desired values: http://napi.hbcontent.com/document/index.php

Here some examples that allow me to simply read monthly energy consumption and monthly cost.

Items

String EnergyMonthHouse "Energia mese Casa [%s kWh]" <myicon> (G_EnergyM) { http="<[http://www.energyhive.com/mobile_proxy/getEnergy?token=XXXXXXXXXXX&period=month&offset=-60:60000:JSONPATH($.sum)]"}
String EnergyCostMonthHouse "Costo Energia mese Casa [%s EUR]" <myicon> (G_EnergyEUR) { http="<[http://www.energyhive.com/mobile_proxy/getCost?token=XXXXXXXXXXX&period=month&offset=-60:60000:JSONPATH($.sum)]"}

The period can be simply changed by using “day”, “week”, “year” instead of “month”.
Change the “getEnergy” or “getCost” with what you like in the API linked page to get different “channels”.
Obviously use your personal token instead of “XXXXX”.
I am not using transformation files or rules on these items, but see for yourself if you need them.
I hope it works for you too! :grinning:

I am finally migrating my Efergy / Energyhive system to OH3.2.0 (manual installation of Build #2546).
Here my setup in short (not shown here: my second Efergy account and period channels “day” and “week”; offset is related to my timezone).
I am using a “hybrid” approach: Things in UI and Items in config file.

Things (HTTP Binding):

UID: http:url:HTTP_ENERGIA
label: HTTP Energia
thingTypeUID: http:url
configuration:
  authMode: BASIC
  ignoreSSLErrors: false
  baseURL: http://www.energyhive.com/mobile_proxy
  delay: 0
  stateMethod: GET
  refresh: 10
  commandMethod: GET
  contentType: text/plain
  timeout: 60000
  bufferSize: 2048
location: Home
channels:
  - id: PowerHouse
    channelTypeUID: http:string
    label: Potenza assorbita Casa
    description: null
    configuration:
      mode: READONLY
      unit: W
      stateExtension: /getCurrentValuesSummary?token=XXXXXXXXXXXXXXXXXXX
      stateTransformation: JS:efergy.js
  - id: EnergyMonthHouse
    channelTypeUID: http:string
    label: Energia mese Casa
    description: null
    configuration:
      mode: READONLY
      stateExtension: /getEnergy?token=XXXXXXXXXXXXXXXXXXX&period=month&offset=-60
      stateTransformation: JSONPATH:$.sum
  - id: EnergyCostMonthHouse
    channelTypeUID: http:string
    label: Costo Energia mese Casa
    description: null
    configuration:
      mode: READONLY
      unit: kWh
      stateExtension: /getCost?token=XXXXXXXXXXXXXXXXXXX&period=month&offset=-60
      stateTransformation: JSONPATH:$.sum

In the file efergy.js in “transform” folder:

JSON.parse(input)[0].data[0][Object.keys(JSON.parse(input)[0].data[0])[0]];

In Items file:

Number PowerHouse 	"Potenza assorbita Casa [%d W]" 	<energy> 		(G_Power, G_House) 	["Point_Measurement","Property_Power"] 	{channel="http:url:HTTP_ENERGIA:PowerHouse"} 
Number EnergyMonthHouse "Energia mese Casa [%.1f kWh]" 		<qualityofservice> 	(G_Power, G_House) 	["Point_Measurement","Property_Power"] 	{channel="http:url:HTTP_ENERGIA:EnergyMonthHouse"} 
Number EnergyCostMonthHouse "Costo Energia mese Casa [%.2f €]" 		<price> 	(G_Power,G_House) 	["Point_Measurement","Property_Power"] 	{channel="http:url:HTTP_ENERGIA:EnergyCostMonthHouse"} 

Works fine :grinning: