[New Binding] Rainforest Eagle 200 local binding

Maybe try re-downloading? Perhaps it got corrupt somehow. Here’s my cksum:

$ cksum org.openhab.binding.eagle200-0.0.7.jar
2607188344 2545145 org.openhab.binding.eagle200-0.0.7.jar

I’m using 2.4.0. Not sure if that matters.

I’m also using 2.4.0, and it’s mostly working. I did have to add a status check and binding reload as noted above, but it definitely loads and runs.

Thanks John & Lou. I had a download problem somehow. The size of the .jar was nowhere near the 2545145 it should have been.

The new download loaded much better and I was able to create the things, items, etc.

I don’t seem to get any data from PG&E other than InstantaneousDemand. Wondering if any other PG&E customers see anything more.

I have PG&E too and I do get more than just instantaneous demand. I know I get the cumulative energy demand, and I believe the price comes in but I don’t use it.

My PG&E meter offers a whole bunch of things…

I was going to put the list of channels, but can’t find it now. Or where to link items to them.

I don’t think it’s a Rainforest problem, as I can’t find any of the channel lists.

If you turn the logs up, you can see the XML traffic, and from there you can get the channel names.

Mind sharing the rule text / items for your watchdog setup?

Sure, happy to. I use two Items to hold the value I care about. One is the real value from the meter, and the other is the one I use to persist changes and to display. The “real” value is updated every time the meter is read, but only if the value changes. We have a rule that copies that updated value into the human-readable copy and then resets itself to undef. This forces the meter to trigger an update every time it is read.

There’s also a switch that uses the expire module to force the system to reset if it doesn’t get updated.

Here are the items (from eagle200.items):

Number ElectricityMeter_InstantaneousDemand "Current Electric Usage [%f kWh]" (ChartData)
Number ElectricityMeter_InstantaneousDemandLoader "Current Electric Usage [%f kWh]" { channel="eagle200:eagle200_electric_meter:0x0013500100c8adae:InstantaneousDemand" }

Switch ElectricityMeter_BindingReset { expire="5m,command=OFF" }

Here’s the rules (from eagle200.rules):

// The ElectricityMeter_InstantaneousDemandLoader item is changed by the
// Eagle200 binding.  This triggers this rule only when there's an actual
// change.  Since we want to use this as a heartbeat, we need to make sure
// the value is actually changing.
//
// To make that happen, the "Loader" value is changed by the binding.
// This rule copies any changes to the ElectricityMeter_InstantaneousDemand
// item, which is what's persisted and used with the user.  The rule then
// sets the ElectricityMeter_InstantaneousDemandLoader back to UNDEF so that
// next time the binding updates it will always trigger the rule.
//
// The rule also resets the expire timer whenever data comes in.  If the
// timer goes off then the Eagle200 binding needs to be reloaded.

rule "Keep Eagle200 Alive"
when
        Item ElectricityMeter_InstantaneousDemandLoader changed
then

        // Don't take any actions if we don't have a sensible value
        if (!(ElectricityMeter_InstantaneousDemandLoader.state instanceof Number)) {
                return
        }

        var Number kwh = ElectricityMeter_InstantaneousDemandLoader.state as Number;
        ElectricityMeter_InstantaneousDemand.sendCommand(kwh)

        // Reset the timer for bundle load.
logWarn("eagle200", "reset timer!")
        ElectricityMeter_BindingReset.postUpdate(OFF)
        ElectricityMeter_BindingReset.sendCommand(ON)

        ElectricityMeter_InstantaneousDemandLoader.postUpdate(UNDEF)
end


rule "Reset Eagle200 Binding"
when
        Item ElectricityMeter_BindingReset received command OFF
then
        logWarn("eagle200", "Timer has expired.  Looks like we need to reload the binding!")
        executeCommandLine("/usr/bin/openhab-cli@@client@@bundle:restart@@\"Eagle200@@Binding\"")
end

rule "Start Eagle200 Watchdog on System Startup"
when
        System started
then
        logWarn("eagle200", "Setting up Eagle200 Watchdog")
        ElectricityMeter_BindingReset.postUpdate(OFF)
        ElectricityMeter_BindingReset.sendCommand(ON)
end

Yes, I use files for everything, and the older rules format, because I started with 1.6 and it all still makes sense to me. Someday I’ll move on. Today, these work.

1 Like

