[New Binding] Rainforest Eagle 200 local binding

Turns out, there was more to it than that. I was seeing the device simply stop sending data for a while, and only a full restart of openhab would fix it.

I was seeing this in the logs:

20:49:43.540 [WARN ] [core.common.registry.AbstractRegistry] - Cannot add "ItemChannelLink" with key "ElectricityMeter_InstantaneousDemand -> eagle200:eagle200_electric_meter:0x0013500100c8adae:InstantaneousDemand". It exists already from provider "GenericItemChannelLinkProvider"! Failed to add a second with the same UID from provider "ManagedItemChannelLinkProvider"!

It didn’t seem to matter, but later, I’d see this:

2019-02-11 21:43:15.038 [vent.ItemStateChangedEvent] - ElectricityMeter_InstantaneousDemand changed from 1.453000 to 1.475000
2019-02-11 21:43:49.394 [temChannelLinkRemovedEvent] - Link 'ElectricityMeter_InstantaneousDemand => eagle200:eagle200_electric_meter:0x0013500100c8adae:InstantaneousDemand' has been removed.
2019-02-11 21:45:42.603 [.ItemChannelLinkAddedEvent] - Link 'ElectricityMeter_InstantaneousDemand-eagle200:eagle200_electric_meter:0x0013500100c8adae:InstantaneousDemand' has been added.

After that remove and add of the links, no more data would be updated.

I don’t know what caused that. It could be I did something that caused a config file reload.

So, I removed the binding, the things, the item, AND the extra link and I tried again. The extra link showed only in the karaf console, and I had to remove it there. It stuck around even after everything else was gone.

Once my config was clear, I reinstalled the addon, added the Eagle thing, and then let it find the Electricity Meter thing. I used PaperUI to create an item connected to the channel I wanted from the Electricity Meter thing.

This time I got no data. A post earlier in this thread made me wonder if there was something going wrong, and when I looked at the list of links, there was no link between the Electricity Meter thing and the item. So I removed the item that PaperUI created one and inserted one manually in a .items file - I used one the first time, so just updated the channel name and put it back.

I’m getting data now. All I have to see is if I keep getting data! Hopefully the extra link is all that was wrong. I have no idea where it came from, though, or how to find it except by prowling around the console and looking at things I’ve never heard of before. The warning got me looking there, and other posts in this thread got me to use an items file instead of the UI to create the item that can be persisted and used in the sitemap!

So far, so good! Hopefully if this bites someone else they’ll be able to sort it out.

UPDATE: Nope, still not right.

I’m seeing the oddest behavior.

Sometimes, the binding works great, and I get data. That’ll run for hours. And then it simply stops updating data. Often a reboot will fix it - I have a nightly reboot of my RPi at 4:37am. But not always.

Here’s my configuration:

Here’s the things, as shown by smarthome:things in karaf. Both were automatically discovered and added via PaperUI:

eagle200:eagle200_electric_meter:0x0013500100c8adae (Type=Thing, Status=ONLINE, Label=Electricity Meter, Bridge=eagle200:eagle200_bridge:6a25dc04)
eagle200:eagle200_bridge:6a25dc04 (Type=Bridge, Status=ONLINE, Label=Eagle 200, Bridge=null)

There is the electric meter, and the bridge. Both have sensible values, and openhab showes them as on-line.

Here’s the thing, also from karaf:

ElectricityMeter_InstantaneousDemand (Type=NumberItem, State=NULL, Label=Current Electric Usage, Category=null, Groups=[ChartData])

The state is NULL, and has stayed that way. Interestingly, when the device fails, the state goes from a sensible number to NULL and then stays NULL.

The link is showing up in karaf as well:

ElectricityMeter_InstantaneousDemand -> eagle200:eagle200_electric_meter:0x0013500100c8adae:InstantaneousDemand

The Item and the link are defined in an items file:

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

When the system runs, and shows a failure, I’ve gotten a bunch more debug information (yay!)

