Rainforest EAGLE-200 Energy Gateway - Does you have one?

I’m in the same boat with the 200. It’s been a week and a half so far trying to pair with SCE. I also submitted the original codes, then Rainforest support gave me an updated MAC/Install code which I then gave to SCE. I can’t get anyone on the phone from either side, so it feels impossible to make progress on this or understand what the hang up is. I have no way of verifying MAC addresses on either front, let alone beginning the project of experimenting with running these containers.

What a pain so far.

Rainforest took over two weeks after receiving my defective unit via RMA to issue me a replacement. After setting it up, joining it to my cloud account, and activating it with SCE, it paired up right away and began emitting data. Well, now I know what I should have expected.

For an mqtt broker, I’ve been running emqx as a container in an ubuntu-derived VM. Looking forward to finally trying out this rainforest mqtt bridge.

Just wanted to follow up:

  • Eagle-200 user here
  • SCE customer (enabled and can see stuff on rainforestcloud.com)
  • Running emqx (mosquitto should work though) as an MQTT broker

Start a container running the following:

docker run -e MQTT_BROKER_IP=<BROKER_IP> -e MQTT_BROKER_PORT=<BROKER_PORT> -p 22042:22042 evanrich/py-eagle-mqtt

Go to rainforestcloud.com portal, Cloud tab, Add Upload Destination

  • Custom
  • Label (make up anything)
  • Protocol: HTTP (unless you put this container behind an SSL termination)
  • Hostname: IP or hostname of the machine you ran the docker command from
  • URL: /
  • Format: XML:RAW

If you subscribe to your broker on topic power/#, you should start to see data points like this:

# about every 8 seconds
power/elec/Home/power {"time": 1553059760.0, "power": 1125.0}
# about every 180 seconds
power/elec/Home/price {"time": 1553059840.0, "price": 0.0, "tier": 0} # or whatever these values should be
# about every 240 seconds
power/elec/Home/energy {"time": 1553059920.0, "consumed": 4856.396, "produced": 3651.877}

For some reason docker logs [containerID] wasn’t working, so you can tail the logs of the container by starting the container as a shell:

docker exec -it [containerID] /bin/sh
tail -f /var/log/tHome/eagle.log

So far, I’m seeing the same publish events to my broker, but also see these errors on occasion:

2019-03-20 05:37:22,368 : ERROR: Error parsing Eagle posted data
Traceback (most recent call last):
  File "/app/src/bin/tHome-eagle.py", line 75, in root_post
    obj = T.eagle.parse( data )
  File "/app/src/python/tHome/eagle/parse.py", line 18, in parse
    child = root[0]
IndexError: child index out of range

2019-03-20 05:39:07,096 : ERROR: Error parsing Eagle posted data
Traceback (most recent call last):
  File "/app/src/bin/tHome-eagle.py", line 75, in root_post
    obj = T.eagle.parse( data )
  File "/app/src/python/tHome/eagle/parse.py", line 15, in parse
    root = ET.fromstring( xmlText )
  File "/usr/local/lib/python3.7/xml/etree/ElementTree.py", line 1315, in XML
    parser.feed(text)
  File "<string>", line None

2019-03-20 05:39:00,830 : ERROR: Error parsing Eagle posted data
Traceback (most recent call last):
  File "/app/src/bin/tHome-eagle.py", line 75, in root_post
    obj = T.eagle.parse( data )
  File "/app/src/python/tHome/eagle/parse.py", line 15, in parse
    root = ET.fromstring( xmlText )
  File "/usr/local/lib/python3.7/xml/etree/ElementTree.py", line 1315, in XML
    parser.feed(text)
  File "<string>", line None
xml.etree.ElementTree.ParseError: not well-formed (invalid token): line 2, column 1

Hi Thanks for the good work, is it possible to submit this as a native component to home assistant?

@estebanp thank you for the elegant rest call. works great! Now to figure out a $$ amount.

In my case, SDGE does not configure the meter to have the $ amount. So I ended up creating a set of sensors/automations that calculate the tariff type (superoffpeak, offpeak, onpeak) and then use the utility_meter to accumulate the kWh and amount over days/months.

Is far from ideal, but gives me a good idea on how my energy consumption is going.