I plan to purchase this product this week against ComEd in IL, US. Anything I should be aware of (heads up) when setting this up in OH?

From a ComEd utility standpoint setup; this is what I found on Amazon.

Waited months for the Eagle 200 to get back in stock and as it stands now, it was worth the wait. The device has been reporting energy use for about an hour without issue. Im currently using both the Android EnergyVUE app and the Rainforest Cloud Service web interface.

In my case, I had to connect with ComEd of Illinois to get the device registered. Im not sure if it was necessary because I registered the device with ComEd before installing it on my LAN (as per the instructions) or if it was necessary because it was not listed as a supported device when I set it up at the ComEd site. Regardless, Im glad we connected. As soon as the setup failed, I received an email from ComEd with minutes which (1) suggested that for security reasons, that I turn OFF Rainforest Automation Remote Support/VPN service and (2) send them (ComEd) a photo of the Eagle 200 label containing the MAC/Install addresses (required for setup). After hitting send, ComEd had me up and running within minutes. They were absolutely AWESOME.

So far Rainforest Automation (device and cloud service) is delivering on the promise and Im very happy.

IMPORTANT NOTE:
ComEd recommends users turn OFF the VPN / Rainforest Remote Access service via the devices browser interface. To do this, get the Eagle 200 IP address from your router, use your web browser to log in using the cloud ID and install code for username/password, head to Advanced Gateway and uncheck the box.

UPDATE:
Its been 3 months since I installed the EAGLE-200. The device itself, along with the associated Android app and web service, have worked absolutely flawlessly!

Best, Jay

I like the Eagle 200. It works quite well for me. I did give up on this binding, however. The binding works fine for the most part, but every night I would get an exception in the openhab log. I suspect that the Eagle does a bit of maintenance at that time and didn’t respond to the binding. This is not a big deal, but I don’t like having recurring exceptions in the log file. And the author of this binding seems to have disappeared.

So I wrote a very small nodejs program that runs as a daemon, and I turned on the uploader mode in the Eagle 200 which you can get to from the Rainforest Automation web site. This will send POST requests directly from the Eagle to your server. The nodejs program takes in the POST requests and in turn sends POST requests to openHAB. This works really well and I haven’t had an issue in several months. And no exceptions in the openHAB log. I could do one step better and use a curl command to set the uploader locally which would let me control the rate of updates (currently I use the nodejs program to regulate the rate). I will post my nodejs program if you like.

Please and thank you. I haven’t installed nodejs on my Synology. I’m assuming it shouldn’t be too hard to get up and running?

Best, Jay

Okay, here’s the basic recipe to get the Eagle to send to openHAB via nodejs. First, this is the uploader manual from Rainforest.

These are the settings I used in the Rainforest uploader page after logging in (the custom uploader). You will need to match the IP address to wherever you run the nodejs server and match the port in the nodejs code (set to 8079 in my code below).

Here is my nodejs code. I do not have much experience with this coding and I’m sure it can be improved, but it works for me. You can see that it collects the current power and energy reading from the meter and sends it to the openHAB Items InstantaneousDemand and CurrentSummationDelivered (this is the terminology Rainforest uses, but you can certainly change to Power and Energy or anything else you like). The Eagle can send other information but none of it was useful for me. In some areas you can get price information which might be interesting to track if it changes. I can help with that.

I went to this site to get nodejs: https://nodejs.org/en/ I found this for Synology https://www.synology.com/en-us/dsm/packages/Node_js I’ve never used Synology so I can’t say much about it.

const express = require('express')
const http = require('http')
const app = express()
const bodyParser = require('body-parser')

// Eagle sends out data quite often.  This limits the rate of packets going to openHAB.  Note
// that it could be more sophisticated and do averaging or other processing, but this is just
// dropping packets.
//
// 5 min * 60 seconds * 1000ms = 300000
const InstaneousDemandTimeLimit = 300000;
// 15 min * 60 seconds * 1000ms = 1800000
const SummationTimeLimit = 1800000;
//
var LastInstantaneousDemandTimestamp = 0;
var LastSummationTimestamp = 0;

// Tell express to use the body-parser middleware and to not parse extended bodies
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json()); // for parsing application/json

// the content-length header and the path header (to define the openHAB Item) are generated
// on the fly in the post request handling
var options = {
  // set the openHAB IP/hostname and port here
  host: '192.168.1.216',
  port: 8080,
  method: 'PUT',
  headers: {
    'Content-Type': 'text/plain',
    'Accept': 'application/json'
  }
};