2019-02-14 22:05:24.540 [TRACE] [b.binding.eagle200.discovery.EagleDiscoveryService] - Scanning for energy meters
2019-02-14 22:05:24.808 [TRACE] [penhab.binding.eagle200.handler.Eagle200Connection] - Eagle200 meter HW address: <DeviceList>  <Device>    <HardwareAddress>0x0013500100c8adae</HardwareAddress>    <Manufacturer>Generic</Manufacturer>    <ModelId>electric_meter</ModelId>    <Protocol>Zigbee</Protocol>    <LastContact>0x5c6656a3</LastContact>    <ConnectionStatus>Connected</ConnectionStatus>    <NetworkAddress>0xffff</NetworkAddress>  </Device></DeviceList>
2019-02-14 22:05:24.815 [TRACE] [b.binding.eagle200.discovery.EagleDiscoveryService] - Bridge eagle200:eagle200_bridge:6a25dc04 for device eagle200:eagle200_electric_meter:0x0013500100c8adae is in state ONLINE, scan count 329
2019-02-14 22:05:39.821 [TRACE] [b.binding.eagle200.discovery.EagleDiscoveryService] - Scanning for energy meters
2019-02-14 22:05:40.067 [TRACE] [penhab.binding.eagle200.handler.Eagle200Connection] - Eagle200 meter HW address: <DeviceList>  <Device>    <HardwareAddress>0x0013500100c8adae</HardwareAddress>    <Manufacturer>Generic</Manufacturer>    <ModelId>electric_meter</ModelId>    <Protocol>Zigbee</Protocol>    <LastContact>0x5c6656ac</LastContact>    <ConnectionStatus>Connected</ConnectionStatus>    <NetworkAddress>0xffff</NetworkAddress>  </Device></DeviceList>
2019-02-14 22:05:40.093 [TRACE] [b.binding.eagle200.discovery.EagleDiscoveryService] - Bridge eagle200:eagle200_bridge:6a25dc04 for device eagle200:eagle200_electric_meter:0x0013500100c8adae is in state ONLINE, scan count 330
2019-02-14 22:05:55.100 [TRACE] [b.binding.eagle200.discovery.EagleDiscoveryService] - Scanning for energy meters
2019-02-14 22:05:55.337 [TRACE] [penhab.binding.eagle200.handler.Eagle200Connection] - Eagle200 meter HW address: <DeviceList>  <Device>    <HardwareAddress>0x0013500100c8adae</HardwareAddress>    <Manufacturer>Generic</Manufacturer>    <ModelId>electric_meter</ModelId>    <Protocol>Zigbee</Protocol>    <LastContact>0x5c6656bc</LastContact>    <ConnectionStatus>Connected</ConnectionStatus>    <NetworkAddress>0xffff</NetworkAddress>  </Device></DeviceList>
2019-02-14 22:05:55.346 [TRACE] [b.binding.eagle200.discovery.EagleDiscoveryService] - Bridge eagle200:eagle200_bridge:6a25dc04 for device eagle200:eagle200_electric_meter:0x0013500100c8adae is in state ONLINE, scan count 331
2019-02-14 22:06:10.352 [TRACE] [b.binding.eagle200.discovery.EagleDiscoveryService] - Scanning for energy meters
2019-02-14 22:06:10.691 [TRACE] [penhab.binding.eagle200.handler.Eagle200Connection] - Eagle200 meter HW address: <DeviceList>  <Device>    <HardwareAddress>0x0013500100c8adae</HardwareAddress>    <Manufacturer>Generic</Manufacturer>    <ModelId>electric_meter</ModelId>    <Protocol>Zigbee</Protocol>    <LastContact>0x5c6656cb</LastContact>    <ConnectionStatus>Connected</ConnectionStatus>    <NetworkAddress>0xffff</NetworkAddress>  </Device></DeviceList>
2019-02-14 22:06:10.700 [TRACE] [b.binding.eagle200.discovery.EagleDiscoveryService] - Bridge eagle200:eagle200_bridge:6a25dc04 for device eagle200:eagle200_electric_meter:0x0013500100c8adae is in state ONLINE, scan count 332
2019-02-14 22:06:15.598 [TRACE] [penhab.binding.eagle200.handler.Eagle200Connection] - Eagle200 meter query 0x0013500100c8adae: <Device>  <DeviceDetails>    <Name>Power Meter</Name>    <HardwareAddress>0x0013500100c8adae</HardwareAddress>    <NetworkInterface>0xd8d5b9000000fede</NetworkInterface>    <Protocol>Zigbee</Protocol>    <NetworkAddress>0xffff</NetworkAddress>    <Manufacturer>Generic</Manufacturer>    <ModelId>electric_meter</ModelId>    <LastContact>0x5c6656d3</LastContact>    <ConnectionStatus>Connected</ConnectionStatus>  </DeviceDetails>  <Components>    <Component>      <HardwareId></HardwareId>      <FixedId>0</FixedId>      <Name>Main</Name>      <Variables>        <Variable>          <Name>zigbee:InstantaneousDemand</Name>          <Value>1.390000</Value>          <Units>kW</Units>          <Description>Instantaneous Demand</Description>        </Variable>        <Variable>          <Name>zigbee:Multiplier</Name>          <Value>1</Value>          <Units></Units>          <Description>Multiplier applied to demand and summation values</Description>        </Variable>        <Variable>          <Name>zigbee:Divisor</Name>          <Value>1000</Value>          <Units></Units>          <Description>Divisor applied to demand and summation values</Description>        </Variable>        <Variable>          <Name>zigbee:CurrentSummationDelivered</Name>          <Value>27168.103000</Value>          <Units>kWh</Units>          <Description>Summation Delivered to Home</Description>        </Variable>        <Variable>          <Name>zigbee:CurrentSummationReceived</Name>          <Value>0.000000</Value>          <Units>kWh</Units>          <Description>Summation Received from Home</Description>        </Variable>        <Variable>          <Name>zigbee:Price</Name>          <Value></Value>          <Units></Units>          <Description>Price of electricity</Description>        </Variable>        <Variable>          <Name>zigbee:TrailingDigits</Name>          <Value></Value>          <Units></Units>          <Description>Indicates the number of digits to the right of the decimal point</Description>        </Variable>        <Variable>          <Name>zigbee:RateLabel</Name>          <Value></Value>          <Units></Units>          <Description>Active priuce rate label</Description>        </Variable>        <Variable>          <Name>zigbee:Currency</Name>          <Value></Value>          <Units></Units>          <Description>The local unit of currency used in the price field</Description>        </Variable>        <Variable>          <Name>zigbee:PriceTier</Name>          <Value></Value>          <Units></Units>          <Description>The current Price Tier</Description>        </Variable>        <Variable>          <Name>zigbee:PriceStartTime</Name>          <Value></Value>          <Units></Units>          <Description>The time at which the price signal becomes valid</Description>        </Variable>        <Variable>          <Name>zigbee:PriceDuration</Name>          <Value></Value>          <Units>min</Units>          <Description>Amount of time in minutes after the Start Time during which the price signal is valid</Description>        </Variable>        <Variable>          <Name>zigbee:Message</Name>          <Value></Value>          <Units></Units>          <Description>Message from utility to customer</Description>        </Variable>        <Variable>          <Name>zigbee:MessageId</Name>          <Value></Value>          <Units></Units>          <Description>Message unique ID</Description>        </Variable>        <Variable>          <Name>zigbee:MessageStartTime</Name>          <Value></Value>          <Units></Units>          <Description>Start time for current message</Description>        </Variable>        <Variable>          <Name>zigbee:MessageDurationInMinutes</Name>          <Value></Value>          <Units>min</Units>          <Description>Start time for current message</Description>        </Variable>        <Variable>          <Name>zigbee:MessagePriority</Name>          <Value></Value>          <Units></Units>          <Description>Message priority</Description>        </Variable>        <Variable>          <Name>zigbee:MessageConfirmationRequired</Name>          <Value></Value>          <Units></Units>          <Description>Indicates if the message requires user confirmation</Description>        </Variable>        <Variable>          <Name>zigbee:MessageConfirmed</Name>          <Value></Value>          <Units></Units>          <Description>Indicates if the message has received user confirmation</Description>        </Variable>        <Variable>          <Name>zigbee:BlockPeriodNumberOfBlocks</Name>          <Value></Value>          <Units></Units>          <Description></Description>        </Variable>        <Variable>          <Name>zigbee:BlockPeriodConsumption</Name>          <Value></Value>          <Units>kWh</Units>          <Description>The most recent summed value of Energy, Gas or Water delivered and consumed in the premises during the Block Tariff Period</Description>        </Variable>        <Variable>          <Name>zigbee:Block1Price</Name>          <Value></Value>          <Units>USD/kWh</Units>          <Description>The price of Energy, Gas, or Water delivered to the premises at a specific price tier</Description>        </Variable>        <Variable>          <Name>zigbee:Block2Price</Name>          <Value></Value>          <Units>USD/kWh</Units>          <Description>The price of Energy, Gas, or Water delivered to the premises at a specific price tier</Description>        </Variable>        <Variable>          <Name>zigbee:Block3Price</Name>          <Value></Value>          <Units>USD/kWh</Units>          <Description>The price of Energy, Gas, or Water delivered to the premises at a specific price tier</Description>        </Variable>        <Variable>          <Name>zigbee:Block4Price</Name>          <Value></Value>          <Units>USD/kWh</Units>          <Description>The price of Energy, Gas, or Water delivered to the premises at a specific price tier</Description>        </Variable>        <Variable>          <Name>zigbee:Block5Price</Name>          <Value></Value>          <Units>USD/kWh</Units>          <Description>The price of Energy, Gas, or Water delivered to the premises at a specific price tier</Description>        </Variable>        <Variable>          <Name>zigbee:Block6Price</Name>          <Value></Value>          <Units>USD/kWh</Units>          <Description>The price of Energy, Gas, or Water delivered to the premises at a specific price tier</Description>        </Variable>        <Variable>          <Name>zigbee:Block7Price</Name>          <Value></Value>          <Units>USD/kWh</Units>          <Description>The price of Energy, Gas, or Water delivered to the premises at a specific price tier</Description>        </Variable>        <Variable>          <Name>zigbee:Block8Price</Name>          <Value></Value>          <Units>USD/kWh</Units>          <Description>The price of Energy, Gas, or Water delivered to the premises at a specific price tier</Description>        </Variable>        <Variable>          <Name>zigbee:Block1Threshold</Name>          <Value></Value>          <Units>kWh</Units>          <Description>the block threshold values for a given period (typically the billing cycle)</Description>        </Variable>        <Variable>          <Name>zigbee:Block2Threshold</Name>          <Value></Value>          <Units>kWh</Units>          <Description>the block threshold values for a given period (typically the billing cycle)</Description>        </Variable>        <Variable>          <Name>zigbee:Block3Threshold</Name>          <Value></Value>          <Units>kWh</Units>          <Description>the block threshold values for a given period (typically the billing cycle)</Description>        </Variable>        <Variable>          <Name>zigbee:Block4Threshold</Name>          <Value></Value>          <Units>kWh</Units>          <Description>the block threshold values for a given period (typically the billing cycle)</Description>        </Variable>        <Variable>          <Name>zigbee:Block5Threshold</Name>          <Value></Value>          <Units>kWh</Units>          <Description>the block threshold values for a given period (typically the billing cycle)</Description>        </Variable>        <Variable>          <Name>zigbee:Block6Threshold</Name>          <Value></Value>          <Units>kWh</Units>          <Description>the block threshold values for a given period (typically the billing cycle)</Description>        </Variable>        <Variable>          <Name>zigbee:Block7Threshold</Name>          <Value></Value>          <Units>kWh</Units>          <Description>the block threshold values for a given period (typically the billing cycle)</Description>        </Variable>        <Variable>          <Name>zigbee:Block8Threshold</Name>          <Value></Value>          <Units>kWh</Units>          <Description>the block threshold values for a given period (typically the billing cycle)</Description>        </Variable>        <Variable>          <Name>zigbee:BlockPeriodStart</Name>          <Value></Value>          <Units></Units>          <Description>The start time of the current block tariff period</Description>        </Variable>        <Variable>          <Name>zigbee:BlockPeriodDuration</Name>          <Value></Value>          <Units>min</Units>          <Description>The current block tariff period duration in minutes</Description>        </Variable>        <Variable>          <Name>zigbee:BlockThresholdMultiplier</Name>          <Value></Value>          <Units></Units>          <Description>Provides a value to be multiplied against Threshold attributes</Description>        </Variable>        <Variable>          <Name>zigbee:BlockThresholdDivisor</Name>          <Value></Value>          <Units></Units>          <Description>Provides a value to divide the result of applying the threshold multiplier attribute to Block Threshold values</Description>        </Variable>        <Variable>          <Name>zigbee:BillingPeriodStart</Name>          <Value></Value>          <Units></Units>          <Description>The start time of the current billing period</Description>        </Variable>        <Variable>          <Name>zigbee:BillingPeriodDuration</Name>          <Value></Value>          <Units>min</Units>          <Description>The current billing period duration in minutes</Description>        </Variable>      </Variables>    </Component>  </Components></Device>