Notes:

  • I noticed that the meter has a different “time” (a couple of minutes off), so I am going to eventually move to use that for automations that trigger “energy consumption events” (e.g. pool pump, car charging, tesla gateway mode, etc)
  • The holiday calendar will require updating every year. This is me being lazy, I could pull it down from their webpage.
  • I have not discriminated the prices for exporting energy. I just got solar.
  • I am on EV-TOU-5 (thanks Tesla). Therefore I do not have baseline. The change of tariff will be the same for any TOU plan, but the price will change based on your consumption vs baseline and the plan you are actually on.
  • SDGE has a weird way to do their bill cycle. I am using month cycle, eventually I will move to use their billing cycle.

These are extracts of it:
In configuration.yaml

utility_meter:
  energy_meter_monthly_imported:
    source: sensor.energy_meter_imported
    cycle: monthly
    tariffs:
      - onpeak
      - offpeak
      - superoffpeak

An automation that switches the tariff:

# EV-TOU-5
# https://www.sdge.com/residential/pricing-plans/about-our-pricing-plans/electric-vehicle-plans
# Winter: Nov 1 - May 31
# Summer: June 1 - Oct 31
# On-Peak: Winter: 24c, Summer: 52c
#   Everyday: 16:00 - 21:00
# Super Off-Peak: Winter: 9c, Summer: 9c
#   Weekdays: 00:00 - 06:00
#   Weekends and holidays: 00:00 - 14:00
# Off-Peak: Winter: 24c, Summer: 28c
#   Weekdays: 06:00 - 16:00, 21:00 - 00:00
#   Weekends and holidays: 14:00 - 16:00, 21:00 - 00:00
# Holidays:
# January 1 (New Year's Day) February 18 (Presidents' Day) April 10 (No Read Day) May 27 (Memorial Day) July 4 (Independence Day)
# September 2 (Labor Day) October 30 (No Read Day) November 28 (Thanksgiving Day) December 25 (Christmas Day)
# Holiday's list: 0101, 0218, 0410, 0527, 0704, 0902, 1030, 1128, 1225

alias: energy_tariff
trigger:
- platform: time
  at: '00:00:00'
- platform: time
  at: '06:00:00'
- platform: time
  at: '14:00:00'
- platform: time
  at: '16:00:00'
- platform: time
  at: '21:00:00'
- platform: homeassistant
  event: start
action:
- service: utility_meter.select_tariff
  data_template:
    entity_id:
    - utility_meter.energy_meter_monthly_imported
    - utility_meter.energy_meter_daily_imported
    - utility_meter.energy_meter_monthly_exported
    - utility_meter.energy_meter_daily_exported
    tariff: >
      {% set current_date = now().strftime("%m%d") | int %}
      {% set day_of_week = now().strftime("%w") | int %}
      {% set current_time = now().strftime("%H%M%S") | int %}
      {% if current_time < 60000 %}
        superoffpeak
      {% elif current_time < 140000 and (day_of_week == 6 or day_of_week == 0 or current_date in [0101, 0218, 0410, 0527, 0704, 0902, 1030, 1128, 1225]) %}
        superoffpeak
      {% elif current_time < 160000 %}
        offpeak
      {% elif current_time < 210000 %}
        onpeak
      {% else %}
        offpeak
      {% endif %}

Then some template sensors:

# Extract the relevant measurements into their own sensors
- platform: template
  sensors:
    energy_meter_instant_power:
      friendly_name: Instant power
      value_template: '{{ states.sensor.energy_meter.attributes.demand | float | round(3) }}'
      unit_of_measurement: kW
    energy_meter_imported:
      friendly_name: Imported
      value_template: '{{ states.sensor.energy_meter.attributes.summation_delivered | float | round(3) }}'
      unit_of_measurement: kWh
    energy_meter_exported:
      friendly_name: Exported
      value_template: '{{ states.sensor.energy_meter.attributes.summation_received | float | round(3) }}'
      unit_of_measurement: kWh

    energy_meter_imported_current_price:
      friendly_name: Current price
      entity_id: utility_meter.energy_meter_daily_imported
      unit_of_measurement: $/kWh
      value_template: >
        {% set current_date = now().strftime("%m%d") | int %}
        {% set summer_tariffs = {'superoffpeak': 0.09, 'offpeak': 0.28, 'onpeak': 0.52} %}
        {% set winter_tariffs = {'superoffpeak': 0.09, 'offpeak': 0.24, 'onpeak': 0.24} %}
        {% if current_date >= 0601 and current_date <= 1031 %}
          {{ summer_tariffs[states('utility_meter.energy_meter_daily_imported')] }}
        {% else %}
          {{ winter_tariffs[states('utility_meter.energy_meter_daily_imported')] }}
        {% endif %}
  
    energy_meter_imported_current_hour_price:
      friendly_name: Current price/h
      entity_id: sensor.energy_meter_instant_power
      unit_of_measurement: $/h
      value_template: >
        {{ (states('sensor.energy_meter_imported_current_price') | float * states('sensor.energy_meter_instant_power') | float) | round(2) }}
  
    energy_meter_daily_imported_cost_onpeak:
      friendly_name: On peak cost
      unit_of_measurement: $
      value_template: >
        {% set current_date = now().strftime("%m%d") | int %}
        {% if current_date >= 0601 and current_date <= 1031 %}
        {%   set price = 0.52 | float %}
        {% else %}
        {%   set price = 0.24 | float %}
        {% endif %}
        {{ (price * states('sensor.energy_meter_daily_imported_onpeak') | float) | round(2) }}
    energy_meter_daily_imported_cost_offpeak:
      friendly_name: Off peak cost
      unit_of_measurement: $
      value_template: >
        {% set current_date = now().strftime("%m%d") | int %}
        {% if current_date >= 0601 and current_date <= 1031 %}
        {%   set price = 0.28 | float %}
        {% else %}
        {%   set price = 0.24 | float %}
        {% endif %}
        {{ (price * states('sensor.energy_meter_daily_imported_offpeak') | float) | round(2) }}
    energy_meter_daily_imported_cost_superoffpeak:
      friendly_name: Super off peak cost
      unit_of_measurement: $
      value_template: >
        {% set current_date = now().strftime("%m%d") | int %}
        {% set price = 0.09 | float %}
        {{ (price * states('sensor.energy_meter_daily_imported_superoffpeak') | float) | round(2) }}
    
    energy_meter_monthly_imported_cost_onpeak:
      friendly_name: On peak cost
      unit_of_measurement: $
      value_template: >
        {% set current_date = now().strftime("%m%d") | int %}
        {% if current_date >= 0601 and current_date <= 1031 %}
        {%   set price = 0.52 | float %}
        {% else %}
        {%   set price = 0.24 | float %}
        {% endif %}
        {{ (price * states('sensor.energy_meter_monthly_imported_onpeak') | float) | round(2) }}
    energy_meter_monthly_imported_cost_offpeak:
      friendly_name: Off peak cost
      unit_of_measurement: $
      value_template: >
        {% set current_date = now().strftime("%m%d") | int %}
        {% if current_date >= 0601 and current_date <= 1031 %}
        {%   set price = 0.28 | float %}
        {% else %}
        {%   set price = 0.24 | float %}
        {% endif %}
        {{ (price * states('sensor.energy_meter_monthly_imported_offpeak') | float) | round(2) }}
    energy_meter_monthly_imported_cost_superoffpeak:
      friendly_name: Super off peak cost
      unit_of_measurement: $
      value_template: >
        {% set current_date = now().strftime("%m%d") | int %}
        {% set price = 0.09 | float %}
        {{ (price * states('sensor.energy_meter_monthly_imported_superoffpeak') | float) | round(2) }}

And this is my UI, I have some days missing data because SDGE unsubscribed my rainforest. I had to re-subscribed it and missed a couple of days.

5 Likes

@estebanp You, sir, are a gentleman and a scholar. I sat down to figure out all this SDGE nonsense the other day, but i was couple of beers in and the maths won that battle.Thank you for this!!!

Holiday list for 2020:

Just update the list to this:
0101, 0217, 0415, 0525, 0703, 0812, 0907, 1021, 1126, 1225