// this one handles the Eagle 200 packets
app.post('/eagle200', (req, res) => {

  if (req.body.body[0].dataType == 'InstantaneousDemand') {
    if (parseInt(req.body.body[0].timestamp) > (LastInstantaneousDemandTimestamp + InstaneousDemandTimeLimit)) {
      LastInstantaneousDemandTimestamp = parseInt(req.body.body[0].timestamp);
      console.log('PUT Instantaneous Demand: ' + req.body.body[0].data.demand);
      // console.log('Instantaneous TS: ' + req.body.body[0].timestamp);
      options.path = '/rest/items/InstantaneousDemand/state';
      options.headers['Content-Length'] = req.body.body[0].data.demand.toString().length;
      putReq = http.request(options, function(res) {
        res.setEncoding('utf8');
        res.on('data', function (chunk) {
	  // if you are getting something here, it is probably an error from the server
          console.log('post2put error from openHAB server: ' + chunk);
        });
      });
      putReq.on('error', (error) => {
        console.error(error) });
      putReq.write(req.body.body[0].data.demand.toString());
      putReq.end();
    }
  }

  if (req.body.body[0].dataType == 'CurrentSummation') {
    if (parseInt(req.body.body[0].timestamp) > (LastSummationTimestamp + SummationTimeLimit)) {
      LastSummationTimestamp = parseInt(req.body.body[0].timestamp);
      console.log('Current Summation: ' + req.body.body[0].data.summationDelivered);
      // console.log(req.body.body[0].data);
      options.path = '/rest/items/CurrentSummationDelivered/state';
      options.headers['Content-Length'] = req.body.body[0].data.summationDelivered.toString().length;
      putReq = http.request(options, function(res) {
        res.setEncoding('utf8');
        res.on('data', function (chunk) {
	  // if you are getting something here, it is probably an error from the server
          console.log('post2put error from openHAB server: ' + chunk);
        });
      });
      putReq.on('error', (error) => {
        console.error(error) });
      putReq.write(req.body.body[0].data.summationDelivered.toString());
      putReq.end();
    }
  }
  res.set('Content-Type', 'text/plain')
  res.send('Okay')
})

// choose an unused port for this use:
app.listen(8079)

Save this code in a file. I called it “post2put.js”.

You can see that I am rate limiting the Eagle in this code. I do plan to take a look at the uploader manual and use it to lower the rate instead of doing it here.

To test this out on my Ubuntu based system I ran this command:

nodejs post2put.js

Once you are happy with it, set it up as a service.

4 Likes

Hey, thanks for putting this together!

I was also having the connection reset problems with the binding, so it’s nice to have an alternative choice.

Just got it running successfully. Time will tell how the nodejs version holds up, but it’s already great so far!

Has anyone gotten the binding working with OpenHab3?

I would also be interested in this binding for OH 3. I used it for a long time with OH2 and I’m missing it!

I never saw sources for this, only the release of the beta, and the author has been quiet a while.

I’m finally looking at a move to OH3 and wondering how to fix this. I did find an API guide for the local API, so it should be pretty possible.

See this post: [New Binding] Rainforest Eagle 200 local binding - #73 by jswim788
You don’t need a binding for this. A small script and you can get the data pushed into OH.

Interesting. I’m not sure a whole service running node.js is better than a binding, or that the limitations of the IP rigidity are helpful, but the push mode from the device is definitely something I hadn’t found yet.

Thank you for sharing it, though, as it’s definitely interesting and useful.

Just wanted to report back with a long term update.

I’ve been using the nodejs version since the timeframe mentioned above (over 14 months now) and it’s still running perfectly. I had the same reservations about a whole separate service being too heavy, but the reliability has been undeniably good.

1 Like

That’s my experience as well. I have 2 of the Eagle’s and they appear to be happier pushing data. Polling is a little problematic with them. If you are going to poll, you have to be ready for timeouts and other error conditions. I found them to be far more reliable when they push data. No errors, no issues.

Thank you for this - I’d been battling with a Python->MQTT solution (which was working until I updated mosquitto), and then last night I tried setting this up and within a matter of minutes had it working better and more smoothly than either the binding or the Python version ever did. Set it up as a LaunchAgent this morning.