It looks like it scans three times, then does a query, which returns what looks like sensible data. You can see it’s found the InstantaneousDemand item that I’m linking to. Here’s an excerpt with carriage returns:

<Variable>
          <Name>zigbee:InstantaneousDemand</Name>
          <Value>1.390000</Value>
          <Units>kW</Units>
          <Description>Instantaneous Demand</Description>
</Variable>

That seems to be a sensible value to me, but I don’t know for sure.

When the values are being read, an ItemStateChangedEvent is logged, which records the old and the new value. When things don’t work, I don’t see that.

I don’t know why it works for a while, and then stops. And why a restart fixes it. Sometimes. I haven’t found any notable differences or other errors when it’s working versus when it is not.

After a restart, I see the same pattern of discovery and then a full query to the meter. The behaviors look the same in the detailed logs, except that I get the updates:

2019-02-14 22:17:36.674 [vent.ItemStateChangedEvent] - ElectricityMeter_InstantaneousDemand changed from NULL to 1.368000

Those will keep going for a while… hours, probably. And then it’s just stuck again.

More information. More information. Last night I left debugging up very high and found this in the logs:

2019-02-15 02:08:10.412 [TRACE] [b.binding.eagle200.discovery.EagleDiscoveryService] - Scanning for energy meters
2019-02-15 02:08:45.518 [WARN ] [b.binding.eagle200.discovery.EagleDiscoveryService] - connection to Eagle failed, stopping device scan. Fix network or configuration: No route to host (Host unreachable)
2019-02-15 02:08:45.521 [WARN ] [nhab.binding.eagle200.handler.Eagle200MeterHandler] - connection to Eagle200 caused error
java.net.NoRouteToHostException: No route to host (Host unreachable)
        at java.net.PlainSocketImpl.socketConnect(Native Method) ~[?:?]
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[?:?]
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[?:?]
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[?:?]
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[?:?]
        at java.net.Socket.connect(Socket.java:589) ~[?:?]
        at java.net.Socket.connect(Socket.java:538) ~[?:?]
        at sun.net.NetworkClient.doConnect(NetworkClient.java:180) ~[?:?]
        at sun.net.www.http.HttpClient.openServer(HttpClient.java:463) ~[?:?]
        at sun.net.www.http.HttpClient.openServer(HttpClient.java:558) ~[?:?]
        at sun.net.www.http.HttpClient.<init>(HttpClient.java:242) ~[?:?]
        at sun.net.www.http.HttpClient.New(HttpClient.java:339) ~[?:?]
        at sun.net.www.http.HttpClient.New(HttpClient.java:357) ~[?:?]
        at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1220) ~[?:?]
        at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1156) ~[?:?]
        at sun.net.www.protocol.http.HttpURLConnection$6.run(HttpURLConnection.java:1040) ~[?:?]
        at sun.net.www.protocol.http.HttpURLConnection$6.run(HttpURLConnection.java:1038) ~[?:?]
        at java.security.AccessController.doPrivileged(Native Method) ~[?:?]
        at java.security.AccessController.doPrivilegedWithCombiner(AccessController.java:782) ~[?:?]
        at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1037) ~[?:?]
        at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:984) ~[?:?]
        at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1334) ~[?:?]
        at sun.net.www.protocol.http.HttpURLConnection.access$100(HttpURLConnection.java:91) ~[?:?]
        at sun.net.www.protocol.http.HttpURLConnection$8.run(HttpURLConnection.java:1301) ~[?:?]
        at sun.net.www.protocol.http.HttpURLConnection$8.run(HttpURLConnection.java:1299) ~[?:?]
        at java.security.AccessController.doPrivileged(Native Method) ~[?:?]
        at java.security.AccessController.doPrivilegedWithCombiner(AccessController.java:782) ~[?:?]
        at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1298) ~[?:?]
        at org.openhab.binding.eagle200.handler.Eagle200Connection.doPost(Eagle200Connection.java:81) ~[24:org.openhab.binding.eagle200:0.0.7.201807012222]
        at org.openhab.binding.eagle200.handler.Eagle200Connection.queryMeter(Eagle200Connection.java:108) ~[24:org.openhab.binding.eagle200:0.0.7.201807012222]
        at org.openhab.binding.eagle200.handler.Eagle200MeterHandler$1.run(Eagle200MeterHandler.java:73) [24:org.openhab.binding.eagle200:0.0.7.201807012222]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:?]
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [?:?]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [?:?]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [?:?]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:?]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:?]
        at java.lang.Thread.run(Thread.java:748) [?:?]