Thanks for those posts that showed how to make a template and rest sensor for the rainforestcloud API. I was able to condense that into just 1 sensor, if anyone else was interested

  - platform: rest
    name: Energy Instant Demand
    resource: 'https://rainforestcloud.com:9445/cgi-bin/post_manager'
    method: POST
    payload: '{ <Command><Name>get_instantaneous_demand</Name><Format>JSON</Format></Command> }'
    headers:
      Content-Type: application/json
      Cloud-ID: XXXXXX
      User: XXXXX
      Password: XXXXX
    value_template: >
      {% if value_json.InstantaneousDemand.Demand | length > 0 %}
        {{value_json.InstantaneousDemand.Demand | int(value_json.InstantaneousDemand.Demand, 16)/1000}}
      {% endif %}
    force_update: true
    unit_of_measurement: 'kW'
    device_class: 'power'
    scan_interval: 300
1 Like

@veep60 I tried to use this idea on the price function to get the current price from the utility, but it did not work. Have you had any luck with this?

@poldim the price comes as one of the XML replies from the meter, although your meter may not transmit it. If you do a TCPDUMP on the receiving side (what your eagle sends to) you should see price data. run tcpump -i any port <whatever> -A. and record the output, look for XML blocks of data.

I have the older Rainforest Raven USB device. It doesnt have any cloud connection, it just spits out the same XML data that the Eagle does in XML mode on the serial port it is plugged into every 4 seconds for power data and 40 seconds for energy data. I have had it plugged into a Raspberry Pi that is running a python script that processes the output and updates emoncms and pvoutput for me. How do I get this talking to HA and what is the best way? I am happy to dump emoncms if HA can do all the same things, but would like to keep the pvoutput going.

Same here, thanks for this hack, it works great. Somebody should update the Eagle plugin to use this endpoint instead.

Does anyone know if it is possible to get this running in portainer? I’ve been trying to add the command args but just can’t seem to get my head around it. Thanks.

what have you tried and what’s not working?

Hi Poldim, thanks, on reflection my question was not the best;

I’ve tried running it without any command arguments and get this in the log:

Traceback (most recent call last):
File “/app/src/bin/tHome-eagle.py”, line 114, in
client = T.broker.connect( c.configDir, log )
File “/app/src/python/tHome/broker/connect.py”, line 37, in connect
client.connect( cfg.host, cfg.port, cfg.keepAlive )
File “/usr/local/lib/python3.9/site-packages/paho/mqtt/client.py”, line 941, in connect
return self.reconnect()
File “/usr/local/lib/python3.9/site-packages/paho/mqtt/client.py”, line 1075, in reconnect
sock = self._create_socket_connection()
File “/usr/local/lib/python3.9/site-packages/paho/mqtt/client.py”, line 3546, in _create_socket_connection
return socket.create_connection(addr, source_address=source, timeout=self._keepalive)
File “/usr/local/lib/python3.9/socket.py”, line 843, in create_connection
raise err
File “/usr/local/lib/python3.9/socket.py”, line 831, in create_connection
sock.connect(sa)
socket.timeout: timed out

So then I’ve tried to add arguments:

but I get this error in the logs:
usage: /app/src/bin/tHome-eagle.py [-h] [-c configDir] [-l logFile]
/app/src/bin/tHome-eagle.py: error: unrecognized arguments: -e “MQTT_BROKER_IP=192.168.68.111”

I know enough to know I’m doing something wrong, but don’t know nearly enough to figure out what to do.
Thanks for any help.

Hi all again, for anyone else who is as much of a noob as me, here is how I got evan’s to wotk with Portainer:

In ‘Duplicate/Edit’ (dont know if this is needed)


under the ‘Env’ tab:

On the rainforestcloud web page added a new location;
Select Destination: Custom
Label: HomeAssistant
Protocol: HTTP
Hostname: 192.168.68.111 ← my mqtt address
URL: /
Port: 22042
Username: blank
Password: blank
Format: XML Raw

Hopefully this will help someone else :slight_smile:

Anyone on this thread using Rainforest Eagle in TX? I have a smart meter and my provider is Veterans through ONCOR. I would like to plug into the system and see what my usage is like. This is the message on the sellers website Oncor: Does not support new device connections as of Dec 8, 2019. Customers that connected prior to that date can get support at: [email protected], but since it’s a few years old I want to what others were doing.

I’m new to HA but have had a RF Eagle 100 for years. I just added it to my first HA install and noticed it going offline. I have my Eagle 100 connected to Wattvision but I’d love to also connect it reliably to HA. What are the steps I need to do to get it all working? I’ve reviewed all the steps over the years of posts and could use some help on the basics of what is needed for the Eagle to post to the HA.