Monitoring your Ethereum 2.0 Validator with Beaconchain.in

WARNING: Something changed, this puppy doesn’t work anymore.

So I took the plunge and staked 32ETH to run a proof-of-stake validator on a Raspberry Pi 4 8GB machine running Ubuntu 20.04. That’s locked up 32 ETH for two years but in exchange for keeping that machine up and running, I earn ETH on a sliding scale depending on how many validators are running. The value of that ETH fluctuates with the price of Ethereum. I need to keep my eye on that validator to make sure it’s running all the time, and I get a kick out of knowing how much I’m making in my sleep, so I want the status and the balance of my validator to be ready to hand in my Home Assistant dashboard.

There’s a great website, Beaconchain.in, where you can monitor your validator’s performance and use a REST API to grab a bunch of info on your validator’s status, your ETH balance, and many more details. When you set up on Beaconchain.in, you associate your validator with the ETH address that funded it: below.

One useful query is this:

https://beaconcha.in/api/v1/validator/<ETHADDR>/performance

Which yields something like the following JSON:

{
  "status": "OK",
  "data": {
    "balance": 32119989791,
    "performance1d": 18433321,
    "performance31d": 119989791,
    "performance365d": 119989791,
    "performance7d": 114388393,
    "validatorindex": XXXX
  }
}

Now, I’d love to know how to parse those 1 Day, 31 Day, and 365 Day performance numbers, but I can’t find any documentation on how to do that. (Add comments if you know!) But I do want two things: That OK status which says my validator is online and attesting, and the balance. (I also monitor the hardware health directly with Glances, but there are plenty of other good tutorials on how to do that).

So this is what goes in my configuration.yaml:

sensor: 
  - platform: rest
    resource: https://beaconcha.in/api/v1/validator/<ETHADDR>/performance 
    name: Beacon 
    value_template: "{{ value_json.data.balance }}"
    unit_of_measurement: "ETH"
    scan_interval:
      minutes: 15
    json_attributes:
      - data
      - status

That allows me to monitor the balance in a graph card and display the OK status on an image card:

          - type: sensor
            entity: sensor.validator_balance
            graph: line
          - type: picture-entity
            entity: sensor.validator_status

Which look like this:
Screenshot 2020-12-08 at 22.11.19

Screenshot 2020-12-08 at 22.11.35

But that’s not really a complete picture. I want to know how much my initial investment has grown. So I want to know how much ETH I’ve earned since staking my initial 32 ETH, I want to know how much that’s worth in USD at the current market price, and I want to deduct the cost of my initial investment, i.e. the ETH I staked at the market price in November 2020 when I plunked it down. That requires a currency converter, which I get from coinbase. You can follow the coinbase integration instructions here which will give you a sensor.eth_exchange_rate to report the USD value of ETH.

What follows is the result of a half hour’s work tweaking template variables and syntax to deliver my data just so:

      stakedethprofit:
        friendly_name: 'ETH Staking Profit'
        unit_of_measurement: 'U$D'
        value_template: "{{((state_attr('sensor.beacon', 'data').balance | float * states.sensor.eth_exchange_rate.state | int /1000000000) - 15432) | round(2) }}"

In plain english, that value_template says get the JSON value for the current balance of my validator and render it as a floating-point number. Multiply it times the value of the ETH to USD exchange rate extracted from the coinbase sensor and show me the result rendered as an integer divided by a one followed by enough zeros to make the damn thing look right. Now subtract the value of the ETH in USD that I staked at its value in November (15,432 USD) and round the result to two decimal points.

And that, rendered as a graph card, looks like this:

Screenshot 2020-12-08 at 22.30.14

That is all.

4 Likes

Hi Brian
Thank you for this nice little guide
Last weekend we did the same :love_you_gesture:

May I ask how you get from

''balance": 32119989791, to the sensor showing the correct 32.1…

I see the sensors name is not the sensor.beacon but sensor.validator_balance

Regard
Max

FYI the “status” in the API response I think is just the status of the reply itself (i.e. HTTP 200, 404, 503, etc.) and not the status of the validator. If you put in a non-existent validator key, it sill returns “OK”.

Doh, right you are.

Hi Max,
I did it like this:

        value_template: "{{(state_attr('sensor.beacon', 'data').balance | float * states.sensor.eth_exchange_rate.state | int /1000000000) | round(2)}}"

I believe something has changed some weeks ago, didn’t it?
I used to have this working, but now I don’t get any data from the sensor anymore. I think something might have changed with how json data is handled…?
It was working for months, until it just didn’t anymore.

Hello my friend,

I make a adjust on yaml file and i think this solve your problem to.
One tip is create e rest.yaml file if you want make your configuration.yaml keep organized

In configuration.yaml

rest: !include rest.yaml

==
In rest.yaml File

rest:
  - authentication: basic
    scan_interval: 15
    resource: https://beaconcha.in/api/v1/validator/<ADDRESS_VALIDATOR>
    method: GET
    sensor:
      - name: "Beacon-Status"
        unique_id: beacon_status
        value_template: >-
          {% if value_json.data.status == 'active_online' %}
            ONLINE
          {% else %}
            OFFLINE
          {% endif %}

And i make automations to alert me on chage status.
You can get “balance”, “withdraws” and another informations if you want.

I hope help you.

1 Like

Thank you, friend!!! I had to tweak it slightly to go into my sensor: block, but it works a treat!

- platform: rest
  authentication: basic
  scan_interval: 15
  resource: https://beaconcha.in/api/v1/validator/<Public Key>
  method: GET
  name: "Beacon-Status"
  unique_id: beacon_status
  value_template: "{% if value_json.data.status == 'active_online' %} ONLINE 😀 {% else %} OFFLINE 🥵 {% endif %}"