I don’t know what could cause a network problem with the device; it’s on wired Ethernet, connected to the same network that the openhab server is. I don’t know if one of my switches flaked for a moment, or if the device was rebooting itself or what.

After this, the discovery of the meter stopped. The queries of the meter kept going, though, and updates to the item continued.

At 4:37am, via a Cron job, the host rebooted.

The logs show the binding loading and starting normally, and it’s doing the queries to the Eagle… but there are no updates being made to the item. I do not have any idea why not!

Updated to add:

I’m still seeing the binding go silent. I’ve instrumented it with a watchdog rule that restarts the binding if it sees five minutes without any updates. There’s two extra items; one is a switch with an expire on it that gets turned ON every time data comes in, and the other is a “Loader”, which is what the binding actually updates. A rule on the loader cause it to update the actual item I’m using for the data, then reset the timer, and reset itself to UNDEF. It resets itself to undef so that any value coming in causes a change, so it should update once a minute. Hopefully this will get me data through the night! :slight_smile:

Well, folks here seem to be having better luck than me.

I’ve added the binding to /usr/share/openhab2/addons. I’ve got a couple of other bindings in there that load just fine.

The eagle200 binding, however, is giving me an error when I restart OH.

2019-03-16 09:18:20.412 [ERROR] [core.karaf.internal.FeatureInstaller] - Failed installing 'openhab-binding-eagle200': Error restarting bundles:

I’m running the 2.3.0 release. Any help certainly appreciated.

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